From 28f693a681b303d815623ab65065dbddf511e3de Mon Sep 17 00:00:00 2001 From: Patrick Stewart Date: Tue, 12 Nov 2024 01:00:05 -0700 Subject: [PATCH] gitflow-feature-stash: pstewart-refactor --- .melos/base.yaml | 1 + docs/.gitignore | 77 + docs/CHANGELOG.md | 163 ++ docs/CONTRIBUTING.md | 280 ++++ docs/README.md | 271 +++ docs/assets/README.md | 231 +++ docs/assets/diagrams/architecture/README.md | 187 +++ .../diagrams/architecture/system_overview.mmd | 105 ++ docs/assets/diagrams/flows/README.md | 625 +++++++ .../diagrams/flows/event_processing.mmd | 112 ++ .../assets/diagrams/flows/model_lifecycle.mmd | 161 ++ .../diagrams/flows/queue_processing.mmd | 119 ++ .../diagrams/flows/request_lifecycle.mmd | 98 ++ docs/bus_gap_analysis.md | 303 ++++ docs/bus_package_specification.md | 424 +++++ docs/config_gap_analysis.md | 335 ++++ docs/config_package_specification.md | 451 +++++ docs/container_feature_integration.md | 379 +++++ docs/container_gap_analysis.md | 261 +++ docs/container_migration_guide.md | 452 +++++ docs/container_package_specification.md | 77 + docs/contracts_package_specification.md | 448 +++++ docs/core_architecture.md | 309 ++++ docs/core_package_specification.md | 556 +++++++ docs/events_gap_analysis.md | 295 ++++ docs/events_package_specification.md | 453 +++++ docs/filesystem_gap_analysis.md | 349 ++++ docs/filesystem_package_specification.md | 554 +++++++ docs/foundation_integration_guide.md | 316 ++++ docs/getting_started.md | 142 ++ docs/index.md | 234 +++ docs/laravel_compatibility_roadmap.md | 251 +++ docs/model_gap_analysis.md | 316 ++++ docs/model_package_specification.md | 486 ++++++ docs/package_integration_map.md | 540 ++++++ docs/pipeline_gap_analysis.md | 316 ++++ docs/pipeline_package_specification.md | 408 +++++ docs/process_gap_analysis.md | 299 ++++ docs/process_package_specification.md | 408 +++++ docs/queue_gap_analysis.md | 301 ++++ docs/queue_package_specification.md | 623 +++++++ docs/route_gap_analysis.md | 295 ++++ docs/route_package_specification.md | 550 ++++++ docs/support_package_specification.md | 436 +++++ docs/testing.md | 10 - docs/testing_gap_analysis.md | 312 ++++ docs/testing_guide.md | 343 ++++ docs/testing_package_specification.md | 466 ++++++ melos.yaml | 1 + packages/bus/.gitignore | 7 + packages/bus/CHANGELOG.md | 3 + packages/bus/LICENSE.md | 10 + packages/bus/README.md | 1 + packages/bus/analysis_options.yaml | 30 + packages/bus/lib/angel3_bus.dart | 9 + packages/bus/lib/src/batch.dart | 19 + .../bus/lib/src/bus_service_provider.dart | 60 + packages/bus/lib/src/chain.dart | 15 + packages/bus/lib/src/command.dart | 5 + packages/bus/lib/src/dispatcher.dart | 251 +++ packages/bus/lib/src/handler.dart | 5 + packages/bus/lib/src/queue.dart | 8 + packages/bus/pubspec.yaml | 24 + packages/bus/test/dispatcher_test.dart | 197 +++ packages/events/.gitignore | 7 + packages/events/CHANGELOG.md | 3 + packages/events/LICENSE.md | 10 + packages/events/README.md | 1 + packages/events/analysis_options.yaml | 30 + packages/events/lib/dispatcher.dart | 3 + packages/events/lib/src/dispatcher.dart | 499 ++++++ packages/events/pubspec.yaml | 21 + packages/events/test/event_test.dart | 430 +++++ packages/pipeline/.gitignore | 7 + packages/pipeline/CHANGELOG.md | 3 + packages/pipeline/LICENSE.md | 10 + packages/pipeline/README.md | 380 +++++ packages/pipeline/analysis_options.yaml | 30 + .../pipeline/examples/async_pipeline.dart | 38 + packages/pipeline/examples/basic_usage.dart | 36 + .../pipeline/examples/error_handling.dart | 34 + packages/pipeline/examples/mixed_pipes.dart | 35 + packages/pipeline/lib/pipeline.dart | 5 + packages/pipeline/lib/src/conditionable.dart | 16 + packages/pipeline/lib/src/pipeline.dart | 241 +++ .../pipeline/lib/src/pipeline_contract.dart | 9 + packages/pipeline/pubspec.yaml | 19 + .../pipeline/test/laravel_pipeline_test.dart | 258 +++ packages/pipeline/test/pipeline_test.dart | 106 ++ packages/process/.gitignore | 7 + packages/process/CHANGELOG.md | 3 + packages/process/LICENSE.md | 10 + packages/process/README.md | 1 + packages/process/analysis_options.yaml | 30 + .../process/examples/basic_process/main.dart | 36 + .../examples/process_pipeline/main.dart | 37 + .../process/examples/process_pool/main.dart | 37 + .../web_server_with_processes/main.dart | 67 + .../views/index.mustache | 39 + packages/process/lib/angel3_process.dart | 7 + packages/process/lib/src/process.dart | 250 +++ packages/process/lib/src/process_helper.dart | 21 + packages/process/lib/src/process_manager.dart | 148 ++ .../process/lib/src/process_pipeline.dart | 50 + packages/process/lib/src/process_pool.dart | 62 + .../lib/src/process_service_provider.dart | 24 + packages/process/pubspec.yaml | 25 + packages/process/test/process_test.dart | 80 + .../process/test/process_test_extended.dart | 102 ++ packages/queue/.gitignore | 10 + packages/queue/CHANGELOG.md | 3 + packages/queue/LICENSE.md | 10 + packages/queue/README.md | 1 + packages/queue/analysis_options.yaml | 30 + packages/queue/lib/queue.dart | 75 + packages/queue/lib/src/job_queued_event.dart | 70 + .../queue/lib/src/job_queueing_event.dart | 72 + packages/queue/lib/src/queue.dart | 396 +++++ .../queue/lib/src/should_be_encrypted.dart | 18 + .../lib/src/should_queue_after_commit.dart | 22 + packages/queue/pubspec.yaml | 25 + packages/queue/test/queue_test.dart | 317 ++++ .../example/service_provider_example.dart | 67 + packages/support/lib/providers.dart | 6 + .../providers/contracts/service_provider.dart | 30 + .../providers/deferred_service_provider.dart | 20 + .../support/lib/src/providers/providers.dart | 11 + .../lib/src/providers/service_provider.dart | 271 +++ .../providers/service_provider_static.dart | 11 + .../providers/service_provider_support.dart | 87 + packages/support/pubspec.yaml | 11 +- .../support/test/providers_http_test.dart | 129 ++ packages/support/test/providers_test.dart | 236 +++ sandbox/eventbus/.github/workflows/dart.yml | 54 + sandbox/eventbus/.gitignore | 30 + sandbox/eventbus/.metadata | 10 + sandbox/eventbus/.vscode/settings.json | 7 + sandbox/eventbus/CHANGELOG.md | 67 + sandbox/eventbus/LICENSE | 21 + sandbox/eventbus/README.md | 98 ++ sandbox/eventbus/analysis_options.yaml | 224 +++ sandbox/eventbus/doc/pub_sub.webp | Bin 0 -> 16548 bytes sandbox/eventbus/doc/video_presentation.gif | Bin 0 -> 1887898 bytes sandbox/eventbus/lib/event_bus.dart | 3 + sandbox/eventbus/lib/res/app_event.dart | 29 + sandbox/eventbus/lib/res/event_bus.dart | 212 +++ sandbox/eventbus/lib/res/history_entry.dart | 18 + sandbox/eventbus/lib/res/res.dart | 4 + sandbox/eventbus/lib/res/subscription.dart | 78 + sandbox/eventbus/pubspec.yaml | 20 + sandbox/eventbus/test/completion_test.dart | 70 + sandbox/eventbus/test/distinct_test.dart | 58 + sandbox/eventbus/test/empty_event_test.dart | 20 + sandbox/eventbus/test/event_bus_test.dart | 63 + sandbox/eventbus/test/history_test.dart | 75 + .../test/mapping/map_ignore_test.dart | 36 + sandbox/eventbus/test/mapping/map_test.dart | 34 + sandbox/eventbus/test/models.dart | 42 + sandbox/eventbus/test/respond_test.dart | 74 + sandbox/eventbus/test/streams_test.dart | 56 + sandbox/eventbus/test/timestamp_test.dart | 36 + sandbox/eventbus/tool/coverage.sh | 13 + sandbox/mqueue/.github/workflows/action.yaml | 43 + sandbox/mqueue/.gitignore | 7 + sandbox/mqueue/CHANGELOG.md | 19 + sandbox/mqueue/LICENSE | 21 + sandbox/mqueue/README.md | 165 ++ sandbox/mqueue/analysis_options.yaml | 211 +++ sandbox/mqueue/assets/components-mq.png | Bin 0 -> 94259 bytes sandbox/mqueue/assets/components.png | Bin 0 -> 30338 bytes sandbox/mqueue/assets/default-exchange.png | Bin 0 -> 24526 bytes sandbox/mqueue/assets/detailed-view.png | Bin 0 -> 138254 bytes sandbox/mqueue/assets/direct-exchange.png | Bin 0 -> 42545 bytes sandbox/mqueue/assets/fanout-exchange.png | Bin 0 -> 26191 bytes sandbox/mqueue/assets/simple-view.png | Bin 0 -> 36356 bytes sandbox/mqueue/example/main.dart | 16 + .../example/message_filtering/main.dart | 27 + .../message_filtering/task_manager.dart | 12 + .../example/message_filtering/worker_one.dart | 22 + .../example/message_filtering/worker_two.dart | 24 + sandbox/mqueue/example/receiver.dart | 18 + .../mqueue/example/routing/debug_logger.dart | 39 + sandbox/mqueue/example/routing/logger.dart | 21 + sandbox/mqueue/example/routing/main.dart | 30 + .../example/routing/production_logger.dart | 29 + sandbox/mqueue/example/rpc/main.dart | 19 + sandbox/mqueue/example/rpc/service_one.dart | 19 + sandbox/mqueue/example/rpc/service_two.dart | 46 + sandbox/mqueue/example/sender.dart | 12 + sandbox/mqueue/lib/mq.dart | 11 + sandbox/mqueue/lib/src/binding/binding.dart | 75 + .../lib/src/binding/binding.interface.dart | 44 + sandbox/mqueue/lib/src/consumer/consumer.dart | 95 ++ .../lib/src/consumer/consumer.interface.dart | 74 + .../lib/src/consumer/consumer.mixin.dart | 92 + .../mqueue/lib/src/core/constants/enums.dart | 22 + .../lib/src/core/constants/error_strings.dart | 99 ++ .../core/exceptions/binding_exceptions.dart | 42 + .../core/exceptions/consumer_exceptions.dart | 73 + .../lib/src/core/exceptions/exceptions.dart | 7 + .../core/exceptions/exchange_exceptions.dart | 44 + .../core/exceptions/mq_client_exceptions.dart | 31 + .../src/core/exceptions/queue_exceptions.dart | 54 + .../core/exceptions/registrar_exceptions.dart | 43 + .../exceptions/routing_key_exceptions.dart | 30 + .../src/core/registrar/simple_registrar.dart | 100 ++ .../lib/src/exchange/default_exchange.dart | 86 + .../lib/src/exchange/direct_exchange.dart | 89 + .../lib/src/exchange/exchange.base.dart | 27 + .../lib/src/exchange/exchange_interface.dart | 51 + .../lib/src/exchange/fanout_exchange.dart | 70 + .../mqueue/lib/src/message/message.base.dart | 43 + sandbox/mqueue/lib/src/message/message.dart | 86 + sandbox/mqueue/lib/src/mq/mq.base.dart | 14 + sandbox/mqueue/lib/src/mq/mq.dart | 256 +++ sandbox/mqueue/lib/src/mq/mq.interface.dart | 115 ++ sandbox/mqueue/lib/src/producer/producer.dart | 91 + .../lib/src/producer/producer.interface.dart | 56 + .../lib/src/producer/producer.mixin.dart | 90 + .../lib/src/queue/data_stream.base.dart | 54 + sandbox/mqueue/lib/src/queue/queue.dart | 60 + sandbox/mqueue/pubspec.yaml | 18 + sandbox/mqueue/test/binding/binding_test.dart | 97 ++ .../mqueue/test/consumer/consumer_test.dart | 333 ++++ .../exceptions/binding_exceptions_test.dart | 24 + .../exceptions/consumer_exceptions_test.dart | 60 + .../exceptions/exchange_exceptions_test.dart | 21 + .../exceptions/mq_client_exceptions_test.dart | 17 + .../exceptions/queue_exceptions_test.dart | 30 + .../exceptions/registrar_exceptions_test.dart | 25 + .../routing_key_exceptionss_test.dart | 12 + .../core/registrar/simple_registrar_test.dart | 105 ++ .../test/exchange/default_exchange_test.dart | 79 + .../test/exchange/direct_exchange_test.dart | 88 + .../test/exchange/fanout_exchange_test.dart | 69 + .../test/message/message.base_test.dart | 59 + sandbox/mqueue/test/mq/mq_test.dart | 342 ++++ .../mqueue/test/producer/producer_test.dart | 111 ++ sandbox/mqueue/test/queue/queue_test.dart | 98 ++ sandbox/reactivex/.gitignore | 30 + sandbox/reactivex/CHANGELOG.md | 775 +++++++++ sandbox/reactivex/LICENSE | 201 +++ sandbox/reactivex/README.md | 277 ++++ sandbox/reactivex/analysis_options.yaml | 15 + sandbox/reactivex/lib/angel3_reactivex.dart | 7 + sandbox/reactivex/lib/src/rx.dart | 1357 +++++++++++++++ .../lib/src/streams/combine_latest.dart | 352 ++++ sandbox/reactivex/lib/src/streams/concat.dart | 75 + .../lib/src/streams/concat_eager.dart | 88 + .../lib/src/streams/connectable_stream.dart | 516 ++++++ sandbox/reactivex/lib/src/streams/defer.dart | 57 + .../reactivex/lib/src/streams/fork_join.dart | 366 ++++ .../lib/src/streams/from_callable.dart | 67 + sandbox/reactivex/lib/src/streams/merge.dart | 74 + sandbox/reactivex/lib/src/streams/never.dart | 31 + sandbox/reactivex/lib/src/streams/race.dart | 70 + sandbox/reactivex/lib/src/streams/range.dart | 41 + sandbox/reactivex/lib/src/streams/repeat.dart | 78 + .../lib/src/streams/replay_stream.dart | 26 + sandbox/reactivex/lib/src/streams/retry.dart | 89 + .../reactivex/lib/src/streams/retry_when.dart | 142 ++ .../lib/src/streams/sequence_equal.dart | 95 ++ .../lib/src/streams/switch_latest.dart | 99 ++ sandbox/reactivex/lib/src/streams/timer.dart | 69 + sandbox/reactivex/lib/src/streams/using.dart | 107 ++ .../lib/src/streams/value_stream.dart | 97 ++ sandbox/reactivex/lib/src/streams/zip.dart | 388 +++++ .../lib/src/subjects/behavior_subject.dart | 275 +++ .../lib/src/subjects/publish_subject.dart | 51 + .../lib/src/subjects/replay_subject.dart | 204 +++ .../reactivex/lib/src/subjects/subject.dart | 231 +++ .../backpressure/backpressure.dart | 357 ++++ .../src/transformers/backpressure/buffer.dart | 149 ++ .../transformers/backpressure/debounce.dart | 85 + .../transformers/backpressure/pairwise.dart | 35 + .../src/transformers/backpressure/sample.dart | 50 + .../transformers/backpressure/throttle.dart | 79 + .../src/transformers/backpressure/window.dart | 158 ++ .../src/transformers/default_if_empty.dart | 60 + .../reactivex/lib/src/transformers/delay.dart | 98 ++ .../lib/src/transformers/delay_when.dart | 171 ++ .../lib/src/transformers/dematerialize.dart | 81 + .../lib/src/transformers/distinct_unique.dart | 92 + .../reactivex/lib/src/transformers/do.dart | 305 ++++ .../lib/src/transformers/end_with.dart | 52 + .../lib/src/transformers/end_with_many.dart | 52 + .../lib/src/transformers/exhaust_map.dart | 113 ++ .../lib/src/transformers/flat_map.dart | 148 ++ .../lib/src/transformers/group_by.dart | 157 ++ .../lib/src/transformers/ignore_elements.dart | 61 + .../lib/src/transformers/interval.dart | 91 + .../lib/src/transformers/map_not_null.dart | 75 + .../lib/src/transformers/map_to.dart | 52 + .../lib/src/transformers/materialize.dart | 68 + .../reactivex/lib/src/transformers/max.dart | 25 + .../reactivex/lib/src/transformers/min.dart | 27 + .../lib/src/transformers/on_error_resume.dart | 181 ++ .../reactivex/lib/src/transformers/scan.dart | 62 + .../lib/src/transformers/skip_last.dart | 79 + .../lib/src/transformers/skip_until.dart | 82 + .../lib/src/transformers/start_with.dart | 65 + .../src/transformers/start_with_error.dart | 57 + .../lib/src/transformers/start_with_many.dart | 66 + .../lib/src/transformers/switch_if_empty.dart | 119 ++ .../lib/src/transformers/switch_map.dart | 155 ++ .../lib/src/transformers/take_last.dart | 83 + .../lib/src/transformers/take_until.dart | 80 + .../transformers/take_while_inclusive.dart | 74 + .../lib/src/transformers/time_interval.dart | 111 ++ .../lib/src/transformers/timestamp.dart | 87 + .../lib/src/transformers/where_not_null.dart | 65 + .../lib/src/transformers/where_type.dart | 71 + .../src/transformers/with_latest_from.dart | 738 +++++++++ .../lib/src/utils/collection_extensions.dart | 65 + .../lib/src/utils/composite_subscription.dart | 121 ++ sandbox/reactivex/lib/src/utils/empty.dart | 18 + .../lib/src/utils/error_and_stacktrace.dart | 28 + .../lib/src/utils/forwarding_sink.dart | 82 + .../lib/src/utils/forwarding_stream.dart | 165 ++ sandbox/reactivex/lib/src/utils/future.dart | 25 + sandbox/reactivex/lib/src/utils/min_max.dart | 76 + .../reactivex/lib/src/utils/notification.dart | 169 ++ .../reactivex/lib/src/utils/subscription.dart | 34 + sandbox/reactivex/lib/streams.dart | 23 + sandbox/reactivex/lib/subjects.dart | 6 + sandbox/reactivex/lib/transformers.dart | 42 + sandbox/reactivex/lib/utils.dart | 5 + sandbox/reactivex/pubspec.yaml | 25 + sandbox/reactivex/screenshots/logo.png | Bin 0 -> 54748 bytes sandbox/reactivex/test/rxdart_test.dart | 187 +++ .../test/streams/combine_latest_test.dart | 394 +++++ .../test/streams/concat_eager_test.dart | 185 +++ .../reactivex/test/streams/concat_test.dart | 136 ++ .../reactivex/test/streams/defer_test.dart | 128 ++ .../test/streams/fork_join_test.dart | 452 +++++ .../test/streams/from_callable_test.dart | 130 ++ .../reactivex/test/streams/merge_test.dart | 92 + .../reactivex/test/streams/never_test.dart | 67 + .../publish_connectable_stream_test.dart | 164 ++ sandbox/reactivex/test/streams/race_test.dart | 136 ++ .../reactivex/test/streams/range_test.dart | 52 + .../reactivex/test/streams/repeat_test.dart | 99 ++ .../replay_connectable_stream_test.dart | 229 +++ .../reactivex/test/streams/retry_test.dart | 142 ++ .../test/streams/retry_when_test.dart | 224 +++ .../test/streams/sequence_equals_test.dart | 112 ++ .../test/streams/switch_latest_test.dart | 88 + .../reactivex/test/streams/timer_test.dart | 140 ++ .../reactivex/test/streams/using_test.dart | 378 +++++ .../value_connectable_stream_test.dart | 295 ++++ sandbox/reactivex/test/streams/zip_test.dart | 395 +++++ .../test/subject/behavior_subject_test.dart | 1475 +++++++++++++++++ .../test/subject/publish_subject_test.dart | 323 ++++ .../test/subject/replay_subject_test.dart | 478 ++++++ .../backpressure/buffer_count_test.dart | 125 ++ .../backpressure/buffer_test.dart | 118 ++ .../backpressure/buffer_test_test.dart | 67 + .../backpressure/buffer_time_test.dart | 96 ++ .../backpressure/debounce_test.dart | 145 ++ .../backpressure/debounce_time_test.dart | 126 ++ .../backpressure/pairwise_test.dart | 78 + .../backpressure/sample_test.dart | 109 ++ .../backpressure/sample_time_test.dart | 99 ++ .../backpressure/throttle_test.dart | 160 ++ .../backpressure/throttle_time_test.dart | 102 ++ .../backpressure/window_count_test.dart | 125 ++ .../backpressure/window_test.dart | 123 ++ .../backpressure/window_test_test.dart | 67 + .../backpressure/window_time_test.dart | 99 ++ .../test/transformers/concat_with_test.dart | 39 + .../transformers/default_if_empty_test.dart | 88 + .../test/transformers/delay_test.dart | 127 ++ .../test/transformers/delay_when_test.dart | 280 ++++ .../test/transformers/dematerialize_test.dart | 105 ++ .../test/transformers/distinct_test.dart | 25 + .../transformers/distinct_unique_test.dart | 157 ++ .../reactivex/test/transformers/do_test.dart | 489 ++++++ .../test/transformers/end_with_many_test.dart | 78 + .../test/transformers/end_with_test.dart | 76 + .../test/transformers/exhaust_map_test.dart | 110 ++ .../transformers/flat_map_iterable_test.dart | 35 + .../test/transformers/flat_map_test.dart | 267 +++ .../test/transformers/group_by_test.dart | 312 ++++ .../transformers/ignore_elements_test.dart | 126 ++ .../test/transformers/interval_test.dart | 87 + .../test/transformers/join_test.dart | 11 + .../test/transformers/map_not_null_test.dart | 100 ++ .../test/transformers/map_to_test.dart | 67 + .../test/transformers/materialize_test.dart | 99 ++ .../reactivex/test/transformers/max_test.dart | 124 ++ .../test/transformers/merge_with_test.dart | 62 + .../reactivex/test/transformers/min_test.dart | 117 ++ .../transformers/on_error_resume_test.dart | 209 +++ .../transformers/on_error_return_test.dart | 80 + .../on_error_return_with_test.dart | 82 + .../test/transformers/scan_test.dart | 85 + .../test/transformers/skip_last_test.dart | 110 ++ .../test/transformers/skip_until_test.dart | 130 ++ .../transformers/start_with_error_test.dart | 86 + .../transformers/start_with_many_test.dart | 87 + .../test/transformers/start_with_test.dart | 102 ++ .../transformers/switch_if_empty_test.dart | 96 ++ .../test/transformers/switch_map_test.dart | 359 ++++ .../test/transformers/take_last_test.dart | 109 ++ .../test/transformers/take_until_test.dart | 120 ++ .../take_while_inclusive_test.dart | 92 + .../test/transformers/time_interval_test.dart | 112 ++ .../test/transformers/timeout_test.dart | 19 + .../test/transformers/timestamp_test.dart | 105 ++ .../transformers/where_not_null_test.dart | 87 + .../test/transformers/where_type_test.dart | 94 ++ .../transformers/with_latest_from_test.dart | 541 ++++++ .../test/transformers/zip_with_test.dart | 63 + sandbox/reactivex/test/utils.dart | 25 + .../utils/composite_subscription_test.dart | 316 ++++ .../test/utils/notification_test.dart | 234 +++ 416 files changed, 53433 insertions(+), 13 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/CHANGELOG.md create mode 100644 docs/CONTRIBUTING.md create mode 100644 docs/README.md create mode 100644 docs/assets/README.md create mode 100644 docs/assets/diagrams/architecture/README.md create mode 100644 docs/assets/diagrams/architecture/system_overview.mmd create mode 100644 docs/assets/diagrams/flows/README.md create mode 100644 docs/assets/diagrams/flows/event_processing.mmd create mode 100644 docs/assets/diagrams/flows/model_lifecycle.mmd create mode 100644 docs/assets/diagrams/flows/queue_processing.mmd create mode 100644 docs/assets/diagrams/flows/request_lifecycle.mmd create mode 100644 docs/bus_gap_analysis.md create mode 100644 docs/bus_package_specification.md create mode 100644 docs/config_gap_analysis.md create mode 100644 docs/config_package_specification.md create mode 100644 docs/container_feature_integration.md create mode 100644 docs/container_gap_analysis.md create mode 100644 docs/container_migration_guide.md create mode 100644 docs/container_package_specification.md create mode 100644 docs/contracts_package_specification.md create mode 100644 docs/core_architecture.md create mode 100644 docs/core_package_specification.md create mode 100644 docs/events_gap_analysis.md create mode 100644 docs/events_package_specification.md create mode 100644 docs/filesystem_gap_analysis.md create mode 100644 docs/filesystem_package_specification.md create mode 100644 docs/foundation_integration_guide.md create mode 100644 docs/getting_started.md create mode 100644 docs/index.md create mode 100644 docs/laravel_compatibility_roadmap.md create mode 100644 docs/model_gap_analysis.md create mode 100644 docs/model_package_specification.md create mode 100644 docs/package_integration_map.md create mode 100644 docs/pipeline_gap_analysis.md create mode 100644 docs/pipeline_package_specification.md create mode 100644 docs/process_gap_analysis.md create mode 100644 docs/process_package_specification.md create mode 100644 docs/queue_gap_analysis.md create mode 100644 docs/queue_package_specification.md create mode 100644 docs/route_gap_analysis.md create mode 100644 docs/route_package_specification.md create mode 100644 docs/support_package_specification.md delete mode 100644 docs/testing.md create mode 100644 docs/testing_gap_analysis.md create mode 100644 docs/testing_guide.md create mode 100644 docs/testing_package_specification.md create mode 100644 packages/bus/.gitignore create mode 100644 packages/bus/CHANGELOG.md create mode 100644 packages/bus/LICENSE.md create mode 100644 packages/bus/README.md create mode 100644 packages/bus/analysis_options.yaml create mode 100644 packages/bus/lib/angel3_bus.dart create mode 100644 packages/bus/lib/src/batch.dart create mode 100644 packages/bus/lib/src/bus_service_provider.dart create mode 100644 packages/bus/lib/src/chain.dart create mode 100644 packages/bus/lib/src/command.dart create mode 100644 packages/bus/lib/src/dispatcher.dart create mode 100644 packages/bus/lib/src/handler.dart create mode 100644 packages/bus/lib/src/queue.dart create mode 100644 packages/bus/pubspec.yaml create mode 100644 packages/bus/test/dispatcher_test.dart create mode 100644 packages/events/.gitignore create mode 100644 packages/events/CHANGELOG.md create mode 100644 packages/events/LICENSE.md create mode 100644 packages/events/README.md create mode 100644 packages/events/analysis_options.yaml create mode 100644 packages/events/lib/dispatcher.dart create mode 100644 packages/events/lib/src/dispatcher.dart create mode 100644 packages/events/pubspec.yaml create mode 100644 packages/events/test/event_test.dart create mode 100644 packages/pipeline/.gitignore create mode 100644 packages/pipeline/CHANGELOG.md create mode 100644 packages/pipeline/LICENSE.md create mode 100644 packages/pipeline/README.md create mode 100644 packages/pipeline/analysis_options.yaml create mode 100644 packages/pipeline/examples/async_pipeline.dart create mode 100644 packages/pipeline/examples/basic_usage.dart create mode 100644 packages/pipeline/examples/error_handling.dart create mode 100644 packages/pipeline/examples/mixed_pipes.dart create mode 100644 packages/pipeline/lib/pipeline.dart create mode 100644 packages/pipeline/lib/src/conditionable.dart create mode 100644 packages/pipeline/lib/src/pipeline.dart create mode 100644 packages/pipeline/lib/src/pipeline_contract.dart create mode 100644 packages/pipeline/pubspec.yaml create mode 100644 packages/pipeline/test/laravel_pipeline_test.dart create mode 100644 packages/pipeline/test/pipeline_test.dart create mode 100644 packages/process/.gitignore create mode 100644 packages/process/CHANGELOG.md create mode 100644 packages/process/LICENSE.md create mode 100644 packages/process/README.md create mode 100644 packages/process/analysis_options.yaml create mode 100644 packages/process/examples/basic_process/main.dart create mode 100644 packages/process/examples/process_pipeline/main.dart create mode 100644 packages/process/examples/process_pool/main.dart create mode 100644 packages/process/examples/web_server_with_processes/main.dart create mode 100644 packages/process/examples/web_server_with_processes/views/index.mustache create mode 100644 packages/process/lib/angel3_process.dart create mode 100644 packages/process/lib/src/process.dart create mode 100644 packages/process/lib/src/process_helper.dart create mode 100644 packages/process/lib/src/process_manager.dart create mode 100644 packages/process/lib/src/process_pipeline.dart create mode 100644 packages/process/lib/src/process_pool.dart create mode 100644 packages/process/lib/src/process_service_provider.dart create mode 100644 packages/process/pubspec.yaml create mode 100644 packages/process/test/process_test.dart create mode 100644 packages/process/test/process_test_extended.dart create mode 100644 packages/queue/.gitignore create mode 100644 packages/queue/CHANGELOG.md create mode 100644 packages/queue/LICENSE.md create mode 100644 packages/queue/README.md create mode 100644 packages/queue/analysis_options.yaml create mode 100644 packages/queue/lib/queue.dart create mode 100644 packages/queue/lib/src/job_queued_event.dart create mode 100644 packages/queue/lib/src/job_queueing_event.dart create mode 100644 packages/queue/lib/src/queue.dart create mode 100644 packages/queue/lib/src/should_be_encrypted.dart create mode 100644 packages/queue/lib/src/should_queue_after_commit.dart create mode 100644 packages/queue/pubspec.yaml create mode 100644 packages/queue/test/queue_test.dart create mode 100644 packages/support/example/service_provider_example.dart create mode 100644 packages/support/lib/providers.dart create mode 100644 packages/support/lib/src/providers/contracts/service_provider.dart create mode 100644 packages/support/lib/src/providers/deferred_service_provider.dart create mode 100644 packages/support/lib/src/providers/providers.dart create mode 100644 packages/support/lib/src/providers/service_provider.dart create mode 100644 packages/support/lib/src/providers/service_provider_static.dart create mode 100644 packages/support/lib/src/providers/service_provider_support.dart create mode 100644 packages/support/test/providers_http_test.dart create mode 100644 packages/support/test/providers_test.dart create mode 100644 sandbox/eventbus/.github/workflows/dart.yml create mode 100644 sandbox/eventbus/.gitignore create mode 100644 sandbox/eventbus/.metadata create mode 100644 sandbox/eventbus/.vscode/settings.json create mode 100644 sandbox/eventbus/CHANGELOG.md create mode 100644 sandbox/eventbus/LICENSE create mode 100644 sandbox/eventbus/README.md create mode 100644 sandbox/eventbus/analysis_options.yaml create mode 100644 sandbox/eventbus/doc/pub_sub.webp create mode 100644 sandbox/eventbus/doc/video_presentation.gif create mode 100644 sandbox/eventbus/lib/event_bus.dart create mode 100644 sandbox/eventbus/lib/res/app_event.dart create mode 100644 sandbox/eventbus/lib/res/event_bus.dart create mode 100644 sandbox/eventbus/lib/res/history_entry.dart create mode 100644 sandbox/eventbus/lib/res/res.dart create mode 100644 sandbox/eventbus/lib/res/subscription.dart create mode 100644 sandbox/eventbus/pubspec.yaml create mode 100644 sandbox/eventbus/test/completion_test.dart create mode 100644 sandbox/eventbus/test/distinct_test.dart create mode 100644 sandbox/eventbus/test/empty_event_test.dart create mode 100644 sandbox/eventbus/test/event_bus_test.dart create mode 100644 sandbox/eventbus/test/history_test.dart create mode 100644 sandbox/eventbus/test/mapping/map_ignore_test.dart create mode 100644 sandbox/eventbus/test/mapping/map_test.dart create mode 100644 sandbox/eventbus/test/models.dart create mode 100644 sandbox/eventbus/test/respond_test.dart create mode 100644 sandbox/eventbus/test/streams_test.dart create mode 100644 sandbox/eventbus/test/timestamp_test.dart create mode 100755 sandbox/eventbus/tool/coverage.sh create mode 100644 sandbox/mqueue/.github/workflows/action.yaml create mode 100644 sandbox/mqueue/.gitignore create mode 100644 sandbox/mqueue/CHANGELOG.md create mode 100644 sandbox/mqueue/LICENSE create mode 100644 sandbox/mqueue/README.md create mode 100644 sandbox/mqueue/analysis_options.yaml create mode 100644 sandbox/mqueue/assets/components-mq.png create mode 100644 sandbox/mqueue/assets/components.png create mode 100644 sandbox/mqueue/assets/default-exchange.png create mode 100644 sandbox/mqueue/assets/detailed-view.png create mode 100644 sandbox/mqueue/assets/direct-exchange.png create mode 100644 sandbox/mqueue/assets/fanout-exchange.png create mode 100644 sandbox/mqueue/assets/simple-view.png create mode 100644 sandbox/mqueue/example/main.dart create mode 100644 sandbox/mqueue/example/message_filtering/main.dart create mode 100644 sandbox/mqueue/example/message_filtering/task_manager.dart create mode 100644 sandbox/mqueue/example/message_filtering/worker_one.dart create mode 100644 sandbox/mqueue/example/message_filtering/worker_two.dart create mode 100644 sandbox/mqueue/example/receiver.dart create mode 100644 sandbox/mqueue/example/routing/debug_logger.dart create mode 100644 sandbox/mqueue/example/routing/logger.dart create mode 100644 sandbox/mqueue/example/routing/main.dart create mode 100644 sandbox/mqueue/example/routing/production_logger.dart create mode 100644 sandbox/mqueue/example/rpc/main.dart create mode 100644 sandbox/mqueue/example/rpc/service_one.dart create mode 100644 sandbox/mqueue/example/rpc/service_two.dart create mode 100644 sandbox/mqueue/example/sender.dart create mode 100644 sandbox/mqueue/lib/mq.dart create mode 100644 sandbox/mqueue/lib/src/binding/binding.dart create mode 100644 sandbox/mqueue/lib/src/binding/binding.interface.dart create mode 100644 sandbox/mqueue/lib/src/consumer/consumer.dart create mode 100644 sandbox/mqueue/lib/src/consumer/consumer.interface.dart create mode 100644 sandbox/mqueue/lib/src/consumer/consumer.mixin.dart create mode 100644 sandbox/mqueue/lib/src/core/constants/enums.dart create mode 100644 sandbox/mqueue/lib/src/core/constants/error_strings.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/binding_exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/consumer_exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/exchange_exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/mq_client_exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/queue_exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/registrar_exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/exceptions/routing_key_exceptions.dart create mode 100644 sandbox/mqueue/lib/src/core/registrar/simple_registrar.dart create mode 100644 sandbox/mqueue/lib/src/exchange/default_exchange.dart create mode 100644 sandbox/mqueue/lib/src/exchange/direct_exchange.dart create mode 100644 sandbox/mqueue/lib/src/exchange/exchange.base.dart create mode 100644 sandbox/mqueue/lib/src/exchange/exchange_interface.dart create mode 100644 sandbox/mqueue/lib/src/exchange/fanout_exchange.dart create mode 100644 sandbox/mqueue/lib/src/message/message.base.dart create mode 100644 sandbox/mqueue/lib/src/message/message.dart create mode 100644 sandbox/mqueue/lib/src/mq/mq.base.dart create mode 100644 sandbox/mqueue/lib/src/mq/mq.dart create mode 100644 sandbox/mqueue/lib/src/mq/mq.interface.dart create mode 100644 sandbox/mqueue/lib/src/producer/producer.dart create mode 100644 sandbox/mqueue/lib/src/producer/producer.interface.dart create mode 100644 sandbox/mqueue/lib/src/producer/producer.mixin.dart create mode 100644 sandbox/mqueue/lib/src/queue/data_stream.base.dart create mode 100644 sandbox/mqueue/lib/src/queue/queue.dart create mode 100644 sandbox/mqueue/pubspec.yaml create mode 100644 sandbox/mqueue/test/binding/binding_test.dart create mode 100644 sandbox/mqueue/test/consumer/consumer_test.dart create mode 100644 sandbox/mqueue/test/core/exceptions/binding_exceptions_test.dart create mode 100644 sandbox/mqueue/test/core/exceptions/consumer_exceptions_test.dart create mode 100644 sandbox/mqueue/test/core/exceptions/exchange_exceptions_test.dart create mode 100644 sandbox/mqueue/test/core/exceptions/mq_client_exceptions_test.dart create mode 100644 sandbox/mqueue/test/core/exceptions/queue_exceptions_test.dart create mode 100644 sandbox/mqueue/test/core/exceptions/registrar_exceptions_test.dart create mode 100644 sandbox/mqueue/test/core/exceptions/routing_key_exceptionss_test.dart create mode 100644 sandbox/mqueue/test/core/registrar/simple_registrar_test.dart create mode 100644 sandbox/mqueue/test/exchange/default_exchange_test.dart create mode 100644 sandbox/mqueue/test/exchange/direct_exchange_test.dart create mode 100644 sandbox/mqueue/test/exchange/fanout_exchange_test.dart create mode 100644 sandbox/mqueue/test/message/message.base_test.dart create mode 100644 sandbox/mqueue/test/mq/mq_test.dart create mode 100644 sandbox/mqueue/test/producer/producer_test.dart create mode 100644 sandbox/mqueue/test/queue/queue_test.dart create mode 100644 sandbox/reactivex/.gitignore create mode 100644 sandbox/reactivex/CHANGELOG.md create mode 100644 sandbox/reactivex/LICENSE create mode 100644 sandbox/reactivex/README.md create mode 100644 sandbox/reactivex/analysis_options.yaml create mode 100644 sandbox/reactivex/lib/angel3_reactivex.dart create mode 100644 sandbox/reactivex/lib/src/rx.dart create mode 100644 sandbox/reactivex/lib/src/streams/combine_latest.dart create mode 100644 sandbox/reactivex/lib/src/streams/concat.dart create mode 100644 sandbox/reactivex/lib/src/streams/concat_eager.dart create mode 100644 sandbox/reactivex/lib/src/streams/connectable_stream.dart create mode 100644 sandbox/reactivex/lib/src/streams/defer.dart create mode 100644 sandbox/reactivex/lib/src/streams/fork_join.dart create mode 100644 sandbox/reactivex/lib/src/streams/from_callable.dart create mode 100644 sandbox/reactivex/lib/src/streams/merge.dart create mode 100644 sandbox/reactivex/lib/src/streams/never.dart create mode 100644 sandbox/reactivex/lib/src/streams/race.dart create mode 100644 sandbox/reactivex/lib/src/streams/range.dart create mode 100644 sandbox/reactivex/lib/src/streams/repeat.dart create mode 100644 sandbox/reactivex/lib/src/streams/replay_stream.dart create mode 100644 sandbox/reactivex/lib/src/streams/retry.dart create mode 100644 sandbox/reactivex/lib/src/streams/retry_when.dart create mode 100644 sandbox/reactivex/lib/src/streams/sequence_equal.dart create mode 100644 sandbox/reactivex/lib/src/streams/switch_latest.dart create mode 100644 sandbox/reactivex/lib/src/streams/timer.dart create mode 100644 sandbox/reactivex/lib/src/streams/using.dart create mode 100644 sandbox/reactivex/lib/src/streams/value_stream.dart create mode 100644 sandbox/reactivex/lib/src/streams/zip.dart create mode 100644 sandbox/reactivex/lib/src/subjects/behavior_subject.dart create mode 100644 sandbox/reactivex/lib/src/subjects/publish_subject.dart create mode 100644 sandbox/reactivex/lib/src/subjects/replay_subject.dart create mode 100644 sandbox/reactivex/lib/src/subjects/subject.dart create mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/backpressure.dart create mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/buffer.dart create mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/debounce.dart create mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/pairwise.dart create mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/sample.dart create mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/throttle.dart create mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/window.dart create mode 100644 sandbox/reactivex/lib/src/transformers/default_if_empty.dart create mode 100644 sandbox/reactivex/lib/src/transformers/delay.dart create mode 100644 sandbox/reactivex/lib/src/transformers/delay_when.dart create mode 100644 sandbox/reactivex/lib/src/transformers/dematerialize.dart create mode 100644 sandbox/reactivex/lib/src/transformers/distinct_unique.dart create mode 100644 sandbox/reactivex/lib/src/transformers/do.dart create mode 100644 sandbox/reactivex/lib/src/transformers/end_with.dart create mode 100644 sandbox/reactivex/lib/src/transformers/end_with_many.dart create mode 100644 sandbox/reactivex/lib/src/transformers/exhaust_map.dart create mode 100644 sandbox/reactivex/lib/src/transformers/flat_map.dart create mode 100644 sandbox/reactivex/lib/src/transformers/group_by.dart create mode 100644 sandbox/reactivex/lib/src/transformers/ignore_elements.dart create mode 100644 sandbox/reactivex/lib/src/transformers/interval.dart create mode 100644 sandbox/reactivex/lib/src/transformers/map_not_null.dart create mode 100644 sandbox/reactivex/lib/src/transformers/map_to.dart create mode 100644 sandbox/reactivex/lib/src/transformers/materialize.dart create mode 100644 sandbox/reactivex/lib/src/transformers/max.dart create mode 100644 sandbox/reactivex/lib/src/transformers/min.dart create mode 100644 sandbox/reactivex/lib/src/transformers/on_error_resume.dart create mode 100644 sandbox/reactivex/lib/src/transformers/scan.dart create mode 100644 sandbox/reactivex/lib/src/transformers/skip_last.dart create mode 100644 sandbox/reactivex/lib/src/transformers/skip_until.dart create mode 100644 sandbox/reactivex/lib/src/transformers/start_with.dart create mode 100644 sandbox/reactivex/lib/src/transformers/start_with_error.dart create mode 100644 sandbox/reactivex/lib/src/transformers/start_with_many.dart create mode 100644 sandbox/reactivex/lib/src/transformers/switch_if_empty.dart create mode 100644 sandbox/reactivex/lib/src/transformers/switch_map.dart create mode 100644 sandbox/reactivex/lib/src/transformers/take_last.dart create mode 100644 sandbox/reactivex/lib/src/transformers/take_until.dart create mode 100644 sandbox/reactivex/lib/src/transformers/take_while_inclusive.dart create mode 100644 sandbox/reactivex/lib/src/transformers/time_interval.dart create mode 100644 sandbox/reactivex/lib/src/transformers/timestamp.dart create mode 100644 sandbox/reactivex/lib/src/transformers/where_not_null.dart create mode 100644 sandbox/reactivex/lib/src/transformers/where_type.dart create mode 100644 sandbox/reactivex/lib/src/transformers/with_latest_from.dart create mode 100644 sandbox/reactivex/lib/src/utils/collection_extensions.dart create mode 100644 sandbox/reactivex/lib/src/utils/composite_subscription.dart create mode 100644 sandbox/reactivex/lib/src/utils/empty.dart create mode 100644 sandbox/reactivex/lib/src/utils/error_and_stacktrace.dart create mode 100644 sandbox/reactivex/lib/src/utils/forwarding_sink.dart create mode 100644 sandbox/reactivex/lib/src/utils/forwarding_stream.dart create mode 100644 sandbox/reactivex/lib/src/utils/future.dart create mode 100644 sandbox/reactivex/lib/src/utils/min_max.dart create mode 100644 sandbox/reactivex/lib/src/utils/notification.dart create mode 100644 sandbox/reactivex/lib/src/utils/subscription.dart create mode 100644 sandbox/reactivex/lib/streams.dart create mode 100644 sandbox/reactivex/lib/subjects.dart create mode 100644 sandbox/reactivex/lib/transformers.dart create mode 100644 sandbox/reactivex/lib/utils.dart create mode 100644 sandbox/reactivex/pubspec.yaml create mode 100644 sandbox/reactivex/screenshots/logo.png create mode 100644 sandbox/reactivex/test/rxdart_test.dart create mode 100644 sandbox/reactivex/test/streams/combine_latest_test.dart create mode 100644 sandbox/reactivex/test/streams/concat_eager_test.dart create mode 100644 sandbox/reactivex/test/streams/concat_test.dart create mode 100644 sandbox/reactivex/test/streams/defer_test.dart create mode 100644 sandbox/reactivex/test/streams/fork_join_test.dart create mode 100644 sandbox/reactivex/test/streams/from_callable_test.dart create mode 100644 sandbox/reactivex/test/streams/merge_test.dart create mode 100644 sandbox/reactivex/test/streams/never_test.dart create mode 100644 sandbox/reactivex/test/streams/publish_connectable_stream_test.dart create mode 100644 sandbox/reactivex/test/streams/race_test.dart create mode 100644 sandbox/reactivex/test/streams/range_test.dart create mode 100644 sandbox/reactivex/test/streams/repeat_test.dart create mode 100644 sandbox/reactivex/test/streams/replay_connectable_stream_test.dart create mode 100644 sandbox/reactivex/test/streams/retry_test.dart create mode 100644 sandbox/reactivex/test/streams/retry_when_test.dart create mode 100644 sandbox/reactivex/test/streams/sequence_equals_test.dart create mode 100644 sandbox/reactivex/test/streams/switch_latest_test.dart create mode 100644 sandbox/reactivex/test/streams/timer_test.dart create mode 100644 sandbox/reactivex/test/streams/using_test.dart create mode 100644 sandbox/reactivex/test/streams/value_connectable_stream_test.dart create mode 100644 sandbox/reactivex/test/streams/zip_test.dart create mode 100644 sandbox/reactivex/test/subject/behavior_subject_test.dart create mode 100644 sandbox/reactivex/test/subject/publish_subject_test.dart create mode 100644 sandbox/reactivex/test/subject/replay_subject_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_count_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_test_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_time_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/debounce_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/debounce_time_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/pairwise_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/sample_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/sample_time_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/throttle_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/throttle_time_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/window_count_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/window_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/window_test_test.dart create mode 100644 sandbox/reactivex/test/transformers/backpressure/window_time_test.dart create mode 100644 sandbox/reactivex/test/transformers/concat_with_test.dart create mode 100644 sandbox/reactivex/test/transformers/default_if_empty_test.dart create mode 100644 sandbox/reactivex/test/transformers/delay_test.dart create mode 100644 sandbox/reactivex/test/transformers/delay_when_test.dart create mode 100644 sandbox/reactivex/test/transformers/dematerialize_test.dart create mode 100644 sandbox/reactivex/test/transformers/distinct_test.dart create mode 100644 sandbox/reactivex/test/transformers/distinct_unique_test.dart create mode 100644 sandbox/reactivex/test/transformers/do_test.dart create mode 100644 sandbox/reactivex/test/transformers/end_with_many_test.dart create mode 100644 sandbox/reactivex/test/transformers/end_with_test.dart create mode 100644 sandbox/reactivex/test/transformers/exhaust_map_test.dart create mode 100644 sandbox/reactivex/test/transformers/flat_map_iterable_test.dart create mode 100644 sandbox/reactivex/test/transformers/flat_map_test.dart create mode 100644 sandbox/reactivex/test/transformers/group_by_test.dart create mode 100644 sandbox/reactivex/test/transformers/ignore_elements_test.dart create mode 100644 sandbox/reactivex/test/transformers/interval_test.dart create mode 100644 sandbox/reactivex/test/transformers/join_test.dart create mode 100644 sandbox/reactivex/test/transformers/map_not_null_test.dart create mode 100644 sandbox/reactivex/test/transformers/map_to_test.dart create mode 100644 sandbox/reactivex/test/transformers/materialize_test.dart create mode 100644 sandbox/reactivex/test/transformers/max_test.dart create mode 100644 sandbox/reactivex/test/transformers/merge_with_test.dart create mode 100644 sandbox/reactivex/test/transformers/min_test.dart create mode 100644 sandbox/reactivex/test/transformers/on_error_resume_test.dart create mode 100644 sandbox/reactivex/test/transformers/on_error_return_test.dart create mode 100644 sandbox/reactivex/test/transformers/on_error_return_with_test.dart create mode 100644 sandbox/reactivex/test/transformers/scan_test.dart create mode 100644 sandbox/reactivex/test/transformers/skip_last_test.dart create mode 100644 sandbox/reactivex/test/transformers/skip_until_test.dart create mode 100644 sandbox/reactivex/test/transformers/start_with_error_test.dart create mode 100644 sandbox/reactivex/test/transformers/start_with_many_test.dart create mode 100644 sandbox/reactivex/test/transformers/start_with_test.dart create mode 100644 sandbox/reactivex/test/transformers/switch_if_empty_test.dart create mode 100644 sandbox/reactivex/test/transformers/switch_map_test.dart create mode 100644 sandbox/reactivex/test/transformers/take_last_test.dart create mode 100644 sandbox/reactivex/test/transformers/take_until_test.dart create mode 100644 sandbox/reactivex/test/transformers/take_while_inclusive_test.dart create mode 100644 sandbox/reactivex/test/transformers/time_interval_test.dart create mode 100644 sandbox/reactivex/test/transformers/timeout_test.dart create mode 100644 sandbox/reactivex/test/transformers/timestamp_test.dart create mode 100644 sandbox/reactivex/test/transformers/where_not_null_test.dart create mode 100644 sandbox/reactivex/test/transformers/where_type_test.dart create mode 100644 sandbox/reactivex/test/transformers/with_latest_from_test.dart create mode 100644 sandbox/reactivex/test/transformers/zip_with_test.dart create mode 100644 sandbox/reactivex/test/utils.dart create mode 100644 sandbox/reactivex/test/utils/composite_subscription_test.dart create mode 100644 sandbox/reactivex/test/utils/notification_test.dart diff --git a/.melos/base.yaml b/.melos/base.yaml index f5eedef..d01b63e 100644 --- a/.melos/base.yaml +++ b/.melos/base.yaml @@ -3,6 +3,7 @@ repository: https://github.com/protevus/platform packages: - apps/** - packages/** + - sandbox/** - helpers/tools/** - examples/** diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..9f7dfc1 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,77 @@ +# Generated documentation +api/ +build/ +site/ +_site/ +.dart_tool/ +.pub-cache/ +.pub/ +doc/api/ + +# Temporary files +*.tmp +*.temp +*.bak +*.swp +*~ +.DS_Store +Thumbs.db + +# IDE files +.idea/ +.vscode/ +*.iml +*.iws +*.ipr +.settings/ +.project +.classpath + +# Build artifacts +*.html +*.pdf +*.epub +*.mobi +*.docx +*.doc +*.rtf + +# Local configuration +.env +.env.local +*.local +local.* + +# Documentation tools +node_modules/ +package-lock.json +yarn.lock +pubspec.lock + +# Generated diagrams +*.svg +*.png +*.jpg +*.jpeg +*.gif +!assets/*.svg +!assets/*.png +!assets/*.jpg +!assets/*.jpeg +!assets/*.gif + +# Generated markdown +*.generated.md +*.auto.md +*.temp.md + +# Coverage reports +coverage/ +.coverage/ +coverage.xml +*.lcov + +# Log files +*.log +log/ +logs/ diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md new file mode 100644 index 0000000..ebe3cc9 --- /dev/null +++ b/docs/CHANGELOG.md @@ -0,0 +1,163 @@ +# Documentation Changelog + +All notable changes to framework documentation will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2024-01-17 + +### Added +- Core Documentation + * Created Getting Started Guide + * Created Laravel Compatibility Roadmap + * Created Foundation Integration Guide + * Created Testing Guide + * Created Package Integration Map + * Created README.md + * Created index.md + * Created CONTRIBUTING.md + * Created CHANGELOG.md + +- Core Architecture + * Created Core Architecture documentation + * Created Core Package Specification + +- Package Specifications + * Created Container Package Specification + * Created Contracts Package Specification + * Created Events Package Specification + * Created Pipeline Package Specification + * Created Support Package Specification + * Created Bus Package Specification + * Created Config Package Specification + * Created Filesystem Package Specification + * Created Model Package Specification + * Created Process Package Specification + * Created Queue Package Specification + * Created Route Package Specification + * Created Testing Package Specification + +- Gap Analyses + * Created Container Gap Analysis + * Created Events Gap Analysis + * Created Pipeline Gap Analysis + * Created Bus Gap Analysis + * Created Config Gap Analysis + * Created Filesystem Gap Analysis + * Created Model Gap Analysis + * Created Process Gap Analysis + * Created Queue Gap Analysis + * Created Route Gap Analysis + * Created Testing Gap Analysis + +- Integration Guides + * Created Container Feature Integration + * Created Container Migration Guide + +### Documentation Features +- Complete package specifications with no placeholders +- Comprehensive gap analyses for Laravel compatibility +- Detailed integration guides and examples +- Cross-referenced documentation +- Consistent style and formatting +- Development guidelines for each package +- Testing requirements and examples +- Performance considerations +- Security guidelines + +### Documentation Structure +- Organized by package +- Clear navigation +- Related documentation links +- Code examples +- Implementation status +- Development guidelines + +### Documentation Standards +- No placeholders or truncation +- Complete code examples +- Working cross-references +- Proper markdown formatting +- Technical accuracy + +### Contributing Guidelines +- Documentation standards +- Writing style guide +- Review process +- Development workflow +- Content organization + +## Types of Changes +- `Added` for new documentation +- `Changed` for changes in existing documentation +- `Deprecated` for soon-to-be removed documentation +- `Removed` for now removed documentation +- `Fixed` for any documentation fixes +- `Security` for documentation about security updates + +## Maintaining the Changelog + +### Format +Each version should: +1. List version number and date +2. Group changes by type +3. List changes with bullet points +4. Reference related issues/PRs +5. Credit contributors + +### Example +```markdown +## [1.1.0] - YYYY-MM-DD +### Added +- New documentation for feature X (#123) +- Guide for implementing Y (@contributor) + +### Changed +- Updated Z documentation for clarity (#456) +- Improved examples in W guide (@contributor) + +### Fixed +- Corrected code example in V doc (#789) +- Fixed broken links in U guide (@contributor) +``` + +### Version Numbers +- MAJOR version for significant documentation restructuring +- MINOR version for new documentation additions +- PATCH version for documentation fixes and updates + +## Unreleased Changes + +### To Be Added +- Package-specific changelogs +- Version-specific documentation +- Migration guides for each version +- API documentation +- Additional examples + +### To Be Updated +- Performance guidelines +- Security considerations +- Testing strategies +- Integration patterns +- Development workflows + +## Previous Versions + +No previous versions. This is the initial documentation release. + +## Contributors + +- Initial documentation team +- Package maintainers +- Documentation reviewers +- Community contributors + +## Questions? + +For questions about documentation changes: +1. Review CONTRIBUTING.md +2. Check existing documentation +3. Ask in pull request +4. Update changelog as needed diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..418a5ce --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,280 @@ +# Contributing to Framework Documentation + +## Overview + +This guide explains how to contribute to our framework documentation. We maintain comprehensive documentation covering package specifications, gap analyses, integration guides, and architectural documentation. + +## Documentation Structure + +### Core Documentation +1. [Getting Started Guide](getting_started.md) - Framework introduction and setup +2. [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) - Implementation timeline +3. [Foundation Integration Guide](foundation_integration_guide.md) - Integration patterns +4. [Testing Guide](testing_guide.md) - Testing approaches +5. [Package Integration Map](package_integration_map.md) - Package relationships + +### Core Architecture +1. [Core Architecture](core_architecture.md) - System design and patterns +2. [Core Package Specification](core_package_specification.md) - Core implementation + +### Package Documentation +Each package has: +1. Package Specification - Implementation details +2. Gap Analysis - Laravel compatibility gaps +3. Integration Guide - Package integration patterns +4. Development Guidelines - Implementation standards + +## Contribution Guidelines + +### 1. Documentation Standards + +#### File Naming +- Use lowercase with underscores +- End with .md extension +- Be descriptive and specific +- Examples: + * package_specification.md + * gap_analysis.md + * integration_guide.md + +#### File Structure +- Start with # Title +- Include Overview section +- Add Related Documentation links +- Use clear section headers +- Include code examples +- End with development guidelines + +#### Content Requirements +- No placeholders or truncation +- Complete code examples +- Clear cross-references +- Proper markdown formatting +- Comprehensive coverage + +### 2. Writing Style + +#### Technical Writing +- Be clear and concise +- Use active voice +- Write in present tense +- Focus on technical accuracy +- Include practical examples + +#### Code Examples +```dart +// Include complete, working examples +class Example { + final String name; + + Example(this.name); + + void demonstrate() { + print('Demonstrating: $name'); + } +} + +// Show usage +var example = Example('feature'); +example.demonstrate(); +``` + +#### Cross-References +- Use relative links +- Link to related docs +- Reference specific sections +- Example: + ```markdown + See [Container Integration](container_package_specification.md#integration) for details. + ``` + +### 3. Documentation Types + +#### Package Specification +- Implementation details +- API documentation +- Integration examples +- Testing guidelines +- Development workflow + +#### Gap Analysis +- Current implementation +- Laravel features +- Missing functionality +- Implementation plan +- Priority order + +#### Integration Guide +- Integration points +- Package dependencies +- Code examples +- Best practices +- Common patterns + +### 4. Review Process + +#### Before Submitting +1. Check content completeness +2. Verify code examples +3. Test all links +4. Run markdown linter +5. Review formatting + +#### Pull Request +1. Clear description +2. Reference related issues +3. List documentation changes +4. Include review checklist +5. Add relevant labels + +#### Review Checklist +- [ ] No placeholders or truncation +- [ ] Complete code examples +- [ ] Working cross-references +- [ ] Proper formatting +- [ ] Technical accuracy + +### 5. Development Workflow + +#### Creating Documentation +1. Create feature branch +2. Write documentation +3. Add code examples +4. Include cross-references +5. Submit pull request + +#### Updating Documentation +1. Review existing content +2. Make necessary changes +3. Update related docs +4. Verify all links +5. Submit pull request + +#### Review Process +1. Technical review +2. Style review +3. Code example review +4. Cross-reference check +5. Final approval + +## Style Guide + +### 1. Markdown + +#### Headers +```markdown +# Main Title +## Section Title +### Subsection Title +#### Minor Section +``` + +#### Lists +```markdown +1. Ordered Item +2. Ordered Item + - Unordered Sub-item + - Unordered Sub-item + +- Unordered Item +- Unordered Item + 1. Ordered Sub-item + 2. Ordered Sub-item +``` + +#### Code Blocks +```markdown +/// Code with syntax highlighting +```dart +class Example { + void method() { + // Implementation + } +} +``` + +/// Inline code +Use `var` for variable declaration. +``` + +#### Links +```markdown +[Link Text](relative/path/to/file.md) +[Link Text](relative/path/to/file.md#section) +``` + +### 2. Content Organization + +#### Package Documentation +1. Overview +2. Core Features +3. Integration Examples +4. Testing +5. Development Guidelines + +#### Gap Analysis +1. Overview +2. Missing Features +3. Implementation Gaps +4. Priority Order +5. Next Steps + +#### Integration Guide +1. Overview +2. Integration Points +3. Code Examples +4. Best Practices +5. Development Guidelines + +### 3. Code Examples + +#### Complete Examples +```dart +// Include all necessary imports +import 'package:framework/core.dart'; + +// Show complete implementation +class ServiceProvider { + final Container container; + + ServiceProvider(this.container); + + void register() { + container.singleton((c) => + ServiceImplementation() + ); + } +} + +// Demonstrate usage +void main() { + var container = Container(); + var provider = ServiceProvider(container); + provider.register(); +} +``` + +#### Integration Examples +```dart +// Show real integration scenarios +class UserService { + final EventDispatcher events; + final Database db; + + UserService(this.events, this.db); + + Future createUser(User user) async { + await events.dispatch(UserCreating(user)); + await db.users.insert(user); + await events.dispatch(UserCreated(user)); + } +} +``` + +## Questions? + +For questions or clarification: +1. Review existing documentation +2. Check style guide +3. Ask in pull request +4. Update guidelines as needed diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..7e270e9 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,271 @@ +# Framework Documentation + +## Overview + +This documentation covers our Dart framework implementation, including Laravel compatibility, package specifications, and architectural guides. The framework provides Laravel's powerful features and patterns while leveraging Dart's strengths. + +## Documentation Structure + +### Core Documentation +1. [Getting Started Guide](getting_started.md) - Framework introduction and setup +2. [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) - Implementation timeline +3. [Foundation Integration Guide](foundation_integration_guide.md) - Integration patterns +4. [Testing Guide](testing_guide.md) - Testing approaches and patterns +5. [Package Integration Map](package_integration_map.md) - Package relationships + +### Core Architecture +1. [Core Architecture](core_architecture.md) - System design and patterns + - Architectural decisions + - System patterns + - Extension points + - Package interactions + +### Package Documentation + +#### Core Framework +1. Core Package + - [Core Package Specification](core_package_specification.md) + - [Core Architecture](core_architecture.md) + +2. Container Package + - [Container Package Specification](container_package_specification.md) + - [Container Gap Analysis](container_gap_analysis.md) + - [Container Feature Integration](container_feature_integration.md) + - [Container Migration Guide](container_migration_guide.md) + +3. Contracts Package + - [Contracts Package Specification](contracts_package_specification.md) + +4. Events Package + - [Events Package Specification](events_package_specification.md) + - [Events Gap Analysis](events_gap_analysis.md) + +5. Pipeline Package + - [Pipeline Package Specification](pipeline_package_specification.md) + - [Pipeline Gap Analysis](pipeline_gap_analysis.md) + +6. Support Package + - [Support Package Specification](support_package_specification.md) + +#### Infrastructure +1. Bus Package + - [Bus Package Specification](bus_package_specification.md) + - [Bus Gap Analysis](bus_gap_analysis.md) + +2. Config Package + - [Config Package Specification](config_package_specification.md) + - [Config Gap Analysis](config_gap_analysis.md) + +3. Filesystem Package + - [Filesystem Package Specification](filesystem_package_specification.md) + - [Filesystem Gap Analysis](filesystem_gap_analysis.md) + +4. Model Package + - [Model Package Specification](model_package_specification.md) + - [Model Gap Analysis](model_gap_analysis.md) + +5. Process Package + - [Process Package Specification](process_package_specification.md) + - [Process Gap Analysis](process_gap_analysis.md) + +6. Queue Package + - [Queue Package Specification](queue_package_specification.md) + - [Queue Gap Analysis](queue_gap_analysis.md) + +7. Route Package + - [Route Package Specification](route_package_specification.md) + - [Route Gap Analysis](route_gap_analysis.md) + +8. Testing Package + - [Testing Package Specification](testing_package_specification.md) + - [Testing Gap Analysis](testing_gap_analysis.md) + +## Getting Started + +1. **Understanding the Framework** +```dart +// Start with these documents in order: +1. Getting Started Guide +2. Core Architecture +3. Laravel Compatibility Roadmap +4. Foundation Integration Guide +``` + +2. **Package Development** +```dart +// For each package: +1. Review package specification +2. Check gap analysis +3. Follow integration guide +4. Write tests +``` + +3. **Development Workflow** +```dart +// For each feature: +1. Review specifications +2. Write tests +3. Implement changes +4. Update documentation +``` + +## Key Concepts + +### 1. Service Container Architecture +```dart +// Core application setup +var container = Container(); +var app = Application(container) + ..environment = 'production' + ..basePath = Directory.current.path; + +await app.boot(); +``` + +### 2. Service Providers +```dart +class AppServiceProvider extends ServiceProvider { + @override + void register() { + // Register services + } + + @override + void boot() { + // Bootstrap services + } +} +``` + +### 3. Package Integration +```dart +// Cross-package usage +class UserService { + final EventDispatcher events; + final Queue queue; + + Future process(User user) async { + await events.dispatch(UserProcessing(user)); + await queue.push(ProcessUser(user)); + } +} +``` + +## Implementation Status + +### Core Framework (90%) +- Core Package (95%) + * Application lifecycle ✓ + * Service providers ✓ + * HTTP kernel ✓ + * Console kernel ✓ + * Exception handling ✓ + * Needs: Performance optimizations + +- Container Package (90%) + * Basic DI ✓ + * Auto-wiring ✓ + * Service providers ✓ + * Needs: Contextual binding + +### Infrastructure (80%) +- Bus Package (85%) + * Command dispatching ✓ + * Command queuing ✓ + * Needs: Command batching + +- Config Package (80%) + * Configuration repository ✓ + * Environment loading ✓ + * Needs: Config caching + +[Previous implementation status content remains exactly the same] + +## Contributing + +1. **Before Starting** +- Review relevant documentation +- Check implementation status +- Understand dependencies +- Write tests first + +2. **Development Process** +```dart +// 1. Create feature branch +git checkout -b feature/package-name/feature-name + +// 2. Write tests +void main() { + test('should implement feature', () { + // Test implementation + }); +} + +// 3. Implement feature +class Implementation { + // Feature code +} + +// 4. Submit PR +// - Include tests +// - Update documentation +// - Add examples +``` + +3. **Code Review** +- Verify specifications +- Check test coverage +- Review documentation +- Validate performance + +## Best Practices + +1. **API Design** +```dart +// Follow framework patterns +class Service { + // Match framework method signatures + Future handle(); + Future process(); +} +``` + +2. **Testing** +```dart +// Comprehensive test coverage +void main() { + group('Feature', () { + // Unit tests + // Integration tests + // Performance tests + // Error cases + }); +} +``` + +3. **Documentation** +```dart +/// Document framework compatibility +class Service { + /// Processes data following framework patterns. + /// + /// Example: + /// ```dart + /// var service = container.make(); + /// await service.process(); + /// ``` + Future process(); +} +``` + +## Questions? + +For questions or clarification: +1. Review relevant documentation +2. Check implementation examples +3. Consult team leads +4. Update documentation as needed + +## License + +This framework is open-sourced software licensed under the [MIT license](../LICENSE). diff --git a/docs/assets/README.md b/docs/assets/README.md new file mode 100644 index 0000000..a13bc53 --- /dev/null +++ b/docs/assets/README.md @@ -0,0 +1,231 @@ +# Documentation Assets + +## Directory Structure + +``` +assets/ +├── diagrams/ # Architecture and flow diagrams +├── images/ # Screenshots and general images +├── logos/ # Framework and package logos +└── icons/ # UI and feature icons +``` + +## Asset Organization + +### 1. Diagrams +- Architecture diagrams +- Flow charts +- Sequence diagrams +- Component diagrams +- Class diagrams + +Example naming: +``` +diagrams/ +├── architecture/ +│ ├── system_overview.svg +│ ├── package_dependencies.svg +│ └── service_interaction.svg +├── flows/ +│ ├── request_lifecycle.svg +│ ├── event_handling.svg +│ └── queue_processing.svg +└── sequences/ + ├── authentication_flow.svg + ├── job_dispatch.svg + └── model_events.svg +``` + +### 2. Images +- Documentation screenshots +- Example outputs +- Visual guides +- Tutorial images + +Example naming: +``` +images/ +├── getting_started/ +│ ├── installation_step1.png +│ ├── configuration_step2.png +│ └── running_tests_step3.png +├── tutorials/ +│ ├── creating_service_provider.png +│ ├── setting_up_queue.png +│ └── configuring_cache.png +└── examples/ + ├── api_response.png + ├── console_output.png + └── test_results.png +``` + +### 3. Logos +- Framework logos +- Package logos +- Integration logos +- Partner logos + +Example naming: +``` +logos/ +├── framework/ +│ ├── full_logo.svg +│ ├── icon_only.svg +│ └── text_only.svg +├── packages/ +│ ├── container_logo.svg +│ ├── events_logo.svg +│ └── queue_logo.svg +└── partners/ + ├── vendor_logo.svg + ├── cloud_logo.svg + └── tools_logo.svg +``` + +### 4. Icons +- Feature icons +- UI elements +- Status indicators +- Action icons + +Example naming: +``` +icons/ +├── features/ +│ ├── caching.svg +│ ├── queuing.svg +│ └── routing.svg +├── status/ +│ ├── success.svg +│ ├── warning.svg +│ └── error.svg +└── actions/ + ├── configure.svg + ├── deploy.svg + └── monitor.svg +``` + +## Naming Conventions + +1. **File Names** + - Use lowercase + - Use underscores for spaces + - Include category prefix + - Include size/variant suffix + - Examples: + * diagram_system_overview_large.svg + * screenshot_installation_step1.png + * logo_framework_dark.svg + * icon_feature_cache_16px.svg + +2. **Directory Names** + - Use lowercase + - Use descriptive categories + - Group related assets + - Examples: + * diagrams/architecture/ + * images/tutorials/ + * logos/packages/ + * icons/features/ + +## File Formats + +1. **Diagrams** + - SVG (preferred for diagrams) + - PNG (when SVG not possible) + - Source files in separate repo + +2. **Images** + - PNG (preferred for screenshots) + - JPG (for photos) + - WebP (for web optimization) + +3. **Logos** + - SVG (preferred for logos) + - PNG (with multiple resolutions) + - Include source files + +4. **Icons** + - SVG (preferred for icons) + - PNG (with multiple sizes) + - Include source files + +## Usage Guidelines + +1. **Diagrams** + - Use consistent styling + - Include source files + - Maintain aspect ratios + - Use standard colors + +2. **Images** + - Optimize for web + - Use descriptive names + - Include alt text + - Maintain quality + +3. **Logos** + - Follow brand guidelines + - Include all variants + - Maintain proportions + - Use vector formats + +4. **Icons** + - Use consistent style + - Include multiple sizes + - Optimize for display + - Follow naming pattern + +## Contributing Assets + +1. **Adding New Assets** + - Follow naming conventions + - Use appropriate format + - Include source files + - Update documentation + +2. **Updating Assets** + - Maintain version history + - Update all variants + - Keep source files + - Document changes + +3. **Removing Assets** + - Update documentation + - Remove all variants + - Archive if needed + - Document removal + +## Best Practices + +1. **File Organization** + - Use correct directories + - Follow naming patterns + - Group related assets + - Maintain structure + +2. **Version Control** + - Commit source files + - Track large files properly + - Document changes + - Use git LFS if needed + +3. **Quality Control** + - Optimize for web + - Check resolutions + - Verify formats + - Test displays + +4. **Documentation** + - Reference assets properly + - Include alt text + - Document sources + - Credit creators + +## Questions? + +For questions about assets: +1. Check naming conventions +2. Review directory structure +3. Consult usage guidelines +4. Ask in pull request diff --git a/docs/assets/diagrams/architecture/README.md b/docs/assets/diagrams/architecture/README.md new file mode 100644 index 0000000..df0f933 --- /dev/null +++ b/docs/assets/diagrams/architecture/README.md @@ -0,0 +1,187 @@ +# Architecture Diagrams + +## System Overview + +The `system_overview.mmd` diagram shows the high-level architecture of our framework, including: + +1. Core System + - Application lifecycle + - Dependency injection (Container) + - Event handling + - Pipeline processing + +2. HTTP Layer + - Server handling + - HTTP kernel + - Routing + - Controllers + +3. Service Layer + - Configuration + - Caching + - Queue management + - Database operations + +4. Infrastructure + - Filesystem operations + - Process management + - Command bus + - Model layer + +5. Testing Integration + - Test cases + - HTTP testing + - Database testing + - Event testing + +## Rendering the Diagram + +### Using Mermaid CLI +```bash +# Install Mermaid CLI +npm install -g @mermaid-js/mermaid-cli + +# Generate SVG +mmdc -i system_overview.mmd -o system_overview.svg + +# Generate PNG +mmdc -i system_overview.mmd -o system_overview.png +``` + +### Using Online Tools +1. Visit [Mermaid Live Editor](https://mermaid.live) +2. Copy content of system_overview.mmd +3. Export as SVG or PNG + +### Using VSCode +1. Install "Markdown Preview Mermaid Support" extension +2. Open system_overview.mmd +3. Use preview to view diagram + +## Modifying the Diagram + +### Component Structure +```mermaid +%% Component Template +subgraph ComponentName ["Display Name"] + Node1[Node One] + Node2[Node Two] + + Node1 --> Node2 +end +``` + +### Style Definitions +```mermaid +%% Style Classes +classDef core fill:#f9f,stroke:#333,stroke-width:2px +classDef http fill:#bbf,stroke:#333,stroke-width:2px +classDef service fill:#bfb,stroke:#333,stroke-width:2px +classDef infra fill:#fbb,stroke:#333,stroke-width:2px +classDef test fill:#fff,stroke:#333,stroke-width:2px +``` + +### Adding Components +1. Define component in appropriate subgraph +2. Add relationships using arrows +3. Apply style class +4. Update documentation + +## Component Descriptions + +### Core System +- **Application**: Main entry point and lifecycle manager +- **Container**: Dependency injection container +- **Events**: Event dispatching and handling +- **Pipeline**: Request/process pipeline handling + +### HTTP Layer +- **Server**: HTTP server implementation +- **Kernel**: HTTP request kernel +- **Router**: Route matching and handling +- **Controller**: Request controllers + +### Service Layer +- **Config**: Configuration management +- **Cache**: Data caching +- **Queue**: Job queue management +- **Database**: Database operations + +### Infrastructure +- **FileSystem**: File operations +- **Process**: Process management +- **Bus**: Command bus implementation +- **Model**: Data model layer + +### Testing +- **TestCase**: Base test functionality +- **HttpTest**: HTTP testing utilities +- **DBTest**: Database testing utilities +- **EventTest**: Event testing utilities + +## Relationships + +### Core Dependencies +```mermaid +graph LR + App --> Container + App --> Events + App --> Pipeline +``` + +### Service Registration +```mermaid +graph LR + Container --> Services + Container --> Infrastructure +``` + +### Request Flow +```mermaid +graph LR + Server --> App + Controller --> Services + Services --> Infrastructure +``` + +### Event Flow +```mermaid +graph LR + Events --> Queue + Queue --> Process + Events --> Bus +``` + +## Best Practices + +1. **Adding Components** + - Place in appropriate subgraph + - Use consistent naming + - Add clear relationships + - Apply correct style + +2. **Updating Relationships** + - Keep lines clear + - Show direct dependencies + - Avoid crossing lines + - Group related flows + +3. **Maintaining Styles** + - Use defined classes + - Keep consistent colors + - Maintain line weights + - Use clear labels + +4. **Documentation** + - Update README.md + - Explain changes + - Document relationships + - Keep synchronized + +## Questions? + +For questions about architecture diagrams: +1. Check diagram documentation +2. Review Mermaid syntax +3. Consult team leads +4. Update documentation diff --git a/docs/assets/diagrams/architecture/system_overview.mmd b/docs/assets/diagrams/architecture/system_overview.mmd new file mode 100644 index 0000000..9765e8a --- /dev/null +++ b/docs/assets/diagrams/architecture/system_overview.mmd @@ -0,0 +1,105 @@ +graph TB + %% Core System + subgraph Core ["Core System"] + App[Application] + Container[Container] + Events[Events] + Pipeline[Pipeline] + + App --> Container + App --> Events + App --> Pipeline + end + + %% HTTP Layer + subgraph HTTP ["HTTP Layer"] + Server[HTTP Server] + Kernel[HTTP Kernel] + Router[Router] + Controller[Controller] + + Server --> Kernel + Kernel --> Router + Router --> Controller + end + + %% Service Layer + subgraph Services ["Service Layer"] + Config[Config] + Cache[Cache] + Queue[Queue] + DB[Database] + + Config --> Container + Cache --> Container + Queue --> Events + DB --> Events + end + + %% Infrastructure + subgraph Infrastructure ["Infrastructure"] + FileSystem[FileSystem] + Process[Process] + Bus[Command Bus] + Model[Model] + + FileSystem --> Container + Process --> Queue + Bus --> Queue + Model --> Events + end + + %% Request Flow + Server --> App + Controller --> Services + Services --> Infrastructure + + %% Event Flow + Events --> Queue + Queue --> Process + Events --> Bus + + %% Service Provider Registration + Container --> Services + Container --> Infrastructure + + %% Middleware Pipeline + Pipeline --> HTTP + Pipeline --> Services + + %% Testing Integration + subgraph Testing ["Testing"] + TestCase[TestCase] + HttpTest[HTTP Tests] + DBTest[DB Tests] + EventTest[Event Tests] + + TestCase --> App + HttpTest --> Server + DBTest --> DB + EventTest --> Events + end + + %% Style Definitions + classDef core fill:#f9f,stroke:#333,stroke-width:2px + classDef http fill:#bbf,stroke:#333,stroke-width:2px + classDef service fill:#bfb,stroke:#333,stroke-width:2px + classDef infra fill:#fbb,stroke:#333,stroke-width:2px + classDef test fill:#fff,stroke:#333,stroke-width:2px + + %% Apply Styles + class App,Container,Events,Pipeline core + class Server,Kernel,Router,Controller http + class Config,Cache,Queue,DB service + class FileSystem,Process,Bus,Model infra + class TestCase,HttpTest,DBTest,EventTest test + + %% Relationships + linkStyle default stroke:#333,stroke-width:2px + + %% Notes + %% Core System handles application lifecycle + %% HTTP Layer processes web requests + %% Service Layer provides business functionality + %% Infrastructure provides system services + %% Testing ensures system quality diff --git a/docs/assets/diagrams/flows/README.md b/docs/assets/diagrams/flows/README.md new file mode 100644 index 0000000..782058e --- /dev/null +++ b/docs/assets/diagrams/flows/README.md @@ -0,0 +1,625 @@ +# Flow Diagrams + +## Request Lifecycle + +The `request_lifecycle.mmd` diagram shows the complete lifecycle of an HTTP request through our framework, including: + +### 1. Entry Points +- Client HTTP Request +- Server Reception +- Kernel Handling + +### 2. Middleware Processing +1. **Global Middleware** + - Maintenance Mode Check + - Post Size Validation + - String Trimming + - Empty to Null Conversion + +2. **Route Middleware** + - Authentication + - Authorization + - Throttling + - CSRF Protection + +3. **Response Middleware** + - Session Handling + - Cookie Processing + - Header Management + - Response Compression + +### 3. Core Processing +1. **Route Resolution** + - Pattern Matching + - Parameter Binding + - Controller Resolution + +2. **Controller Handling** + - Action Execution + - Parameter Injection + - Response Generation + +### 4. Service Layer +1. **Business Logic** + - Service Processing + - Data Validation + - Business Rules + +2. **Data Operations** + - Database Queries + - Cache Access + - File Operations + +### 5. Event System +1. **Event Types** + - Model Events + - Custom Events + - System Events + +2. **Event Processing** + - Synchronous Events + - Queued Events + - Broadcast Events + +## Event Processing + +The `event_processing.mmd` diagram shows the complete lifecycle of events through our framework, including: + +### 1. Event Sources +- System Components +- User Actions +- External Triggers +- Scheduled Tasks + +### 2. Event Types +1. **Immediate Events** + - Synchronous Processing + - Direct Response + - In-Memory Handling + +2. **Queued Events** + - Asynchronous Processing + - Background Jobs + - Delayed Execution + +3. **Broadcast Events** + - Real-time Updates + - WebSocket Integration + - Channel Broadcasting + +### 3. Processing Components +1. **Event Dispatcher** + - Event Creation + - Type Detection + - Handler Resolution + - Event Routing + +2. **Queue System** + - Job Queuing + - Background Processing + - Retry Handling + - Failed Job Management + +3. **Broadcaster** + - Channel Management + - Real-time Delivery + - Client Connections + - Message Formatting + +4. **Event Listeners** + - Event Handling + - Business Logic + - Response Generation + - Error Handling + +### 4. Integration Points +1. **Database Operations** + - Transaction Management + - Data Persistence + - State Changes + - Audit Logging + +2. **Cache Operations** + - Cache Invalidation + - Cache Updates + - Performance Optimization + - State Management + +3. **Event Subscribers** + - Multiple Event Handling + - Event Grouping + - Subscriber Management + - Event Filtering + +### 5. Channel Types +1. **Public Channels** + - Open Access + - Public Events + - General Updates + +2. **Private Channels** + - Authentication Required + - User-Specific Events + - Secure Communication + +3. **Presence Channels** + - User Presence + - Online Status + - User Lists + - Real-time State + +## Queue Processing + +The `queue_processing.mmd` diagram shows the complete lifecycle of queued jobs through our framework, including: + +### 1. Job Sources +- Application Code +- Event Listeners +- Scheduled Tasks +- External Triggers + +### 2. Job States +1. **Pending** + - Initial State + - Awaiting Processing + - In Queue + +2. **Reserved** + - Worker Assigned + - Being Processed + - Locked for Processing + +3. **Released** + - Failed Attempt + - Ready for Retry + - Back in Queue + +4. **Failed** + - Max Retries Exceeded + - Permanent Failure + - Requires Attention + +### 3. Processing Components +1. **Queue Manager** + - Job Registration + - Queue Selection + - Job Scheduling + - State Management + +2. **Queue Worker** + - Job Processing + - Error Handling + - Retry Management + - Resource Cleanup + +3. **Job Handler** + - Business Logic + - Data Processing + - Event Dispatching + - Error Reporting + +4. **Failed Jobs** + - Failure Logging + - Retry Tracking + - Error Analysis + - Admin Notification + +### 4. Integration Points +1. **Database Operations** + - Job Storage + - State Tracking + - Transaction Management + - Failure Logging + +2. **Event System** + - Job Events + - Status Updates + - Error Notifications + - Progress Tracking + +3. **Queue Monitor** + - Health Checks + - Performance Metrics + - Worker Status + - Error Rates + +### 5. Processing Types +1. **Immediate Processing** + - Direct Execution + - No Delay + - Synchronous Option + +2. **Delayed Processing** + - Scheduled Execution + - Time-based Delays + - Future Processing + +3. **Batch Processing** + - Multiple Jobs + - Grouped Execution + - Bulk Operations + +4. **Chained Processing** + - Sequential Jobs + - Dependent Tasks + - Pipeline Processing + +### 6. Retry Strategy +1. **Exponential Backoff** + - Increasing Delays + - Retry Limits + - Failure Thresholds + +2. **Custom Delays** + - Job-specific Timing + - Conditional Delays + - Priority-based + +3. **Max Attempts** + - Attempt Limits + - Failure Handling + - Final State + +## Model Lifecycle + +The `model_lifecycle.mmd` diagram shows the complete lifecycle of models through our framework, including: + +### 1. Model Operations +1. **Creation** + - Instance Creation + - Event Dispatching + - Database Insertion + - Cache Management + +2. **Retrieval** + - Cache Checking + - Database Query + - Relationship Loading + - Model Hydration + +3. **Update** + - Change Tracking + - Event Dispatching + - Database Update + - Cache Invalidation + +4. **Deletion** + - Event Dispatching + - Database Deletion + - Cache Clearing + - Relationship Cleanup + +### 2. Event Integration +1. **Lifecycle Events** + - Creating/Created + - Updating/Updated + - Deleting/Deleted + - Retrieved/Saving + +2. **Relationship Events** + - Loading Relations + - Relation Loaded + - Relation Updated + - Relation Deleted + +3. **Cache Events** + - Cache Hit/Miss + - Cache Stored + - Cache Invalidated + - Cache Cleared + +### 3. Processing Components +1. **Model Instance** + - Attribute Management + - Change Tracking + - Event Dispatching + - State Management + +2. **Event System** + - Event Creation + - Observer Notification + - Queue Integration + - Event Broadcasting + +3. **Cache Layer** + - Cache Checking + - Cache Storage + - Cache Invalidation + - Cache Strategy + +4. **Database Layer** + - Query Execution + - Record Management + - Transaction Handling + - Relationship Loading + +### 4. Integration Points +1. **Observer System** + - Lifecycle Hooks + - Event Handling + - State Tracking + - Custom Logic + +2. **Cache Strategy** + - Read Through + - Write Behind + - Cache Invalidation + - Cache Tags + +3. **Queue Integration** + - Event Queueing + - Job Processing + - Async Operations + - Retry Handling + +### 5. Model States +1. **Pending** + - New Instance + - Not Persisted + - No Events + +2. **Active** + - Persisted + - Trackable + - Observable + +3. **Modified** + - Changes Tracked + - Events Pending + - Cache Invalid + +4. **Deleted** + - Soft Deleted + - Hard Deleted + - Cache Cleared + +### 6. Performance Features +1. **Eager Loading** + - Relationship Loading + - Query Optimization + - N+1 Prevention + +2. **Cache Management** + - Query Cache + - Model Cache + - Relationship Cache + +3. **Batch Operations** + - Bulk Insert + - Bulk Update + - Bulk Delete + +## Rendering the Diagrams + +### Using Mermaid CLI +```bash +# Install Mermaid CLI +npm install -g @mermaid-js/mermaid-cli + +# Generate SVG +mmdc -i request_lifecycle.mmd -o request_lifecycle.svg +mmdc -i event_processing.mmd -o event_processing.svg +mmdc -i queue_processing.mmd -o queue_processing.svg +mmdc -i model_lifecycle.mmd -o model_lifecycle.svg + +# Generate PNG +mmdc -i request_lifecycle.mmd -o request_lifecycle.png +mmdc -i event_processing.mmd -o event_processing.png +mmdc -i queue_processing.mmd -o queue_processing.png +mmdc -i model_lifecycle.mmd -o model_lifecycle.png +``` + +### Using Online Tools +1. Visit [Mermaid Live Editor](https://mermaid.live) +2. Copy content of .mmd files +3. Export as SVG or PNG + +### Using VSCode +1. Install "Markdown Preview Mermaid Support" extension +2. Open .mmd files +3. Use preview to view diagrams + +## Modifying the Diagrams + +### Sequence Structure +```mermaid +sequenceDiagram + participant A + participant B + + A->>B: Message + activate B + B-->>A: Response + deactivate B + + Note over A,B: Description +``` + +### Style Definitions +```mermaid +style Client fill:#f9f,stroke:#333,stroke-width:2px +style Server fill:#bbf,stroke:#333,stroke-width:2px +style Kernel fill:#bbf,stroke:#333,stroke-width:2px +style Pipeline fill:#bfb,stroke:#333,stroke-width:2px +``` + +### Adding Components +1. Add participant declaration +2. Add message sequences +3. Add activation/deactivation +4. Add notes and descriptions + +## Component Interactions + +### 1. Request Processing +```mermaid +sequenceDiagram + Client->>Server: Request + Server->>Kernel: Handle + Kernel->>Pipeline: Process +``` + +### 2. Middleware Chain +```mermaid +sequenceDiagram + Kernel->>Pipeline: Global Middleware + Pipeline->>Pipeline: Route Middleware + Pipeline->>Pipeline: Response Middleware +``` + +### 3. Business Logic +```mermaid +sequenceDiagram + Controller->>Services: Process + Services->>DB: Query + Services->>Events: Dispatch +``` + +### 4. Event Flow +```mermaid +sequenceDiagram + Source->>Dispatcher: Dispatch Event + Dispatcher->>Queue: Queue Event + Queue->>Listeners: Process Later +``` + +### 5. Broadcasting +```mermaid +sequenceDiagram + Dispatcher->>Broadcast: Send Event + Broadcast->>Clients: Real-time Update + Clients-->>Broadcast: Received +``` + +### 6. Queue Processing +```mermaid +sequenceDiagram + Source->>Queue: Dispatch Job + Queue->>Worker: Process Job + Worker->>Handler: Execute Job + Handler-->>Worker: Job Complete +``` + +### 7. Model Operations +```mermaid +sequenceDiagram + Client->>Model: Create/Update/Delete + Model->>Events: Dispatch Event + Events->>Observer: Handle Event + Model->>DB: Persist Changes + Model->>Cache: Update Cache +``` + +## Component Details + +### HTTP Layer +- **Server**: Handles raw HTTP requests +- **Kernel**: Manages request processing +- **Pipeline**: Executes middleware chain +- **Router**: Matches routes to controllers + +### Processing Layer +- **Controller**: Handles business logic +- **Services**: Processes domain logic +- **Events**: Manages system events +- **Database**: Handles data persistence + +### Event System +- **Dispatcher**: Central event hub +- **Queue**: Async processing +- **Broadcast**: Real-time updates +- **Listeners**: Event handlers + +### Queue System +- **Manager**: Queue management +- **Worker**: Job processing +- **Handler**: Job execution +- **Monitor**: Health checks + +### Model System +- **Model**: Data representation +- **Observer**: Event handling +- **Cache**: Performance layer +- **Relations**: Relationship management + +### Integration Points +- **Database**: Data persistence +- **Cache**: Performance layer +- **Subscribers**: Event consumers +- **External Systems**: Third-party services + +### Processing Types +- **Synchronous**: Immediate processing +- **Asynchronous**: Queued processing +- **Real-time**: Broadcast processing +- **Batch**: Grouped processing + +### Event Categories +- **System Events**: Framework operations +- **Domain Events**: Business logic +- **User Events**: User actions +- **Integration Events**: External systems + +## Best Practices + +### 1. Adding Sequences +- Use clear message names +- Show activation state +- Add relevant notes +- Group related actions + +### 2. Updating Flow +- Maintain sequence order +- Show parallel operations +- Indicate async processes +- Document timing + +### 3. Maintaining Style +- Use consistent colors +- Keep clear spacing +- Add helpful notes +- Use proper arrows + +### 4. Documentation +- Update README.md +- Explain changes +- Document new flows +- Keep synchronized + +### 5. Event Design +- Use clear event names +- Include necessary data +- Consider async needs +- Plan broadcast strategy + +### 6. Queue Management +- Set appropriate delays +- Handle failures +- Monitor queue size +- Implement retries + +### 7. Broadcast Strategy +- Choose correct channels +- Manage authentication +- Handle disconnections +- Optimize payload + +### 8. Error Handling +- Log failures +- Implement retries +- Notify administrators +- Maintain state + +### 9. Model Operations +- Track changes +- Manage cache +- Handle events +- Optimize queries + +## Questions? + +For questions about flow diagrams: +1. Check diagram documentation +2. Review Mermaid syntax +3. Consult team leads +4. Update documentation diff --git a/docs/assets/diagrams/flows/event_processing.mmd b/docs/assets/diagrams/flows/event_processing.mmd new file mode 100644 index 0000000..283916d --- /dev/null +++ b/docs/assets/diagrams/flows/event_processing.mmd @@ -0,0 +1,112 @@ +sequenceDiagram + participant Source as Event Source + participant Dispatcher as Event Dispatcher + participant Queue as Queue System + participant Broadcast as Broadcaster + participant Listeners as Event Listeners + participant DB as Database + participant Cache as Cache System + participant Subscribers as Event Subscribers + + %% Event Creation + Source->>Dispatcher: Dispatch Event + activate Dispatcher + Note over Dispatcher: Event Created + + %% Event Type Check + alt Is Queued Event + Dispatcher->>Queue: Push to Queue + activate Queue + Queue-->>Dispatcher: Queued Successfully + deactivate Queue + else Is Immediate Event + Dispatcher->>Listeners: Process Immediately + activate Listeners + end + + %% Broadcasting Check + alt Should Broadcast + Dispatcher->>Broadcast: Broadcast Event + activate Broadcast + Note over Broadcast: WebSocket/Redis/Pusher + Broadcast-->>Dispatcher: Broadcast Complete + deactivate Broadcast + end + + %% Database Operations + alt Has Database Operations + Dispatcher->>DB: Begin Transaction + activate DB + Note over DB: Event-related Changes + DB-->>Dispatcher: Transaction Complete + deactivate DB + end + + %% Cache Operations + alt Has Cache Operations + Dispatcher->>Cache: Update Cache + activate Cache + Note over Cache: Cache Invalidation/Update + Cache-->>Dispatcher: Cache Updated + deactivate Cache + end + + %% Event Subscribers + Dispatcher->>Subscribers: Notify Subscribers + activate Subscribers + Note over Subscribers: Handle Multiple Events + Subscribers-->>Dispatcher: Processing Complete + deactivate Subscribers + + %% Queued Event Processing + alt Is Queued Event + Queue->>Listeners: Process Queue + activate Queue + Note over Queue: Background Processing + Listeners-->>Queue: Processing Complete + deactivate Queue + end + + %% Event Listeners Processing + Note over Listeners: Process Event + Listeners-->>Dispatcher: Handling Complete + deactivate Listeners + + %% Event Completion + Dispatcher-->>Source: Event Processed + deactivate Dispatcher + + %% Style Definitions + style Source fill:#f9f,stroke:#333,stroke-width:2px + style Dispatcher fill:#bbf,stroke:#333,stroke-width:2px + style Queue fill:#bfb,stroke:#333,stroke-width:2px + style Broadcast fill:#fbb,stroke:#333,stroke-width:2px + style Listeners fill:#bfb,stroke:#333,stroke-width:2px + style DB fill:#fbb,stroke:#333,stroke-width:2px + style Cache fill:#fbb,stroke:#333,stroke-width:2px + style Subscribers fill:#bfb,stroke:#333,stroke-width:2px + + %% Notes + Note right of Source: System Component + Note right of Dispatcher: Event Management + Note right of Queue: Async Processing + Note right of Broadcast: Real-time Updates + Note right of Listeners: Event Handlers + Note right of DB: Persistence Layer + Note right of Cache: Performance Layer + Note right of Subscribers: Event Subscribers + + %% Event Types + Note over Dispatcher: Event Types:
1. Immediate Events
2. Queued Events
3. Broadcast Events + + %% Processing Types + Note over Listeners: Processing Types:
1. Sync Processing
2. Async Processing
3. Batch Processing + + %% Integration Points + Note over Queue: Integration:
1. Redis Queue
2. Database Queue
3. Memory Queue + + %% Broadcast Channels + Note over Broadcast: Channels:
1. Public Channels
2. Private Channels
3. Presence Channels + + %% Subscriber Types + Note over Subscribers: Subscriber Types:
1. Model Subscribers
2. System Subscribers
3. Custom Subscribers diff --git a/docs/assets/diagrams/flows/model_lifecycle.mmd b/docs/assets/diagrams/flows/model_lifecycle.mmd new file mode 100644 index 0000000..936ced3 --- /dev/null +++ b/docs/assets/diagrams/flows/model_lifecycle.mmd @@ -0,0 +1,161 @@ +sequenceDiagram + participant Client as Model Client + participant Model as Model Instance + participant Events as Event System + participant Cache as Cache Layer + participant DB as Database + participant Queue as Queue System + participant Relations as Relationship Loader + participant Observer as Model Observer + + %% Model Creation + Client->>Model: Create Model + activate Model + Model->>Events: Dispatch Creating Event + activate Events + Events->>Observer: Handle Creating + Observer-->>Events: Continue + Events-->>Model: Proceed + deactivate Events + + %% Database Operation + Model->>DB: Insert Record + activate DB + DB-->>Model: Record Created + deactivate DB + + %% Post Creation + Model->>Events: Dispatch Created Event + activate Events + Events->>Observer: Handle Created + Observer-->>Events: Continue + Events->>Queue: Queue Events + Queue-->>Events: Queued + Events-->>Model: Complete + deactivate Events + Model-->>Client: Model Instance + deactivate Model + + %% Model Retrieval + Client->>Model: Find Model + activate Model + Model->>Cache: Check Cache + activate Cache + + alt Cache Hit + Cache-->>Model: Return Cached + else Cache Miss + Cache-->>Model: Not Found + Model->>DB: Query Database + activate DB + DB-->>Model: Record Found + deactivate DB + Model->>Cache: Store in Cache + Cache-->>Model: Cached + end + deactivate Cache + + %% Relationship Loading + Model->>Relations: Load Relations + activate Relations + Relations->>DB: Query Relations + activate DB + DB-->>Relations: Related Records + deactivate DB + Relations-->>Model: Relations Loaded + deactivate Relations + Model-->>Client: Complete Model + deactivate Model + + %% Model Update + Client->>Model: Update Model + activate Model + Model->>Events: Dispatch Updating Event + activate Events + Events->>Observer: Handle Updating + Observer-->>Events: Continue + Events-->>Model: Proceed + deactivate Events + + Model->>DB: Update Record + activate DB + DB-->>Model: Record Updated + deactivate DB + + Model->>Cache: Invalidate Cache + activate Cache + Cache-->>Model: Cache Cleared + deactivate Cache + + Model->>Events: Dispatch Updated Event + activate Events + Events->>Observer: Handle Updated + Observer-->>Events: Continue + Events->>Queue: Queue Events + Queue-->>Events: Queued + Events-->>Model: Complete + deactivate Events + Model-->>Client: Updated Model + deactivate Model + + %% Model Deletion + Client->>Model: Delete Model + activate Model + Model->>Events: Dispatch Deleting Event + activate Events + Events->>Observer: Handle Deleting + Observer-->>Events: Continue + Events-->>Model: Proceed + deactivate Events + + Model->>DB: Delete Record + activate DB + DB-->>Model: Record Deleted + deactivate DB + + Model->>Cache: Clear Cache + activate Cache + Cache-->>Model: Cache Cleared + deactivate Cache + + Model->>Events: Dispatch Deleted Event + activate Events + Events->>Observer: Handle Deleted + Observer-->>Events: Continue + Events->>Queue: Queue Events + Queue-->>Events: Queued + Events-->>Model: Complete + deactivate Events + Model-->>Client: Deletion Confirmed + deactivate Model + + %% Style Definitions + style Client fill:#f9f,stroke:#333,stroke-width:2px + style Model fill:#bbf,stroke:#333,stroke-width:2px + style Events fill:#bfb,stroke:#333,stroke-width:2px + style Cache fill:#fbb,stroke:#333,stroke-width:2px + style DB fill:#fbb,stroke:#333,stroke-width:2px + style Queue fill:#bfb,stroke:#333,stroke-width:2px + style Relations fill:#bbf,stroke:#333,stroke-width:2px + style Observer fill:#bfb,stroke:#333,stroke-width:2px + + %% Notes + Note over Model: Model Lifecycle + Note over Events: Event Handling + Note over Cache: Cache Management + Note over DB: Data Persistence + Note over Queue: Async Processing + Note over Relations: Relationship Management + Note over Observer: Lifecycle Hooks + + %% Model States + Note over Model: States:
1. Creating/Created
2. Retrieving/Retrieved
3. Updating/Updated
4. Deleting/Deleted + + %% Event Types + Note over Events: Events:
1. Model Events
2. Relation Events
3. Cache Events
4. Queue Events + + %% Cache Strategy + Note over Cache: Strategy:
1. Read Through
2. Write Behind
3. Cache Invalidation + + %% Observer Points + Note over Observer: Hooks:
1. Before Events
2. After Events
3. Around Events diff --git a/docs/assets/diagrams/flows/queue_processing.mmd b/docs/assets/diagrams/flows/queue_processing.mmd new file mode 100644 index 0000000..1f7a1dd --- /dev/null +++ b/docs/assets/diagrams/flows/queue_processing.mmd @@ -0,0 +1,119 @@ +sequenceDiagram + participant Source as Job Source + participant Queue as Queue Manager + participant Worker as Queue Worker + participant Job as Job Handler + participant Events as Event System + participant DB as Database + participant Failed as Failed Jobs + participant Monitor as Queue Monitor + + %% Job Creation + Source->>Queue: Dispatch Job + activate Queue + Note over Queue: Create Job Record + + %% Job Configuration + alt Has Delay + Queue->>Queue: Schedule for Later + else No Delay + Queue->>Queue: Available Immediately + end + + %% Worker Pickup + Queue->>Worker: Worker Picks Up Job + activate Worker + Note over Worker: Start Processing + + %% Job Processing + Worker->>Job: Handle Job + activate Job + + %% Database Transaction + alt Has Database Operations + Job->>DB: Begin Transaction + activate DB + Note over DB: Perform Operations + DB-->>Job: Transaction Complete + deactivate DB + end + + %% Event Dispatching + alt Has Events + Job->>Events: Dispatch Events + activate Events + Note over Events: Process Events + Events-->>Job: Events Handled + deactivate Events + end + + %% Job Completion Check + alt Job Succeeds + Job-->>Worker: Processing Complete + Worker-->>Queue: Job Completed + Queue->>Events: JobProcessed Event + else Job Fails + Job-->>Worker: Throws Exception + + %% Retry Logic + alt Can Retry + Worker->>Queue: Release Job + Note over Queue: Increment Attempts + Queue-->>Worker: Job Released + else Max Retries Exceeded + Worker->>Failed: Move to Failed Jobs + activate Failed + Note over Failed: Log Failure + Failed-->>Worker: Failure Logged + deactivate Failed + end + end + + deactivate Job + deactivate Worker + deactivate Queue + + %% Queue Monitoring + Monitor->>Queue: Check Status + activate Monitor + Queue-->>Monitor: Queue Statistics + Note over Monitor: Monitor Queue Health + + Monitor->>Failed: Check Failed Jobs + Failed-->>Monitor: Failed Job Count + + Monitor->>Worker: Check Workers + Worker-->>Monitor: Worker Status + deactivate Monitor + + %% Style Definitions + style Source fill:#f9f,stroke:#333,stroke-width:2px + style Queue fill:#bbf,stroke:#333,stroke-width:2px + style Worker fill:#bfb,stroke:#333,stroke-width:2px + style Job fill:#bfb,stroke:#333,stroke-width:2px + style Events fill:#fbb,stroke:#333,stroke-width:2px + style DB fill:#fbb,stroke:#333,stroke-width:2px + style Failed fill:#fbb,stroke:#333,stroke-width:2px + style Monitor fill:#bbf,stroke:#333,stroke-width:2px + + %% Notes + Note right of Source: Application Code + Note right of Queue: Queue Management + Note right of Worker: Job Processing + Note right of Job: Business Logic + Note right of Events: Event System + Note right of DB: Data Layer + Note right of Failed: Error Handling + Note right of Monitor: Health Checks + + %% Job States + Note over Queue: Job States:
1. Pending
2. Reserved
3. Released
4. Failed + + %% Processing Types + Note over Worker: Processing:
1. Immediate
2. Delayed
3. Batched
4. Chained + + %% Retry Strategy + Note over Failed: Retry Strategy:
1. Exponential Backoff
2. Max Attempts
3. Custom Delays + + %% Monitoring Aspects + Note over Monitor: Monitoring:
1. Queue Size
2. Processing Rate
3. Error Rate
4. Worker Health diff --git a/docs/assets/diagrams/flows/request_lifecycle.mmd b/docs/assets/diagrams/flows/request_lifecycle.mmd new file mode 100644 index 0000000..f3b5004 --- /dev/null +++ b/docs/assets/diagrams/flows/request_lifecycle.mmd @@ -0,0 +1,98 @@ +sequenceDiagram + participant Client + participant Server as HTTP Server + participant Kernel as HTTP Kernel + participant Pipeline as Middleware Pipeline + participant Router + participant Controller + participant Services + participant Events + participant DB as Database + + %% Initial Request + Client->>Server: HTTP Request + activate Server + Server->>Kernel: Handle Request + activate Kernel + + %% Global Middleware + Kernel->>Pipeline: Process Global Middleware + activate Pipeline + Note over Pipeline: - Check Maintenance Mode
- Validate Post Size
- Trim Strings
- Convert Empty to Null + Pipeline-->>Kernel: Request Processed + deactivate Pipeline + + %% Route Matching + Kernel->>Router: Match Route + activate Router + Router-->>Kernel: Route Found + deactivate Router + + %% Route Middleware + Kernel->>Pipeline: Process Route Middleware + activate Pipeline + Note over Pipeline: - Authentication
- Authorization
- Throttling
- CSRF Protection + Pipeline-->>Kernel: Request Processed + deactivate Pipeline + + %% Controller Action + Kernel->>Controller: Handle Request + activate Controller + + %% Service Layer + Controller->>Services: Process Business Logic + activate Services + + %% Database Operations + Services->>DB: Query Data + activate DB + DB-->>Services: Data Retrieved + deactivate DB + + %% Event Dispatching + Services->>Events: Dispatch Events + activate Events + Note over Events: - Model Events
- Custom Events
- System Events + Events-->>Services: Events Processed + deactivate Events + + Services-->>Controller: Logic Processed + deactivate Services + + %% Response Generation + Controller-->>Kernel: Generate Response + deactivate Controller + + %% Response Middleware + Kernel->>Pipeline: Process Response Middleware + activate Pipeline + Note over Pipeline: - Session
- Cookies
- Headers
- Response Compression + Pipeline-->>Kernel: Response Processed + deactivate Pipeline + + %% Final Response + Kernel-->>Server: Return Response + deactivate Kernel + Server-->>Client: HTTP Response + deactivate Server + + %% Style Definitions + style Client fill:#f9f,stroke:#333,stroke-width:2px + style Server fill:#bbf,stroke:#333,stroke-width:2px + style Kernel fill:#bbf,stroke:#333,stroke-width:2px + style Pipeline fill:#bfb,stroke:#333,stroke-width:2px + style Router fill:#bfb,stroke:#333,stroke-width:2px + style Controller fill:#bfb,stroke:#333,stroke-width:2px + style Services fill:#fbb,stroke:#333,stroke-width:2px + style Events fill:#fbb,stroke:#333,stroke-width:2px + style DB fill:#fbb,stroke:#333,stroke-width:2px + + %% Notes + Note right of Server: Entry Point + Note right of Kernel: Request Processing + Note right of Pipeline: Middleware Chain + Note right of Router: Route Resolution + Note right of Controller: Business Logic + Note right of Services: Service Layer + Note right of Events: Event System + Note right of DB: Data Layer diff --git a/docs/bus_gap_analysis.md b/docs/bus_gap_analysis.md new file mode 100644 index 0000000..607913c --- /dev/null +++ b/docs/bus_gap_analysis.md @@ -0,0 +1,303 @@ +# Bus Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Bus package's actual implementation and Laravel's Bus functionality, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Bus Package Specification](bus_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Job Chaining +class ChainedCommand { + // Need to implement: + void onConnection(String connection); + void onQueue(String queue); + void delay(Duration duration); + void middleware(List middleware); +} + +// 2. Rate Limiting +class RateLimitedCommand { + // Need to implement: + void rateLimit(int maxAttempts, Duration duration); + void rateLimitPerUser(int maxAttempts, Duration duration); + void withoutOverlapping(); +} + +// 3. Error Handling +class FailedCommandHandler { + // Need to implement: + Future failed(Command command, Exception exception); + Future retry(String commandId); + Future forget(String commandId); + Future flush(); +} +``` + +### 2. Existing Features Not Documented + +```dart +// Implemented but not documented: + +// 1. Command Mapping +class CommandMapper { + /// Maps command types to handlers + final Map _handlers = {}; + + /// Registers command handler + void map( + THandler Function() factory + ); +} + +// 2. Command Context +class CommandContext { + /// Command metadata + final Map _metadata = {}; + + /// Sets command context + void withContext(String key, dynamic value); + + /// Gets command context + T? getContext(String key); +} + +// 3. Command Lifecycle +class CommandLifecycle { + /// Command hooks + final List _beforeHandling = []; + final List _afterHandling = []; + + /// Registers lifecycle hooks + void beforeHandling(Function callback); + void afterHandling(Function callback); +} +``` + +### 3. Integration Points Not Documented + +```dart +// 1. Queue Integration +class QueuedCommand { + /// Queue configuration + String get connection => 'default'; + String get queue => 'default'; + Duration? get delay => null; + + /// Queue callbacks + void onQueue(QueueContract queue); + void onConnection(String connection); +} + +// 2. Event Integration +class EventedCommand { + /// Event dispatcher + final EventDispatcherContract _events; + + /// Dispatches command events + void dispatchCommandEvent(String event, dynamic data); + void subscribeCommandEvents(EventSubscriber subscriber); +} + +// 3. Cache Integration +class CachedCommand { + /// Cache configuration + String get cacheKey => ''; + Duration get cacheTTL => Duration(minutes: 60); + + /// Cache operations + Future cache(); + Future clearCache(); +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation + +```dart +// Need to document: + +/// Maps command types to their handlers. +/// +/// Example: +/// ```dart +/// mapper.map( +/// () => CreateOrderHandler(repository) +/// ); +/// ``` +void map( + THandler Function() factory +); + +/// Sets command execution context. +/// +/// Example: +/// ```dart +/// command.withContext('user_id', userId); +/// command.withContext('tenant', tenant); +/// ``` +void withContext(String key, dynamic value); +``` + +### 2. Missing Integration Examples + +```dart +// Need examples for: + +// 1. Queue Integration +var command = CreateOrder(...) + ..onQueue('orders') + ..delay(Duration(minutes: 5)); + +await bus.dispatch(command); + +// 2. Event Integration +class OrderCommand extends EventedCommand { + void handle() { + // Handle command + dispatchCommandEvent('order.handled', order); + } +} + +// 3. Cache Integration +class GetOrderCommand extends CachedCommand { + @override + String get cacheKey => 'order.$orderId'; + + Future handle() async { + return await cache(() => repository.find(orderId)); + } +} +``` + +### 3. Missing Test Coverage + +```dart +// Need tests for: + +void main() { + group('Command Mapping', () { + test('maps commands to handlers', () { + var mapper = CommandMapper(); + mapper.map( + () => CreateOrderHandler(repository) + ); + + var handler = mapper.resolveHandler(CreateOrder()); + expect(handler, isA()); + }); + }); + + group('Command Context', () { + test('handles command context', () { + var command = TestCommand() + ..withContext('key', 'value'); + + expect(command.getContext('key'), equals('value')); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Command chaining (Laravel compatibility) + - Rate limiting (Laravel compatibility) + - Better error handling + +2. **Medium Priority** + - Command mapping + - Command context + - Performance optimizations + +3. **Low Priority** + - Additional helper methods + - Extended testing utilities + - Debug/profiling tools + +## Next Steps + +1. **Implementation Tasks** + - Add command chaining + - Add rate limiting + - Add error handling + - Improve queue integration + +2. **Documentation Tasks** + - Document command mapping + - Document command context + - Document command lifecycle + - Add integration examples + +3. **Testing Tasks** + - Add command mapping tests + - Add context tests + - Add lifecycle tests + - Add integration tests + +## Development Guidelines + +### 1. Getting Started +Before implementing bus features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Bus Package Specification](bus_package_specification.md) + +### 2. Implementation Process +For each bus feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Bus Package Specification](bus_package_specification.md) + +### 4. Integration Considerations +When implementing bus features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Bus system must: +1. Handle high command throughput +2. Process chains efficiently +3. Support async operations +4. Scale horizontally +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Bus tests must: +1. Cover all command scenarios +2. Test chaining behavior +3. Verify rate limiting +4. Check error handling +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Bus documentation must: +1. Explain command patterns +2. Show chaining examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/bus_package_specification.md b/docs/bus_package_specification.md new file mode 100644 index 0000000..8bc2435 --- /dev/null +++ b/docs/bus_package_specification.md @@ -0,0 +1,424 @@ +# Bus Package Specification + +## Overview + +The Bus package provides a robust command and event bus implementation that matches Laravel's bus functionality. It integrates with our Queue, Event, and Pipeline packages to provide a complete message bus solution with support for command handling, event dispatching, and middleware processing. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Events Package Specification](events_package_specification.md) for event handling +> - See [Queue Package Specification](queue_package_specification.md) for queue integration + +## Core Features + +### 1. Command Bus + +```dart +/// Core command bus implementation +class CommandBus implements CommandBusContract { + final Container _container; + final QueueContract? _queue; + final PipelineContract _pipeline; + + CommandBus( + this._container, + this._pipeline, [ + this._queue + ]); + + /// Dispatches a command + Future dispatch(Command command) async { + if (command is ShouldQueue && _queue != null) { + return await dispatchToQueue(command); + } + + return await dispatchNow(command); + } + + /// Dispatches a command immediately + Future dispatchNow(Command command) async { + var handler = _resolveHandler(command); + + return await _pipeline + .send(command) + .through(_getPipes()) + .then((cmd) => handler.handle(cmd)); + } + + /// Dispatches a command to queue + Future dispatchToQueue(Command command) async { + await _queue!.push(QueuedCommandJob( + command: command, + handler: _resolveHandler(command) + )); + } + + /// Creates a command batch + PendingBatch batch(List commands) { + return PendingCommandBatch(this, commands); + } + + /// Creates a command chain + PendingChain chain(List commands) { + return PendingCommandChain(this, commands); + } + + /// Resolves command handler + Handler _resolveHandler(Command command) { + var handlerType = command.handler; + return _container.make(handlerType); + } + + /// Gets command pipes + List _getPipes() { + return [ + TransactionPipe(), + ValidationPipe(), + AuthorizationPipe() + ]; + } +} +``` + +### 2. Event Bus + +```dart +/// Core event bus implementation +class EventBus implements EventBusContract { + final Container _container; + final EventDispatcherContract _events; + final QueueContract? _queue; + + EventBus( + this._container, + this._events, [ + this._queue + ]); + + /// Dispatches an event + Future dispatch(Event event) async { + if (event is ShouldQueue && _queue != null) { + await dispatchToQueue(event); + } else { + await dispatchNow(event); + } + } + + /// Dispatches an event immediately + Future dispatchNow(Event event) async { + await _events.dispatch(event); + } + + /// Dispatches an event to queue + Future dispatchToQueue(Event event) async { + await _queue!.push(QueuedEventJob( + event: event, + listeners: _events.getListeners(event.runtimeType) + )); + } + + /// Registers an event listener + void listen(void Function(T event) listener) { + _events.listen(listener); + } + + /// Registers an event subscriber + void subscribe(EventSubscriber subscriber) { + _events.subscribe(subscriber); + } +} +``` + +### 3. Bus Middleware + +```dart +/// Transaction middleware +class TransactionPipe implements PipeContract { + final DatabaseManager _db; + + TransactionPipe(this._db); + + @override + Future handle(dynamic passable, Function next) async { + return await _db.transaction((tx) async { + return await next(passable); + }); + } +} + +/// Validation middleware +class ValidationPipe implements PipeContract { + final Validator _validator; + + ValidationPipe(this._validator); + + @override + Future handle(dynamic passable, Function next) async { + if (passable is ValidatableCommand) { + await _validator.validate( + passable.toMap(), + passable.rules() + ); + } + + return await next(passable); + } +} + +/// Authorization middleware +class AuthorizationPipe implements PipeContract { + final AuthManager _auth; + + AuthorizationPipe(this._auth); + + @override + Future handle(dynamic passable, Function next) async { + if (passable is AuthorizableCommand) { + if (!await passable.authorize(_auth)) { + throw UnauthorizedException(); + } + } + + return await next(passable); + } +} +``` + +### 4. Command Batching + +```dart +/// Pending command batch +class PendingCommandBatch implements PendingBatch { + final CommandBus _bus; + final List _commands; + bool _allowFailures = false; + + PendingCommandBatch(this._bus, this._commands); + + /// Allows failures in batch + PendingBatch allowFailures() { + _allowFailures = true; + return this; + } + + /// Dispatches the batch + Future dispatch() async { + for (var command in _commands) { + try { + await _bus.dispatchNow(command); + } catch (e) { + if (!_allowFailures) rethrow; + } + } + } +} + +/// Pending command chain +class PendingCommandChain implements PendingChain { + final CommandBus _bus; + final List _commands; + + PendingCommandChain(this._bus, this._commands); + + /// Dispatches the chain + Future dispatch() async { + dynamic result; + + for (var command in _commands) { + if (command is ChainedCommand) { + command.setPreviousResult(result); + } + + result = await _bus.dispatchNow(command); + } + } +} +``` + +## Integration Examples + +### 1. Command Bus Usage +```dart +// Define command +class CreateOrder implements Command { + final String customerId; + final List products; + + @override + Type get handler => CreateOrderHandler; +} + +// Define handler +class CreateOrderHandler implements Handler { + final OrderRepository _orders; + + CreateOrderHandler(this._orders); + + @override + Future handle(CreateOrder command) async { + return await _orders.create( + customerId: command.customerId, + products: command.products + ); + } +} + +// Dispatch command +var order = await bus.dispatch(CreateOrder( + customerId: '123', + products: ['abc', 'xyz'] +)); +``` + +### 2. Event Bus Usage +```dart +// Define event +class OrderCreated implements Event { + final Order order; + OrderCreated(this.order); +} + +// Register listener +eventBus.listen((event) async { + await notifyCustomer(event.order); +}); + +// Dispatch event +await eventBus.dispatch(OrderCreated(order)); +``` + +### 3. Command Batching +```dart +// Create batch +await bus.batch([ + CreateOrder(...), + UpdateInventory(...), + NotifyShipping(...) +]) +.allowFailures() +.dispatch(); + +// Create chain +await bus.chain([ + CreateOrder(...), + ProcessPayment(...), + ShipOrder(...) +]) +.dispatch(); +``` + +## Testing + +```dart +void main() { + group('Command Bus', () { + test('dispatches commands', () async { + var bus = CommandBus(container, pipeline); + var command = CreateOrder(...); + + await bus.dispatch(command); + + verify(() => handler.handle(command)).called(1); + }); + + test('handles command batch', () async { + var bus = CommandBus(container, pipeline); + + await bus.batch([ + CreateOrder(...), + UpdateInventory(...) + ]).dispatch(); + + verify(() => bus.dispatchNow(any())).called(2); + }); + }); + + group('Event Bus', () { + test('dispatches events', () async { + var bus = EventBus(container, dispatcher); + var event = OrderCreated(order); + + await bus.dispatch(event); + + verify(() => dispatcher.dispatch(event)).called(1); + }); + + test('queues events', () async { + var bus = EventBus(container, dispatcher, queue); + var event = OrderShipped(order); + + await bus.dispatch(event); + + verify(() => queue.push(any())).called(1); + }); + }); +} +``` + +## Next Steps + +1. Implement core bus features +2. Add middleware support +3. Add batching/chaining +4. Add queue integration +5. Write tests +6. Add benchmarks + +## Development Guidelines + +### 1. Getting Started +Before implementing bus features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Events Package Specification](events_package_specification.md) +6. Review [Queue Package Specification](queue_package_specification.md) + +### 2. Implementation Process +For each bus feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in related packages + +### 4. Integration Considerations +When implementing bus features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Bus system must: +1. Handle high command throughput +2. Process events efficiently +3. Support async operations +4. Scale horizontally +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Bus tests must: +1. Cover all command scenarios +2. Test event handling +3. Verify queue integration +4. Check middleware behavior +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Bus documentation must: +1. Explain command patterns +2. Show event examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/config_gap_analysis.md b/docs/config_gap_analysis.md new file mode 100644 index 0000000..e1cc0a4 --- /dev/null +++ b/docs/config_gap_analysis.md @@ -0,0 +1,335 @@ +# Config Package Gap Analysis + +## Overview + +This document analyzes the gaps between our current configuration handling (in Core package) and Laravel's Config package functionality, identifying what needs to be implemented as a standalone Config package. + +> **Related Documentation** +> - See [Config Package Specification](config_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup + +## Implementation Gaps + +### 1. Missing Package Structure +```dart +// Need to create dedicated Config package: + +packages/config/ +├── lib/ +│ ├── src/ +│ │ ├── config_repository.dart +│ │ ├── environment_loader.dart +│ │ ├── config_loader.dart +│ │ └── config_cache.dart +│ └── config.dart +├── test/ +└── example/ +``` + +### 2. Missing Core Features +```dart +// 1. Config Repository +class ConfigRepository { + // Need to implement: + T? get(String key, [T? defaultValue]); + void set(String key, dynamic value); + bool has(String key); + Map all(); + void merge(Map items); +} + +// 2. Environment Loading +class EnvironmentLoader { + // Need to implement: + Future load([String? path]); + String? get(String key, [String? defaultValue]); + void set(String key, String value); + bool has(String key); +} + +// 3. Configuration Loading +class ConfigurationLoader { + // Need to implement: + Future> load(); + Future> loadFile(String path); + Future reload(); +} +``` + +### 3. Missing Laravel Features +```dart +// 1. Package Configuration +class PackageConfig { + // Need to implement: + Future publish(String package, Map paths); + Future publishForce(String package, Map paths); + List publishedPackages(); +} + +// 2. Configuration Groups +class ConfigurationGroups { + // Need to implement: + void group(String name, List paths); + List getGroup(String name); + bool hasGroup(String name); +} + +// 3. Configuration Caching +class ConfigCache { + // Need to implement: + Future cache(Map config); + Future?> load(); + Future clear(); +} +``` + +## Integration Gaps + +### 1. Container Integration +```dart +// Need to implement: + +class ConfigServiceProvider { + void register() { + // Register config repository + container.singleton((c) => + ConfigRepository( + loader: c.make(), + cache: c.make() + ) + ); + + // Register environment loader + container.singleton((c) => + EnvironmentLoader( + path: c.make().base + ) + ); + } +} +``` + +### 2. Package Integration +```dart +// Need to implement: + +class PackageServiceProvider { + void register() { + // Register package config + publishConfig('my-package', { + 'config/my-package.php': 'my-package' + }); + } + + void boot() { + // Merge package config + config.merge({ + 'my-package': { + 'key': 'value' + } + }); + } +} +``` + +### 3. Environment Integration +```dart +// Need to implement: + +class EnvironmentServiceProvider { + void boot() { + var env = container.make(); + + // Load environment files + env.load(); + + if (env.get('APP_ENV') == 'local') { + env.load('.env.local'); + } + + // Set environment variables + config.set('app.env', env.get('APP_ENV', 'production')); + config.set('app.debug', env.get('APP_DEBUG', 'false') == 'true'); + } +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation +```dart +// Need to document: + +/// Manages application configuration. +/// +/// Provides access to configuration values using dot notation: +/// ```dart +/// var dbHost = config.get('database.connections.mysql.host'); +/// ``` +class ConfigRepository { + /// Gets a configuration value. + /// + /// Returns [defaultValue] if key not found. + T? get(String key, [T? defaultValue]); +} +``` + +### 2. Missing Usage Examples +```dart +// Need examples for: + +// 1. Basic Configuration +var appName = config.get('app.name', 'My App'); +var debug = config.get('app.debug', false); + +// 2. Environment Configuration +var dbConfig = { + 'host': env('DB_HOST', 'localhost'), + 'port': env('DB_PORT', '3306'), + 'database': env('DB_DATABASE'), + 'username': env('DB_USERNAME'), + 'password': env('DB_PASSWORD') +}; + +// 3. Package Configuration +class MyPackageServiceProvider { + void register() { + publishConfig('my-package', { + 'config/my-package.php': 'my-package' + }); + } +} +``` + +### 3. Missing Test Coverage +```dart +// Need tests for: + +void main() { + group('Config Repository', () { + test('gets nested values', () { + var config = ConfigRepository({ + 'app': { + 'name': 'Test App', + 'nested': {'key': 'value'} + } + }); + + expect(config.get('app.name'), equals('Test App')); + expect(config.get('app.nested.key'), equals('value')); + }); + }); + + group('Environment Loader', () { + test('loads env files', () async { + var env = EnvironmentLoader(); + await env.load('.env.test'); + + expect(env.get('APP_NAME'), equals('Test App')); + expect(env.get('APP_ENV'), equals('testing')); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Create Config package structure + - Implement core repository + - Add environment loading + - Add configuration loading + +2. **Medium Priority** + - Add package configuration + - Add configuration groups + - Add configuration caching + - Add container integration + +3. **Low Priority** + - Add helper functions + - Add testing utilities + - Add debugging tools + +## Next Steps + +1. **Package Creation** + - Create package structure + - Move config code from Core + - Add package dependencies + - Setup testing + +2. **Core Implementation** + - Implement ConfigRepository + - Implement EnvironmentLoader + - Implement ConfigurationLoader + - Add caching support + +3. **Integration Implementation** + - Add container integration + - Add package support + - Add environment support + - Add service providers + +Would you like me to: +1. Create the Config package structure? +2. Start implementing core features? +3. Create detailed implementation plans? + +## Development Guidelines + +### 1. Getting Started +Before implementing config features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Config Package Specification](config_package_specification.md) + +### 2. Implementation Process +For each config feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Config Package Specification](config_package_specification.md) + +### 4. Integration Considerations +When implementing config features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Config system must: +1. Cache configuration efficiently +2. Minimize file I/O +3. Support lazy loading +4. Handle environment variables efficiently +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Config tests must: +1. Cover all configuration scenarios +2. Test environment handling +3. Verify caching behavior +4. Check file operations +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Config documentation must: +1. Explain configuration patterns +2. Show environment examples +3. Cover caching strategies +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/config_package_specification.md b/docs/config_package_specification.md new file mode 100644 index 0000000..3c9186a --- /dev/null +++ b/docs/config_package_specification.md @@ -0,0 +1,451 @@ +# Config Package Specification + +## Overview + +The Config package provides a flexible configuration management system that matches Laravel's config functionality. It integrates with our Container and Package systems while supporting hierarchical configuration, environment-based settings, and caching. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Contracts Package Specification](contracts_package_specification.md) for config contracts + +## Core Features + +### 1. Configuration Repository + +```dart +/// Core configuration repository +class ConfigRepository implements ConfigContract { + final Container _container; + final Map _items; + final EnvironmentLoader _env; + final ConfigCache? _cache; + + ConfigRepository( + this._container, [ + Map? items, + EnvironmentLoader? env, + ConfigCache? cache + ]) : _items = items ?? {}, + _env = env ?? EnvironmentLoader(), + _cache = cache; + + @override + T? get(String key, [T? defaultValue]) { + var value = _getNestedValue(key); + if (value == null) { + return defaultValue; + } + return _cast(value); + } + + @override + void set(String key, dynamic value) { + _setNestedValue(key, value); + _cache?.clear(); + } + + @override + bool has(String key) { + return _getNestedValue(key) != null; + } + + /// Gets all configuration items + Map all() => Map.from(_items); + + /// Merges configuration values + void merge(Map items) { + _items.addAll(_deepMerge(_items, items)); + _cache?.clear(); + } + + /// Deep merges two maps + Map _deepMerge( + Map target, + Map source + ) { + source.forEach((key, value) { + if (value is Map && target[key] is Map) { + target[key] = _deepMerge( + target[key] as Map, + value as Map + ); + } else { + target[key] = value; + } + }); + return target; + } + + /// Casts a value to the requested type + T _cast(dynamic value) { + if (value is T) return value; + + // Handle common type conversions + if (T == bool) { + if (value is String) { + return (value.toLowerCase() == 'true') as T; + } + return (value == 1) as T; + } + + if (T == int && value is String) { + return int.parse(value) as T; + } + + if (T == double && value is String) { + return double.parse(value) as T; + } + + throw ConfigCastException( + 'Cannot cast $value to $T' + ); + } +} +``` + +### 2. Environment Management + +```dart +/// Manages environment configuration +class EnvironmentManager { + final Container _container; + final Map _cache = {}; + final List _files = ['.env']; + + EnvironmentManager(this._container); + + /// Loads environment files + Future load([String? path]) async { + path ??= _container.make().base; + + for (var file in _files) { + var envFile = File('$path/$file'); + if (await envFile.exists()) { + var contents = await envFile.readAsString(); + _parseEnvFile(contents); + } + } + } + + /// Gets an environment variable + String? get(String key, [String? defaultValue]) { + return _cache[key] ?? + Platform.environment[key] ?? + defaultValue; + } + + /// Sets an environment variable + void set(String key, String value) { + _cache[key] = value; + } + + /// Adds an environment file + void addEnvFile(String file) { + _files.add(file); + } + + /// Parses an environment file + void _parseEnvFile(String contents) { + var lines = contents.split('\n'); + for (var line in lines) { + if (_isComment(line)) continue; + if (_isEmpty(line)) continue; + + var parts = line.split('='); + if (parts.length != 2) continue; + + var key = parts[0].trim(); + var value = _parseValue(parts[1].trim()); + + _cache[key] = value; + } + } + + /// Parses an environment value + String _parseValue(String value) { + // Remove quotes + if (value.startsWith('"') && value.endsWith('"')) { + value = value.substring(1, value.length - 1); + } + + // Handle special values + switch (value.toLowerCase()) { + case 'true': + case '(true)': + return 'true'; + case 'false': + case '(false)': + return 'false'; + case 'empty': + case '(empty)': + return ''; + case 'null': + case '(null)': + return ''; + } + + return value; + } +} +``` + +### 3. Package Configuration + +```dart +/// Manages package configuration publishing +class ConfigPublisher { + final Container _container; + final Map> _publishGroups = {}; + + ConfigPublisher(this._container); + + /// Publishes configuration files + Future publish( + String package, + Map paths, [ + List? groups + ]) async { + var resolver = _container.make(); + var configPath = resolver.config; + + for (var entry in paths.entries) { + var source = entry.key; + var dest = '$configPath/${entry.value}'; + + await _publishFile(source, dest); + + if (groups != null) { + for (var group in groups) { + _publishGroups.putIfAbsent(group, () => []) + .add(dest); + } + } + } + } + + /// Gets files in a publish group + List getGroup(String name) { + return _publishGroups[name] ?? []; + } + + /// Copies a configuration file + Future _publishFile( + String source, + String destination + ) async { + var sourceFile = File(source); + var destFile = File(destination); + + if (!await destFile.exists()) { + await destFile.create(recursive: true); + await sourceFile.copy(destination); + } + } +} +``` + +### 4. Configuration Cache + +```dart +/// Caches configuration values +class ConfigCache { + final Container _container; + final String _cacheKey = 'config.cache'; + + ConfigCache(this._container); + + /// Caches configuration values + Future cache(Map items) async { + var cache = _container.make(); + await cache.forever(_cacheKey, items); + } + + /// Gets cached configuration + Future?> get() async { + var cache = _container.make(); + return await cache.get>(_cacheKey); + } + + /// Clears cached configuration + Future clear() async { + var cache = _container.make(); + await cache.forget(_cacheKey); + } +} +``` + +## Integration Examples + +### 1. Package Configuration +```dart +class MyPackageServiceProvider extends ServiceProvider { + @override + void register() { + // Publish package config + publishConfig('my-package', { + 'config/my-package.php': 'my-package' + }); + } + + @override + void boot() { + // Merge package config + var config = container.make(); + config.merge({ + 'my-package': { + 'key': 'value' + } + }); + } +} +``` + +### 2. Environment Configuration +```dart +class AppServiceProvider extends ServiceProvider { + @override + void boot() { + var env = container.make(); + + // Add environment files + env.addEnvFile('.env.local'); + if (protevusEnv.isTesting) { + env.addEnvFile('.env.testing'); + } + + // Load environment + await env.load(); + } +} +``` + +### 3. Configuration Cache +```dart +class CacheCommand { + Future handle() async { + var config = container.make(); + var cache = container.make(); + + // Cache config + await cache.cache(config.all()); + + // Clear config cache + await cache.clear(); + } +} +``` + +## Testing + +```dart +void main() { + group('Config Repository', () { + test('merges configuration', () { + var config = ConfigRepository(container); + + config.set('database', { + 'default': 'mysql', + 'connections': { + 'mysql': {'host': 'localhost'} + } + }); + + config.merge({ + 'database': { + 'connections': { + 'mysql': {'port': 3306} + } + } + }); + + expect( + config.get('database.connections.mysql'), + equals({ + 'host': 'localhost', + 'port': 3306 + }) + ); + }); + }); + + group('Environment Manager', () { + test('loads multiple env files', () async { + var env = EnvironmentManager(container); + env.addEnvFile('.env.testing'); + + await env.load(); + + expect(env.get('APP_ENV'), equals('testing')); + }); + }); +} +``` + +## Next Steps + +1. Complete package config publishing +2. Add config merging +3. Enhance environment handling +4. Add caching improvements +5. Write more tests + +Would you like me to enhance any other package specifications? + +## Development Guidelines + +### 1. Getting Started +Before implementing config features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Understand [Contracts Package Specification](contracts_package_specification.md) + +### 2. Implementation Process +For each config feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Implement required contracts (see [Contracts Package Specification](contracts_package_specification.md)) + +### 4. Integration Considerations +When implementing config features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) +5. Implement all contracts from [Contracts Package Specification](contracts_package_specification.md) + +### 5. Performance Guidelines +Config system must: +1. Cache configuration efficiently +2. Minimize file I/O +3. Support lazy loading +4. Handle environment variables efficiently +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Config tests must: +1. Cover all configuration scenarios +2. Test environment handling +3. Verify caching behavior +4. Check file operations +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Config documentation must: +1. Explain configuration patterns +2. Show environment examples +3. Cover caching strategies +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/container_feature_integration.md b/docs/container_feature_integration.md new file mode 100644 index 0000000..91c70c0 --- /dev/null +++ b/docs/container_feature_integration.md @@ -0,0 +1,379 @@ +# Container Feature Integration Guide + +## Overview + +This guide demonstrates how the Container's three major features work together to provide powerful dependency management: +1. Contextual Binding - Different implementations based on context +2. Method Injection - Automatic dependency resolution for methods +3. Tagged Bindings - Grouping related services + +## Real World Example: Multi-tenant Reporting System + +Let's build a complete multi-tenant reporting system that showcases all three features working together. + +### System Requirements + +1. Multiple tenants (clients) each need their own: + - Database connection + - Storage system + - Report formatting + +2. Various types of reports: + - Performance reports + - Financial reports + - User activity reports + +3. Each report needs: + - Data access + - Formatting + - Storage + - Logging + +### Base Interfaces + +```dart +/// Base interface for all reports +abstract class Report { + Future generate(); + Future save(); +} + +/// Database connection interface +abstract class Database { + Future>> query(String sql); +} + +/// Storage system interface +abstract class Storage { + Future save(String path, List data); + Future> load(String path); +} + +/// Report formatter interface +abstract class ReportFormatter { + String format(Map data); +} +``` + +### Tenant-Specific Implementations + +```dart +/// Tenant A's database implementation +class TenantADatabase implements Database { + @override + Future>> query(String sql) { + // Tenant A specific database logic + } +} + +/// Tenant B's database implementation +class TenantBDatabase implements Database { + @override + Future>> query(String sql) { + // Tenant B specific database logic + } +} + +/// Similar implementations for Storage and Formatter... +``` + +### Report Implementations + +```dart +class PerformanceReport implements Report { + final Database db; + final Storage storage; + final ReportFormatter formatter; + + PerformanceReport(this.db, this.storage, this.formatter); + + @override + Future generate() async { + var data = await db.query('SELECT * FROM performance_metrics'); + var formatted = formatter.format(data); + await storage.save('performance.report', formatted.codeUnits); + } +} + +// Similar implementations for Financial and UserActivity reports... +``` + +### Using All Three Features Together + +1. First, set up contextual bindings for tenant-specific services: + +```dart +void configureTenantA(Container container) { + // Bind tenant-specific implementations + container.when(TenantAContext) + .needs() + .give(TenantADatabase()); + + container.when(TenantAContext) + .needs() + .give(TenantAStorage()); + + container.when(TenantAContext) + .needs() + .give(TenantAFormatter()); +} + +void configureTenantB(Container container) { + // Similar bindings for Tenant B... +} +``` + +2. Set up tagged bindings for reports: + +```dart +void configureReports(Container container) { + // Bind report implementations + container.bind(PerformanceReport); + container.bind(FinancialReport); + container.bind(UserActivityReport); + + // Tag them for easy retrieval + container.tag([ + PerformanceReport, + FinancialReport, + UserActivityReport + ], 'reports'); + + // Additional tags for categorization + container.tag([PerformanceReport], 'metrics-reports'); + container.tag([FinancialReport], 'financial-reports'); +} +``` + +3. Create a report manager that uses method injection: + +```dart +class ReportManager { + final Container container; + + ReportManager(this.container); + + /// Generates all reports for a tenant + /// Uses method injection for the logger parameter + Future generateAllReports( + TenantContext tenant, + {required DateTime date} + ) async { + // Get all tagged reports + var reports = container.taggedAs('reports'); + + // Generate each report using tenant context + for (var report in reports) { + await container.call( + report, + 'generate', + parameters: {'date': date}, + context: tenant // Uses contextual binding + ); + } + } + + /// Generates specific report types + /// Uses method injection for dependencies + Future generateMetricsReports( + TenantContext tenant, + Logger logger, // Injected automatically + MetricsService metrics // Injected automatically + ) async { + var reports = container.taggedAs('metrics-reports'); + + for (var report in reports) { + logger.info('Generating metrics report: ${report.runtimeType}'); + await container.call(report, 'generate', context: tenant); + metrics.recordReportGeneration(report); + } + } +} +``` + +### Using the Integrated System + +```dart +void main() async { + var container = Container(); + + // Configure container + configureTenantA(container); + configureTenantB(container); + configureReports(container); + + // Create report manager + var manager = ReportManager(container); + + // Generate reports for Tenant A + await manager.generateAllReports( + TenantAContext(), + date: DateTime.now() + ); + + // Generate only metrics reports for Tenant B + await manager.generateMetricsReports( + TenantBContext() + ); +} +``` + +## How the Features Work Together + +1. **Contextual Binding** ensures: + - Each tenant gets their own implementations + - Services are properly scoped + - No cross-tenant data leakage + +2. **Method Injection** provides: + - Automatic dependency resolution + - Clean method signatures + - Flexible parameter handling + +3. **Tagged Bindings** enable: + - Easy service grouping + - Dynamic service discovery + - Flexible categorization + +## Common Integration Patterns + +1. **Service Location with Context** +```dart +// Get tenant-specific service +var db = container.make(context: tenantContext); + +// Get all services of a type for a tenant +var reports = container.taggedAs('reports') + .map((r) => container.make(r, context: tenantContext)) + .toList(); +``` + +2. **Method Injection with Tags** +```dart +Future processReports(Logger logger) async { + // Logger is injected, reports are retrieved by tag + var reports = container.taggedAs('reports'); + + for (var report in reports) { + logger.info('Processing ${report.runtimeType}'); + await container.call(report, 'process'); + } +} +``` + +3. **Contextual Services with Tags** +```dart +Future generateTenantReports(TenantContext tenant) async { + // Get all reports + var reports = container.taggedAs('reports'); + + // Process each with tenant context + for (var report in reports) { + await container.call( + report, + 'generate', + context: tenant + ); + } +} +``` + +## Best Practices + +1. **Clear Service Organization** +```dart +// Group related tags +container.tag([Service1, Service2], 'data-services'); +container.tag([Service1], 'cacheable-services'); + +// Group related contexts +container.when(TenantContext) + .needs() + .give(TenantDatabase()); +``` + +2. **Consistent Dependency Resolution** +```dart +// Prefer method injection for flexible dependencies +Future processReport( + Report report, + Logger logger, // Injected + MetricsService metrics // Injected +) async { + // Implementation +} + +// Use contextual binding for tenant-specific services +container.when(TenantContext) + .needs() + .give(TenantStorage()); +``` + +3. **Documentation** +```dart +/// Report processor that handles multiple report types +/// +/// Uses the following container features: +/// - Tagged bindings for report retrieval ('reports' tag) +/// - Contextual binding for tenant-specific services +/// - Method injection for logging and metrics +class ReportProcessor { + // Implementation +} +``` + +## Testing Integrated Features + +```dart +void main() { + group('Integrated Container Features', () { + late Container container; + + setUp(() { + container = Container(); + + // Set up test bindings + configureTenantA(container); + configureReports(container); + }); + + test('should handle tenant-specific tagged services', () { + var tenantA = TenantAContext(); + + // Get all reports for tenant + var reports = container.taggedAs('reports') + .map((r) => container.make(r, context: tenantA)) + .toList(); + + expect(reports, hasLength(3)); + expect(reports.every((r) => r.db is TenantADatabase), isTrue); + }); + + test('should inject dependencies with context', () async { + var processor = ReportProcessor(); + var tenantA = TenantAContext(); + + await container.call( + processor, + 'processReports', + context: tenantA + ); + + // Verify correct services were injected + verify(() => processor.logger is Logger).called(1); + verify(() => processor.db is TenantADatabase).called(1); + }); + }); +} +``` + +## Next Steps + +1. Implement integration tests +2. Add performance monitoring +3. Add dependency validation +4. Create usage documentation +5. Add debugging tools +6. Create migration guides + +Would you like me to create detailed specifications for any of these next steps? diff --git a/docs/container_gap_analysis.md b/docs/container_gap_analysis.md new file mode 100644 index 0000000..893eab0 --- /dev/null +++ b/docs/container_gap_analysis.md @@ -0,0 +1,261 @@ +# Container Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Container package's actual implementation and our documentation, identifying areas that need implementation or documentation updates. It also outlines the migration strategy to achieve full Laravel compatibility. + +> **Related Documentation** +> - See [Container Package Specification](container_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing requirements + +## Implementation Status + +> **Status Note**: This status aligns with our [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#implementation-status). See there for overall framework status. + +### 1. Core Features + +#### Implemented +```dart +✓ Basic dependency injection +✓ Service location +✓ Auto-wiring +✓ Parent/child containers +✓ Named singletons +✓ Lazy singleton registration +✓ Async dependency resolution +``` + +#### Partially Implemented +```dart +~ Contextual binding (basic structure) +~ Method injection (basic reflection) +~ Tagged bindings (basic tagging) +``` + +#### Not Implemented +```dart +- Advanced contextual binding features + * Instance-based context + * Multiple contexts + * Context inheritance + +- Advanced method injection features + * Parameter validation + * Optional parameters + * Named parameters + +- Advanced tagged binding features + * Tag inheritance + * Tag groups + * Tag conditions +``` + +## Migration Strategy + +> **Integration Note**: This migration strategy follows patterns from [Foundation Integration Guide](foundation_integration_guide.md). See there for detailed integration examples. + +### Phase 1: Internal Restructuring (No Breaking Changes) + +1. **Extract Binding Logic** +```dart +// Move from current implementation: +class Container { + final Map _bindings = {}; + void bind(T instance) => _bindings[T] = instance; +} + +// To new implementation: +class Container { + final Map _bindings = {}; + + void bind(T Function(Container) concrete) { + _bindings[T] = Binding( + concrete: concrete, + shared: false, + implementedType: T + ); + } +} +``` + +2. **Add Resolution Context** +```dart +class Container { + T make([dynamic context]) { + var resolutionContext = ResolutionContext( + resolvingType: T, + context: context, + container: this, + resolutionStack: {} + ); + + return _resolve(T, resolutionContext); + } +} +``` + +### Phase 2: Add New Features (Backward Compatible) + +1. **Contextual Binding** +```dart +class Container { + final Map> _contextualBindings = {}; + + ContextualBindingBuilder when(Type concrete) { + return ContextualBindingBuilder(this, concrete); + } +} +``` + +2. **Method Injection** +```dart +class Container { + dynamic call( + Object instance, + String methodName, [ + Map? parameters + ]) { + var method = reflector.reflectInstance(instance) + .type + .declarations[Symbol(methodName)]; + + var resolvedParams = _resolveMethodParameters( + method, + parameters + ); + + return Function.apply( + instance.runtimeType.getMethod(methodName), + resolvedParams + ); + } +} +``` + +3. **Tagged Bindings** +```dart +class Container { + final Map> _tags = {}; + + void tag(List types, String tag) { + _tags.putIfAbsent(tag, () => {}).addAll(types); + } + + List taggedAs(String tag) { + return _tags[tag]?.map((t) => make(t)).toList() ?? []; + } +} +``` + +### Phase 3: Performance Optimization + +> **Performance Note**: These optimizations align with our [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) performance targets. + +1. **Add Resolution Cache** +```dart +class Container { + final ResolutionCache _cache = ResolutionCache(); + + T make([dynamic context]) { + var cached = _cache.get(context); + if (cached != null) return cached; + + var instance = _resolve(T, context); + _cache.cache(instance, context); + return instance; + } +} +``` + +2. **Add Reflection Cache** +```dart +class Container { + final ReflectionCache _reflectionCache = ReflectionCache(); + + dynamic call(Object instance, String methodName, [Map? parameters]) { + var methodMirror = _reflectionCache.getMethod( + instance.runtimeType, + methodName + ) ?? _cacheMethod(instance, methodName); + + return _invokeMethod(instance, methodMirror, parameters); + } +} +``` + +## Backward Compatibility Requirements + +> **Note**: These requirements ensure compatibility while following [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) guidelines. + +1. **Maintain Existing APIs** +```dart +// These must continue to work: +container.make(); +container.makeAsync(); +container.has(); +container.hasNamed(); +container.registerFactory(); +container.registerSingleton(); +container.registerNamedSingleton(); +container.registerLazySingleton(); +``` + +2. **Preserve Behavior** +```dart +// Parent/child resolution +var parent = Container(reflector); +var child = parent.createChild(); +parent.registerSingleton(service); +var resolved = child.make(); // Must work + +// Named singletons +container.registerNamedSingleton('key', service); +var found = container.findByName('key'); // Must work + +// Async resolution +var future = container.makeAsync(); // Must work +``` + +## Implementation Priority + +> **Priority Note**: These priorities align with our [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#implementation-priorities). + +### 1. High Priority +- Complete contextual binding implementation +- Add parameter validation to method injection +- Implement tag inheritance + +### 2. Medium Priority +- Add cache integration +- Improve error handling +- Add event system integration + +### 3. Low Priority +- Add helper methods +- Add debugging tools +- Add performance monitoring + +## Development Guidelines + +### 1. Getting Started +Before implementing features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Container Package Specification](container_package_specification.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) + +### 2. Implementation Process +For each feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +## Next Steps + +Would you like me to: +1. Start implementing Phase 1 changes? +2. Create detailed specifications for Phase 2? +3. Design the caching system for Phase 3? diff --git a/docs/container_migration_guide.md b/docs/container_migration_guide.md new file mode 100644 index 0000000..c74c847 --- /dev/null +++ b/docs/container_migration_guide.md @@ -0,0 +1,452 @@ +# Container Migration Guide + +## Overview + +This guide helps you migrate from the current Container implementation to the new Laravel-compatible version. It covers: +1. Breaking changes +2. New features +3. Migration strategies +4. Code examples +5. Best practices + +## Breaking Changes + +### 1. Binding Registration + +#### Old Way +```dart +// Old implementation +container.bind(instance); +container.singleton(instance); +``` + +#### New Way +```dart +// New implementation +container.bind((c) => instance); +container.singleton((c) => instance); + +// With contextual binding +container.when(UserController) + .needs() + .give((c) => SpecialService()); +``` + +### 2. Service Resolution + +#### Old Way +```dart +// Old implementation +var service = container.make(); +var namedService = container.makeNamed('name'); +``` + +#### New Way +```dart +// New implementation +var service = container.make(); +var contextualService = container.make(context: UserController); +var taggedServices = container.taggedAs('tag'); +``` + +### 3. Method Injection + +#### Old Way +```dart +// Old implementation - manual parameter resolution +class UserService { + void process(User user) { + var logger = container.make(); + var validator = container.make(); + // Process user... + } +} +``` + +#### New Way +```dart +// New implementation - automatic method injection +class UserService { + void process( + User user, + Logger logger, // Automatically injected + Validator validator // Automatically injected + ) { + // Process user... + } +} + +// Usage +container.call(userService, 'process', {'user': user}); +``` + +## New Features + +### 1. Contextual Binding + +```dart +// Register different implementations based on context +void setupBindings(Container container) { + // Default storage + container.bind((c) => LocalStorage()); + + // User uploads use cloud storage + container.when(UserUploadController) + .needs() + .give((c) => CloudStorage()); + + // System files use local storage + container.when(SystemFileController) + .needs() + .give((c) => LocalStorage()); +} +``` + +### 2. Tagged Bindings + +```dart +// Register and tag related services +void setupReportServices(Container container) { + // Register services + container.bind((c) => PerformanceReport()); + container.bind((c) => FinancialReport()); + container.bind((c) => UserReport()); + + // Tag them for easy retrieval + container.tag([ + PerformanceReport, + FinancialReport, + UserReport + ], 'reports'); + + // Additional categorization + container.tag([PerformanceReport], 'metrics'); + container.tag([FinancialReport], 'financial'); +} + +// Usage +var reports = container.taggedAs('reports'); +var metricReports = container.taggedAs('metrics'); +``` + +### 3. Method Injection + +```dart +class ReportGenerator { + void generateReport( + Report report, + Logger logger, // Automatically injected + Formatter formatter, // Automatically injected + {required DateTime date} // Manually provided + ) { + logger.info('Generating report...'); + var data = report.getData(); + var formatted = formatter.format(data); + // Generate report... + } +} + +// Usage +container.call( + generator, + 'generateReport', + {'report': report, 'date': DateTime.now()} +); +``` + +## Migration Strategies + +### 1. Gradual Migration + +```dart +// Step 1: Update bindings +class ServiceRegistry { + void register(Container container) { + // Old way (still works) + container.bind(OldService()); + + // New way + container.bind((c) => NewService()); + + // Add contextual bindings + container.when(NewController) + .needs() + .give((c) => NewService()); + } +} + +// Step 2: Update resolution +class ServiceConsumer { + void process() { + // Old way (still works) + var oldService = container.make(); + + // New way + var newService = container.make(); + var contextual = container.make( + context: NewController + ); + } +} + +// Step 3: Add method injection +class ServiceProcessor { + // Old way + void processOld(Data data) { + var service = container.make(); + service.process(data); + } + + // New way + void processNew( + Data data, + Service service // Injected automatically + ) { + service.process(data); + } +} +``` + +### 2. Feature-by-Feature Migration + +1. **Update Bindings First** +```dart +// Update all bindings to new style +void registerBindings(Container container) { + // Update simple bindings + container.bind((c) => ServiceImpl()); + + // Add contextual bindings + container.when(Controller) + .needs() + .give((c) => SpecialService()); +} +``` + +2. **Add Tagged Services** +```dart +// Group related services +void registerServices(Container container) { + // Register services + container.bind((c) => ServiceA()); + container.bind((c) => ServiceB()); + + // Add tags + container.tag([ServiceA, ServiceB], 'services'); +} +``` + +3. **Implement Method Injection** +```dart +// Convert to method injection +class UserController { + // Before + void oldProcess(User user) { + var validator = container.make(); + var logger = container.make(); + // Process... + } + + // After + void newProcess( + User user, + Validator validator, + Logger logger + ) { + // Process... + } +} +``` + +## Testing During Migration + +### 1. Verify Bindings + +```dart +void main() { + group('Container Migration Tests', () { + late Container container; + + setUp(() { + container = Container(); + registerBindings(container); + }); + + test('should support old-style bindings', () { + var oldService = container.make(); + expect(oldService, isNotNull); + }); + + test('should support new-style bindings', () { + var newService = container.make(); + expect(newService, isNotNull); + }); + + test('should resolve contextual bindings', () { + var service = container.make( + context: Controller + ); + expect(service, isA()); + }); + }); +} +``` + +### 2. Verify Tagged Services + +```dart +void main() { + group('Tagged Services Tests', () { + late Container container; + + setUp(() { + container = Container(); + registerServices(container); + }); + + test('should resolve tagged services', () { + var services = container.taggedAs('services'); + expect(services, hasLength(2)); + expect(services, contains(isA())); + expect(services, contains(isA())); + }); + }); +} +``` + +### 3. Verify Method Injection + +```dart +void main() { + group('Method Injection Tests', () { + late Container container; + + setUp(() { + container = Container(); + registerServices(container); + }); + + test('should inject method dependencies', () { + var controller = UserController(); + + // Call with only required parameters + container.call( + controller, + 'newProcess', + {'user': testUser} + ); + + // Verify injection worked + verify(() => mockValidator.validate(any)).called(1); + verify(() => mockLogger.log(any)).called(1); + }); + }); +} +``` + +## Best Practices + +1. **Update Bindings Consistently** +```dart +// Good: Consistent new style +container.bind((c) => ServiceImpl()); +container.singleton((c) => FileLogger()); + +// Bad: Mixed styles +container.bind(ServiceImpl()); // Old style +container.singleton((c) => FileLogger()); // New style +``` + +2. **Use Contextual Bindings Appropriately** +```dart +// Good: Clear context and purpose +container.when(UserController) + .needs() + .give((c) => UserStorage()); + +// Bad: Unclear or overly broad context +container.when(Object) + .needs() + .give((c) => GenericStorage()); +``` + +3. **Organize Tagged Services** +```dart +// Good: Logical grouping +container.tag([ + PerformanceReport, + SystemReport +], 'system-reports'); + +container.tag([ + UserReport, + ActivityReport +], 'user-reports'); + +// Bad: Mixed concerns +container.tag([ + PerformanceReport, + UserReport, + Logger, + Storage +], 'services'); +``` + +## Common Issues and Solutions + +1. **Binding Resolution Errors** +```dart +// Problem: Missing binding +var service = container.make(); // Throws error + +// Solution: Register binding first +container.bind((c) => ServiceImpl()); +var service = container.make(); // Works +``` + +2. **Contextual Binding Conflicts** +```dart +// Problem: Multiple contexts +container.when(Controller) + .needs() + .give((c) => ServiceA()); + +container.when(Controller) // Conflict! + .needs() + .give((c) => ServiceB()); + +// Solution: Use specific contexts +container.when(UserController) + .needs() + .give((c) => ServiceA()); + +container.when(AdminController) + .needs() + .give((c) => ServiceB()); +``` + +3. **Method Injection Failures** +```dart +// Problem: Unresolvable parameter +void process( + CustomType param // Not registered with container +) { } + +// Solution: Register or provide parameter +container.bind((c) => CustomType()); +// or +container.call(instance, 'process', { + 'param': customInstance +}); +``` + +## Next Steps + +1. Audit existing container usage +2. Plan migration phases +3. Update bindings +4. Add new features +5. Update tests +6. Document changes + +Would you like me to create detailed specifications for any of these next steps? diff --git a/docs/container_package_specification.md b/docs/container_package_specification.md new file mode 100644 index 0000000..b3aae7c --- /dev/null +++ b/docs/container_package_specification.md @@ -0,0 +1,77 @@ +# Container Package Specification + +## Overview + +The Container package provides a powerful dependency injection container that matches Laravel's container functionality while leveraging Dart's type system. It supports auto-wiring, contextual binding, method injection, and tagged bindings. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Container Gap Analysis](container_gap_analysis.md) for missing features +> - See [Testing Guide](testing_guide.md) for testing approaches + +[Previous content remains the same until Core Features section, then add:] + +## Core Features + +> **Implementation Note**: These features are part of our Laravel compatibility effort. See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for the full feature list and status. + +[Previous features content remains the same, then add:] + +## Integration Examples + +> **Integration Note**: These examples demonstrate common integration patterns. See [Foundation Integration Guide](foundation_integration_guide.md) for more patterns and best practices. + +[Previous examples content remains the same, then add:] + +## Testing + +> **Testing Note**: These examples show package-specific tests. See [Testing Guide](testing_guide.md) for comprehensive testing approaches. + +[Previous testing content remains the same, then add:] + +## Performance Considerations + +> **Performance Note**: These optimizations align with our performance targets. See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) for specific metrics. + +[Previous performance content remains the same, then add:] + +## Development Guidelines + +### 1. Getting Started +Before contributing to this package: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Container Gap Analysis](container_gap_analysis.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) + +### 2. Integration Patterns +When integrating with other packages: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Check [Package Integration Map](package_integration_map.md) +3. Review [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) + +### 3. Testing Requirements +All contributions must: +1. Include unit tests (see [Testing Guide](testing_guide.md#unit-tests)) +2. Include integration tests (see [Testing Guide](testing_guide.md#integration-tests)) +3. Meet performance targets (see [Testing Guide](testing_guide.md#performance-tests)) + +### 4. Documentation Requirements +All changes must: +1. Update this specification if needed +2. Update [Container Gap Analysis](container_gap_analysis.md) if needed +3. Follow documentation standards in [Getting Started Guide](getting_started.md#documentation) + +## Next Steps + +See [Container Gap Analysis](container_gap_analysis.md) for: +1. Missing features to implement +2. Areas needing improvement +3. Integration gaps +4. Documentation gaps + +Would you like me to: +1. Add more integration examples? +2. Enhance testing documentation? +3. Add performance optimizations? diff --git a/docs/contracts_package_specification.md b/docs/contracts_package_specification.md new file mode 100644 index 0000000..2aec250 --- /dev/null +++ b/docs/contracts_package_specification.md @@ -0,0 +1,448 @@ +# Contracts Package Specification + +## Overview + +The Contracts package defines the core interfaces and contracts that form the foundation of the framework. These contracts ensure consistency and interoperability between components while enabling loose coupling and dependency injection. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup + +## Core Contracts + +### 1. Container Contracts + +```dart +/// Core container interface +abstract class ContainerContract { + /// Resolves a type from the container + T make([dynamic context]); + + /// Binds a type to the container + void bind(T Function(ContainerContract) concrete); + + /// Binds a singleton to the container + void singleton(T Function(ContainerContract) concrete); + + /// Checks if a type is bound + bool has(); + + /// Tags implementations for grouped resolution + void tag(List implementations, String tag); + + /// Gets all implementations with a tag + List tagged(String tag); + + /// Adds a contextual binding + void addContextualBinding(Type concrete, Type abstract, dynamic implementation); + + /// Creates a new child container + ContainerContract createChild(); +} + +/// Interface for contextual binding +abstract class ContextualBindingBuilder { + /// Specifies the type needed in this context + ContextualNeedsBuilder needs(); +} + +/// Interface for contextual needs +abstract class ContextualNeedsBuilder { + /// Specifies what to give for this need + void give(dynamic implementation); +} + +/// Interface for service providers +abstract class ServiceProviderContract { + /// Registers services with the container + void register(); + + /// Bootstraps any services + Future boot(); + + /// Gets provided services + List provides(); + + /// Whether provider is deferred + bool get isDeferred => false; +} +``` + +### 2. Event Contracts + +```dart +/// Core event dispatcher interface +abstract class EventDispatcherContract { + /// Registers an event listener + void listen(void Function(T event) listener); + + /// Dispatches an event + Future dispatch(T event); + + /// Registers an event subscriber + void subscribe(EventSubscriber subscriber); + + /// Dispatches an event after database commit + Future dispatchAfterCommit(T event); + + /// Gets registered listeners + List getListeners(Type event); +} + +/// Interface for event subscribers +abstract class EventSubscriber { + /// Gets events to subscribe to + Map subscribe(); +} + +/// Interface for queueable events +abstract class ShouldQueue { + /// Gets the queue to use + String get queue => 'default'; + + /// Gets the delay before processing + Duration? get delay => null; + + /// Gets the number of tries + int get tries => 1; +} + +/// Interface for broadcastable events +abstract class ShouldBroadcast { + /// Gets channels to broadcast on + List broadcastOn(); + + /// Gets event name for broadcasting + String broadcastAs() => runtimeType.toString(); + + /// Gets broadcast data + Map get broadcastWith => {}; +} +``` + +### 3. Queue Contracts + +```dart +/// Core queue interface +abstract class QueueContract { + /// Pushes a job onto the queue + Future push(dynamic job, [String? queue]); + + /// Pushes a job with delay + Future later(Duration delay, dynamic job, [String? queue]); + + /// Gets next job from queue + Future pop([String? queue]); + + /// Creates a job batch + Batch batch(List jobs); + + /// Gets a queue connection + QueueConnection connection([String? name]); +} + +/// Interface for queue jobs +abstract class Job { + /// Unique job ID + String get id; + + /// Job payload + Map get payload; + + /// Number of attempts + int get attempts; + + /// Maximum tries + int get tries => 1; + + /// Timeout in seconds + int get timeout => 60; + + /// Executes the job + Future handle(); + + /// Handles job failure + Future failed([Exception? exception]); +} + +/// Interface for job batches +abstract class Batch { + /// Batch ID + String get id; + + /// Jobs in batch + List get jobs; + + /// Adds jobs to batch + void add(List jobs); + + /// Dispatches the batch + Future dispatch(); +} +``` + +### 4. Bus Contracts + +```dart +/// Core command bus interface +abstract class CommandBusContract { + /// Dispatches a command + Future dispatch(Command command); + + /// Dispatches a command now + Future dispatchNow(Command command); + + /// Dispatches a command to queue + Future dispatchToQueue(Command command); + + /// Creates a command batch + PendingBatch batch(List commands); + + /// Creates a command chain + PendingChain chain(List commands); +} + +/// Interface for commands +abstract class Command { + /// Gets command handler + Type get handler; +} + +/// Interface for command handlers +abstract class Handler { + /// Handles the command + Future handle(T command); +} + +/// Interface for command batches +abstract class PendingBatch { + /// Dispatches the batch + Future dispatch(); + + /// Allows failures + PendingBatch allowFailures(); +} +``` + +### 5. Pipeline Contracts + +```dart +/// Core pipeline interface +abstract class PipelineContract { + /// Sends value through pipeline + PipelineContract send(T passable); + + /// Sets the pipes + PipelineContract through(List> pipes); + + /// Processes the pipeline + Future then(Future Function(T) destination); +} + +/// Interface for pipes +abstract class PipeContract { + /// Handles the passable + Future handle(T passable, Function next); +} + +/// Interface for pipeline hub +abstract class PipelineHubContract { + /// Gets a pipeline + PipelineContract pipeline(String name); + + /// Sets default pipes + void defaults(List pipes); +} +``` + +## Usage Examples + +### Container Usage +```dart +// Register service provider +class AppServiceProvider implements ServiceProviderContract { + @override + void register() { + container.bind((c) => UserService( + c.make(), + c.make() + )); + } + + @override + Future boot() async { + // Bootstrap services + } +} +``` + +### Event Handling +```dart +// Define event +class OrderShipped implements ShouldQueue, ShouldBroadcast { + final Order order; + + @override + List broadcastOn() => ['orders.${order.id}']; + + @override + String get queue => 'notifications'; +} + +// Handle event +dispatcher.listen((event) async { + await notifyCustomer(event.order); +}); +``` + +### Command Bus Usage +```dart +// Define command +class CreateOrder implements Command { + final String customerId; + final List products; + + @override + Type get handler => CreateOrderHandler; +} + +// Handle command +class CreateOrderHandler implements Handler { + @override + Future handle(CreateOrder command) async { + // Create order + } +} + +// Dispatch command +var order = await bus.dispatch(CreateOrder( + customerId: '123', + products: ['abc', 'xyz'] +)); +``` + +## Testing + +```dart +void main() { + group('Event Dispatcher', () { + test('dispatches after commit', () async { + var dispatcher = MockEventDispatcher(); + var db = MockDatabase(); + + await db.transaction((tx) async { + await dispatcher.dispatchAfterCommit(OrderShipped(order)); + }); + + verify(() => dispatcher.dispatch(any())).called(1); + }); + }); + + group('Command Bus', () { + test('handles command batch', () async { + var bus = MockCommandBus(); + + await bus.batch([ + CreateOrder(...), + UpdateInventory(...) + ]).dispatch(); + + verify(() => bus.dispatchNow(any())).called(2); + }); + }); +} +``` + +## Contract Guidelines + +1. **Keep Contracts Minimal** +```dart +// Good: Focused contract +abstract class Cache { + Future get(String key); + Future put(String key, T value); +} + +// Bad: Too many responsibilities +abstract class Cache { + Future get(String key); + Future put(String key, T value); + void clearMemory(); + void optimizeStorage(); + void defragment(); +} +``` + +2. **Use Type Parameters** +```dart +// Good: Type safe +abstract class Repository { + Future find(String id); + Future save(T entity); +} + +// Bad: Dynamic typing +abstract class Repository { + Future find(String id); + Future save(dynamic entity); +} +``` + +3. **Document Contracts** +```dart +/// Contract for caching implementations. +/// +/// Implementations must: +/// - Handle serialization +/// - Be thread-safe +/// - Support TTL +abstract class Cache { + /// Gets a value from cache. + /// + /// Returns null if not found. + /// Throws [CacheException] on error. + Future get(String key); +} +``` + +## Next Steps + +1. Implement core contracts +2. Add integration tests +3. Document Laravel compatibility +4. Add migration guides +5. Create examples +6. Write tests + +Would you like me to enhance any other package specifications? + +## Development Guidelines + +### 1. Getting Started +Before implementing contracts: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) + +### 2. Implementation Process +For each contract: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) + +### 4. Integration Considerations +When implementing contracts: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) diff --git a/docs/core_architecture.md b/docs/core_architecture.md new file mode 100644 index 0000000..8efe51e --- /dev/null +++ b/docs/core_architecture.md @@ -0,0 +1,309 @@ +# Core Architecture + +## Overview + +This document explains the architectural decisions, patterns, and system design of our core package. It provides insights into how the framework components interact and how to extend the system. + +> **Related Documentation** +> - See [Core Package Specification](core_package_specification.md) for implementation details +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Container Package Specification](container_package_specification.md) for dependency injection +> - See [Events Package Specification](events_package_specification.md) for event system + +## Architectural Patterns + +### 1. Service Container Architecture + +The framework is built around a central service container that manages dependencies and provides inversion of control: + +``` +┌─────────────────────────────────────────┐ +│ Application │ +│ │ +│ ┌─────────────────┐ ┌──────────────┐ │ +│ │Service Container│ │Event Dispatch│ │ +│ └─────────────────┘ └──────────────┘ │ +│ │ +│ ┌─────────────────┐ ┌──────────────┐ │ +│ │Service Providers│ │ Pipeline │ │ +│ └─────────────────┘ └──────────────┘ │ +│ │ +└─────────────────────────────────────────┘ +``` + +Key aspects: +- Central service container manages all dependencies +- Service providers bootstrap framework services +- Event system enables loose coupling +- Pipeline pattern for request/response handling + +### 2. Request Lifecycle + +The request flows through several layers: + +``` +┌──────────┐ ┌────────────┐ ┌─────────────┐ +│ Server │ -> │HTTP Kernel │ -> │ Pipeline │ +└──────────┘ └────────────┘ └─────────────┘ + | +┌──────────┐ ┌────────────┐ ┌─────▼─────┐ +│ Response │ <- │ Controller │ <- │ Router │ +└──────────┘ └────────────┘ └───────────┘ +``` + +Stages: +1. Server receives HTTP request +2. HTTP Kernel applies global middleware +3. Pipeline processes middleware stack +4. Router matches route +5. Controller handles request +6. Response flows back through layers + +### 3. Service Provider Pattern + +Service providers bootstrap framework components: + +``` +┌─────────────────┐ +│ Application │ +└───────┬─────────┘ + | +┌───────▼─────────┐ +│Register Providers│ +└───────┬─────────┘ + | +┌───────▼─────────┐ +│ Boot Providers │ +└───────┬─────────┘ + | +┌───────▼─────────┐ +│ Ready to Handle │ +└─────────────────┘ +``` + +Process: +1. Register core providers +2. Register package providers +3. Register application providers +4. Boot all providers +5. Application ready + +### 4. Event-Driven Architecture + +Events enable loose coupling between components: + +``` +┌────────────┐ ┌─────────────┐ ┌──────────┐ +│ Dispatcher │ -> │ Events │ -> │Listeners │ +└────────────┘ └─────────────┘ └──────────┘ + | +┌────────────┐ ┌─────────────┐ ┌──────────┐ +│ Queued │ <- │ Handler │ <- │ Process │ +└────────────┘ └─────────────┘ └──────────┘ +``` + +Features: +- Event dispatching +- Synchronous/async listeners +- Event queueing +- Event subscribers +- Event broadcasting + +## Extension Points + +### 1. Service Providers + +Create custom service providers to: +- Register services +- Bootstrap components +- Configure framework +- Add middleware +- Register routes + +```dart +class CustomServiceProvider extends ServiceProvider { + @override + void register() { + // Register services + } + + @override + void boot() { + // Bootstrap components + } +} +``` + +### 2. Middleware + +Add middleware to: +- Process requests +- Modify responses +- Handle authentication +- Rate limiting +- Custom processing + +```dart +class CustomMiddleware implements Middleware { + Future handle(Request request, Next next) async { + // Process request + var response = await next(request); + // Modify response + return response; + } +} +``` + +### 3. Event Listeners + +Create event listeners to: +- React to system events +- Handle async tasks +- Integrate external systems +- Add logging/monitoring +- Custom processing + +```dart +class CustomListener { + void handle(CustomEvent event) { + // Handle event + } +} +``` + +### 4. Console Commands + +Add console commands to: +- Run maintenance tasks +- Process queues +- Generate files +- Custom CLI tools +- System management + +```dart +class CustomCommand extends Command { + String get name => 'custom:command'; + + Future handle() async { + // Command logic + } +} +``` + +## Package Integration + +### 1. Core Package Dependencies + +``` +┌─────────────┐ +│ Core │ +└─────┬───────┘ + | +┌─────▼───────┐ ┌────────────┐ +│ Container │ --> │ Events │ +└─────────────┘ └────────────┘ + | +┌─────▼───────┐ ┌────────────┐ +│ Pipeline │ --> │ Route │ +└─────────────┘ └────────────┘ +``` + +### 2. Optional Package Integration + +``` +┌─────────────┐ +│ Core │ +└─────┬───────┘ + | +┌─────▼───────┐ ┌────────────┐ +│ Queue │ --> │ Bus │ +└─────────────┘ └────────────┘ + | +┌─────▼───────┐ ┌────────────┐ +│ Cache │ --> │ Mail │ +└─────────────┘ └────────────┘ +``` + +## Performance Considerations + +### 1. Service Container +- Optimize bindings +- Use singletons where appropriate +- Lazy load services +- Cache resolved instances + +### 2. Request Handling +- Efficient middleware pipeline +- Route caching +- Response caching +- Resource pooling + +### 3. Event System +- Async event processing +- Event batching +- Queue throttling +- Listener optimization + +### 4. Memory Management +- Clean up resources +- Limit instance caching +- Monitor memory usage +- Handle memory pressure + +## Security Considerations + +### 1. Request Validation +- Input sanitization +- CSRF protection +- XSS prevention +- SQL injection prevention + +### 2. Authentication +- Secure session handling +- Token management +- Password hashing +- Rate limiting + +### 3. Authorization +- Role-based access +- Permission checking +- Policy enforcement +- Resource protection + +### 4. Data Protection +- Encryption at rest +- Secure communication +- Data sanitization +- Audit logging + +## Development Guidelines + +### 1. Core Development +- Follow framework patterns +- Maintain backward compatibility +- Document changes +- Write tests +- Consider performance + +### 2. Package Development +- Use service providers +- Integrate with events +- Follow naming conventions +- Add package tests +- Document features + +### 3. Application Development +- Use dependency injection +- Handle events properly +- Follow middleware patterns +- Write clean code +- Test thoroughly + +## Next Steps + +1. Review architecture with team +2. Document design decisions +3. Create development guides +4. Set up monitoring +5. Plan optimizations +6. Schedule security review diff --git a/docs/core_package_specification.md b/docs/core_package_specification.md new file mode 100644 index 0000000..9ebbdd0 --- /dev/null +++ b/docs/core_package_specification.md @@ -0,0 +1,556 @@ +# Core Package Specification + +## Overview + +The Core package provides the foundation and entry point for our framework. It manages the application lifecycle, bootstraps services, handles HTTP requests, and coordinates all other framework packages. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Container Package Specification](container_package_specification.md) for dependency injection +> - See [Events Package Specification](events_package_specification.md) for application events + +## Core Features + +### 1. Application + +```dart +/// Core application class +class Application { + /// Container instance + final Container _container; + + /// Service providers + final List _providers = []; + + /// Booted flag + bool _booted = false; + + /// Environment + late final String environment; + + /// Base path + late final String basePath; + + Application(this._container) { + _container.instance(this); + _registerBaseBindings(); + _registerCoreProviders(); + } + + /// Registers base bindings + void _registerBaseBindings() { + _container.instance(_container); + _container.instance('base_path', basePath); + _container.instance('env', environment); + } + + /// Registers core providers + void _registerCoreProviders() { + register(EventServiceProvider()); + register(LogServiceProvider()); + register(RoutingServiceProvider()); + register(ConfigServiceProvider()); + } + + /// Registers a service provider + void register(ServiceProvider provider) { + provider.app = this; + provider.register(); + _providers.add(provider); + + if (_booted) { + _bootProvider(provider); + } + } + + /// Boots the application + Future boot() async { + if (_booted) return; + + for (var provider in _providers) { + await _bootProvider(provider); + } + + _booted = true; + } + + /// Boots a provider + Future _bootProvider(ServiceProvider provider) async { + await provider.callBootingCallbacks(); + await provider.boot(); + await provider.callBootedCallbacks(); + } + + /// Handles HTTP request + Future handle(Request request) async { + try { + return await _pipeline.handle(request); + } catch (e) { + return _handleError(e, request); + } + } + + /// Gets container instance + Container get container => _container; + + /// Makes instance from container + T make([dynamic parameters]) { + return _container.make(parameters); + } + + /// Gets environment + bool environment(String env) { + return this.environment == env; + } + + /// Determines if application is in production + bool get isProduction => environment == 'production'; + + /// Determines if application is in development + bool get isDevelopment => environment == 'development'; + + /// Determines if application is in testing + bool get isTesting => environment == 'testing'; + + /// Gets base path + String path([String? path]) { + return [basePath, path].where((p) => p != null).join('/'); + } +} +``` + +### 2. Service Providers + +```dart +/// Base service provider +abstract class ServiceProvider { + /// Application instance + late Application app; + + /// Container instance + Container get container => app.container; + + /// Booting callbacks + final List _bootingCallbacks = []; + + /// Booted callbacks + final List _bootedCallbacks = []; + + /// Registers services + void register(); + + /// Boots services + Future boot() async {} + + /// Registers booting callback + void booting(Function callback) { + _bootingCallbacks.add(callback); + } + + /// Registers booted callback + void booted(Function callback) { + _bootedCallbacks.add(callback); + } + + /// Calls booting callbacks + Future callBootingCallbacks() async { + for (var callback in _bootingCallbacks) { + await callback(app); + } + } + + /// Calls booted callbacks + Future callBootedCallbacks() async { + for (var callback in _bootedCallbacks) { + await callback(app); + } + } +} + +/// Event service provider +class EventServiceProvider extends ServiceProvider { + @override + void register() { + container.singleton((c) => + EventDispatcher(c) + ); + } +} + +/// Routing service provider +class RoutingServiceProvider extends ServiceProvider { + @override + void register() { + container.singleton((c) => + Router(c) + ); + } + + @override + Future boot() async { + var router = container.make(); + await loadRoutes(router); + } +} +``` + +### 3. HTTP Kernel + +```dart +/// HTTP kernel +class HttpKernel { + /// Application instance + final Application _app; + + /// Global middleware + final List middleware = [ + CheckForMaintenanceMode::class, + ValidatePostSize::class, + TrimStrings::class, + ConvertEmptyStringsToNull::class + ]; + + /// Route middleware groups + final Map> middlewareGroups = { + 'web': [ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class + ], + + 'api': [ + 'throttle:60,1', + SubstituteBindings::class + ] + }; + + /// Route middleware aliases + final Map routeMiddleware = { + 'auth': Authenticate::class, + 'auth.basic': AuthenticateWithBasicAuth::class, + 'bindings': SubstituteBindings::class, + 'cache.headers': SetCacheHeaders::class, + 'can': Authorize::class, + 'guest': RedirectIfAuthenticated::class, + 'signed': ValidateSignature::class, + 'throttle': ThrottleRequests::class, + 'verified': EnsureEmailIsVerified::class, + }; + + HttpKernel(this._app); + + /// Handles HTTP request + Future handle(Request request) async { + try { + request = await _handleGlobalMiddleware(request); + return await _app.handle(request); + } catch (e) { + return _handleError(e, request); + } + } + + /// Handles global middleware + Future _handleGlobalMiddleware(Request request) async { + var pipeline = _app.make(); + + return await pipeline + .send(request) + .through(middleware) + .then((request) => request); + } + + /// Handles error + Response _handleError(Object error, Request request) { + var handler = _app.make(); + return handler.render(error, request); + } +} +``` + +### 4. Console Kernel + +```dart +/// Console kernel +class ConsoleKernel { + /// Application instance + final Application _app; + + /// Console commands + final List commands = [ + // Framework Commands + KeyGenerateCommand::class, + ConfigCacheCommand::class, + ConfigClearCommand::class, + RouteListCommand::class, + RouteCacheCommand::class, + RouteClearCommand::class, + + // App Commands + SendEmailsCommand::class, + PruneOldRecordsCommand::class + ]; + + /// Command schedules + final Map schedules = { + 'emails:send': '0 * * * *', + 'records:prune': '0 0 * * *' + }; + + ConsoleKernel(this._app); + + /// Handles console command + Future handle(List args) async { + try { + var status = await _runCommand(args); + return status ?? 0; + } catch (e) { + _handleError(e); + return 1; + } + } + + /// Runs console command + Future _runCommand(List args) async { + var command = _resolveCommand(args); + if (command == null) return null; + + return await command.run(args); + } + + /// Resolves command from arguments + Command? _resolveCommand(List args) { + if (args.isEmpty) return null; + + var name = args.first; + var command = commands.firstWhere( + (c) => c.name == name, + orElse: () => null + ); + + if (command == null) return null; + return _app.make(command); + } + + /// Handles error + void _handleError(Object error) { + stderr.writeln(error); + } +} +``` + +### 5. Exception Handler + +```dart +/// Exception handler +class ExceptionHandler { + /// Application instance + final Application _app; + + /// Exception renderers + final Map _renderers = { + ValidationException: _renderValidationException, + AuthenticationException: _renderAuthenticationException, + AuthorizationException: _renderAuthorizationException, + NotFoundException: _renderNotFoundException, + HttpException: _renderHttpException + }; + + ExceptionHandler(this._app); + + /// Renders exception to response + Response render(Object error, Request request) { + var renderer = _renderers[error.runtimeType]; + if (renderer != null) { + return renderer(error, request); + } + + return _renderGenericException(error, request); + } + + /// Renders validation exception + Response _renderValidationException( + ValidationException e, + Request request + ) { + if (request.wantsJson) { + return Response.json({ + 'message': 'The given data was invalid.', + 'errors': e.errors + }, 422); + } + + return Response.redirect() + .back() + .withErrors(e.errors) + .withInput(request.all()); + } + + /// Renders generic exception + Response _renderGenericException(Object e, Request request) { + if (_app.isProduction) { + return Response('Server Error', 500); + } + + return Response(e.toString(), 500); + } +} +``` + +## Integration Examples + +### 1. Application Bootstrap +```dart +void main() async { + var container = Container(); + var app = Application(container) + ..environment = 'production' + ..basePath = Directory.current.path; + + await app.boot(); + + var server = HttpServer(app); + await server.start(); +} +``` + +### 2. Service Provider +```dart +class AppServiceProvider extends ServiceProvider { + @override + void register() { + container.singleton((c) => + DatabaseUserRepository(c.make()) + ); + } + + @override + Future boot() async { + var config = container.make(); + TimeZone.setDefault(config.get('app.timezone')); + } +} +``` + +### 3. HTTP Request Handling +```dart +class Server { + final HttpKernel kernel; + + Future handle(HttpRequest request) async { + var protevusRequest = await Request.fromHttpRequest(request); + var response = await kernel.handle(protevusRequest); + await response.send(request.response); + } +} +``` + +## Testing + +```dart +void main() { + group('Application', () { + test('boots providers', () async { + var app = Application(Container()); + var provider = TestProvider(); + + app.register(provider); + await app.boot(); + + expect(provider.booted, isTrue); + }); + + test('handles requests', () async { + var app = Application(Container()); + await app.boot(); + + var request = Request('GET', '/'); + var response = await app.handle(request); + + expect(response.statusCode, equals(200)); + }); + }); + + group('Service Provider', () { + test('registers services', () async { + var app = Application(Container()); + var provider = TestProvider(); + + app.register(provider); + + expect(app.make(), isNotNull); + }); + }); +} +``` + +## Next Steps + +1. Implement core application +2. Add service providers +3. Add HTTP kernel +4. Add console kernel +5. Write tests +6. Add benchmarks + +## Development Guidelines + +### 1. Getting Started +Before implementing core features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Container Package Specification](container_package_specification.md) +6. Review [Events Package Specification](events_package_specification.md) + +### 2. Implementation Process +For each core feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following framework patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Follow framework patterns +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Support dependency injection (see [Container Package Specification](container_package_specification.md)) +5. Support event system (see [Events Package Specification](events_package_specification.md)) + +### 4. Integration Considerations +When implementing core features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Use framework patterns consistently +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Core system must: +1. Boot efficiently +2. Handle requests quickly +3. Manage memory usage +4. Scale horizontally +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Core tests must: +1. Cover all core features +2. Test application lifecycle +3. Verify service providers +4. Check error handling +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Core documentation must: +1. Explain framework patterns +2. Show lifecycle examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/events_gap_analysis.md b/docs/events_gap_analysis.md new file mode 100644 index 0000000..7047c17 --- /dev/null +++ b/docs/events_gap_analysis.md @@ -0,0 +1,295 @@ +# Events Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Events package's actual implementation and our documentation, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Events Package Specification](events_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Event Discovery +class EventDiscovery { + // Need to implement: + Map discoverHandlers(Type type); + void discoverEvents(String path); +} + +// 2. After Commit Handling +class DatabaseEventDispatcher { + // Need to implement: + Future dispatchAfterCommit(T event); + void afterCommit(Function callback); +} + +// 3. Better Broadcasting +class BroadcastManager { + // Need to implement: + Channel privateChannel(String name); + PresenceChannel presenceChannel(String name); + Future broadcast(List channels, String event, dynamic data); +} +``` + +### 2. Existing Features Not Documented + +```dart +// Implemented but not documented: + +// 1. Wildcard Event Listeners +class Dispatcher { + /// Adds wildcard event listener + void _setupWildcardListen(String event, Function listener) { + _wildcards.putIfAbsent(event, () => []).add(listener); + _wildcardsCache.clear(); + } + + /// Gets wildcard listeners + List _getWildcardListeners(String eventName); +} + +// 2. Event Bus Integration +class Dispatcher { + /// EventBus integration + final EventBus _eventBus; + final Map _eventBusSubscriptions = {}; + + /// Subscribes to EventBus + void subscribe(EventBusSubscriber subscriber); +} + +// 3. Message Queue Integration +class Dispatcher { + /// MQ integration + late final MQClient? _mqClient; + + /// Queue setup + void _setupQueuesAndExchanges(); + void _startProcessingQueuedEvents(); +} +``` + +### 3. Integration Points Not Documented + +```dart +// 1. Container Integration +class Dispatcher { + /// Container reference + final Container container; + + /// Queue resolver + late final Function _queueResolver; + + /// Transaction manager resolver + late final Function _transactionManagerResolver; +} + +// 2. ReactiveX Integration +class Dispatcher { + /// Subject management + final Map> _subjects = {}; + + /// Stream access + Stream on(String event); +} + +// 3. Resource Management +class Dispatcher { + /// Cleanup + Future close(); + void dispose(); +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation + +```dart +// Need to document: + +/// Listens for events using wildcard patterns. +/// +/// Example: +/// ```dart +/// dispatcher.listen('user.*', (event, data) { +/// // Handles all user events +/// }); +/// ``` +void listen(String pattern, Function listener); + +/// Subscribes to event streams using ReactiveX. +/// +/// Example: +/// ```dart +/// dispatcher.on('user.created') +/// .listen((event) { +/// // Handle user created event +/// }); +/// ``` +Stream on(String event); +``` + +### 2. Missing Integration Examples + +```dart +// Need examples for: + +// 1. EventBus Integration +var subscriber = MyEventSubscriber(); +dispatcher.subscribe(subscriber); + +// 2. Message Queue Integration +dispatcher.setMQClient(mqClient); +await dispatcher.push('user.created', userData); + +// 3. ReactiveX Integration +dispatcher.on('user.*') + .where((e) => e.type == 'premium') + .listen((e) => handlePremiumUser(e)); +``` + +### 3. Missing Test Coverage + +```dart +// Need tests for: + +void main() { + group('Wildcard Events', () { + test('matches wildcard patterns', () { + var dispatcher = Dispatcher(container); + var received = []; + + dispatcher.listen('user.*', (event, _) { + received.add(event); + }); + + await dispatcher.dispatch('user.created'); + await dispatcher.dispatch('user.updated'); + + expect(received, ['user.created', 'user.updated']); + }); + }); + + group('Queue Integration', () { + test('queues events properly', () async { + var dispatcher = Dispatcher(container); + dispatcher.setMQClient(mockClient); + + await dispatcher.push('delayed.event', data); + + verify(() => mockClient.sendMessage( + exchangeName: any, + routingKey: any, + message: any + )).called(1); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Event discovery (Laravel compatibility) + - After commit handling (Laravel compatibility) + - Better broadcasting support + +2. **Medium Priority** + - Better queue integration + - Enhanced wildcard support + - Performance optimizations + +3. **Low Priority** + - Additional helper methods + - Extended testing utilities + - Debug/profiling tools + +## Next Steps + +1. **Implementation Tasks** + - Add event discovery + - Add after commit handling + - Enhance broadcasting + - Improve queue integration + +2. **Documentation Tasks** + - Document wildcard events + - Document EventBus integration + - Document MQ integration + - Add integration examples + +3. **Testing Tasks** + - Add wildcard event tests + - Add queue integration tests + - Add ReactiveX integration tests + - Add resource cleanup tests + +Would you like me to: +1. Start implementing missing features? +2. Update documentation for existing features? +3. Create test cases for missing coverage? + +## Development Guidelines + +### 1. Getting Started +Before implementing event features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Events Package Specification](events_package_specification.md) + +### 2. Implementation Process +For each event feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Events Package Specification](events_package_specification.md) + +### 4. Integration Considerations +When implementing event features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Events system must: +1. Handle high event throughput +2. Minimize memory usage +3. Support async operations +4. Scale horizontally +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Event tests must: +1. Cover all event scenarios +2. Test async behavior +3. Verify queue integration +4. Check broadcasting +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Event documentation must: +1. Explain event patterns +2. Show integration examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/events_package_specification.md b/docs/events_package_specification.md new file mode 100644 index 0000000..28e82ae --- /dev/null +++ b/docs/events_package_specification.md @@ -0,0 +1,453 @@ +# Events Package Specification + +## Overview + +The Events package provides a robust event system that matches Laravel's event functionality while leveraging Dart's async capabilities. It integrates with our Queue, Bus, and Database packages to provide a complete event handling solution. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Contracts Package Specification](contracts_package_specification.md) for event contracts + +## Core Features + +### 1. Event Dispatcher + +```dart +/// Core event dispatcher implementation +class EventDispatcher implements EventDispatcherContract { + final Container _container; + final Map> _listeners = {}; + final List _subscribers = {}; + final QueueContract? _queue; + final BroadcasterContract? _broadcaster; + final List _afterCommitEvents = []; + + EventDispatcher( + this._container, { + QueueContract? queue, + BroadcasterContract? broadcaster + }) : _queue = queue, + _broadcaster = broadcaster; + + @override + void listen(void Function(T event) listener) { + _listeners.putIfAbsent(T, () => []).add( + EventListener(listener) + ); + } + + @override + Future dispatch(T event) async { + var listeners = _listeners[T] ?? []; + + // Handle after commit events + if (event is ShouldDispatchAfterCommit && _isWithinTransaction()) { + _afterCommitEvents.add(event); + return; + } + + // Handle queued events + if (event is ShouldQueue && _queue != null) { + await _queueEvent(event, listeners); + return; + } + + // Handle broadcasting + if (event is ShouldBroadcast && _broadcaster != null) { + await _broadcastEvent(event); + } + + // Notify listeners + await _notifyListeners(event, listeners); + } + + @override + Future dispatchAfterCommit(T event) async { + if (_isWithinTransaction()) { + _afterCommitEvents.add(event); + } else { + await dispatch(event); + } + } + + bool _isWithinTransaction() { + if (_container.has()) { + var db = _container.make(); + return db.transactionLevel > 0; + } + return false; + } + + Future _dispatchAfterCommitEvents() async { + var events = List.from(_afterCommitEvents); + _afterCommitEvents.clear(); + + for (var event in events) { + await dispatch(event); + } + } +} +``` + +### 2. Event Discovery + +```dart +/// Discovers event handlers through reflection and attributes +class EventDiscovery { + final Container _container; + final Reflector _reflector; + + EventDiscovery(this._container, this._reflector); + + /// Discovers event handlers in a directory + Future discoverEvents(String path) async { + var files = Directory(path).listSync(recursive: true); + + for (var file in files) { + if (file.path.endsWith('.dart')) { + await _processFile(file.path); + } + } + } + + Future _processFile(String path) async { + var library = await _reflector.loadLibrary(path); + + for (var type in library.declarations.values) { + if (type is ClassMirror) { + _processClass(type); + } + } + } + + void _processClass(ClassMirror classMirror) { + // Find @Handles annotations + for (var method in classMirror.declarations.values) { + if (method is MethodMirror) { + var handles = method.metadata + .firstWhere((m) => m.type == Handles, + orElse: () => null); + + if (handles != null) { + var eventType = handles.getField('event').reflectee; + _registerHandler(classMirror.reflectedType, method.simpleName, eventType); + } + } + } + } + + void _registerHandler(Type classType, Symbol methodName, Type eventType) { + var instance = _container.make(classType); + var dispatcher = _container.make(); + + dispatcher.listen(eventType, (event) { + var mirror = reflect(instance); + mirror.invoke(methodName, [event]); + }); + } +} +``` + +### 3. Event Broadcasting + +```dart +/// Contract for event broadcasters +abstract class BroadcasterContract { + /// Broadcasts an event + Future broadcast( + List channels, + String eventName, + dynamic data + ); + + /// Creates a private channel + Channel privateChannel(String name); + + /// Creates a presence channel + PresenceChannel presenceChannel(String name); +} + +/// Pusher event broadcaster +class PusherBroadcaster implements BroadcasterContract { + final PusherClient _client; + final AuthManager _auth; + + PusherBroadcaster(this._client, this._auth); + + @override + Future broadcast( + List channels, + String eventName, + dynamic data + ) async { + for (var channel in channels) { + await _client.trigger(channel, eventName, data); + } + } + + @override + Channel privateChannel(String name) { + return PrivateChannel(_client, _auth, name); + } + + @override + PresenceChannel presenceChannel(String name) { + return PresenceChannel(_client, _auth, name); + } +} +``` + +### 4. Integration with Queue + +```dart +/// Job for processing queued events +class QueuedEventJob implements Job { + final dynamic event; + final List listeners; + final Map data; + + QueuedEventJob({ + required this.event, + required this.listeners, + this.data = const {} + }); + + @override + Future handle() async { + for (var listener in listeners) { + try { + await listener.handle(event); + } catch (e) { + await _handleFailure(e); + } + } + } + + @override + Future failed([Exception? e]) async { + if (event is FailedEventHandler) { + await (event as FailedEventHandler).failed(e); + } + } + + @override + int get tries => event is HasTries ? (event as HasTries).tries : 1; + + @override + Duration? get timeout => + event is HasTimeout ? (event as HasTimeout).timeout : null; +} +``` + +### 5. Integration with Bus + +```dart +/// Event command for command bus integration +class EventCommand implements Command { + final dynamic event; + final List listeners; + + EventCommand(this.event, this.listeners); + + @override + Type get handler => EventCommandHandler; +} + +/// Handler for event commands +class EventCommandHandler implements Handler { + final EventDispatcher _events; + + EventCommandHandler(this._events); + + @override + Future handle(EventCommand command) async { + await _events._notifyListeners( + command.event, + command.listeners + ); + } +} +``` + +## Usage Examples + +### Basic Event Handling +```dart +// Define event +class OrderShipped { + final Order order; + OrderShipped(this.order); +} + +// Create listener +@Handles(OrderShipped) +class OrderShippedListener { + void handle(OrderShipped event) { + // Handle event + } +} + +// Register and dispatch +dispatcher.listen((event) { + // Handle event +}); + +await dispatcher.dispatch(OrderShipped(order)); +``` + +### After Commit Events +```dart +class OrderCreated implements ShouldDispatchAfterCommit { + final Order order; + OrderCreated(this.order); +} + +// In transaction +await db.transaction((tx) async { + var order = await tx.create(orderData); + await dispatcher.dispatchAfterCommit(OrderCreated(order)); +}); +``` + +### Broadcasting +```dart +class MessageSent implements ShouldBroadcast { + final Message message; + + @override + List broadcastOn() => [ + 'private-chat.${message.roomId}' + ]; + + @override + Map get broadcastWith => { + 'id': message.id, + 'content': message.content, + 'user': message.user.toJson() + }; +} + +// Create private channel +var channel = broadcaster.privateChannel('chat.123'); +await channel.whisper('typing', {'user': 'john'}); +``` + +### Queue Integration +```dart +class ProcessOrder implements ShouldQueue { + final Order order; + + @override + String get queue => 'orders'; + + @override + int get tries => 3; + + @override + Duration get timeout => Duration(minutes: 5); +} + +// Dispatch queued event +await dispatcher.dispatch(ProcessOrder(order)); +``` + +## Testing + +```dart +void main() { + group('Event Dispatcher', () { + test('dispatches after commit', () async { + var dispatcher = MockEventDispatcher(); + var db = MockDatabase(); + + await db.transaction((tx) async { + await dispatcher.dispatchAfterCommit(OrderShipped(order)); + expect(dispatcher.hasAfterCommitEvents, isTrue); + }); + + expect(dispatcher.hasAfterCommitEvents, isFalse); + verify(() => dispatcher.dispatch(any())).called(1); + }); + + test('discovers event handlers', () async { + var discovery = EventDiscovery(container, reflector); + await discovery.discoverEvents('lib/events'); + + var dispatcher = container.make(); + await dispatcher.dispatch(OrderShipped(order)); + + verify(() => orderListener.handle(any())).called(1); + }); + }); +} +``` + +## Next Steps + +1. Complete after commit handling +2. Enhance event discovery +3. Add more broadcast drivers +4. Improve queue integration +5. Add performance optimizations +6. Write more tests + +Would you like me to enhance any other package specifications? + +## Development Guidelines + +### 1. Getting Started +Before implementing event features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Understand [Contracts Package Specification](contracts_package_specification.md) + +### 2. Implementation Process +For each event feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Implement required contracts (see [Contracts Package Specification](contracts_package_specification.md)) + +### 4. Integration Considerations +When implementing events: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) +5. Implement all contracts from [Contracts Package Specification](contracts_package_specification.md) + +### 5. Performance Guidelines +Event system must: +1. Handle high throughput efficiently +2. Minimize memory usage +3. Support async operations +4. Scale horizontally +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Event tests must: +1. Cover all event scenarios +2. Test async behavior +3. Verify queue integration +4. Check broadcasting +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Event documentation must: +1. Explain event patterns +2. Show integration examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/filesystem_gap_analysis.md b/docs/filesystem_gap_analysis.md new file mode 100644 index 0000000..f671a47 --- /dev/null +++ b/docs/filesystem_gap_analysis.md @@ -0,0 +1,349 @@ +# FileSystem Package Gap Analysis + +## Overview + +This document analyzes the gaps between our current filesystem handling (in Core package) and Laravel's FileSystem package functionality, identifying what needs to be implemented as a standalone FileSystem package. + +> **Related Documentation** +> - See [FileSystem Package Specification](filesystem_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup + +## Implementation Gaps + +### 1. Missing Package Structure +```dart +// Need to create dedicated FileSystem package: + +packages/filesystem/ +├── lib/ +│ ├── src/ +│ │ ├── filesystem.dart +│ │ ├── filesystem_manager.dart +│ │ ├── drivers/ +│ │ │ ├── local_driver.dart +│ │ │ ├── s3_driver.dart +│ │ │ └── gcs_driver.dart +│ │ └── contracts/ +│ │ ├── filesystem.dart +│ │ └── driver.dart +│ └── filesystem.dart +├── test/ +└── example/ +``` + +### 2. Missing Core Features +```dart +// 1. Filesystem Manager +class FilesystemManager { + // Need to implement: + Filesystem disk([String? name]); + void extend(String driver, FilesystemDriver Function() callback); + FilesystemDriver createDriver(Map config); +} + +// 2. Filesystem Implementation +class Filesystem { + // Need to implement: + Future exists(String path); + Future get(String path); + Future put(String path, dynamic contents, [Map? options]); + Future delete(String path); + Future copy(String from, String to); + Future move(String from, String to); + Future url(String path); + Future>> readStream(String path); + Future writeStream(String path, Stream> contents); +} + +// 3. Driver Implementations +class LocalDriver { + // Need to implement: + Future ensureDirectory(String path); + Future setVisibility(String path, String visibility); + Future> getMetadata(String path); +} +``` + +### 3. Missing Laravel Features +```dart +// 1. Cloud Storage +class S3Driver { + // Need to implement: + Future upload(String path, dynamic contents, String visibility); + Future temporaryUrl(String path, Duration expiration); + Future setVisibility(String path, String visibility); +} + +// 2. Directory Operations +class DirectoryOperations { + // Need to implement: + Future> files(String directory); + Future> allFiles(String directory); + Future> directories(String directory); + Future> allDirectories(String directory); + Future makeDirectory(String path); + Future deleteDirectory(String directory); +} + +// 3. File Visibility +class VisibilityConverter { + // Need to implement: + String toOctal(String visibility); + String fromOctal(String permissions); + bool isPublic(String path); + bool isPrivate(String path); +} +``` + +## Integration Gaps + +### 1. Container Integration +```dart +// Need to implement: + +class FilesystemServiceProvider { + void register() { + // Register filesystem manager + container.singleton((c) => + FilesystemManager( + config: c.make() + ) + ); + + // Register default filesystem + container.singleton((c) => + c.make().disk() + ); + } +} +``` + +### 2. Config Integration +```dart +// Need to implement: + +// config/filesystems.dart +class FilesystemsConfig { + static Map get config => { + 'default': 'local', + 'disks': { + 'local': { + 'driver': 'local', + 'root': 'storage/app' + }, + 's3': { + 'driver': 's3', + 'key': env('AWS_ACCESS_KEY_ID'), + 'secret': env('AWS_SECRET_ACCESS_KEY'), + 'region': env('AWS_DEFAULT_REGION'), + 'bucket': env('AWS_BUCKET') + } + } + }; +} +``` + +### 3. Event Integration +```dart +// Need to implement: + +class FilesystemEvents { + // File events + static const String writing = 'filesystem.writing'; + static const String written = 'filesystem.written'; + static const String deleting = 'filesystem.deleting'; + static const String deleted = 'filesystem.deleted'; + + // Directory events + static const String makingDirectory = 'filesystem.making_directory'; + static const String madeDirectory = 'filesystem.made_directory'; + static const String deletingDirectory = 'filesystem.deleting_directory'; + static const String deletedDirectory = 'filesystem.deleted_directory'; +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation +```dart +// Need to document: + +/// Manages filesystem operations across multiple storage drivers. +/// +/// Provides a unified API for working with files across different storage systems: +/// ```dart +/// // Store a file +/// await storage.put('avatars/user1.jpg', fileContents); +/// +/// // Get a file +/// var contents = await storage.get('avatars/user1.jpg'); +/// ``` +class Filesystem { + /// Stores a file at the specified path. + /// + /// Options can include: + /// - visibility: 'public' or 'private' + /// - mime: MIME type of the file + Future put(String path, dynamic contents, [Map? options]); +} +``` + +### 2. Missing Usage Examples +```dart +// Need examples for: + +// 1. Basic File Operations +var storage = Storage.disk(); +await storage.put('file.txt', 'Hello World'); +var contents = await storage.get('file.txt'); +await storage.delete('file.txt'); + +// 2. Stream Operations +var fileStream = File('large.zip').openRead(); +await storage.writeStream('uploads/large.zip', fileStream); +var downloadStream = await storage.readStream('uploads/large.zip'); + +// 3. Cloud Storage +var s3 = Storage.disk('s3'); +await s3.put( + 'images/photo.jpg', + photoBytes, + {'visibility': 'public'} +); +var url = await s3.url('images/photo.jpg'); +``` + +### 3. Missing Test Coverage +```dart +// Need tests for: + +void main() { + group('Local Driver', () { + test('handles file operations', () async { + var storage = Filesystem(LocalDriver(root: 'storage')); + + await storage.put('test.txt', 'contents'); + expect(await storage.exists('test.txt'), isTrue); + expect(await storage.get('test.txt'), equals('contents')); + + await storage.delete('test.txt'); + expect(await storage.exists('test.txt'), isFalse); + }); + }); + + group('S3 Driver', () { + test('handles cloud operations', () async { + var storage = Filesystem(S3Driver(config)); + + await storage.put('test.txt', 'contents', { + 'visibility': 'public' + }); + + var url = await storage.url('test.txt'); + expect(url, startsWith('https://')); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Create FileSystem package structure + - Implement core filesystem + - Add local driver + - Add basic operations + +2. **Medium Priority** + - Add cloud drivers + - Add streaming support + - Add directory operations + - Add container integration + +3. **Low Priority** + - Add helper functions + - Add testing utilities + - Add debugging tools + +## Next Steps + +1. **Package Creation** + - Create package structure + - Move filesystem code from Core + - Add package dependencies + - Setup testing + +2. **Core Implementation** + - Implement FilesystemManager + - Implement Filesystem + - Implement LocalDriver + - Add cloud drivers + +3. **Integration Implementation** + - Add container integration + - Add config support + - Add event support + - Add service providers + +Would you like me to: +1. Create the FileSystem package structure? +2. Start implementing core features? +3. Create detailed implementation plans? + +## Development Guidelines + +### 1. Getting Started +Before implementing filesystem features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [FileSystem Package Specification](filesystem_package_specification.md) + +### 2. Implementation Process +For each filesystem feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [FileSystem Package Specification](filesystem_package_specification.md) + +### 4. Integration Considerations +When implementing filesystem features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Filesystem system must: +1. Handle large files efficiently +2. Use streaming where appropriate +3. Minimize memory usage +4. Support concurrent operations +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Filesystem tests must: +1. Cover all file operations +2. Test streaming behavior +3. Verify cloud storage +4. Check metadata handling +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Filesystem documentation must: +1. Explain filesystem patterns +2. Show driver examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/filesystem_package_specification.md b/docs/filesystem_package_specification.md new file mode 100644 index 0000000..6e0f171 --- /dev/null +++ b/docs/filesystem_package_specification.md @@ -0,0 +1,554 @@ +# FileSystem Package Specification + +## Overview + +The FileSystem package provides a robust abstraction layer for file operations, matching Laravel's filesystem functionality. It supports local and cloud storage systems through a unified API, with support for streaming, visibility control, and metadata management. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Contracts Package Specification](contracts_package_specification.md) for filesystem contracts + +## Core Features + +### 1. Filesystem Manager + +```dart +/// Manages filesystem drivers +class FilesystemManager implements FilesystemFactory { + /// Available filesystem drivers + final Map _drivers = {}; + + /// Default driver name + final String _defaultDriver; + + /// Configuration repository + final ConfigContract _config; + + FilesystemManager(this._config) + : _defaultDriver = _config.get('filesystems.default', 'local'); + + @override + Filesystem disk([String? name]) { + name ??= _defaultDriver; + + return _drivers.putIfAbsent(name, () { + var config = _getConfig(name!); + var driver = _createDriver(config); + return Filesystem(driver); + }); + } + + /// Creates a driver instance + FilesystemDriver _createDriver(Map config) { + switch (config['driver']) { + case 'local': + return LocalDriver(config); + case 's3': + return S3Driver(config); + case 'gcs': + return GoogleCloudDriver(config); + default: + throw UnsupportedError( + 'Unsupported filesystem driver: ${config['driver']}' + ); + } + } + + /// Gets configuration for driver + Map _getConfig(String name) { + var config = _config.get('filesystems.disks.$name'); + if (config == null) { + throw ArgumentError('Disk [$name] not configured.'); + } + return config; + } +} +``` + +### 2. Filesystem Implementation + +```dart +/// Core filesystem implementation +class Filesystem implements FilesystemContract { + /// The filesystem driver + final FilesystemDriver _driver; + + Filesystem(this._driver); + + @override + Future exists(String path) { + return _driver.exists(path); + } + + @override + Future get(String path) { + return _driver.get(path); + } + + @override + Stream> readStream(String path) { + return _driver.readStream(path); + } + + @override + Future put(String path, dynamic contents, [Map? options]) { + return _driver.put(path, contents, options); + } + + @override + Future putStream(String path, Stream> contents, [Map? options]) { + return _driver.putStream(path, contents, options); + } + + @override + Future delete(String path) { + return _driver.delete(path); + } + + @override + Future copy(String from, String to) { + return _driver.copy(from, to); + } + + @override + Future move(String from, String to) { + return _driver.move(from, to); + } + + @override + Future url(String path) { + return _driver.url(path); + } + + @override + Future> metadata(String path) { + return _driver.metadata(path); + } + + @override + Future size(String path) { + return _driver.size(path); + } + + @override + Future mimeType(String path) { + return _driver.mimeType(path); + } + + @override + Future lastModified(String path) { + return _driver.lastModified(path); + } +} +``` + +### 3. Local Driver + +```dart +/// Local filesystem driver +class LocalDriver implements FilesystemDriver { + /// Root path for local filesystem + final String _root; + + /// Default visibility + final String _visibility; + + LocalDriver(Map config) + : _root = config['root'], + _visibility = config['visibility'] ?? 'private'; + + @override + Future exists(String path) async { + return File(_fullPath(path)).exists(); + } + + @override + Future get(String path) async { + return File(_fullPath(path)).readAsString(); + } + + @override + Stream> readStream(String path) { + return File(_fullPath(path)).openRead(); + } + + @override + Future put(String path, dynamic contents, [Map? options]) async { + var file = File(_fullPath(path)); + await file.create(recursive: true); + + if (contents is String) { + await file.writeAsString(contents); + } else if (contents is List) { + await file.writeAsBytes(contents); + } else { + throw ArgumentError('Invalid content type'); + } + + await _setVisibility(file, options?['visibility'] ?? _visibility); + } + + @override + Future putStream(String path, Stream> contents, [Map? options]) async { + var file = File(_fullPath(path)); + await file.create(recursive: true); + + var sink = file.openWrite(); + await contents.pipe(sink); + await sink.close(); + + await _setVisibility(file, options?['visibility'] ?? _visibility); + } + + /// Gets full path for file + String _fullPath(String path) { + return p.join(_root, path); + } + + /// Sets file visibility + Future _setVisibility(File file, String visibility) async { + // Set file permissions based on visibility + if (visibility == 'public') { + await file.setPermissions( + unix: 0644, + windows: FilePermissions.readWrite + ); + } else { + await file.setPermissions( + unix: 0600, + windows: FilePermissions.readWriteExecute + ); + } + } +} +``` + +### 4. Cloud Drivers + +```dart +/// Amazon S3 driver +class S3Driver implements FilesystemDriver { + /// S3 client + final S3Client _client; + + /// Bucket name + final String _bucket; + + /// Optional path prefix + final String? _prefix; + + S3Driver(Map config) + : _client = S3Client( + region: config['region'], + credentials: AWSCredentials( + accessKey: config['key'], + secretKey: config['secret'] + ) + ), + _bucket = config['bucket'], + _prefix = config['prefix']; + + @override + Future exists(String path) async { + try { + await _client.headObject( + bucket: _bucket, + key: _prefixPath(path) + ); + return true; + } catch (e) { + return false; + } + } + + @override + Future put(String path, dynamic contents, [Map? options]) async { + await _client.putObject( + bucket: _bucket, + key: _prefixPath(path), + body: contents, + acl: options?['visibility'] == 'public' + ? 'public-read' + : 'private' + ); + } + + /// Adds prefix to path + String _prefixPath(String path) { + return _prefix != null ? '$_prefix/$path' : path; + } +} + +/// Google Cloud Storage driver +class GoogleCloudDriver implements FilesystemDriver { + /// Storage client + final Storage _storage; + + /// Bucket name + final String _bucket; + + GoogleCloudDriver(Map config) + : _storage = Storage( + projectId: config['project_id'], + credentials: config['credentials'] + ), + _bucket = config['bucket']; + + @override + Future exists(String path) async { + try { + await _storage.bucket(_bucket).file(path).exists(); + return true; + } catch (e) { + return false; + } + } + + @override + Future put(String path, dynamic contents, [Map? options]) async { + var file = _storage.bucket(_bucket).file(path); + + if (contents is String) { + await file.writeAsString(contents); + } else if (contents is List) { + await file.writeAsBytes(contents); + } else { + throw ArgumentError('Invalid content type'); + } + + if (options?['visibility'] == 'public') { + await file.makePublic(); + } + } +} +``` + +## Integration with Container + +```dart +/// Registers filesystem services +class FilesystemServiceProvider extends ServiceProvider { + @override + void register() { + // Register filesystem factory + container.singleton((c) { + return FilesystemManager(c.make()); + }); + + // Register default filesystem + container.singleton((c) { + return c.make().disk(); + }); + } +} +``` + +## Usage Examples + +### Basic File Operations +```dart +// Get default disk +var storage = Storage.disk(); + +// Check if file exists +if (await storage.exists('file.txt')) { + // Read file contents + var contents = await storage.get('file.txt'); + + // Write file contents + await storage.put('new-file.txt', contents); + + // Delete file + await storage.delete('file.txt'); +} +``` + +### Stream Operations +```dart +// Read file as stream +var stream = storage.readStream('large-file.txt'); + +// Write stream to file +await storage.putStream( + 'output.txt', + stream, + {'visibility': 'public'} +); +``` + +### Cloud Storage +```dart +// Use S3 disk +var s3 = Storage.disk('s3'); + +// Upload file +await s3.put( + 'uploads/image.jpg', + imageBytes, + {'visibility': 'public'} +); + +// Get public URL +var url = await s3.url('uploads/image.jpg'); +``` + +### File Metadata +```dart +// Get file metadata +var meta = await storage.metadata('document.pdf'); +print('Size: ${meta['size']}'); +print('Type: ${meta['mime_type']}'); +print('Modified: ${meta['last_modified']}'); +``` + +## Testing + +```dart +void main() { + group('Filesystem Tests', () { + late Filesystem storage; + + setUp(() { + storage = Filesystem(MockDriver()); + }); + + test('should check file existence', () async { + expect(await storage.exists('test.txt'), isTrue); + expect(await storage.exists('missing.txt'), isFalse); + }); + + test('should read and write files', () async { + await storage.put('test.txt', 'contents'); + var contents = await storage.get('test.txt'); + expect(contents, equals('contents')); + }); + + test('should handle streams', () async { + var input = Stream.fromIterable([ + [1, 2, 3], + [4, 5, 6] + ]); + + await storage.putStream('test.bin', input); + var output = storage.readStream('test.bin'); + + expect( + await output.toList(), + equals([[1, 2, 3], [4, 5, 6]]) + ); + }); + }); +} +``` + +## Performance Considerations + +1. **Streaming Large Files** +```dart +// Use streams for large files +class Filesystem { + Future copyLarge(String from, String to) async { + await readStream(from) + .pipe(writeStream(to)); + } +} +``` + +2. **Caching URLs** +```dart +class CachingFilesystem implements FilesystemContract { + final Cache _cache; + final Duration _ttl; + + @override + Future url(String path) async { + var key = 'file_url:$path'; + return _cache.remember(key, _ttl, () { + return _driver.url(path); + }); + } +} +``` + +3. **Batch Operations** +```dart +class Filesystem { + Future putMany(Map files) async { + await Future.wait( + files.entries.map((e) => + put(e.key, e.value) + ) + ); + } +} +``` + +## Next Steps + +1. Implement core filesystem +2. Add local driver +3. Add cloud drivers +4. Create manager +5. Write tests +6. Add benchmarks + +Would you like me to focus on implementing any specific part of these packages or continue with other documentation? + +## Development Guidelines + +### 1. Getting Started +Before implementing filesystem features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Understand [Contracts Package Specification](contracts_package_specification.md) + +### 2. Implementation Process +For each filesystem feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Implement required contracts (see [Contracts Package Specification](contracts_package_specification.md)) + +### 4. Integration Considerations +When implementing filesystem features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) +5. Implement all contracts from [Contracts Package Specification](contracts_package_specification.md) + +### 5. Performance Guidelines +Filesystem system must: +1. Handle large files efficiently +2. Use streaming where appropriate +3. Minimize memory usage +4. Support concurrent operations +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Filesystem tests must: +1. Cover all file operations +2. Test streaming behavior +3. Verify cloud storage +4. Check metadata handling +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Filesystem documentation must: +1. Explain filesystem patterns +2. Show driver examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/foundation_integration_guide.md b/docs/foundation_integration_guide.md new file mode 100644 index 0000000..07c5e67 --- /dev/null +++ b/docs/foundation_integration_guide.md @@ -0,0 +1,316 @@ +# Foundation Integration Guide + +## Overview + +This guide demonstrates how Level 0 and Level 1 packages work together to provide the foundation for the framework. It includes implementation priorities, integration patterns, and best practices. + +## Implementation Timeline + +### Phase 1: Core Foundation (Level 0) + +#### Week 1: Contracts Package +```dart +Priority: Highest +Dependencies: None +Steps: +1. Define core interfaces +2. Create base exceptions +3. Add documentation +4. Write interface tests +``` + +#### Week 2: Support Package +```dart +Priority: Highest +Dependencies: Contracts +Steps: +1. Implement collections +2. Add string helpers +3. Create service provider base +4. Add utility functions +``` + +#### Weeks 3-4: Container Package +```dart +Priority: Highest +Dependencies: Contracts, Support +Steps: +1. Implement core container +2. Add contextual binding +3. Add method injection +4. Add tagged bindings +5. Implement caching +``` + +#### Week 5: Pipeline Package +```dart +Priority: High +Dependencies: Contracts, Support, Container +Steps: +1. Implement core pipeline +2. Add pipeline hub +3. Create middleware support +4. Add async handling +``` + +### Phase 2: Infrastructure (Level 1) + +#### Weeks 6-7: Events Package +```dart +Priority: High +Dependencies: All Level 0 +Steps: +1. Implement event dispatcher +2. Add event discovery +3. Create subscriber support +4. Add queueing integration +``` + +#### Week 8: Config Package +```dart +Priority: High +Dependencies: All Level 0 +Steps: +1. Implement config repository +2. Add environment loading +3. Create config caching +4. Add array casting +``` + +#### Weeks 9-10: FileSystem Package +```dart +Priority: High +Dependencies: All Level 0 +Steps: +1. Implement filesystem manager +2. Create local driver +3. Add cloud drivers +4. Implement streaming +``` + +## Integration Examples + +### 1. Service Provider Integration +```dart +/// Example showing how packages integrate through service providers +void main() { + var container = Container(); + + // Register foundation services + container.register(SupportServiceProvider()); + container.register(PipelineServiceProvider()); + container.register(EventServiceProvider()); + container.register(ConfigServiceProvider()); + container.register(FilesystemServiceProvider()); + + // Boot application + await container.bootProviders(); +} +``` + +### 2. Event-Driven File Operations +```dart +/// Example showing Events and FileSystem integration +class FileUploadHandler { + final EventDispatcherContract _events; + final FilesystemContract _storage; + + Future handleUpload(Upload upload) async { + // Store file using FileSystem + await _storage.put( + 'uploads/${upload.filename}', + upload.contents, + {'visibility': 'public'} + ); + + // Dispatch event using Events + await _events.dispatch(FileUploaded( + filename: upload.filename, + size: upload.size, + url: await _storage.url('uploads/${upload.filename}') + )); + } +} +``` + +### 3. Configuration-Based Pipeline +```dart +/// Example showing Config and Pipeline integration +class RequestHandler { + final ConfigContract _config; + final Pipeline _pipeline; + + Future handle(Request request) async { + // Get middleware from config + var middleware = _config.get('http.middleware', []) + .map((m) => container.make(m)) + .toList(); + + // Process request through pipeline + return _pipeline + .through(middleware) + .send(request) + .then((request) => processRequest(request)); + } +} +``` + +## Common Integration Patterns + +### 1. Service Provider Pattern +```dart +abstract class ServiceProvider { + void register() { + container.singleton((c) => + ServiceImpl( + c.make(), + c.make(), + c.make() + ) + ); + } +} +``` + +### 2. Event-Driven Pattern +```dart +class EventDrivenService { + final EventDispatcherContract events; + + void initialize() { + events.listen(_handleConfigChange); + events.listen(_handleStorageEvent); + } +} +``` + +### 3. Pipeline Pattern +```dart +class ServicePipeline { + final Pipeline pipeline; + + ServicePipeline(this.pipeline) { + pipeline.through([ + ConfigMiddleware(container.make()), + EventMiddleware(container.make()), + StorageMiddleware(container.make()) + ]); + } +} +``` + +## Testing Strategy + +### 1. Unit Tests +```dart +void main() { + group('Package Tests', () { + test('core functionality', () { + // Test core features + }); + + test('integration points', () { + // Test integration with other packages + }); + }); +} +``` + +### 2. Integration Tests +```dart +void main() { + group('Integration Tests', () { + late Container container; + + setUp(() { + container = Container(); + container.register(SupportServiceProvider()); + container.register(EventServiceProvider()); + }); + + test('should handle file upload with events', () async { + var handler = container.make(); + var events = container.make(); + + var received = []; + events.listen((event) { + received.add(event); + }); + + await handler.handleUpload(testUpload); + expect(received, hasLength(1)); + }); + }); +} +``` + +## Quality Checklist + +### 1. Code Quality +- [ ] Follows style guide +- [ ] Uses static analysis +- [ ] Has documentation +- [ ] Has tests +- [ ] Handles errors + +### 2. Package Quality +- [ ] Has README +- [ ] Has examples +- [ ] Has changelog +- [ ] Has license +- [ ] Has CI/CD + +### 3. Integration Quality +- [ ] Works with container +- [ ] Supports events +- [ ] Uses configuration +- [ ] Has providers + +## Best Practices + +1. **Use Service Providers** +```dart +// Register dependencies in providers +class ServiceProvider { + void register() { + // Register all required services + } +} +``` + +2. **Event-Driven Communication** +```dart +// Use events for cross-package communication +class Service { + final EventDispatcherContract _events; + + Future doSomething() async { + await _events.dispatch(SomethingHappened()); + } +} +``` + +3. **Configuration-Based Setup** +```dart +// Use configuration for service setup +class Service { + void initialize(ConfigContract config) { + if (config.get('service.enabled')) { + // Initialize service + } + } +} +``` + +## Next Steps + +1. Follow implementation timeline +2. Review package dependencies +3. Implement integration tests +4. Document common patterns +5. Create example applications + +Would you like me to: +1. Start implementing a specific package? +2. Create detailed integration tests? +3. Build example applications? diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 0000000..cb49d72 --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,142 @@ +# Getting Started Guide + +## Overview + +This guide helps developers get started with implementing and contributing to the framework's foundation packages. It provides step-by-step instructions for setting up the development environment, understanding the codebase, and making contributions. + +## Key Documentation + +Before starting, familiarize yourself with our core documentation: + +1. **Architecture & Implementation** + - [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) - Overall implementation status and plans + - [Foundation Integration Guide](foundation_integration_guide.md) - How packages work together + - [Testing Guide](testing_guide.md) - Testing approaches and standards + +2. **Package Documentation** + - [Container Package](container_package_specification.md) - Dependency injection system + - [Container Gap Analysis](container_gap_analysis.md) - Implementation status and plans + - More package docs coming soon... + +3. **Development Setup** + - [Melos Configuration](melos_config.md) - Build and development tools + +[Previous content remains the same until Project Structure section, then update with:] + +## Project Structure + +### 1. Package Organization +``` +platform/ +├── packages/ +│ ├── container/ # Dependency injection +│ │ ├── container/ # Core container +│ │ └── container_generator/ # Code generation +│ ├── core/ # Framework core +│ ├── events/ # Event system +│ ├── model/ # Model system +│ ├── pipeline/ # Pipeline pattern +│ ├── process/ # Process management +│ ├── queue/ # Queue system +│ ├── route/ # Routing system +│ ├── support/ # Utilities +│ └── testing/ # Testing utilities +├── apps/ # Example applications +├── config/ # Configuration files +├── docs/ # Documentation +├── examples/ # Usage examples +├── resources/ # Additional resources +├── scripts/ # Development scripts +├── templates/ # Project templates +└── tests/ # Integration tests +``` + +### 2. Package Structure +``` +package/ +├── lib/ +│ ├── src/ +│ │ ├── core/ # Core implementation +│ │ ├── contracts/ # Package interfaces +│ │ └── support/ # Package utilities +│ └── package.dart # Public API +├── test/ +│ ├── unit/ # Unit tests +│ ├── integration/ # Integration tests +│ └── performance/ # Performance tests +├── example/ # Usage examples +└── README.md # Package documentation +``` + +[Previous content remains the same until Implementation Guidelines section, then update with:] + +## Implementation Guidelines + +### 1. Laravel Compatibility +```dart +// Follow Laravel patterns where possible +class ServiceProvider { + void register() { + // Register services like Laravel + container.singleton((c) => ServiceImpl()); + + // Use contextual binding + container.when(PhotoController) + .needs() + .give(LocalStorage()); + + // Use tagged bindings + container.tag([ + EmailNotifier, + SmsNotifier + ], 'notifications'); + } +} +``` + +### 2. Testing Approach +```dart +// Follow Laravel testing patterns +void main() { + group('Feature Tests', () { + late TestCase test; + + setUp(() { + test = await TestCase.make(); + }); + + test('user can register', () async { + await test + .post('/register', { + 'name': 'John Doe', + 'email': 'john@example.com', + 'password': 'password' + }) + .assertStatus(302) + .assertRedirect('/home'); + }); + }); +} +``` + +[Previous content remains the same until Getting Help section, then update with:] + +## Getting Help + +1. **Documentation** + - Start with [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) + - Review [Foundation Integration Guide](foundation_integration_guide.md) + - Check [Testing Guide](testing_guide.md) + - Read package-specific documentation + +2. **Development Setup** + - Follow [Melos Configuration](melos_config.md) + - Setup development environment + - Run example applications + +3. **Resources** + - [Laravel Documentation](https://laravel.com/docs) + - [Dart Documentation](https://dart.dev/guides) + - [Package Layout](https://dart.dev/tools/pub/package-layout) + +[Rest of the file remains the same] diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..f4ac1a6 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,234 @@ +# Framework Documentation + +## Core Documentation + +### Getting Started +1. [Getting Started Guide](getting_started.md) +2. [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. [Foundation Integration Guide](foundation_integration_guide.md) +4. [Testing Guide](testing_guide.md) +5. [Package Integration Map](package_integration_map.md) + +### Core Architecture +1. [Core Architecture](core_architecture.md) + - System design + - Architectural patterns + - Extension points + - Package integration + +## Package Documentation + +### Core Framework +1. Core Package + - [Core Package Specification](core_package_specification.md) + - [Core Architecture](core_architecture.md) + +2. Container Package + - [Container Package Specification](container_package_specification.md) + - [Container Gap Analysis](container_gap_analysis.md) + - [Container Feature Integration](container_feature_integration.md) + - [Container Migration Guide](container_migration_guide.md) + +3. Contracts Package + - [Contracts Package Specification](contracts_package_specification.md) + +4. Events Package + - [Events Package Specification](events_package_specification.md) + - [Events Gap Analysis](events_gap_analysis.md) + +5. Pipeline Package + - [Pipeline Package Specification](pipeline_package_specification.md) + - [Pipeline Gap Analysis](pipeline_gap_analysis.md) + +6. Support Package + - [Support Package Specification](support_package_specification.md) + +### Infrastructure +1. Bus Package + - [Bus Package Specification](bus_package_specification.md) + - [Bus Gap Analysis](bus_gap_analysis.md) + +2. Config Package + - [Config Package Specification](config_package_specification.md) + - [Config Gap Analysis](config_gap_analysis.md) + +3. Filesystem Package + - [Filesystem Package Specification](filesystem_package_specification.md) + - [Filesystem Gap Analysis](filesystem_gap_analysis.md) + +4. Model Package + - [Model Package Specification](model_package_specification.md) + - [Model Gap Analysis](model_gap_analysis.md) + +5. Process Package + - [Process Package Specification](process_package_specification.md) + - [Process Gap Analysis](process_gap_analysis.md) + +6. Queue Package + - [Queue Package Specification](queue_package_specification.md) + - [Queue Gap Analysis](queue_gap_analysis.md) + +7. Route Package + - [Route Package Specification](route_package_specification.md) + - [Route Gap Analysis](route_gap_analysis.md) + +8. Testing Package + - [Testing Package Specification](testing_package_specification.md) + - [Testing Gap Analysis](testing_gap_analysis.md) + +## Package Dependencies + +```mermaid +graph TD + Core[Core] --> Container[Container] + Core --> Events[Events] + Core --> Pipeline[Pipeline] + + Container --> Contracts[Contracts] + Events --> Container + Pipeline --> Container + + Bus[Bus] --> Events + Bus --> Queue[Queue] + + Config[Config] --> Container + + Filesystem[Filesystem] --> Container + + Model[Model] --> Events + Model --> Container + + Process[Process] --> Events + Process --> Queue + + Queue --> Events + Queue --> Container + + Route[Route] --> Pipeline + Route --> Container + + Testing[Testing] --> Container + Testing --> Events +``` + +## Implementation Status + +### Core Framework (90%) +- Core Package (95%) + * Application lifecycle ✓ + * Service providers ✓ + * HTTP kernel ✓ + * Console kernel ✓ + * Exception handling ✓ + * Needs: Performance optimizations + +- Container Package (90%) + * Basic DI ✓ + * Auto-wiring ✓ + * Service providers ✓ + * Needs: Contextual binding + +- Events Package (85%) + * Event dispatching ✓ + * Event subscribers ✓ + * Event broadcasting ✓ + * Needs: Event discovery + +### Infrastructure (80%) +- Bus Package (85%) + * Command dispatching ✓ + * Command queuing ✓ + * Needs: Command batching + +- Config Package (80%) + * Configuration repository ✓ + * Environment loading ✓ + * Needs: Config caching + +- Filesystem Package (75%) + * Local driver ✓ + * Cloud storage ✓ + * Needs: Streaming support + +- Model Package (80%) + * Basic ORM ✓ + * Relationships ✓ + * Needs: Model events + +- Process Package (85%) + * Process management ✓ + * Process pools ✓ + * Needs: Process monitoring + +- Queue Package (85%) + * Queue workers ✓ + * Job batching ✓ + * Needs: Rate limiting + +- Route Package (90%) + * Route registration ✓ + * Route matching ✓ + * Middleware ✓ + * Needs: Route caching + +- Testing Package (85%) + * HTTP testing ✓ + * Database testing ✓ + * Needs: Browser testing + +## Development Workflow + +1. **Starting Development** + ```bash + # Clone repository + git clone https://github.com/organization/framework.git + + # Install dependencies + dart pub get + + # Run tests + dart test + ``` + +2. **Development Process** + - Write tests first + - Implement features + - Update documentation + - Submit PR + +3. **Quality Checks** + - Run tests + - Check code style + - Verify documentation + - Review performance + +## Contributing + +See [CONTRIBUTING.md](../CONTRIBUTING.md) for detailed contribution guidelines. + +### Quick Start +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Read relevant package documentation +4. Follow [Testing Guide](testing_guide.md) + +## Resources + +### Documentation +- [Laravel Documentation](https://laravel.com/docs) +- [Dart Documentation](https://dart.dev/guides) +- [Package Layout](https://dart.dev/tools/pub/package-layout) + +### Tools +- [Dart SDK](https://dart.dev/get-dart) +- [VS Code](https://code.visualstudio.com) +- [Git](https://git-scm.com) + +### Community +- GitHub Issues +- Discussion Forum +- Team Chat + +## License + +This framework is open-sourced software licensed under the [MIT license](../LICENSE). diff --git a/docs/laravel_compatibility_roadmap.md b/docs/laravel_compatibility_roadmap.md new file mode 100644 index 0000000..2d5e9a2 --- /dev/null +++ b/docs/laravel_compatibility_roadmap.md @@ -0,0 +1,251 @@ +# Laravel Compatibility Roadmap + +## Overview + +This document outlines our path to Laravel API compatibility while maintaining backward compatibility with existing code. It provides a comprehensive view of package dependencies, implementation status, and migration strategy. + +## Package Dependency Hierarchy + +### Level 0: Core Foundation +```mermaid +graph TD + Container[Container] --> Contracts[Contracts] + Support[Support] --> Container + Pipeline[Pipeline] --> Container +``` + +Core Dependencies: +- Container: Service container, dependency injection +- Contracts: Interfaces and contracts +- Support: Helper functions, utilities +- Pipeline: Pipeline pattern implementation + +### Level 1: Infrastructure +```mermaid +graph TD + Events[Events] --> Container + Events --> Support + Config[Config] --> Container + Config --> Support + FileSystem[FileSystem] --> Support + FileSystem --> Container +``` + +Infrastructure Dependencies: +- Events: Event dispatching system +- Config: Configuration management +- FileSystem: File system abstraction + +### Level 2: Core Services +```mermaid +graph TD + Cache[Cache] --> Events + Cache --> Container + Database[Database] --> Events + Database --> Container + Queue[Queue] --> Events + Queue --> Container + Queue --> Pipeline +``` + +Core Service Dependencies: +- Cache: Caching system +- Database: Database abstraction +- Queue: Queue system and job processing + +### Level 3: HTTP Layer +```mermaid +graph TD + Routing[Routing] --> Pipeline + Routing --> Container + Http[Http] --> Pipeline + Http --> Events + Session[Session] --> Cache + Session --> Events +``` + +HTTP Layer Dependencies: +- Routing: Route registration and matching +- Http: HTTP request/response handling +- Session: Session management + +## Current Implementation Status + +[Previous implementation status section remains the same] + +## Success Metrics + +### 1. API Compatibility +```yaml +Required: +- 100% Laravel interface implementation +- All Laravel patterns supported +- Full feature parity +- Backward compatibility maintained +``` + +### 2. Performance +```yaml +Targets: +- Resolution: < 0.1ms per operation +- Memory: < 10MB overhead +- Cache hit rate: > 90% +- Startup time: < 100ms +``` + +### 3. Code Quality +```yaml +Requirements: +- 100% test coverage +- Static analysis passing +- Documentation complete +- Examples provided +``` + +### 4. Integration +```yaml +Verification: +- Cross-package tests passing +- Performance benchmarks met +- Real-world examples working +- Migration guides verified +``` + +## Key Design Decisions + +### 1. Backward Compatibility +```dart +// Maintain existing APIs +class Container { + // Existing methods stay the same + T make(); + void bind(T instance); + + // New methods add functionality + ContextualBindingBuilder when(Type concrete); + void tag(List types, String tag); +} +``` + +### 2. Laravel Compatibility +```dart +// Match Laravel's patterns +container.when(UserController) + .needs() + .give((c) => SpecialService()); + +container.tag([ServiceA, ServiceB], 'services'); + +container.call(instance, 'method', parameters); +``` + +### 3. Performance Focus +```dart +// Add caching +class Container { + final ResolutionCache _cache; + final ReflectionCache _reflectionCache; + + T make([dynamic context]) { + return _cache.get(context) ?? _resolve(context); + } +} +``` + +## Implementation Strategy + +[Previous implementation strategy section remains the same] + +## Integration Considerations + +### 1. Service Provider Pattern +- Registration phase +- Boot phase +- Deferred providers + +### 2. Event System +- Synchronous events +- Queued events +- Event subscribers + +### 3. Queue System +- Multiple drivers +- Job handling +- Failed jobs + +### 4. Database Layer +- Query builder +- Schema builder +- Migrations + +### 5. HTTP Layer +- Middleware +- Controllers +- Resources + +### 6. Authentication +- Guards +- Providers +- Policies + +## Getting Started + +### 1. Development Environment +```bash +# Clone repository +git clone https://github.com/org/platform.git + +# Install dependencies +dart pub get + +# Run tests +dart test +``` + +### 2. Package Development +```yaml +1. Choose package level: + - Level 0: Foundation packages + - Level 1: Infrastructure packages + - Level 2: Core services + - Level 3: HTTP layer + +2. Review dependencies: + - Check required packages + - Verify integration points + - Plan implementation + +3. Follow implementation order: + - Core functionality + - Laravel compatibility + - Tests and documentation +``` + +### 3. Quality Assurance +```yaml +1. Testing: + - Unit tests + - Integration tests + - Performance tests + - Compatibility tests + +2. Documentation: + - API documentation + - Usage examples + - Integration guides + - Migration guides + +3. Performance: + - Benchmarking + - Profiling + - Optimization +``` + +## Next Steps + +[Previous next steps section remains the same] + +Would you like me to: +1. Create detailed plans for package creation? +2. Start implementing specific features? +3. Create test plans for new functionality? diff --git a/docs/model_gap_analysis.md b/docs/model_gap_analysis.md new file mode 100644 index 0000000..fc7e1a2 --- /dev/null +++ b/docs/model_gap_analysis.md @@ -0,0 +1,316 @@ +# Model Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Model package's actual implementation and Laravel's Eloquent functionality, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Model Package Specification](model_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Model Scopes +class ModelScope { + // Need to implement: + Query apply(Query query); + bool shouldApply(Query query); +} + +// 2. Model Observers +class ModelObserver { + // Need to implement: + void creating(T model); + void created(T model); + void updating(T model); + void updated(T model); + void deleting(T model); + void deleted(T model); + void restored(T model); + void forceDeleted(T model); +} + +// 3. Model Factories +class ModelFactory { + // Need to implement: + T definition(); + T make([Map? attributes]); + Future create([Map? attributes]); + List makeMany(int count, [Map? attributes]); + Future> createMany(int count, [Map? attributes]); +} +``` + +### 2. Missing Relationship Types +```dart +// Need to implement: + +// 1. Many to Many +class BelongsToMany extends Relationship { + // Need to implement: + String get table; + String get foreignPivotKey; + String get relatedPivotKey; + List get pivotColumns; + + Future> get(); + Future attach(List ids, [Map? attributes]); + Future detach(List? ids); + Future sync(List ids); + Future toggle(List ids); + Future updateExistingPivot(dynamic id, Map attributes); +} + +// 2. Has Many Through +class HasManyThrough extends Relationship { + // Need to implement: + String get through; + String get firstKey; + String get secondKey; + String get localKey; + String get secondLocalKey; + + Future> get(); +} + +// 3. Polymorphic Relations +class MorphTo extends Relationship { + // Need to implement: + String get morphType; + String get morphId; + + Future get(); +} +``` + +### 3. Missing Query Features +```dart +// Need to implement: + +// 1. Advanced Where Clauses +class Query { + // Need to implement: + Query whereIn(String column, List values); + Query whereNotIn(String column, List values); + Query whereBetween(String column, List values); + Query whereNotBetween(String column, List values); + Query whereNull(String column); + Query whereNotNull(String column); + Query whereDate(String column, DateTime date); + Query whereMonth(String column, int month); + Query whereYear(String column, int year); + Query whereTime(String column, String operator, DateTime time); +} + +// 2. Joins +class Query { + // Need to implement: + Query join(String table, String first, [String? operator, String? second]); + Query leftJoin(String table, String first, [String? operator, String? second]); + Query rightJoin(String table, String first, [String? operator, String? second]); + Query crossJoin(String table); +} + +// 3. Aggregates +class Query { + // Need to implement: + Future count([String column = '*']); + Future max(String column); + Future min(String column); + Future avg(String column); + Future sum(String column); +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation +```dart +// Need to document: + +/// Applies a scope to the query. +/// +/// Example: +/// ```dart +/// class PublishedScope implements Scope { +/// Query apply(Query query) { +/// return query.where('published', true); +/// } +/// } +/// ``` +void addGlobalScope(Scope scope); + +/// Defines a local scope. +/// +/// Example: +/// ```dart +/// Query published() { +/// return where('published', true); +/// } +/// ``` +void scopePublished(Query query); +``` + +### 2. Missing Integration Examples +```dart +// Need examples for: + +// 1. Model Observers +class UserObserver extends ModelObserver { + @override + void created(User user) { + // Send welcome email + } + + @override + void deleted(User user) { + // Cleanup user data + } +} + +// 2. Model Factories +class UserFactory extends ModelFactory { + @override + User definition() { + return User() + ..name = faker.person.name() + ..email = faker.internet.email(); + } +} + +// 3. Many to Many Relationships +class User extends Model { + Future> roles() { + return belongsToMany('role_user') + .withPivot(['expires_at']) + .wherePivot('active', true) + .get(); + } +} +``` + +### 3. Missing Test Coverage +```dart +// Need tests for: + +void main() { + group('Model Scopes', () { + test('applies global scopes', () async { + var posts = await Post.all(); + expect(posts.every((p) => p.published), isTrue); + }); + + test('applies local scopes', () async { + var posts = await Post().recent().popular().get(); + expect(posts, hasLength(greaterThan(0))); + }); + }); + + group('Model Factories', () { + test('creates model instances', () async { + var users = await UserFactory().createMany(3); + expect(users, hasLength(3)); + expect(users.first.name, isNotEmpty); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Model scopes (Laravel compatibility) + - Model observers (Laravel compatibility) + - Many to Many relationships + +2. **Medium Priority** + - Model factories + - Advanced where clauses + - Query joins + +3. **Low Priority** + - Additional relationship types + - Additional query features + - Performance optimizations + +## Next Steps + +1. **Implementation Tasks** + - Add model scopes + - Add model observers + - Add many to many relationships + - Add model factories + +2. **Documentation Tasks** + - Document model scopes + - Document model observers + - Document relationships + - Add integration examples + +3. **Testing Tasks** + - Add scope tests + - Add observer tests + - Add relationship tests + - Add factory tests + +## Development Guidelines + +### 1. Getting Started +Before implementing model features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Model Package Specification](model_package_specification.md) + +### 2. Implementation Process +For each model feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Model Package Specification](model_package_specification.md) + +### 4. Integration Considerations +When implementing model features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Model system must: +1. Handle large datasets efficiently +2. Optimize relationship loading +3. Support eager loading +4. Cache query results +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Model tests must: +1. Cover all model operations +2. Test relationships +3. Verify events +4. Check query building +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Model documentation must: +1. Explain model patterns +2. Show relationship examples +3. Cover event handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/model_package_specification.md b/docs/model_package_specification.md new file mode 100644 index 0000000..9680cec --- /dev/null +++ b/docs/model_package_specification.md @@ -0,0 +1,486 @@ +# Model Package Specification + +## Overview + +The Model package provides a robust data modeling system that matches Laravel's Eloquent functionality. It supports active record pattern, relationships, attribute casting, serialization, and model events while leveraging Dart's type system. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Events Package Specification](events_package_specification.md) for model events + +## Core Features + +### 1. Base Model + +```dart +/// Core model implementation +abstract class Model { + /// Model attributes + final Map _attributes = {}; + + /// Original attributes + final Map _original = {}; + + /// Changed attributes + final Set _changes = {}; + + /// Model constructor + Model([Map? attributes]) { + fill(attributes ?? {}); + } + + /// Gets table name + String get table; + + /// Gets primary key + String get primaryKey => 'id'; + + /// Gets fillable attributes + List get fillable => []; + + /// Gets guarded attributes + List get guarded => ['id']; + + /// Gets attribute value + dynamic operator [](String key) => getAttribute(key); + + /// Sets attribute value + operator []=(String key, dynamic value) => setAttribute(key, value); + + /// Gets an attribute + dynamic getAttribute(String key) { + return _attributes[key]; + } + + /// Sets an attribute + void setAttribute(String key, dynamic value) { + if (!_original.containsKey(key)) { + _original[key] = _attributes[key]; + } + + _attributes[key] = value; + _changes.add(key); + } + + /// Fills attributes + void fill(Map attributes) { + for (var key in attributes.keys) { + if (_isFillable(key)) { + this[key] = attributes[key]; + } + } + } + + /// Checks if attribute is fillable + bool _isFillable(String key) { + if (guarded.contains(key)) return false; + if (fillable.isEmpty) return true; + return fillable.contains(key); + } + + /// Gets changed attributes + Map getDirty() { + var dirty = {}; + for (var key in _changes) { + dirty[key] = _attributes[key]; + } + return dirty; + } + + /// Checks if model is dirty + bool get isDirty => _changes.isNotEmpty; + + /// Gets original attributes + Map getOriginal() => Map.from(_original); + + /// Resets changes + void syncOriginal() { + _original.clear(); + _original.addAll(_attributes); + _changes.clear(); + } + + /// Converts to map + Map toMap() => Map.from(_attributes); + + /// Converts to JSON + String toJson() => jsonEncode(toMap()); +} +``` + +### 2. Model Relationships + +```dart +/// Has one relationship +class HasOne extends Relationship { + /// Foreign key + final String foreignKey; + + /// Local key + final String localKey; + + HasOne(Query query, Model parent, this.foreignKey, this.localKey) + : super(query, parent); + + @override + Future get() async { + return await query + .where(foreignKey, parent[localKey]) + .first(); + } +} + +/// Has many relationship +class HasMany extends Relationship { + /// Foreign key + final String foreignKey; + + /// Local key + final String localKey; + + HasMany(Query query, Model parent, this.foreignKey, this.localKey) + : super(query, parent); + + @override + Future> get() async { + return await query + .where(foreignKey, parent[localKey]) + .get(); + } +} + +/// Belongs to relationship +class BelongsTo extends Relationship { + /// Foreign key + final String foreignKey; + + /// Owner key + final String ownerKey; + + BelongsTo(Query query, Model child, this.foreignKey, this.ownerKey) + : super(query, child); + + @override + Future get() async { + return await query + .where(ownerKey, parent[foreignKey]) + .first(); + } +} +``` + +### 3. Model Events + +```dart +/// Model events mixin +mixin ModelEvents { + /// Event dispatcher + static EventDispatcherContract? _dispatcher; + + /// Sets event dispatcher + static void setEventDispatcher(EventDispatcherContract dispatcher) { + _dispatcher = dispatcher; + } + + /// Fires a model event + Future fireModelEvent(String event) async { + if (_dispatcher == null) return true; + + var result = await _dispatcher!.dispatch('model.$event', this); + return result != false; + } + + /// Fires creating event + Future fireCreatingEvent() => fireModelEvent('creating'); + + /// Fires created event + Future fireCreatedEvent() => fireModelEvent('created'); + + /// Fires updating event + Future fireUpdatingEvent() => fireModelEvent('updating'); + + /// Fires updated event + Future fireUpdatedEvent() => fireModelEvent('updated'); + + /// Fires deleting event + Future fireDeletingEvent() => fireModelEvent('deleting'); + + /// Fires deleted event + Future fireDeletedEvent() => fireModelEvent('deleted'); +} +``` + +### 4. Model Query Builder + +```dart +/// Model query builder +class Query { + /// Database connection + final DatabaseConnection _connection; + + /// Model instance + final T _model; + + /// Query constraints + final List _wheres = []; + final List _bindings = []; + final List _orders = []; + int? _limit; + int? _offset; + + Query(this._connection, this._model); + + /// Adds where clause + Query where(String column, [dynamic value]) { + _wheres.add('$column = ?'); + _bindings.add(value); + return this; + } + + /// Adds order by clause + Query orderBy(String column, [String direction = 'asc']) { + _orders.add('$column $direction'); + return this; + } + + /// Sets limit + Query limit(int limit) { + _limit = limit; + return this; + } + + /// Sets offset + Query offset(int offset) { + _offset = offset; + return this; + } + + /// Gets first result + Future first() async { + var results = await get(); + return results.isEmpty ? null : results.first; + } + + /// Gets results + Future> get() async { + var sql = _toSql(); + var rows = await _connection.select(sql, _bindings); + return rows.map((row) => _hydrate(row)).toList(); + } + + /// Builds SQL query + String _toSql() { + var sql = 'select * from ${_model.table}'; + + if (_wheres.isNotEmpty) { + sql += ' where ${_wheres.join(' and ')}'; + } + + if (_orders.isNotEmpty) { + sql += ' order by ${_orders.join(', ')}'; + } + + if (_limit != null) { + sql += ' limit $_limit'; + } + + if (_offset != null) { + sql += ' offset $_offset'; + } + + return sql; + } + + /// Hydrates model from row + T _hydrate(Map row) { + var instance = _model.newInstance() as T; + instance.fill(row); + instance.syncOriginal(); + return instance; + } +} +``` + +## Integration Examples + +### 1. Basic Model Usage +```dart +// Define model +class User extends Model { + @override + String get table => 'users'; + + @override + List get fillable => ['name', 'email']; + + String get name => this['name']; + set name(String value) => this['name'] = value; + + String get email => this['email']; + set email(String value) => this['email'] = value; +} + +// Create user +var user = User() + ..name = 'John Doe' + ..email = 'john@example.com'; + +await user.save(); + +// Find user +var found = await User.find(1); +print(found.name); // John Doe +``` + +### 2. Relationships +```dart +class User extends Model { + // Has many posts + Future> posts() { + return hasMany('user_id').get(); + } + + // Has one profile + Future profile() { + return hasOne('user_id').get(); + } +} + +class Post extends Model { + // Belongs to user + Future user() { + return belongsTo('user_id').get(); + } +} + +// Use relationships +var user = await User.find(1); +var posts = await user.posts(); +var profile = await user.profile(); +``` + +### 3. Events +```dart +// Register event listener +Model.getEventDispatcher().listen>((event) { + var user = event.model; + print('User ${user.name} was created'); +}); + +// Create user (triggers event) +var user = User() + ..name = 'Jane Doe' + ..email = 'jane@example.com'; + +await user.save(); +``` + +## Testing + +```dart +void main() { + group('Model', () { + test('handles attributes', () { + var user = User() + ..name = 'John' + ..email = 'john@example.com'; + + expect(user.name, equals('John')); + expect(user.isDirty, isTrue); + expect(user.getDirty(), containsPair('name', 'John')); + }); + + test('tracks changes', () { + var user = User() + ..fill({ + 'name': 'John', + 'email': 'john@example.com' + }); + + user.syncOriginal(); + user.name = 'Jane'; + + expect(user.isDirty, isTrue); + expect(user.getOriginal()['name'], equals('John')); + expect(user.name, equals('Jane')); + }); + }); + + group('Relationships', () { + test('loads relationships', () async { + var user = await User.find(1); + var posts = await user.posts(); + + expect(posts, hasLength(greaterThan(0))); + expect(posts.first, isA()); + }); + }); +} +``` + +## Next Steps + +1. Implement core model features +2. Add relationship types +3. Add model events +4. Add query builder +5. Write tests +6. Add benchmarks + +## Development Guidelines + +### 1. Getting Started +Before implementing model features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Events Package Specification](events_package_specification.md) + +### 2. Implementation Process +For each model feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Support model events (see [Events Package Specification](events_package_specification.md)) + +### 4. Integration Considerations +When implementing model features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Model system must: +1. Handle large datasets efficiently +2. Optimize relationship loading +3. Support eager loading +4. Cache query results +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Model tests must: +1. Cover all model operations +2. Test relationships +3. Verify events +4. Check query building +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Model documentation must: +1. Explain model patterns +2. Show relationship examples +3. Cover event handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/package_integration_map.md b/docs/package_integration_map.md new file mode 100644 index 0000000..52b3997 --- /dev/null +++ b/docs/package_integration_map.md @@ -0,0 +1,540 @@ +# Package Integration Map + +## Overview + +This document maps out the integration points between our framework packages and outlines how to maintain and enhance these integrations while achieving Laravel API compatibility. + +> **Related Documentation** +> - See [Core Architecture](core_architecture.md) for system design +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches + +## Package Documentation + +### Core Framework +1. Core Package + - [Core Package Specification](core_package_specification.md) + - [Core Architecture](core_architecture.md) + +2. Container Package + - [Container Package Specification](container_package_specification.md) + - [Container Gap Analysis](container_gap_analysis.md) + - [Container Feature Integration](container_feature_integration.md) + - [Container Migration Guide](container_migration_guide.md) + +3. Contracts Package + - [Contracts Package Specification](contracts_package_specification.md) + +4. Events Package + - [Events Package Specification](events_package_specification.md) + - [Events Gap Analysis](events_gap_analysis.md) + +5. Pipeline Package + - [Pipeline Package Specification](pipeline_package_specification.md) + - [Pipeline Gap Analysis](pipeline_gap_analysis.md) + +6. Support Package + - [Support Package Specification](support_package_specification.md) + +### Infrastructure +1. Bus Package + - [Bus Package Specification](bus_package_specification.md) + - [Bus Gap Analysis](bus_gap_analysis.md) + +2. Config Package + - [Config Package Specification](config_package_specification.md) + - [Config Gap Analysis](config_gap_analysis.md) + +3. Filesystem Package + - [Filesystem Package Specification](filesystem_package_specification.md) + - [Filesystem Gap Analysis](filesystem_gap_analysis.md) + +4. Model Package + - [Model Package Specification](model_package_specification.md) + - [Model Gap Analysis](model_gap_analysis.md) + +5. Process Package + - [Process Package Specification](process_package_specification.md) + - [Process Gap Analysis](process_gap_analysis.md) + +6. Queue Package + - [Queue Package Specification](queue_package_specification.md) + - [Queue Gap Analysis](queue_gap_analysis.md) + +7. Route Package + - [Route Package Specification](route_package_specification.md) + - [Route Gap Analysis](route_gap_analysis.md) + +8. Testing Package + - [Testing Package Specification](testing_package_specification.md) + - [Testing Gap Analysis](testing_gap_analysis.md) + +## Core Integration Points + +### 1. Container Integration Hub +```dart +// All packages integrate with Container for dependency injection +class ServiceProvider { + final Container container; + + // Current Integration + void register() { + container.registerSingleton(ServiceImpl()); + } + + // Laravel-Compatible Enhancement + void register() { + // Add contextual binding + container.when(Service).needs().give(FileLogger()); + + // Add tagged binding + container.tag([ + EmailNotifier, + SmsNotifier, + PushNotifier + ], 'notifications'); + } +} +``` + +### 2. Event System Integration +```dart +// Events package integrates with multiple packages +class EventServiceProvider { + // Current Integration + void register() { + // Queue Integration + container.singleton((c) => + QueuedEventDispatcher( + queue: c.make(), + broadcaster: c.make() + ) + ); + + // Bus Integration + container.singleton((c) => + CommandDispatcher( + events: c.make(), + queue: c.make() + ) + ); + } + + // Laravel-Compatible Enhancement + void register() { + // Add event discovery + container.singleton((c) => + EventDiscovery(c.make()) + ); + + // Add after commit handling + container.singleton((c) => + DatabaseEventDispatcher( + events: c.make(), + db: c.make() + ) + ); + } +} +``` + +### 3. Queue and Bus Integration +```dart +// Queue and Bus packages work together for job handling +class QueuedCommandDispatcher { + // Current Integration + Future dispatch(Command command) async { + if (command is ShouldQueue) { + await queue.push(QueuedCommandJob(command)); + } else { + await commandBus.dispatch(command); + } + } + + // Laravel-Compatible Enhancement + Future dispatch(Command command) async { + // Add job middleware + var job = QueuedCommandJob(command) + ..through([ + RateLimitedMiddleware(), + WithoutOverlappingMiddleware() + ]); + + // Add job batching + if (command is BatchableCommand) { + await queue.batch([job]) + .allowFailures() + .dispatch(); + } else { + await queue.push(job); + } + } +} +``` + +### 4. Route and Core Integration +```dart +// Route package integrates with Core for HTTP handling +class RouterServiceProvider { + // Current Integration + void register() { + container.singleton((c) => + Router() + ..use(LoggingMiddleware()) + ..use(AuthMiddleware()) + ); + } + + // Laravel-Compatible Enhancement + void register() { + // Add model binding + container.singleton((c) => + RouteModelBinder( + models: c.make(), + db: c.make() + ) + ); + + // Add subdomain routing + container.singleton((c) => + SubdomainRouter( + domains: c.make(), + router: c.make() + ) + ); + } +} +``` + +### 5. Process and Queue Integration +```dart +// Process package integrates with Queue for background tasks +class ProcessManager { + // Current Integration + Future runProcess(String command) async { + var process = await Process.start(command); + queue.push(ProcessMonitorJob(process.pid)); + } + + // Laravel-Compatible Enhancement + Future runProcess(String command) async { + // Add scheduling + scheduler.job(ProcessJob(command)) + .everyFiveMinutes() + .withoutOverlapping() + .onFailure((e) => notifyAdmin(e)); + + // Add process pools + processPool.job(command) + .onServers(['worker-1', 'worker-2']) + .dispatch(); + } +} +``` + +### 6. Model and Event Integration +```dart +// Model package integrates with Events for model events +class ModelEventDispatcher { + // Current Integration + Future save(Model model) async { + await events.dispatch(ModelSaving(model)); + await db.save(model); + await events.dispatch(ModelSaved(model)); + } + + // Laravel-Compatible Enhancement + Future save(Model model) async { + // Add transaction awareness + await db.transaction((tx) async { + await events.dispatch(ModelSaving(model)); + await tx.save(model); + + // Queue after commit + events.afterCommit(() => + events.dispatch(ModelSaved(model)) + ); + }); + } +} +``` + +## Package-Specific Integration Points + +### 1. Container Package +```dart +// Integration with other packages +class Container { + // Current + void bootstrap() { + registerSingleton(); + registerSingleton(); + registerSingleton(); + } + + // Enhanced + void bootstrap() { + // Add service repository + registerSingleton((c) => + ServiceRepository([ + EventServiceProvider(), + QueueServiceProvider(), + BusServiceProvider() + ]) + ); + + // Add deferred loading + registerDeferred((c) => + ReportGenerator(c.make()) + ); + } +} +``` + +### 2. Events Package +```dart +// Integration with other packages +class EventDispatcher { + // Current + Future dispatch(Event event) async { + if (event is QueuedEvent) { + await queue.push(event); + } else { + await notifyListeners(event); + } + } + + // Enhanced + Future dispatch(Event event) async { + // Add broadcast channels + if (event is BroadcastEvent) { + await broadcast.to(event.channels) + .with(['queue' => queue.connection()]) + .send(event); + } + + // Add event subscribers + await container.make() + .dispatch(event); + } +} +``` + +### 3. Queue Package +```dart +// Integration with other packages +class QueueManager { + // Current + Future process() async { + while (true) { + var job = await queue.pop(); + await job.handle(); + } + } + + // Enhanced + Future process() async { + // Add worker management + worker.supervise((worker) { + worker.process('default') + .throughMiddleware([ + RateLimited::class, + PreventOverlapping::class + ]) + .withEvents(events); + }); + } +} +``` + +## Integration Enhancement Strategy + +1. **Container Enhancements** + - Add contextual binding + - Add tagged bindings + - Keep existing integrations working + +2. **Event System Enhancements** + - Add event discovery + - Add after commit handling + - Maintain existing event flow + +3. **Queue System Enhancements** + - Add job batching + - Add better job middleware + - Keep existing job handling + +4. **Route System Enhancements** + - Add model binding + - Add subdomain routing + - Maintain existing routing + +5. **Process System Enhancements** + - Add scheduling + - Add process pools + - Keep existing process management + +6. **Model System Enhancements** + - Add Eloquent features + - Add relationships + - Maintain existing model events + +## Implementation Steps + +1. **Document Current Integration Points** + - Map all package dependencies + - Document integration interfaces + - Note existing functionality + +2. **Plan Laravel-Compatible Interfaces** + - Review Laravel's interfaces + - Design compatible interfaces + - Plan migration strategy + +3. **Implement Enhancements** + - Start with Container enhancements + - Add Event enhancements + - Add Queue enhancements + - Continue with other packages + +4. **Test Integration Points** + - Test existing functionality + - Test new functionality + - Test Laravel compatibility + +5. **Migration Guide** + - Document breaking changes + - Provide upgrade path + - Include examples + +## Package Dependencies + +```mermaid +graph TD + Core[Core] --> Container[Container] + Core --> Events[Events] + Core --> Pipeline[Pipeline] + + Container --> Contracts[Contracts] + Events --> Container + Pipeline --> Container + + Bus[Bus] --> Events + Bus --> Queue[Queue] + + Config[Config] --> Container + + Filesystem[Filesystem] --> Container + + Model[Model] --> Events + Model --> Container + + Process[Process] --> Events + Process --> Queue + + Queue --> Events + Queue --> Container + + Route[Route] --> Pipeline + Route --> Container + + Testing[Testing] --> Container + Testing --> Events +``` + +## Implementation Status + +### Core Framework (90%) +- Core Package (95%) + * Application lifecycle ✓ + * Service providers ✓ + * HTTP kernel ✓ + * Console kernel ✓ + * Exception handling ✓ + * Needs: Performance optimizations + +- Container Package (90%) + * Basic DI ✓ + * Auto-wiring ✓ + * Service providers ✓ + * Needs: Contextual binding + +- Events Package (85%) + * Event dispatching ✓ + * Event subscribers ✓ + * Event broadcasting ✓ + * Needs: Event discovery + +### Infrastructure (80%) +- Bus Package (85%) + * Command dispatching ✓ + * Command queuing ✓ + * Needs: Command batching + +- Config Package (80%) + * Configuration repository ✓ + * Environment loading ✓ + * Needs: Config caching + +- Filesystem Package (75%) + * Local driver ✓ + * Cloud storage ✓ + * Needs: Streaming support + +- Model Package (80%) + * Basic ORM ✓ + * Relationships ✓ + * Needs: Model events + +- Process Package (85%) + * Process management ✓ + * Process pools ✓ + * Needs: Process monitoring + +- Queue Package (85%) + * Queue workers ✓ + * Job batching ✓ + * Needs: Rate limiting + +- Route Package (90%) + * Route registration ✓ + * Route matching ✓ + * Middleware ✓ + * Needs: Route caching + +- Testing Package (85%) + * HTTP testing ✓ + * Database testing ✓ + * Needs: Browser testing + +## Development Guidelines + +### 1. Getting Started +Before implementing integrations: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) + +### 2. Implementation Process +For each integration: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All integrations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match package specifications + +### 4. Documentation Requirements +Integration documentation must: +1. Explain integration patterns +2. Show usage examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/pipeline_gap_analysis.md b/docs/pipeline_gap_analysis.md new file mode 100644 index 0000000..f7d15b5 --- /dev/null +++ b/docs/pipeline_gap_analysis.md @@ -0,0 +1,316 @@ +# Pipeline Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Pipeline package's actual implementation and our documentation, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Pipeline Package Specification](pipeline_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Pipeline Hub +class PipelineHub { + // Need to implement: + Pipeline pipeline(String name); + void defaults(List pipes); + Pipeline middleware(); + Pipeline bus(); +} + +// 2. Pipeline Conditions +class Pipeline { + // Need to implement: + Pipeline when(bool Function() callback); + Pipeline unless(bool Function() callback); + Pipeline whenCallback(Function callback); +} + +// 3. Pipeline Caching +class Pipeline { + // Need to implement: + void enableCache(); + void clearCache(); + dynamic getCached(String key); +} +``` + +### 2. Existing Features Not Documented + +```dart +// Implemented but not documented: + +// 1. Type Registration +class Pipeline { + /// Registers pipe types for string resolution + void registerPipeType(String name, Type type); + + /// Type map for string resolution + final Map _typeMap = {}; +} + +// 2. Method Invocation +class Pipeline { + /// Invokes methods on pipe instances + Future invokeMethod( + dynamic instance, + String methodName, + List arguments + ); + + /// Sets method to call on pipes + Pipeline via(String method); +} + +// 3. Exception Handling +class Pipeline { + /// Logger for pipeline + final Logger _logger; + + /// Handles exceptions in pipeline + dynamic handleException(dynamic passable, Object e); +} +``` + +### 3. Integration Points Not Documented + +```dart +// 1. Container Integration +class Pipeline { + /// Container reference + final Container? _container; + + /// Gets container instance + Container getContainer(); + + /// Sets container instance + Pipeline setContainer(Container container); +} + +// 2. Reflection Integration +class Pipeline { + /// Resolves pipe types using mirrors + Type? _resolvePipeType(String pipeClass) { + try { + for (var lib in currentMirrorSystem().libraries.values) { + // Reflection logic... + } + } catch (_) {} + } +} + +// 3. Logging Integration +class Pipeline { + /// Logger instance + final Logger _logger; + + /// Logs pipeline events + void _logPipelineEvent(String message, [Object? error]); +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation + +```dart +// Need to document: + +/// Registers a pipe type for string resolution. +/// +/// This allows pipes to be specified by string names in the through() method. +/// +/// Example: +/// ```dart +/// pipeline.registerPipeType('auth', AuthMiddleware); +/// pipeline.through(['auth']); +/// ``` +void registerPipeType(String name, Type type); + +/// Sets the method to be called on pipe instances. +/// +/// By default, the 'handle' method is called. This method allows +/// customizing which method is called on each pipe. +/// +/// Example: +/// ```dart +/// pipeline.via('process').through([MyPipe]); +/// // Will call process() instead of handle() +/// ``` +Pipeline via(String method); +``` + +### 2. Missing Integration Examples + +```dart +// Need examples for: + +// 1. Container Integration +var pipeline = Pipeline(container) + ..through([ + AuthMiddleware, + container.make(), + 'validation' // Resolved from container + ]); + +// 2. Exception Handling +pipeline.through([ + (passable, next) async { + try { + return await next(passable); + } catch (e) { + logger.error('Pipeline error', e); + throw PipelineException(e.toString()); + } + } +]); + +// 3. Method Customization +pipeline.via('process') + .through([ + ProcessingPipe(), // Will call process() instead of handle() + ValidationPipe() + ]); +``` + +### 3. Missing Test Coverage + +```dart +// Need tests for: + +void main() { + group('Type Registration', () { + test('resolves string pipes to types', () { + var pipeline = Pipeline(container); + pipeline.registerPipeType('auth', AuthMiddleware); + + await pipeline + .through(['auth']) + .send(request) + .then(handler); + + verify(() => container.make()).called(1); + }); + }); + + group('Method Invocation', () { + test('calls custom methods on pipes', () { + var pipeline = Pipeline(container); + var pipe = MockPipe(); + + await pipeline + .via('process') + .through([pipe]) + .send(data) + .then(handler); + + verify(() => pipe.process(any, any)).called(1); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Pipeline hub (Laravel compatibility) + - Pipeline conditions (Laravel compatibility) + - Better exception handling + +2. **Medium Priority** + - Pipeline caching + - Better type resolution + - Performance optimizations + +3. **Low Priority** + - Additional helper methods + - Extended testing utilities + - Debug/profiling tools + +## Next Steps + +1. **Implementation Tasks** + - Add pipeline hub + - Add pipeline conditions + - Add caching support + - Improve exception handling + +2. **Documentation Tasks** + - Document type registration + - Document method invocation + - Document exception handling + - Add integration examples + +3. **Testing Tasks** + - Add type registration tests + - Add method invocation tests + - Add exception handling tests + - Add integration tests + +Would you like me to: +1. Start implementing missing features? +2. Update documentation for existing features? +3. Create test cases for missing coverage? + +## Development Guidelines + +### 1. Getting Started +Before implementing pipeline features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Pipeline Package Specification](pipeline_package_specification.md) + +### 2. Implementation Process +For each pipeline feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Pipeline Package Specification](pipeline_package_specification.md) + +### 4. Integration Considerations +When implementing pipeline features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Pipeline system must: +1. Handle nested pipelines efficiently +2. Minimize memory usage in long pipelines +3. Support async operations +4. Scale with number of stages +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Pipeline tests must: +1. Cover all pipeline types +2. Test stage ordering +3. Verify error handling +4. Check conditional execution +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Pipeline documentation must: +1. Explain pipeline patterns +2. Show integration examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/pipeline_package_specification.md b/docs/pipeline_package_specification.md new file mode 100644 index 0000000..48621b8 --- /dev/null +++ b/docs/pipeline_package_specification.md @@ -0,0 +1,408 @@ +# Pipeline Package Specification + +## Overview + +The Pipeline package provides a robust implementation of the pipeline pattern, allowing for the sequential processing of tasks through a series of stages. It integrates deeply with our Route, Bus, and Queue packages while maintaining Laravel compatibility. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Contracts Package Specification](contracts_package_specification.md) for pipeline contracts + +## Core Features + +### 1. Pipeline Base + +```dart +/// Core pipeline class with conditional execution +class Pipeline with Conditionable> { + final Container _container; + final List> _pipes; + TPassable? _passable; + String _method = 'handle'; + + Pipeline(this._container, [List>? pipes]) + : _pipes = pipes ?? []; + + /// Sends an object through the pipeline + Pipeline send(TPassable passable) { + _passable = passable; + return this; + } + + /// Sets the stages of the pipeline + Pipeline through(List pipes) { + for (var pipe in pipes) { + if (pipe is String) { + // Resolve from container + _pipes.add(_container.make(pipe)); + } else if (pipe is Type) { + _pipes.add(_container.make(pipe)); + } else if (pipe is Pipe) { + _pipes.add(pipe); + } else if (pipe is Function) { + _pipes.add(FunctionPipe(pipe)); + } + } + return this; + } + + /// Sets the method to call on the pipes + Pipeline via(String method) { + _method = method; + return this; + } + + /// Process the pipeline to final result + Future then( + FutureOr Function(TPassable) destination + ) async { + var pass = _passable; + if (pass == null) { + throw PipelineException('No passable object provided'); + } + + // Build pipeline + var pipeline = _pipes.fold( + destination, + (next, pipe) => (passable) => + _container.call(() => pipe.handle(passable, next)) + ); + + // Execute pipeline + return await pipeline(pass); + } +} +``` + +### 2. Middleware Pipeline + +```dart +/// HTTP middleware pipeline with route integration +class MiddlewarePipeline extends Pipeline { + final Router _router; + + MiddlewarePipeline(Container container, this._router) + : super(container); + + /// Adds route-specific middleware + MiddlewarePipeline throughRoute(Route route) { + // Get global middleware + var middleware = _router.middleware; + + // Add route middleware + if (route.middleware.isNotEmpty) { + middleware.addAll( + route.middleware.map((m) => _container.make(m)) + ); + } + + // Add route group middleware + if (route.group != null) { + middleware.addAll(route.group!.middleware); + } + + return through(middleware); + } + + /// Processes request through middleware + Future process( + Request request, + FutureOr Function(Request) destination + ) { + return send(request) + .when(() => shouldProcessMiddleware(request)) + .then(destination); + } + + /// Checks if middleware should be processed + bool shouldProcessMiddleware(Request request) { + return !request.attributes.containsKey('skip_middleware'); + } +} +``` + +### 3. Bus Pipeline + +```dart +/// Command bus pipeline with handler resolution +class BusPipeline extends Pipeline { + final CommandBus _bus; + + BusPipeline(Container container, this._bus) + : super(container); + + /// Processes command through pipeline + Future process( + TCommand command, + [Handler? handler] + ) { + // Resolve handler + handler ??= _resolveHandler(command); + + return send(command).then((cmd) => + handler!.handle(cmd) as Future + ); + } + + /// Resolves command handler + Handler _resolveHandler(TCommand command) { + if (command is Command) { + return _container.make(command.handler); + } + + var handlerType = _bus.handlers[TCommand]; + if (handlerType == null) { + throw HandlerNotFoundException( + 'No handler found for ${TCommand}' + ); + } + + return _container.make(handlerType); + } +} +``` + +### 4. Job Pipeline + +```dart +/// Queue job pipeline with middleware +class JobPipeline extends Pipeline { + final QueueManager _queue; + + JobPipeline(Container container, this._queue) + : super(container); + + /// Processes job through pipeline + Future process(Job job) { + return send(job) + .through(_queue.middleware) + .then((j) => j.handle()); + } + + /// Adds rate limiting + JobPipeline withRateLimit(int maxAttempts, Duration timeout) { + return through([ + RateLimitedPipe(maxAttempts, timeout) + ]); + } + + /// Prevents overlapping jobs + JobPipeline withoutOverlapping() { + return through([WithoutOverlappingPipe()]); + } +} +``` + +### 5. Pipeline Hub + +```dart +/// Manages application pipelines +class PipelineHub { + final Container _container; + final Map _pipelines = {}; + final List _defaults = []; + + PipelineHub(this._container); + + /// Gets or creates a pipeline + Pipeline pipeline(String name) { + return _pipelines.putIfAbsent( + name, + () => Pipeline(_container, [..._defaults]) + ); + } + + /// Gets middleware pipeline + MiddlewarePipeline middleware() { + return pipeline('middleware') as MiddlewarePipeline; + } + + /// Gets bus pipeline + BusPipeline bus() { + return pipeline('bus') as BusPipeline; + } + + /// Gets job pipeline + JobPipeline job() { + return pipeline('job') as JobPipeline; + } + + /// Sets default pipes + void defaults(List pipes) { + _defaults.addAll(pipes); + } +} +``` + +## Integration Examples + +### 1. Route Integration +```dart +// In RouteServiceProvider +void boot() { + router.middleware([ + StartSession::class, + VerifyCsrfToken::class + ]); + + router.group(['middleware' => ['auth']], () { + router.get('/dashboard', DashboardController); + }); +} + +// In Router +Future dispatch(Request request) { + var route = matchRoute(request); + + return container.make() + .throughRoute(route) + .process(request, (req) => route.handle(req)); +} +``` + +### 2. Command Bus Integration +```dart +// In CommandBus +Future dispatch(Command command) { + return container.make() + .through([ + TransactionPipe(), + ValidationPipe(), + AuthorizationPipe() + ]) + .process(command); +} + +// Usage +class CreateOrder implements Command { + @override + Type get handler => CreateOrderHandler; +} + +var order = await bus.dispatch( + CreateOrder(items: items) +); +``` + +### 3. Queue Integration +```dart +// In QueueWorker +Future process(Job job) { + return container.make() + .withRateLimit(3, Duration(minutes: 1)) + .withoutOverlapping() + .process(job); +} + +// Usage +class ProcessPayment implements Job { + @override + Future handle() async { + // Process payment + } +} + +await queue.push(ProcessPayment( + orderId: order.id +)); +``` + +## Testing + +```dart +void main() { + group('Middleware Pipeline', () { + test('processes route middleware', () async { + var pipeline = MiddlewarePipeline(container, router); + var route = Route('/test', middleware: ['auth']); + + var response = await pipeline + .throughRoute(route) + .process(request, handler); + + verify(() => auth.handle(any, any)).called(1); + }); + }); + + group('Bus Pipeline', () { + test('resolves and executes handler', () async { + var pipeline = BusPipeline(container, bus); + var command = CreateOrder(items: items); + + var result = await pipeline.process(command); + + expect(result, isA()); + verify(() => handler.handle(command)).called(1); + }); + }); +} +``` + +## Next Steps + +1. Add more middleware types +2. Enhance bus pipeline features +3. Add job pipeline features +4. Improve testing coverage +5. Add performance optimizations + +Would you like me to enhance any other package specifications? + +## Development Guidelines + +### 1. Getting Started +Before implementing pipeline features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Understand [Contracts Package Specification](contracts_package_specification.md) + +### 2. Implementation Process +For each pipeline feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Implement required contracts (see [Contracts Package Specification](contracts_package_specification.md)) + +### 4. Integration Considerations +When implementing pipelines: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) +5. Implement all contracts from [Contracts Package Specification](contracts_package_specification.md) + +### 5. Performance Guidelines +Pipeline system must: +1. Handle nested pipelines efficiently +2. Minimize memory usage in long pipelines +3. Support async operations +4. Scale with number of stages +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Pipeline tests must: +1. Cover all pipeline types +2. Test stage ordering +3. Verify error handling +4. Check conditional execution +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Pipeline documentation must: +1. Explain pipeline patterns +2. Show integration examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/process_gap_analysis.md b/docs/process_gap_analysis.md new file mode 100644 index 0000000..d474129 --- /dev/null +++ b/docs/process_gap_analysis.md @@ -0,0 +1,299 @@ +# Process Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Process package's actual implementation and Laravel's process functionality, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Process Package Specification](process_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Events Package Specification](events_package_specification.md) for process events +> - See [Queue Package Specification](queue_package_specification.md) for background processing + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Process Pipelines +class ProcessPipeline { + // Need to implement: + Future pipe(String command); + Future pipeThrough(List commands); + Future pipeInput(String input); + Future pipeOutput(String file); + Future pipeErrorOutput(String file); +} + +// 2. Process Scheduling +class ProcessScheduler { + // Need to implement: + void schedule(String command, String frequency); + void daily(String command, [String time = '00:00']); + void weekly(String command, [int day = 0]); + void monthly(String command, [int day = 1]); + void cron(String expression, String command); +} + +// 3. Process Monitoring +class ProcessMonitor { + // Need to implement: + Future isRunning(int pid); + Future getStats(int pid); + Future onExit(int pid, Function callback); + Future onOutput(int pid, Function callback); + Future onError(int pid, Function callback); +} +``` + +### 2. Missing Process Features +```dart +// Need to implement: + +// 1. Process Groups +class ProcessGroup { + // Need to implement: + Future start(); + Future stop(); + Future restart(); + Future> wait(); + Future signal(ProcessSignal signal); + bool isRunning(); +} + +// 2. Process Isolation +class ProcessIsolation { + // Need to implement: + void setUser(String user); + void setGroup(String group); + void setWorkingDirectory(String directory); + void setEnvironment(Map env); + void setResourceLimits(ResourceLimits limits); +} + +// 3. Process Recovery +class ProcessRecovery { + // Need to implement: + void onCrash(Function callback); + void onHang(Function callback); + void onHighMemory(Function callback); + void onHighCpu(Function callback); + void restart(); +} +``` + +### 3. Missing Integration Features +```dart +// Need to implement: + +// 1. Queue Integration +class QueuedProcess { + // Need to implement: + Future queue(String command); + Future laterOn(String queue, Duration delay, String command); + Future chain(List commands); + Future release(Duration delay); +} + +// 2. Event Integration +class ProcessEvents { + // Need to implement: + void beforeStart(Function callback); + void afterStart(Function callback); + void beforeStop(Function callback); + void afterStop(Function callback); + void onOutput(Function callback); + void onError(Function callback); +} + +// 3. Logging Integration +class ProcessLogging { + // Need to implement: + void enableLogging(); + void setLogFile(String path); + void setLogLevel(LogLevel level); + void rotateLog(); + void purgeOldLogs(Duration age); +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation +```dart +// Need to document: + +/// Pipes process output. +/// +/// Example: +/// ```dart +/// await process +/// .pipe('sort') +/// .pipe('uniq') +/// .pipeOutput('output.txt'); +/// ``` +Future pipe(String command); + +/// Schedules process execution. +/// +/// Example: +/// ```dart +/// scheduler.daily('backup.sh', '02:00'); +/// scheduler.weekly('cleanup.sh', DateTime.sunday); +/// scheduler.cron('0 * * * *', 'hourly.sh'); +/// ``` +void schedule(String command, String frequency); +``` + +### 2. Missing Integration Examples +```dart +// Need examples for: + +// 1. Process Groups +var group = ProcessGroup(); +group.add('web-server', '--port=8080'); +group.add('worker', '--queue=default'); +await group.start(); + +// 2. Process Recovery +var recovery = ProcessRecovery(process); +recovery.onCrash(() async { + await notifyAdmin('Process crashed'); + await process.restart(); +}); + +// 3. Process Monitoring +var monitor = ProcessMonitor(process); +monitor.onHighMemory((usage) async { + await process.restart(); + await notifyAdmin('High memory usage: $usage'); +}); +``` + +### 3. Missing Test Coverage +```dart +// Need tests for: + +void main() { + group('Process Pipelines', () { + test('pipes process output', () async { + var process = await manager.start('ls'); + var result = await process + .pipe('sort') + .pipe('uniq') + .pipeOutput('output.txt'); + + expect(result.exitCode, equals(0)); + expect(File('output.txt').existsSync(), isTrue); + }); + }); + + group('Process Scheduling', () { + test('schedules daily tasks', () async { + var scheduler = ProcessScheduler(); + scheduler.daily('backup.sh', '02:00'); + + var nextRun = scheduler.getNextRun('backup.sh'); + expect(nextRun.hour, equals(2)); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Process pipelines (Laravel compatibility) + - Process scheduling (Laravel compatibility) + - Process monitoring + +2. **Medium Priority** + - Process groups + - Process isolation + - Process recovery + +3. **Low Priority** + - Additional integration features + - Additional monitoring features + - Performance optimizations + +## Next Steps + +1. **Implementation Tasks** + - Add process pipelines + - Add process scheduling + - Add process monitoring + - Add process groups + +2. **Documentation Tasks** + - Document pipelines + - Document scheduling + - Document monitoring + - Add integration examples + +3. **Testing Tasks** + - Add pipeline tests + - Add scheduling tests + - Add monitoring tests + - Add group tests + +## Development Guidelines + +### 1. Getting Started +Before implementing process features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Process Package Specification](process_package_specification.md) +6. Review [Events Package Specification](events_package_specification.md) +7. Review [Queue Package Specification](queue_package_specification.md) + +### 2. Implementation Process +For each process feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Process Package Specification](process_package_specification.md) + +### 4. Integration Considerations +When implementing process features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Process system must: +1. Handle concurrent processes efficiently +2. Manage system resources +3. Support process pooling +4. Scale with process count +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Process tests must: +1. Cover all process operations +2. Test concurrent execution +3. Verify event handling +4. Check resource cleanup +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Process documentation must: +1. Explain process patterns +2. Show pipeline examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/process_package_specification.md b/docs/process_package_specification.md new file mode 100644 index 0000000..bf3c2f3 --- /dev/null +++ b/docs/process_package_specification.md @@ -0,0 +1,408 @@ +# Process Package Specification + +## Overview + +The Process package provides a robust system process handling system that matches Laravel's process functionality. It supports process execution, input/output handling, process pools, and signal handling while integrating with our Event and Queue packages. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Events Package Specification](events_package_specification.md) for process events +> - See [Queue Package Specification](queue_package_specification.md) for background processing + +## Core Features + +### 1. Process Manager + +```dart +/// Core process manager implementation +class ProcessManager implements ProcessContract { + /// Container instance + final Container _container; + + /// Active processes + final Map _processes = {}; + + /// Process event dispatcher + final EventDispatcherContract _events; + + ProcessManager(this._container, this._events); + + /// Starts a process + Future start( + String command, [ + List? arguments, + ProcessOptions? options + ]) async { + options ??= ProcessOptions(); + + var process = await Process.start( + command, + arguments ?? [], + workingDirectory: options.workingDirectory, + environment: options.environment, + includeParentEnvironment: options.includeParentEnvironment, + runInShell: options.runInShell + ); + + _processes[process.pid] = process; + await _events.dispatch(ProcessStarted(process)); + + return process; + } + + /// Runs a process to completion + Future run( + String command, [ + List? arguments, + ProcessOptions? options + ]) async { + var process = await start(command, arguments, options); + var result = await process.exitCode; + + await _events.dispatch(ProcessCompleted( + process, + result + )); + + return ProcessResult( + process.pid, + result, + await _readOutput(process.stdout), + await _readOutput(process.stderr) + ); + } + + /// Kills a process + Future kill(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) async { + var process = _processes[pid]; + if (process == null) return; + + process.kill(signal); + await _events.dispatch(ProcessKilled(process)); + _processes.remove(pid); + } + + /// Gets active processes + List get activeProcesses => List.from(_processes.values); + + /// Reads process output + Future _readOutput(Stream> stream) async { + var buffer = StringBuffer(); + await for (var data in stream) { + buffer.write(String.fromCharCodes(data)); + } + return buffer.toString(); + } +} +``` + +### 2. Process Pool + +```dart +/// Process pool for parallel execution +class ProcessPool { + /// Maximum concurrent processes + final int concurrency; + + /// Process manager + final ProcessManager _manager; + + /// Active processes + final Set _active = {}; + + /// Pending commands + final Queue _pending = Queue(); + + ProcessPool(this._manager, {this.concurrency = 5}); + + /// Starts a process in the pool + Future start( + String command, [ + List? arguments, + ProcessOptions? options + ]) async { + var pending = PendingCommand( + command, + arguments, + options + ); + + _pending.add(pending); + await _processQueue(); + + return await pending.future; + } + + /// Processes pending commands + Future _processQueue() async { + while (_active.length < concurrency && _pending.isNotEmpty) { + var command = _pending.removeFirst(); + await _startProcess(command); + } + } + + /// Starts a process + Future _startProcess(PendingCommand command) async { + var process = await _manager.start( + command.command, + command.arguments, + command.options + ); + + _active.add(process); + + process.exitCode.then((result) { + _active.remove(process); + command.complete(ProcessResult( + process.pid, + result, + '', + '' + )); + _processQueue(); + }); + } +} +``` + +### 3. Process Events + +```dart +/// Process started event +class ProcessStarted { + /// The started process + final Process process; + + ProcessStarted(this.process); +} + +/// Process completed event +class ProcessCompleted { + /// The completed process + final Process process; + + /// Exit code + final int exitCode; + + ProcessCompleted(this.process, this.exitCode); +} + +/// Process killed event +class ProcessKilled { + /// The killed process + final Process process; + + ProcessKilled(this.process); +} + +/// Process failed event +class ProcessFailed { + /// The failed process + final Process process; + + /// Error details + final Object error; + + ProcessFailed(this.process, this.error); +} +``` + +### 4. Process Options + +```dart +/// Process execution options +class ProcessOptions { + /// Working directory + final String? workingDirectory; + + /// Environment variables + final Map? environment; + + /// Include parent environment + final bool includeParentEnvironment; + + /// Run in shell + final bool runInShell; + + /// Process timeout + final Duration? timeout; + + /// Idle timeout + final Duration? idleTimeout; + + /// Retry attempts + final int retryAttempts; + + /// Retry delay + final Duration retryDelay; + + ProcessOptions({ + this.workingDirectory, + this.environment, + this.includeParentEnvironment = true, + this.runInShell = false, + this.timeout, + this.idleTimeout, + this.retryAttempts = 0, + this.retryDelay = const Duration(seconds: 1) + }); +} +``` + +## Integration Examples + +### 1. Basic Process Execution +```dart +// Run process +var result = await processManager.run('ls', ['-la']); +print('Output: ${result.stdout}'); +print('Exit code: ${result.exitCode}'); + +// Start long-running process +var process = await processManager.start('server', ['--port=8080']); +await process.exitCode; // Wait for completion +``` + +### 2. Process Pool +```dart +// Create process pool +var pool = ProcessPool(processManager, concurrency: 3); + +// Run multiple processes +await Future.wait([ + pool.start('task1'), + pool.start('task2'), + pool.start('task3'), + pool.start('task4') // Queued until slot available +]); +``` + +### 3. Process Events +```dart +// Listen for process events +events.listen((event) { + print('Process ${event.process.pid} started'); +}); + +events.listen((event) { + print('Process ${event.process.pid} completed with code ${event.exitCode}'); +}); + +// Start process +await processManager.start('long-task'); +``` + +## Testing + +```dart +void main() { + group('Process Manager', () { + test('runs processes', () async { + var manager = ProcessManager(container, events); + + var result = await manager.run('echo', ['Hello']); + + expect(result.exitCode, equals(0)); + expect(result.stdout, contains('Hello')); + }); + + test('handles process failure', () async { + var manager = ProcessManager(container, events); + + expect( + () => manager.run('invalid-command'), + throwsA(isA()) + ); + }); + }); + + group('Process Pool', () { + test('limits concurrent processes', () async { + var pool = ProcessPool(manager, concurrency: 2); + var started = []; + + events.listen((event) { + started.add(event.process.pid.toString()); + }); + + await Future.wait([ + pool.start('task1'), + pool.start('task2'), + pool.start('task3') + ]); + + expect(started.length, equals(3)); + expect(started.take(2).length, equals(2)); + }); + }); +} +``` + +## Next Steps + +1. Implement core process features +2. Add process pool +3. Add process events +4. Add retry handling +5. Write tests +6. Add benchmarks + +## Development Guidelines + +### 1. Getting Started +Before implementing process features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Events Package Specification](events_package_specification.md) +6. Review [Queue Package Specification](queue_package_specification.md) + +### 2. Implementation Process +For each process feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Support event integration (see [Events Package Specification](events_package_specification.md)) +5. Support queue integration (see [Queue Package Specification](queue_package_specification.md)) + +### 4. Integration Considerations +When implementing process features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Process system must: +1. Handle concurrent processes efficiently +2. Manage system resources +3. Support process pooling +4. Scale with process count +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Process tests must: +1. Cover all process operations +2. Test concurrent execution +3. Verify event handling +4. Check resource cleanup +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Process documentation must: +1. Explain process patterns +2. Show pool examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/queue_gap_analysis.md b/docs/queue_gap_analysis.md new file mode 100644 index 0000000..cc47d5f --- /dev/null +++ b/docs/queue_gap_analysis.md @@ -0,0 +1,301 @@ +# Queue Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Queue package's actual implementation and Laravel's queue functionality, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Queue Package Specification](queue_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Events Package Specification](events_package_specification.md) for event integration +> - See [Bus Package Specification](bus_package_specification.md) for command bus integration + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Job Middleware +class JobMiddleware { + // Need to implement: + Future handle(Job job, Function next); + Future withoutOverlapping(Job job, Function next); + Future rateLimit(Job job, Function next, int maxAttempts); + Future throttle(Job job, Function next, Duration duration); +} + +// 2. Job Events +class JobEvents { + // Need to implement: + void beforeJob(Job job); + void afterJob(Job job); + void failingJob(Job job, Exception exception); + void failedJob(Job job, Exception exception); + void retryingJob(Job job); + void retriedJob(Job job); +} + +// 3. Job Chaining +class JobChain { + // Need to implement: + void chain(List jobs); + void onConnection(String connection); + void onQueue(String queue); + void catch(Function(Exception) handler); + void finally(Function handler); +} +``` + +### 2. Missing Queue Features +```dart +// Need to implement: + +// 1. Queue Monitoring +class QueueMonitor { + // Need to implement: + Future> queueSizes(); + Future>> failedJobs(); + Future retryFailedJob(String id); + Future forgetFailedJob(String id); + Future pruneFailedJobs([Duration? older]); +} + +// 2. Queue Rate Limiting +class QueueRateLimiter { + // Need to implement: + Future tooManyAttempts(String key, int maxAttempts); + Future hit(String key, Duration decay); + Future clear(String key); + Future attempts(String key); + Future remaining(String key, int maxAttempts); +} + +// 3. Queue Batching +class QueueBatch { + // Need to implement: + Future then(Function handler); + Future catch(Function(Exception) handler); + Future finally(Function handler); + Future allowFailures(); + Future onConnection(String connection); + Future onQueue(String queue); +} +``` + +### 3. Missing Worker Features +```dart +// Need to implement: + +// 1. Worker Management +class WorkerManager { + // Need to implement: + Future scale(int processes); + Future pause(); + Future resume(); + Future restart(); + Future> status(); +} + +// 2. Worker Events +class WorkerEvents { + // Need to implement: + void workerStarting(); + void workerStopping(); + void workerStopped(); + void queueEmpty(String queue); + void looping(); +} + +// 3. Worker Options +class WorkerOptions { + // Need to implement: + Duration sleep; + Duration timeout; + int maxTries; + int maxJobs; + bool force; + bool stopWhenEmpty; + bool rest; +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation +```dart +// Need to document: + +/// Handles job middleware. +/// +/// Example: +/// ```dart +/// class RateLimitedJob extends Job with JobMiddleware { +/// @override +/// Future middleware(Function next) async { +/// return await rateLimit(5, Duration(minutes: 1), next); +/// } +/// } +/// ``` +Future middleware(Function next); + +/// Handles job events. +/// +/// Example: +/// ```dart +/// queue.beforeJob((job) { +/// print('Processing ${job.id}'); +/// }); +/// ``` +void beforeJob(Function(Job) callback); +``` + +### 2. Missing Integration Examples +```dart +// Need examples for: + +// 1. Job Chaining +var chain = queue.chain([ + ProcessPodcast(podcast), + OptimizeAudio(podcast), + NotifySubscribers(podcast) +]) +.onQueue('podcasts') +.catch((e) => handleError(e)) +.finally(() => cleanup()); + +// 2. Queue Monitoring +var monitor = QueueMonitor(queue); +var sizes = await monitor.queueSizes(); +print('Default queue size: ${sizes["default"]}'); + +// 3. Worker Management +var manager = WorkerManager(queue); +await manager.scale(4); // Scale to 4 processes +var status = await manager.status(); +print('Active workers: ${status.length}'); +``` + +### 3. Missing Test Coverage +```dart +// Need tests for: + +void main() { + group('Job Middleware', () { + test('applies rate limiting', () async { + var job = RateLimitedJob(); + var limiter = MockRateLimiter(); + + await job.handle(); + + verify(() => limiter.tooManyAttempts(any, any)).called(1); + }); + }); + + group('Queue Monitoring', () { + test('monitors queue sizes', () async { + var monitor = QueueMonitor(queue); + var sizes = await monitor.queueSizes(); + + expect(sizes, containsPair('default', greaterThan(0))); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Job middleware (Laravel compatibility) + - Job events (Laravel compatibility) + - Queue monitoring + +2. **Medium Priority** + - Job chaining + - Queue rate limiting + - Worker management + +3. **Low Priority** + - Additional worker features + - Additional monitoring features + - Performance optimizations + +## Next Steps + +1. **Implementation Tasks** + - Add job middleware + - Add job events + - Add queue monitoring + - Add worker management + +2. **Documentation Tasks** + - Document job middleware + - Document job events + - Document monitoring + - Add integration examples + +3. **Testing Tasks** + - Add middleware tests + - Add event tests + - Add monitoring tests + - Add worker tests + +## Development Guidelines + +### 1. Getting Started +Before implementing queue features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Queue Package Specification](queue_package_specification.md) +6. Review [Events Package Specification](events_package_specification.md) +7. Review [Bus Package Specification](bus_package_specification.md) + +### 2. Implementation Process +For each queue feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Queue Package Specification](queue_package_specification.md) + +### 4. Integration Considerations +When implementing queue features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Queue system must: +1. Handle high job throughput +2. Process chains efficiently +3. Support concurrent workers +4. Scale horizontally +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Queue tests must: +1. Cover all queue operations +2. Test middleware behavior +3. Verify event handling +4. Check worker management +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Queue documentation must: +1. Explain queue patterns +2. Show middleware examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/queue_package_specification.md b/docs/queue_package_specification.md new file mode 100644 index 0000000..1e32454 --- /dev/null +++ b/docs/queue_package_specification.md @@ -0,0 +1,623 @@ +# Queue Package Specification + +## Overview + +The Queue package provides a robust job queueing system that matches Laravel's queue functionality. It supports multiple queue drivers, job retries, rate limiting, and job batching while integrating with our Event and Bus packages. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Events Package Specification](events_package_specification.md) for event integration +> - See [Bus Package Specification](bus_package_specification.md) for command bus integration + +## Core Features + +### 1. Queue Manager + +```dart +/// Core queue manager implementation +class QueueManager implements QueueContract { + /// Available queue connections + final Map _connections = {}; + + /// Default connection name + final String _defaultConnection; + + /// Configuration repository + final ConfigContract _config; + + QueueManager(this._config) + : _defaultConnection = _config.get('queue.default', 'sync'); + + @override + Future push(dynamic job, [String? queue]) async { + return await connection().push(job, queue); + } + + @override + Future later(Duration delay, dynamic job, [String? queue]) async { + return await connection().later(delay, job, queue); + } + + @override + Future pop([String? queue]) async { + return await connection().pop(queue); + } + + @override + QueueConnection connection([String? name]) { + name ??= _defaultConnection; + + return _connections.putIfAbsent(name, () { + var config = _getConfig(name!); + return _createConnection(config); + }); + } + + /// Creates a queue connection + QueueConnection _createConnection(Map config) { + switch (config['driver']) { + case 'sync': + return SyncConnection(config); + case 'database': + return DatabaseConnection(config); + case 'redis': + return RedisConnection(config); + case 'sqs': + return SqsConnection(config); + default: + throw UnsupportedError( + 'Unsupported queue driver: ${config["driver"]}' + ); + } + } + + /// Gets connection config + Map _getConfig(String name) { + var config = _config.get('queue.connections.$name'); + if (config == null) { + throw ArgumentError('Queue connection [$name] not configured.'); + } + return config; + } +} +``` + +### 2. Queue Connections + +```dart +/// Database queue connection +class DatabaseConnection implements QueueConnection { + /// Database connection + final DatabaseConnection _db; + + /// Table name + final String _table; + + DatabaseConnection(Map config) + : _db = DatabaseManager.connection(config['connection']), + _table = config['table'] ?? 'jobs'; + + @override + Future push(dynamic job, [String? queue]) async { + queue ??= 'default'; + var id = Uuid().v4(); + + await _db.table(_table).insert({ + 'id': id, + 'queue': queue, + 'payload': _serialize(job), + 'attempts': 0, + 'reserved_at': null, + 'available_at': DateTime.now(), + 'created_at': DateTime.now() + }); + + return id; + } + + @override + Future later(Duration delay, dynamic job, [String? queue]) async { + queue ??= 'default'; + var id = Uuid().v4(); + + await _db.table(_table).insert({ + 'id': id, + 'queue': queue, + 'payload': _serialize(job), + 'attempts': 0, + 'reserved_at': null, + 'available_at': DateTime.now().add(delay), + 'created_at': DateTime.now() + }); + + return id; + } + + @override + Future pop([String? queue]) async { + queue ??= 'default'; + + var job = await _db.transaction((tx) async { + var job = await tx.table(_table) + .where('queue', queue) + .whereNull('reserved_at') + .where('available_at', '<=', DateTime.now()) + .orderBy('id') + .first(); + + if (job != null) { + await tx.table(_table) + .where('id', job['id']) + .update({ + 'reserved_at': DateTime.now(), + 'attempts': job['attempts'] + 1 + }); + } + + return job; + }); + + if (job == null) return null; + + return DatabaseJob( + connection: this, + queue: queue, + job: job + ); + } + + /// Serializes job payload + String _serialize(dynamic job) { + return jsonEncode({ + 'type': job.runtimeType.toString(), + 'data': job.toMap() + }); + } +} + +/// Redis queue connection +class RedisConnection implements QueueConnection { + /// Redis client + final RedisClient _redis; + + /// Key prefix + final String _prefix; + + RedisConnection(Map config) + : _redis = RedisClient( + host: config['host'], + port: config['port'], + db: config['database'] + ), + _prefix = config['prefix'] ?? 'queues'; + + @override + Future push(dynamic job, [String? queue]) async { + queue ??= 'default'; + var id = Uuid().v4(); + + await _redis.rpush( + _getKey(queue), + _serialize(id, job) + ); + + return id; + } + + @override + Future later(Duration delay, dynamic job, [String? queue]) async { + queue ??= 'default'; + var id = Uuid().v4(); + + await _redis.zadd( + _getDelayedKey(queue), + DateTime.now().add(delay).millisecondsSinceEpoch.toDouble(), + _serialize(id, job) + ); + + return id; + } + + @override + Future pop([String? queue]) async { + queue ??= 'default'; + + // Move delayed jobs + var now = DateTime.now().millisecondsSinceEpoch; + var jobs = await _redis.zrangebyscore( + _getDelayedKey(queue), + '-inf', + now.toString() + ); + + for (var job in jobs) { + await _redis.rpush(_getKey(queue), job); + await _redis.zrem(_getDelayedKey(queue), job); + } + + // Get next job + var payload = await _redis.lpop(_getKey(queue)); + if (payload == null) return null; + + return RedisJob( + connection: this, + queue: queue, + payload: payload + ); + } + + /// Gets queue key + String _getKey(String queue) => '$_prefix:$queue'; + + /// Gets delayed queue key + String _getDelayedKey(String queue) => '$_prefix:$queue:delayed'; + + /// Serializes job payload + String _serialize(String id, dynamic job) { + return jsonEncode({ + 'id': id, + 'type': job.runtimeType.toString(), + 'data': job.toMap(), + 'attempts': 0 + }); + } +} +``` + +### 3. Queue Jobs + +```dart +/// Core job interface +abstract class Job { + /// Job ID + String get id; + + /// Job queue + String get queue; + + /// Number of attempts + int get attempts; + + /// Maximum tries + int get maxTries => 3; + + /// Timeout in seconds + int get timeout => 60; + + /// Executes the job + Future handle(); + + /// Releases the job back onto queue + Future release([Duration? delay]); + + /// Deletes the job + Future delete(); + + /// Fails the job + Future fail([Exception? exception]); +} + +/// Database job implementation +class DatabaseJob implements Job { + /// Database connection + final DatabaseConnection _connection; + + /// Job data + final Map _data; + + /// Job queue + @override + final String queue; + + DatabaseJob({ + required DatabaseConnection connection, + required String queue, + required Map job + }) : _connection = connection, + _data = job, + queue = queue; + + @override + String get id => _data['id']; + + @override + int get attempts => _data['attempts']; + + @override + Future handle() async { + var payload = jsonDecode(_data['payload']); + var job = _deserialize(payload); + await job.handle(); + } + + @override + Future release([Duration? delay]) async { + await _connection._db.table(_connection._table) + .where('id', id) + .update({ + 'reserved_at': null, + 'available_at': delay != null + ? DateTime.now().add(delay) + : DateTime.now() + }); + } + + @override + Future delete() async { + await _connection._db.table(_connection._table) + .where('id', id) + .delete(); + } + + @override + Future fail([Exception? exception]) async { + await _connection._db.table(_connection._table) + .where('id', id) + .update({ + 'failed_at': DateTime.now() + }); + + if (exception != null) { + await _connection._db.table('failed_jobs').insert({ + 'id': Uuid().v4(), + 'connection': _connection.name, + 'queue': queue, + 'payload': _data['payload'], + 'exception': exception.toString(), + 'failed_at': DateTime.now() + }); + } + } + + /// Deserializes job payload + dynamic _deserialize(Map payload) { + var type = payload['type']; + var data = payload['data']; + + return _connection._container.make(type) + ..fromMap(data); + } +} +``` + +### 4. Job Batching + +```dart +/// Job batch +class Batch { + /// Batch ID + final String id; + + /// Queue connection + final QueueConnection _connection; + + /// Jobs in batch + final List _jobs; + + /// Options + final BatchOptions _options; + + Batch(this.id, this._connection, this._jobs, this._options); + + /// Gets total jobs + int get totalJobs => _jobs.length; + + /// Gets pending jobs + Future get pendingJobs async { + return await _connection.table('job_batches') + .where('id', id) + .value('pending_jobs'); + } + + /// Gets failed jobs + Future get failedJobs async { + return await _connection.table('job_batches') + .where('id', id) + .value('failed_jobs'); + } + + /// Adds jobs to batch + Future add(List jobs) async { + _jobs.addAll(jobs); + + await _connection.table('job_batches') + .where('id', id) + .increment('total_jobs', jobs.length) + .increment('pending_jobs', jobs.length); + + for (var job in jobs) { + await _connection.push(job); + } + } + + /// Cancels the batch + Future cancel() async { + await _connection.table('job_batches') + .where('id', id) + .update({ + 'cancelled_at': DateTime.now() + }); + } + + /// Deletes the batch + Future delete() async { + await _connection.table('job_batches') + .where('id', id) + .delete(); + } +} +``` + +## Integration Examples + +### 1. Basic Queue Usage +```dart +// Define job +class ProcessPodcast implements Job { + final Podcast podcast; + + @override + Future handle() async { + await podcast.process(); + } +} + +// Push job to queue +await queue.push(ProcessPodcast(podcast)); + +// Push delayed job +await queue.later( + Duration(minutes: 10), + ProcessPodcast(podcast) +); +``` + +### 2. Job Batching +```dart +// Create batch +var batch = await queue.batch([ + ProcessPodcast(podcast1), + ProcessPodcast(podcast2), + ProcessPodcast(podcast3) +]) +.allowFailures() +.dispatch(); + +// Add more jobs +await batch.add([ + ProcessPodcast(podcast4), + ProcessPodcast(podcast5) +]); + +// Check progress +print('Pending: ${await batch.pendingJobs}'); +print('Failed: ${await batch.failedJobs}'); +``` + +### 3. Queue Worker +```dart +// Start worker +var worker = QueueWorker(connection) + ..onJob((job) async { + print('Processing job ${job.id}'); + }) + ..onException((job, exception) async { + print('Job ${job.id} failed: $exception'); + }); + +await worker.daemon([ + 'default', + 'emails', + 'podcasts' +]); +``` + +## Testing + +```dart +void main() { + group('Queue Manager', () { + test('pushes jobs to queue', () async { + var queue = QueueManager(config); + var job = ProcessPodcast(podcast); + + var id = await queue.push(job); + + expect(id, isNotEmpty); + verify(() => connection.push(job, null)).called(1); + }); + + test('handles delayed jobs', () async { + var queue = QueueManager(config); + var job = ProcessPodcast(podcast); + var delay = Duration(minutes: 5); + + await queue.later(delay, job); + + verify(() => connection.later(delay, job, null)).called(1); + }); + }); + + group('Job Batching', () { + test('processes job batches', () async { + var batch = await queue.batch([ + ProcessPodcast(podcast1), + ProcessPodcast(podcast2) + ]).dispatch(); + + expect(batch.totalJobs, equals(2)); + expect(await batch.pendingJobs, equals(2)); + expect(await batch.failedJobs, equals(0)); + }); + }); +} +``` + +## Next Steps + +1. Implement core queue features +2. Add queue connections +3. Add job batching +4. Add queue worker +5. Write tests +6. Add benchmarks + +## Development Guidelines + +### 1. Getting Started +Before implementing queue features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Events Package Specification](events_package_specification.md) +6. Review [Bus Package Specification](bus_package_specification.md) + +### 2. Implementation Process +For each queue feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Support event integration (see [Events Package Specification](events_package_specification.md)) +5. Support bus integration (see [Bus Package Specification](bus_package_specification.md)) + +### 4. Integration Considerations +When implementing queue features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Queue system must: +1. Handle high job throughput +2. Process batches efficiently +3. Support concurrent workers +4. Scale horizontally +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Queue tests must: +1. Cover all queue operations +2. Test job processing +3. Verify batching +4. Check worker behavior +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Queue documentation must: +1. Explain queue patterns +2. Show job examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/route_gap_analysis.md b/docs/route_gap_analysis.md new file mode 100644 index 0000000..090048e --- /dev/null +++ b/docs/route_gap_analysis.md @@ -0,0 +1,295 @@ +# Route Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Route package's actual implementation and Laravel's routing functionality, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Route Package Specification](route_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Pipeline Package Specification](pipeline_package_specification.md) for middleware pipeline +> - See [Container Package Specification](container_package_specification.md) for dependency injection + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Route Model Binding +class RouteModelBinding { + // Need to implement: + void bind(String key, Type type); + void bindWhere(String key, Type type, Function where); + void bindCallback(String key, Function callback); + void scopeBindings(); +} + +// 2. Route Caching +class RouteCache { + // Need to implement: + Future cache(); + Future clear(); + bool isEnabled(); + Future reload(); + Future compile(); +} + +// 3. Route Fallbacks +class RouteFallback { + // Need to implement: + void fallback(dynamic action); + void missing(Function callback); + void methodNotAllowed(Function callback); + void notFound(Function callback); +} +``` + +### 2. Missing Route Features +```dart +// Need to implement: + +// 1. Route Constraints +class RouteConstraints { + // Need to implement: + void pattern(String name, String pattern); + void patterns(Map patterns); + bool matches(String name, String value); + void whereNumber(List parameters); + void whereAlpha(List parameters); + void whereAlphaNumeric(List parameters); + void whereUuid(List parameters); +} + +// 2. Route Substitutions +class RouteSubstitution { + // Need to implement: + void substitute(String key, dynamic value); + void substituteBindings(Map bindings); + void substituteImplicit(Map bindings); + String resolveBinding(String key); +} + +// 3. Route Rate Limiting +class RouteRateLimiting { + // Need to implement: + void throttle(String name, int maxAttempts, Duration decay); + void rateLimit(String name, int maxAttempts, Duration decay); + void forUser(String name, int maxAttempts, Duration decay); + void exempt(List routes); +} +``` + +### 3. Missing Group Features +```dart +// Need to implement: + +// 1. Group Attributes +class RouteGroupAttributes { + // Need to implement: + void controller(Type controller); + void namespace(String namespace); + void name(String name); + void domain(String domain); + void where(Map patterns); +} + +// 2. Group Middleware +class RouteGroupMiddleware { + // Need to implement: + void aliasMiddleware(String name, Type middleware); + void middlewarePriority(List middleware); + void pushMiddlewareToGroup(String group, String middleware); + List getMiddlewareGroups(); +} + +// 3. Group Resources +class RouteGroupResources { + // Need to implement: + void resources(Map resources); + void apiResources(Map resources); + void singleton(String name, Type controller); + void apiSingleton(String name, Type controller); +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation +```dart +// Need to document: + +/// Binds route model. +/// +/// Example: +/// ```dart +/// router.bind('user', User, (value) async { +/// return await User.find(value); +/// }); +/// ``` +void bind(String key, Type type, [Function? callback]); + +/// Defines route pattern. +/// +/// Example: +/// ```dart +/// router.pattern('id', '[0-9]+'); +/// router.get('users/{id}', UsersController) +/// .where('id', '[0-9]+'); +/// ``` +void pattern(String name, String pattern); +``` + +### 2. Missing Integration Examples +```dart +// Need examples for: + +// 1. Route Model Binding +router.bind('user', User); + +router.get('users/{user}', (User user) { + return user; // Auto-resolved from ID +}); + +// 2. Route Rate Limiting +router.middleware(['throttle:60,1']) + .group(() { + router.get('api/users', UsersController); + }); + +// 3. Route Resources +router.resources({ + 'photos': PhotoController, + 'posts': PostController +}); +``` + +### 3. Missing Test Coverage +```dart +// Need tests for: + +void main() { + group('Route Model Binding', () { + test('resolves bound models', () async { + router.bind('user', User); + + var response = await router.dispatch( + Request('GET', '/users/1') + ); + + expect(response.data, isA()); + expect(response.data.id, equals('1')); + }); + }); + + group('Route Caching', () { + test('caches compiled routes', () async { + await router.cache(); + + var route = router.match( + Request('GET', '/users/1') + ); + + expect(route, isNotNull); + expect(route!.compiled, isTrue); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Route model binding (Laravel compatibility) + - Route caching (Laravel compatibility) + - Route constraints + +2. **Medium Priority** + - Route substitutions + - Route rate limiting + - Group resources + +3. **Low Priority** + - Route fallbacks + - Additional constraints + - Performance optimizations + +## Next Steps + +1. **Implementation Tasks** + - Add route model binding + - Add route caching + - Add route constraints + - Add group resources + +2. **Documentation Tasks** + - Document model binding + - Document caching + - Document constraints + - Add integration examples + +3. **Testing Tasks** + - Add binding tests + - Add caching tests + - Add constraint tests + - Add resource tests + +## Development Guidelines + +### 1. Getting Started +Before implementing routing features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Route Package Specification](route_package_specification.md) +6. Review [Pipeline Package Specification](pipeline_package_specification.md) +7. Review [Container Package Specification](container_package_specification.md) + +### 2. Implementation Process +For each routing feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Route Package Specification](route_package_specification.md) + +### 4. Integration Considerations +When implementing routing features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Routing system must: +1. Match routes efficiently +2. Handle complex patterns +3. Support caching +4. Scale with route count +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Route tests must: +1. Cover all route types +2. Test pattern matching +3. Verify middleware +4. Check parameter binding +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Route documentation must: +1. Explain routing patterns +2. Show group examples +3. Cover parameter binding +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/route_package_specification.md b/docs/route_package_specification.md new file mode 100644 index 0000000..24db217 --- /dev/null +++ b/docs/route_package_specification.md @@ -0,0 +1,550 @@ +# Route Package Specification + +## Overview + +The Route package provides a robust routing system that matches Laravel's routing functionality. It supports route registration, middleware, parameter binding, and route groups while integrating with our Pipeline and Container packages. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Pipeline Package Specification](pipeline_package_specification.md) for middleware pipeline +> - See [Container Package Specification](container_package_specification.md) for dependency injection + +## Core Features + +### 1. Router + +```dart +/// Core router implementation +class Router implements RouterContract { + /// Container instance + final Container _container; + + /// Route collection + final RouteCollection _routes; + + /// Current route + Route? _current; + + /// Global middleware + final List _middleware = []; + + Router(this._container) + : _routes = RouteCollection(); + + /// Gets current route + Route? get current => _current; + + /// Gets global middleware + List get middleware => List.from(_middleware); + + /// Adds global middleware + void pushMiddleware(dynamic middleware) { + _middleware.add(middleware); + } + + /// Registers GET route + Route get(String uri, dynamic action) { + return addRoute(['GET', 'HEAD'], uri, action); + } + + /// Registers POST route + Route post(String uri, dynamic action) { + return addRoute(['POST'], uri, action); + } + + /// Registers PUT route + Route put(String uri, dynamic action) { + return addRoute(['PUT'], uri, action); + } + + /// Registers DELETE route + Route delete(String uri, dynamic action) { + return addRoute(['DELETE'], uri, action); + } + + /// Registers PATCH route + Route patch(String uri, dynamic action) { + return addRoute(['PATCH'], uri, action); + } + + /// Registers OPTIONS route + Route options(String uri, dynamic action) { + return addRoute(['OPTIONS'], uri, action); + } + + /// Adds route to collection + Route addRoute(List methods, String uri, dynamic action) { + var route = Route(methods, uri, action); + _routes.add(route); + return route; + } + + /// Creates route group + void group(Map attributes, Function callback) { + var group = RouteGroup(attributes); + + _routes.pushGroup(group); + callback(); + _routes.popGroup(); + } + + /// Matches request to route + Route? match(Request request) { + _current = _routes.match(request); + return _current; + } + + /// Dispatches request to route + Future dispatch(Request request) async { + var route = match(request); + if (route == null) { + throw RouteNotFoundException(); + } + + return await _runRoute(route, request); + } + + /// Runs route through middleware + Future _runRoute(Route route, Request request) async { + var pipeline = _container.make(); + + return await pipeline + .send(request) + .through([ + ..._middleware, + ...route.gatherMiddleware() + ]) + .then((request) => route.run(request)); + } +} +``` + +### 2. Route Collection + +```dart +/// Route collection +class RouteCollection { + /// Routes by method + final Map> _routes = {}; + + /// Route groups + final List _groups = []; + + /// Adds route to collection + void add(Route route) { + for (var method in route.methods) { + _routes.putIfAbsent(method, () => []).add(route); + } + + if (_groups.isNotEmpty) { + route.group = _groups.last; + } + } + + /// Pushes route group + void pushGroup(RouteGroup group) { + if (_groups.isNotEmpty) { + group.parent = _groups.last; + } + _groups.add(group); + } + + /// Pops route group + void popGroup() { + _groups.removeLast(); + } + + /// Matches request to route + Route? match(Request request) { + var routes = _routes[request.method] ?? []; + + for (var route in routes) { + if (route.matches(request)) { + return route; + } + } + + return null; + } +} +``` + +### 3. Route + +```dart +/// Route definition +class Route { + /// HTTP methods + final List methods; + + /// URI pattern + final String uri; + + /// Route action + final dynamic action; + + /// Route group + RouteGroup? group; + + /// Route middleware + final List _middleware = []; + + /// Route parameters + final Map _parameters = {}; + + Route(this.methods, this.uri, this.action); + + /// Adds middleware + Route middleware(List middleware) { + _middleware.addAll(middleware); + return this; + } + + /// Gets route name + String? get name => _parameters['as']; + + /// Sets route name + Route name(String name) { + _parameters['as'] = name; + return this; + } + + /// Gets route domain + String? get domain => _parameters['domain']; + + /// Sets route domain + Route domain(String domain) { + _parameters['domain'] = domain; + return this; + } + + /// Gets route prefix + String get prefix { + var prefix = ''; + var group = this.group; + + while (group != null) { + if (group.prefix != null) { + prefix = '${group.prefix}/$prefix'; + } + group = group.parent; + } + + return prefix.isEmpty ? '' : prefix; + } + + /// Gets full URI + String get fullUri => '${prefix.isEmpty ? "" : "$prefix/"}$uri'; + + /// Gathers middleware + List gatherMiddleware() { + var middleware = [..._middleware]; + var group = this.group; + + while (group != null) { + middleware.addAll(group.middleware); + group = group.parent; + } + + return middleware; + } + + /// Matches request + bool matches(Request request) { + return _matchesMethod(request.method) && + _matchesUri(request.uri) && + _matchesDomain(request.host); + } + + /// Matches HTTP method + bool _matchesMethod(String method) { + return methods.contains(method); + } + + /// Matches URI pattern + bool _matchesUri(Uri uri) { + var pattern = RegExp(_compilePattern()); + return pattern.hasMatch(uri.path); + } + + /// Matches domain pattern + bool _matchesDomain(String? host) { + if (domain == null) return true; + if (host == null) return false; + + var pattern = RegExp(_compileDomainPattern()); + return pattern.hasMatch(host); + } + + /// Compiles URI pattern + String _compilePattern() { + return fullUri + .replaceAll('/', '\\/') + .replaceAllMapped( + RegExp(r'{([^}]+)}'), + (match) => '(?<${match[1]}>[^/]+)' + ); + } + + /// Compiles domain pattern + String _compileDomainPattern() { + return domain! + .replaceAll('.', '\\.') + .replaceAllMapped( + RegExp(r'{([^}]+)}'), + (match) => '(?<${match[1]}>[^.]+)' + ); + } + + /// Runs route action + Future run(Request request) async { + var action = _resolveAction(); + var parameters = _resolveParameters(request); + + if (action is Function) { + return await Function.apply(action, parameters); + } + + if (action is Controller) { + return await action.callAction( + action.runtimeType.toString(), + parameters + ); + } + + throw RouteActionNotFoundException(); + } + + /// Resolves route action + dynamic _resolveAction() { + if (action is String) { + var parts = action.split('@'); + var controller = _container.make(parts[0]); + controller.method = parts[1]; + return controller; + } + + return action; + } + + /// Resolves route parameters + List _resolveParameters(Request request) { + var pattern = RegExp(_compilePattern()); + var match = pattern.firstMatch(request.uri.path); + + if (match == null) return []; + + return match.groupNames.map((name) { + return _resolveParameter(name, match.namedGroup(name)!); + }).toList(); + } + + /// Resolves route parameter + dynamic _resolveParameter(String name, String value) { + if (_parameters.containsKey(name)) { + return _parameters[name](value); + } + + return value; + } +} +``` + +### 4. Route Groups + +```dart +/// Route group +class RouteGroup { + /// Group attributes + final Map attributes; + + /// Parent group + RouteGroup? parent; + + RouteGroup(this.attributes); + + /// Gets group prefix + String? get prefix => attributes['prefix']; + + /// Gets group middleware + List get middleware => attributes['middleware'] ?? []; + + /// Gets group domain + String? get domain => attributes['domain']; + + /// Gets group name prefix + String? get namePrefix => attributes['as']; + + /// Gets merged attributes + Map get mergedAttributes { + var merged = Map.from(attributes); + var parent = this.parent; + + while (parent != null) { + for (var entry in parent.attributes.entries) { + if (!merged.containsKey(entry.key)) { + merged[entry.key] = entry.value; + } + } + parent = parent.parent; + } + + return merged; + } +} +``` + +## Integration Examples + +### 1. Basic Routing +```dart +// Register routes +router.get('/', HomeController); +router.post('/users', UsersController); +router.get('/users/{id}', (String id) { + return User.find(id); +}); + +// Match and dispatch +var route = router.match(request); +var response = await router.dispatch(request); +``` + +### 2. Route Groups +```dart +router.group({ + 'prefix': 'api', + 'middleware': ['auth'], + 'namespace': 'Api' +}, () { + router.get('users', UsersController); + router.get('posts', PostsController); + + router.group({ + 'prefix': 'admin', + 'middleware': ['admin'] + }, () { + router.get('stats', StatsController); + }); +}); +``` + +### 3. Route Parameters +```dart +// Required parameters +router.get('users/{id}', (String id) { + return User.find(id); +}); + +// Optional parameters +router.get('posts/{id?}', (String? id) { + return id != null ? Post.find(id) : Post.all(); +}); + +// Regular expression constraints +router.get('users/{id}', UsersController) + .where('id', '[0-9]+'); +``` + +## Testing + +```dart +void main() { + group('Router', () { + test('matches routes', () { + var router = Router(container); + router.get('/users/{id}', UsersController); + + var request = Request('GET', '/users/1'); + var route = router.match(request); + + expect(route, isNotNull); + expect(route!.action, equals(UsersController)); + }); + + test('handles route groups', () { + var router = Router(container); + + router.group({ + 'prefix': 'api', + 'middleware': ['auth'] + }, () { + router.get('users', UsersController); + }); + + var route = router.match(Request('GET', '/api/users')); + expect(route, isNotNull); + expect(route!.gatherMiddleware(), contains('auth')); + }); + }); +} +``` + +## Next Steps + +1. Implement core routing +2. Add route groups +3. Add route parameters +4. Add middleware support +5. Write tests +6. Add benchmarks + +## Development Guidelines + +### 1. Getting Started +Before implementing routing features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Pipeline Package Specification](pipeline_package_specification.md) +6. Review [Container Package Specification](container_package_specification.md) + +### 2. Implementation Process +For each routing feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Support middleware (see [Pipeline Package Specification](pipeline_package_specification.md)) +5. Support dependency injection (see [Container Package Specification](container_package_specification.md)) + +### 4. Integration Considerations +When implementing routing features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Routing system must: +1. Match routes efficiently +2. Handle complex patterns +3. Support caching +4. Scale with route count +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Route tests must: +1. Cover all route types +2. Test pattern matching +3. Verify middleware +4. Check parameter binding +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Route documentation must: +1. Explain routing patterns +2. Show group examples +3. Cover parameter binding +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/support_package_specification.md b/docs/support_package_specification.md new file mode 100644 index 0000000..7e47200 --- /dev/null +++ b/docs/support_package_specification.md @@ -0,0 +1,436 @@ +# Support Package Specification + +## Overview + +The Support package provides fundamental utilities, helper functions, and common abstractions used throughout the framework. It aims to match Laravel's Support package functionality while leveraging Dart's strengths. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Contracts Package Specification](contracts_package_specification.md) for support contracts + +## Core Features + +### 1. Collections + +```dart +/// Provides Laravel-like collection operations +class Collection { + final List _items; + + Collection(this._items); + + /// Creates a collection from an iterable + factory Collection.from(Iterable items) { + return Collection(items.toList()); + } + + /// Maps items while maintaining collection type + Collection map(R Function(T) callback) { + return Collection(_items.map(callback).toList()); + } + + /// Filters items + Collection where(bool Function(T) test) { + return Collection(_items.where(test).toList()); + } + + /// Reduces collection to single value + R reduce(R Function(R, T) callback, R initial) { + return _items.fold(initial, callback); + } + + /// Groups items by key + Map> groupBy(K Function(T) keySelector) { + return _items.fold({}, (map, item) { + var key = keySelector(item); + map.putIfAbsent(key, () => []).add(item); + return map; + }); + } +} +``` + +### 2. String Manipulation + +```dart +/// Provides Laravel-like string manipulation +extension StringHelpers on String { + /// Converts string to camelCase + String camelCase() { + var words = split(RegExp(r'[\s_-]+')); + return words.first + + words.skip(1) + .map((w) => w[0].toUpperCase() + w.substring(1)) + .join(); + } + + /// Converts string to snake_case + String snakeCase() { + return replaceAllMapped( + RegExp(r'[A-Z]'), + (m) => '_${m[0]!.toLowerCase()}' + ).replaceAll(RegExp(r'^_'), ''); + } + + /// Converts string to kebab-case + String kebabCase() { + return snakeCase().replaceAll('_', '-'); + } + + /// Converts string to StudlyCase + String studlyCase() { + return split(RegExp(r'[\s_-]+')) + .map((w) => w[0].toUpperCase() + w.substring(1)) + .join(); + } +} +``` + +### 3. Array/List Helpers + +```dart +/// Provides Laravel-like array manipulation +extension ArrayHelpers on List { + /// Gets first item matching predicate + T? firstWhere(bool Function(T) test, {T? orElse()}) { + try { + return super.firstWhere(test); + } catch (e) { + return orElse?.call(); + } + } + + /// Plucks single field from list of maps + List pluck(String key) { + return map((item) => + (item as Map)[key] as V + ).toList(); + } + + /// Groups items by key + Map> groupBy(K Function(T) keySelector) { + return fold({}, (map, item) { + var key = keySelector(item); + map.putIfAbsent(key, () => []).add(item); + return map; + }); + } +} +``` + +### 4. Service Provider Support + +```dart +/// Base class for service providers +abstract class ServiceProvider { + /// The container instance + late final Container container; + + /// Register bindings with the container + void register(); + + /// Bootstrap any application services + void boot() {} + + /// Determines if provider is deferred + bool get isDeferred => false; + + /// Gets services provided + List get provides => []; +} + +/// Marks a provider as deferred +abstract class DeferredServiceProvider extends ServiceProvider { + @override + bool get isDeferred => true; + + /// Gets events that trigger loading + List get when => []; +} +``` + +### 5. Fluent Interface + +```dart +/// Provides fluent interface building +class Fluent { + final Map _attributes; + + Fluent([Map? attributes]) + : _attributes = attributes ?? {}; + + /// Gets attribute value + T? get(String key) => _attributes[key] as T?; + + /// Sets attribute value + Fluent set(String key, dynamic value) { + _attributes[key] = value; + return this; + } + + /// Gets all attributes + Map toMap() => Map.from(_attributes); +} +``` + +### 6. Optional Type + +```dart +/// Provides Laravel-like Optional type +class Optional { + final T? _value; + + const Optional(this._value); + + /// Creates Optional from nullable value + factory Optional.of(T? value) => Optional(value); + + /// Gets value or default + T get(T defaultValue) => _value ?? defaultValue; + + /// Maps value if present + Optional map(R Function(T) mapper) { + return Optional(_value == null ? null : mapper(_value!)); + } + + /// Returns true if value is present + bool get isPresent => _value != null; +} +``` + +### 7. High Order Message Proxies + +```dart +/// Provides Laravel-like high order messaging +class HigherOrderProxy { + final T _target; + + HigherOrderProxy(this._target); + + /// Invokes method on target + R call(String method, [List? args]) { + return Function.apply( + _target.runtimeType.getMethod(method), + args ?? [] + ) as R; + } +} +``` + +## Integration with Container + +```dart +/// Register support services +class SupportServiceProvider extends ServiceProvider { + @override + void register() { + // Register collection factory + container.bind((c) => CollectionFactory()); + + // Register string helpers + container.bind((c) => StringHelpers()); + + // Register array helpers + container.bind((c) => ArrayHelpers()); + } +} +``` + +## Usage Examples + +### Collections +```dart +// Create collection +var collection = Collection([1, 2, 3, 4, 5]); + +// Chain operations +var result = collection + .where((n) => n.isEven) + .map((n) => n * 2) + .reduce((sum, n) => sum + n, 0); + +// Group items +var users = Collection([ + User('John', 'Admin'), + User('Jane', 'User'), + User('Bob', 'Admin') +]); + +var byRole = users.groupBy((u) => u.role); +``` + +### String Helpers +```dart +// Convert cases +'user_name'.camelCase(); // userName +'userName'.snakeCase(); // user_name +'user name'.studlyCase(); // UserName +'UserName'.kebabCase(); // user-name + +// Other operations +'hello'.padLeft(10); // ' hello' +'HELLO'.toLowerCase(); // 'hello' +' text '.trim(); // 'text' +``` + +### Service Providers +```dart +class UserServiceProvider extends ServiceProvider { + @override + void register() { + container.bind((c) => UserRepositoryImpl()); + } + + @override + void boot() { + var repo = container.make(); + repo.initialize(); + } +} + +class CacheServiceProvider extends DeferredServiceProvider { + @override + List get when => ['cache.needed']; + + @override + List get provides => [CacheManager]; + + @override + void register() { + container.bind((c) => CacheManagerImpl()); + } +} +``` + +## Testing + +```dart +void main() { + group('Collection Tests', () { + test('should map values', () { + var collection = Collection([1, 2, 3]); + var result = collection.map((n) => n * 2); + expect(result.toList(), equals([2, 4, 6])); + }); + + test('should filter values', () { + var collection = Collection([1, 2, 3, 4]); + var result = collection.where((n) => n.isEven); + expect(result.toList(), equals([2, 4])); + }); + }); + + group('String Helper Tests', () { + test('should convert to camelCase', () { + expect('user_name'.camelCase(), equals('userName')); + expect('first name'.camelCase(), equals('firstName')); + }); + + test('should convert to snakeCase', () { + expect('userName'.snakeCase(), equals('user_name')); + expect('FirstName'.snakeCase(), equals('first_name')); + }); + }); +} +``` + +## Performance Considerations + +1. **Collection Operations** +```dart +// Use lazy evaluation when possible +collection + .where((n) => n.isEven) // Lazy + .map((n) => n * 2) // Lazy + .toList(); // Eager +``` + +2. **String Manipulations** +```dart +// Cache regex patterns +final _camelCasePattern = RegExp(r'[\s_-]+'); +final _snakeCasePattern = RegExp(r'[A-Z]'); + +// Use StringBuffer for concatenation +final buffer = StringBuffer(); +for (var word in words) { + buffer.write(word); +} +``` + +3. **Service Provider Loading** +```dart +// Defer provider loading when possible +class HeavyServiceProvider extends DeferredServiceProvider { + @override + List get when => ['heavy.needed']; +} +``` + +## Next Steps + +1. Implement core features +2. Add comprehensive tests +3. Create integration examples +4. Add performance benchmarks + +Would you like me to continue with documentation for the Pipeline or Contracts package? + +## Development Guidelines + +### 1. Getting Started +Before implementing support features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Understand [Contracts Package Specification](contracts_package_specification.md) + +### 2. Implementation Process +For each support feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Implement required contracts (see [Contracts Package Specification](contracts_package_specification.md)) + +### 4. Integration Considerations +When implementing support features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) +5. Implement all contracts from [Contracts Package Specification](contracts_package_specification.md) + +### 5. Performance Guidelines +Support utilities must: +1. Handle large collections efficiently +2. Optimize string operations +3. Minimize memory allocations +4. Support async operations where appropriate +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Support tests must: +1. Cover all utility functions +2. Test edge cases +3. Verify error handling +4. Check performance characteristics +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Support documentation must: +1. Explain utility patterns +2. Show usage examples +3. Cover error handling +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/testing.md b/docs/testing.md deleted file mode 100644 index 178c63c..0000000 --- a/docs/testing.md +++ /dev/null @@ -1,10 +0,0 @@ -# Performance Testing - -The performance test can be run with the following tools. - -## WRT - - ```bash - wrk -t12 -c400 -d30s http://localhost:8080/query?queries=20 - ``` -This runs a benchmark for 30 seconds, using 12 threads, and keeping 400 HTTP connections open. diff --git a/docs/testing_gap_analysis.md b/docs/testing_gap_analysis.md new file mode 100644 index 0000000..5814aca --- /dev/null +++ b/docs/testing_gap_analysis.md @@ -0,0 +1,312 @@ +# Testing Package Gap Analysis + +## Overview + +This document analyzes the gaps between our Testing package's actual implementation and Laravel's testing functionality, identifying areas that need implementation or documentation updates. + +> **Related Documentation** +> - See [Testing Package Specification](testing_package_specification.md) for current implementation +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for overall status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Container Package Specification](container_package_specification.md) for dependency injection +> - See [Events Package Specification](events_package_specification.md) for event testing + +## Implementation Gaps + +### 1. Missing Laravel Features +```dart +// Documented but not implemented: + +// 1. Browser Testing +class BrowserTest { + // Need to implement: + Future browse(Function(Browser) callback); + Future visit(String page); + Future click(String text); + Future type(String field, String value); + Future press(String button); + Future assertSee(String text); + Future assertPathIs(String path); +} + +// 2. Parallel Testing +class ParallelTesting { + // Need to implement: + void setToken(String token); + void setProcesses(int count); + Future runInParallel(); + Future withoutOverlapping(String key); + Future isolateDatabase(); +} + +// 3. Time Testing +class TimeTesting { + // Need to implement: + void travel(Duration duration); + void freeze(DateTime time); + void resume(); + void setTestNow(DateTime time); + DateTime now(); +} +``` + +### 2. Missing Test Features +```dart +// Need to implement: + +// 1. Test Data Factories +class TestDataFactory { + // Need to implement: + T define(Map attributes); + T make([Map? attributes]); + Future create([Map? attributes]); + List makeMany(int count, [Map? attributes]); + Future> createMany(int count, [Map? attributes]); +} + +// 2. Test Doubles +class TestDoubles { + // Need to implement: + dynamic spy(dynamic target); + dynamic mock(Type type); + dynamic fake(Type type); + dynamic partial(Type type); + void verifyNever(Function invocation); + void verifyOnce(Function invocation); +} + +// 3. Test Database +class TestDatabase { + // Need to implement: + Future beginTransaction(); + Future rollback(); + Future refresh(); + Future seed(String class); + Future truncate(List tables); +} +``` + +### 3. Missing Assertion Features +```dart +// Need to implement: + +// 1. Collection Assertions +class CollectionAssertions { + // Need to implement: + void assertCount(int count); + void assertEmpty(); + void assertContains(dynamic item); + void assertDoesntContain(dynamic item); + void assertHasKey(String key); + void assertHasValue(dynamic value); +} + +// 2. Response Assertions +class ResponseAssertions { + // Need to implement: + void assertViewIs(String name); + void assertViewHas(String key, [dynamic value]); + void assertViewMissing(String key); + void assertSessionHas(String key, [dynamic value]); + void assertSessionMissing(String key); + void assertCookie(String name, [String? value]); +} + +// 3. Exception Assertions +class ExceptionAssertions { + // Need to implement: + void assertThrows(Function callback); + void assertDoesntThrow(Function callback); + void assertThrowsMessage(Type type, String message); + void assertThrowsIf(bool condition, Function callback); +} +``` + +## Documentation Gaps + +### 1. Missing API Documentation +```dart +// Need to document: + +/// Runs browser test. +/// +/// Example: +/// ```dart +/// await browse((browser) async { +/// await browser.visit('/login'); +/// await browser.type('email', 'user@example.com'); +/// await browser.press('Login'); +/// await browser.assertPathIs('/dashboard'); +/// }); +/// ``` +Future browse(Function(Browser) callback); + +/// Creates test data factory. +/// +/// Example: +/// ```dart +/// class UserFactory extends Factory { +/// @override +/// User define() { +/// return User() +/// ..name = faker.person.name() +/// ..email = faker.internet.email(); +/// } +/// } +/// ``` +abstract class Factory; +``` + +### 2. Missing Integration Examples +```dart +// Need examples for: + +// 1. Parallel Testing +await test.parallel((runner) { + runner.setProcesses(4); + runner.isolateDatabase(); + await runner.run(); +}); + +// 2. Time Testing +await test.freeze(DateTime(2024, 1, 1), () async { + await processScheduledJobs(); + await test.travel(Duration(days: 1)); + await verifyJobsCompleted(); +}); + +// 3. Test Doubles +var mock = test.mock(PaymentGateway); +when(mock.charge(any)).thenReturn(true); + +await processPayment(mock); +verify(mock.charge(any)).called(1); +``` + +### 3. Missing Test Coverage +```dart +// Need tests for: + +void main() { + group('Browser Testing', () { + test('interacts with browser', () async { + await browse((browser) async { + await browser.visit('/login'); + await browser.type('email', 'test@example.com'); + await browser.type('password', 'password'); + await browser.press('Login'); + + await browser.assertPathIs('/dashboard'); + await browser.assertSee('Welcome'); + }); + }); + }); + + group('Test Factories', () { + test('creates test data', () async { + var users = await UserFactory() + .count(3) + .create(); + + expect(users, hasLength(3)); + expect(users.first.email, contains('@')); + }); + }); +} +``` + +## Implementation Priority + +1. **High Priority** + - Browser testing (Laravel compatibility) + - Parallel testing (Laravel compatibility) + - Test data factories + +2. **Medium Priority** + - Test doubles + - Time testing + - Test database features + +3. **Low Priority** + - Additional assertions + - Additional test helpers + - Performance optimizations + +## Next Steps + +1. **Implementation Tasks** + - Add browser testing + - Add parallel testing + - Add test factories + - Add test doubles + +2. **Documentation Tasks** + - Document browser testing + - Document parallel testing + - Document factories + - Add integration examples + +3. **Testing Tasks** + - Add browser tests + - Add parallel tests + - Add factory tests + - Add double tests + +## Development Guidelines + +### 1. Getting Started +Before implementing testing features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Testing Package Specification](testing_package_specification.md) +6. Review [Container Package Specification](container_package_specification.md) +7. Review [Events Package Specification](events_package_specification.md) + +### 2. Implementation Process +For each testing feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Match specifications in [Testing Package Specification](testing_package_specification.md) + +### 4. Integration Considerations +When implementing testing features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Testing system must: +1. Execute tests efficiently +2. Support parallel testing +3. Handle large test suites +4. Manage test isolation +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Testing package tests must: +1. Cover all testing features +2. Test browser interactions +3. Verify parallel execution +4. Check test factories +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Testing documentation must: +1. Explain testing patterns +2. Show browser examples +3. Cover parallel testing +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/docs/testing_guide.md b/docs/testing_guide.md new file mode 100644 index 0000000..d0129e7 --- /dev/null +++ b/docs/testing_guide.md @@ -0,0 +1,343 @@ +# Testing Guide + +## Overview + +This guide outlines our testing approach, which follows Laravel's testing patterns while leveraging Dart's testing capabilities. It covers unit testing, integration testing, performance testing, and Laravel-style testing approaches. + +## Test Types + +### 1. Unit Tests +```dart +void main() { + group('Service Tests', () { + late Container container; + late UserService service; + + setUp(() { + container = Container(reflector); + container.bind((c) => MockDatabase()); + service = container.make(); + }); + + test('creates user', () async { + var user = await service.create({ + 'name': 'John Doe', + 'email': 'john@example.com' + }); + + expect(user.name, equals('John Doe')); + expect(user.email, equals('john@example.com')); + }); + + test('validates user data', () { + expect( + () => service.create({'name': 'John Doe'}), + throwsA(isA()) + ); + }); + }); +} +``` + +### 2. Integration Tests +```dart +void main() { + group('API Integration', () { + late Application app; + + setUp(() async { + app = await createApplication(); + await app.initialize(); + }); + + tearDown(() async { + await app.shutdown(); + }); + + test('creates user through API', () async { + var response = await app.post('/users', body: { + 'name': 'John Doe', + 'email': 'john@example.com' + }); + + expect(response.statusCode, equals(201)); + expect(response.json['name'], equals('John Doe')); + }); + + test('handles validation errors', () async { + var response = await app.post('/users', body: { + 'name': 'John Doe' + }); + + expect(response.statusCode, equals(422)); + expect(response.json['errors'], contains('email')); + }); + }); +} +``` + +### 3. Performance Tests +```dart +void main() { + group('Performance Tests', () { + late Application app; + + setUp(() async { + app = await createApplication(); + await app.initialize(); + }); + + test('handles concurrent requests', () async { + var stopwatch = Stopwatch()..start(); + + // Create 100 concurrent requests + var futures = List.generate(100, (i) => + app.get('/users') + ); + + var responses = await Future.wait(futures); + stopwatch.stop(); + + // Verify responses + expect(responses, everyElement( + predicate((r) => r.statusCode == 200) + )); + + // Check performance + expect( + stopwatch.elapsedMilliseconds / responses.length, + lessThan(100) // Less than 100ms per request + ); + }); + + test('handles database operations efficiently', () async { + var stopwatch = Stopwatch()..start(); + + // Create 1000 records + for (var i = 0; i < 1000; i++) { + await app.post('/users', body: { + 'name': 'User $i', + 'email': 'user$i@example.com' + }); + } + + stopwatch.stop(); + + // Check performance + expect( + stopwatch.elapsedMilliseconds / 1000, + lessThan(50) // Less than 50ms per operation + ); + }); + }); +} +``` + +### 4. Laravel-Style Feature Tests +```dart +void main() { + group('Feature Tests', () { + late TestCase test; + + setUp(() { + test = await TestCase.make(); + }); + + test('user can register', () async { + await test + .post('/register', { + 'name': 'John Doe', + 'email': 'john@example.com', + 'password': 'password', + 'password_confirmation': 'password' + }) + .assertStatus(302) + .assertRedirect('/home'); + + test.assertDatabaseHas('users', { + 'email': 'john@example.com' + }); + }); + + test('user can login', () async { + // Create user + await test.createUser({ + 'email': 'john@example.com', + 'password': 'password' + }); + + await test + .post('/login', { + 'email': 'john@example.com', + 'password': 'password' + }) + .assertAuthenticated(); + }); + }); +} +``` + +## Performance Testing Tools + +### 1. WRK Benchmarking +```bash +# Basic load test +wrk -t12 -c400 -d30s http://localhost:8080/api/endpoint + +# Test with custom script +wrk -t12 -c400 -d30s -s script.lua http://localhost:8080/api/endpoint +``` + +### 2. Custom Load Testing +```dart +void main() { + test('load test', () async { + var client = HttpClient(); + var stopwatch = Stopwatch()..start(); + + // Configure test + var duration = Duration(minutes: 1); + var concurrency = 100; + var results = []; + + // Run test + while (stopwatch.elapsed < duration) { + var requests = List.generate(concurrency, (i) async { + var requestWatch = Stopwatch()..start(); + await client.get('localhost', 8080, '/api/endpoint'); + requestWatch.stop(); + results.add(requestWatch.elapsed); + }); + + await Future.wait(requests); + } + + // Analyze results + var average = results.reduce((a, b) => a + b) ~/ results.length; + var sorted = List.of(results)..sort(); + var p95 = sorted[(sorted.length * 0.95).floor()]; + var p99 = sorted[(sorted.length * 0.99).floor()]; + + print('Results:'); + print('Average: ${average.inMilliseconds}ms'); + print('P95: ${p95.inMilliseconds}ms'); + print('P99: ${p99.inMilliseconds}ms'); + }); +} +``` + +## Best Practices + +### 1. Test Organization +```dart +// Group related tests +group('UserService', () { + group('creation', () { + test('creates valid user', () {}); + test('validates input', () {}); + test('handles duplicates', () {}); + }); + + group('authentication', () { + test('authenticates valid credentials', () {}); + test('rejects invalid credentials', () {}); + }); +}); +``` + +### 2. Test Data Management +```dart +class TestCase { + // Create test data + Future createUser([Map? attributes]) async { + return factory.create(User, attributes); + } + + // Clean up after tests + Future cleanup() async { + await database.truncate(['users', 'posts', 'comments']); + } +} +``` + +### 3. Assertions +```dart +// Use descriptive assertions +expect(user.name, equals('John Doe'), + reason: 'User name should match input'); + +expect(response.statusCode, + isIn([200, 201]), + reason: 'Response should indicate success' +); + +expect( + () => service.validateEmail('invalid'), + throwsA(isA()), + reason: 'Should reject invalid email' +); +``` + +## Performance Benchmarks + +### 1. Response Time Targets +```yaml +API Endpoints: +- Average: < 100ms +- P95: < 200ms +- P99: < 500ms + +Database Operations: +- Simple queries: < 10ms +- Complex queries: < 50ms +- Writes: < 20ms + +Cache Operations: +- Reads: < 5ms +- Writes: < 10ms +``` + +### 2. Throughput Targets +```yaml +API Layer: +- Minimum: 1000 requests/second +- Target: 5000 requests/second + +Database Layer: +- Reads: 10000 operations/second +- Writes: 1000 operations/second + +Cache Layer: +- Operations: 50000/second +``` + +### 3. Resource Usage Targets +```yaml +Memory: +- Base: < 100MB +- Under load: < 500MB +- Leak rate: < 1MB/hour + +CPU: +- Idle: < 5% +- Average load: < 40% +- Peak load: < 80% + +Connections: +- Database: < 100 concurrent +- Cache: < 1000 concurrent +- HTTP: < 10000 concurrent +``` + +## Next Steps + +1. Implement test helpers +2. Add more Laravel-style assertions +3. Create performance test suite +4. Add continuous benchmarking +5. Improve test coverage + +Would you like me to: +1. Create more test examples? +2. Add specific performance tests? +3. Create Laravel-compatible test helpers? diff --git a/docs/testing_package_specification.md b/docs/testing_package_specification.md new file mode 100644 index 0000000..347b75e --- /dev/null +++ b/docs/testing_package_specification.md @@ -0,0 +1,466 @@ +# Testing Package Specification + +## Overview + +The Testing package provides a robust testing framework that matches Laravel's testing functionality. It supports test case base classes, assertions, database testing, HTTP testing, and mocking while integrating with our Container and Event packages. + +> **Related Documentation** +> - See [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) for implementation status +> - See [Foundation Integration Guide](foundation_integration_guide.md) for integration patterns +> - See [Testing Guide](testing_guide.md) for testing approaches +> - See [Getting Started Guide](getting_started.md) for development setup +> - See [Container Package Specification](container_package_specification.md) for dependency injection +> - See [Events Package Specification](events_package_specification.md) for event testing + +## Core Features + +### 1. Test Case + +```dart +/// Base test case class +abstract class TestCase { + /// Container instance + late Container container; + + /// Application instance + late Application app; + + /// Event dispatcher + late EventDispatcherContract events; + + /// Sets up test case + @override + void setUp() { + container = Container(); + app = Application(container); + events = container.make(); + + setUpApplication(); + registerServices(); + } + + /// Sets up application + void setUpApplication() { + app.singleton((c) => app); + app.singleton((c) => container); + app.singleton((c) => events); + } + + /// Registers test services + void registerServices() {} + + /// Creates test instance + T make([dynamic parameters]) { + return container.make(parameters); + } + + /// Runs test in transaction + Future transaction(Future Function() callback) async { + var db = container.make(); + return await db.transaction(callback); + } + + /// Refreshes database + Future refreshDatabase() async { + await artisan.call('migrate:fresh'); + } + + /// Seeds database + Future seed([String? class]) async { + await artisan.call('db:seed', [ + if (class != null) '--class=$class' + ]); + } +} +``` + +### 2. HTTP Testing + +```dart +/// HTTP test case +abstract class HttpTestCase extends TestCase { + /// HTTP client + late TestClient client; + + @override + void setUp() { + super.setUp(); + client = TestClient(app); + } + + /// Makes GET request + Future get(String uri, { + Map? headers, + Map? query + }) { + return client.get(uri, headers: headers, query: query); + } + + /// Makes POST request + Future post(String uri, { + Map? headers, + dynamic body + }) { + return client.post(uri, headers: headers, body: body); + } + + /// Makes PUT request + Future put(String uri, { + Map? headers, + dynamic body + }) { + return client.put(uri, headers: headers, body: body); + } + + /// Makes DELETE request + Future delete(String uri, { + Map? headers + }) { + return client.delete(uri, headers: headers); + } + + /// Acts as user + Future actingAs(User user) async { + await auth.login(user); + } +} + +/// Test HTTP client +class TestClient { + /// Application instance + final Application app; + + TestClient(this.app); + + /// Makes HTTP request + Future request( + String method, + String uri, { + Map? headers, + dynamic body, + Map? query + }) async { + var request = Request(method, uri) + ..headers.addAll(headers ?? {}) + ..body = body + ..uri = uri.replace(queryParameters: query); + + var response = await app.handle(request); + return TestResponse(response); + } +} + +/// Test HTTP response +class TestResponse { + /// Response instance + final Response response; + + TestResponse(this.response); + + /// Asserts response status + void assertStatus(int status) { + expect(response.statusCode, equals(status)); + } + + /// Asserts response is OK + void assertOk() { + assertStatus(200); + } + + /// Asserts response is redirect + void assertRedirect([String? location]) { + expect(response.statusCode, inInclusiveRange(300, 399)); + if (location != null) { + expect(response.headers['location'], equals(location)); + } + } + + /// Asserts response contains JSON + void assertJson(Map json) { + expect(response.json(), equals(json)); + } + + /// Asserts response contains text + void assertSee(String text) { + expect(response.body, contains(text)); + } +} +``` + +### 3. Database Testing + +```dart +/// Database test case +abstract class DatabaseTestCase extends TestCase { + /// Database manager + late DatabaseManager db; + + @override + void setUp() { + super.setUp(); + db = container.make(); + } + + /// Seeds database + Future seed(String seeder) async { + await artisan.call('db:seed', ['--class=$seeder']); + } + + /// Asserts database has record + Future assertDatabaseHas( + String table, + Map data + ) async { + var count = await db.table(table) + .where(data) + .count(); + + expect(count, greaterThan(0)); + } + + /// Asserts database missing record + Future assertDatabaseMissing( + String table, + Map data + ) async { + var count = await db.table(table) + .where(data) + .count(); + + expect(count, equals(0)); + } + + /// Asserts database count + Future assertDatabaseCount( + String table, + int count + ) async { + var actual = await db.table(table).count(); + expect(actual, equals(count)); + } +} +``` + +### 4. Event Testing + +```dart +/// Event test case +abstract class EventTestCase extends TestCase { + /// Fake event dispatcher + late FakeEventDispatcher events; + + @override + void setUp() { + super.setUp(); + events = FakeEventDispatcher(); + container.instance(events); + } + + /// Asserts event dispatched + void assertDispatched(Type event, [Function? callback]) { + expect(events.dispatched(event), isTrue); + + if (callback != null) { + var dispatched = events.dispatched(event, callback); + expect(dispatched, isTrue); + } + } + + /// Asserts event not dispatched + void assertNotDispatched(Type event) { + expect(events.dispatched(event), isFalse); + } + + /// Asserts nothing dispatched + void assertNothingDispatched() { + expect(events.hasDispatched(), isFalse); + } +} + +/// Fake event dispatcher +class FakeEventDispatcher implements EventDispatcherContract { + /// Dispatched events + final List _events = []; + + @override + Future dispatch(T event) async { + _events.add(event); + } + + /// Checks if event dispatched + bool dispatched(Type event, [Function? callback]) { + var dispatched = _events.whereType(); + if (dispatched.isEmpty) return false; + + if (callback == null) return true; + + return dispatched.any((e) => callback(e)); + } + + /// Checks if any events dispatched + bool hasDispatched() => _events.isNotEmpty; +} +``` + +## Integration Examples + +### 1. HTTP Testing +```dart +class UserTest extends HttpTestCase { + test('creates user', () async { + var response = await post('/users', body: { + 'name': 'John Doe', + 'email': 'john@example.com' + }); + + response.assertStatus(201); + await assertDatabaseHas('users', { + 'email': 'john@example.com' + }); + }); + + test('requires authentication', () async { + var user = await User.factory().create(); + await actingAs(user); + + var response = await get('/dashboard'); + response.assertOk(); + }); +} +``` + +### 2. Database Testing +```dart +class OrderTest extends DatabaseTestCase { + test('creates order', () async { + await seed(ProductSeeder); + + var order = await Order.create({ + 'product_id': 1, + 'quantity': 5 + }); + + await assertDatabaseHas('orders', { + 'id': order.id, + 'quantity': 5 + }); + }); +} +``` + +### 3. Event Testing +```dart +class PaymentTest extends EventTestCase { + test('dispatches payment events', () async { + var payment = await processPayment(order); + + assertDispatched(PaymentProcessed, (event) { + return event.payment.id == payment.id; + }); + }); +} +``` + +## Testing + +```dart +void main() { + group('HTTP Testing', () { + test('makes requests', () async { + var client = TestClient(app); + + var response = await client.get('/users'); + + expect(response.statusCode, equals(200)); + expect(response.json(), isA()); + }); + + test('handles authentication', () async { + var case = UserTest(); + await case.setUp(); + + await case.actingAs(user); + var response = await case.get('/profile'); + + response.assertOk(); + }); + }); + + group('Database Testing', () { + test('seeds database', () async { + var case = OrderTest(); + await case.setUp(); + + await case.seed(ProductSeeder); + + await case.assertDatabaseCount('products', 10); + }); + }); +} +``` + +## Next Steps + +1. Implement core testing features +2. Add HTTP testing +3. Add database testing +4. Add event testing +5. Write tests +6. Add examples + +## Development Guidelines + +### 1. Getting Started +Before implementing testing features: +1. Review [Getting Started Guide](getting_started.md) +2. Check [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Follow [Testing Guide](testing_guide.md) +4. Use [Foundation Integration Guide](foundation_integration_guide.md) +5. Review [Container Package Specification](container_package_specification.md) +6. Review [Events Package Specification](events_package_specification.md) + +### 2. Implementation Process +For each testing feature: +1. Write tests following [Testing Guide](testing_guide.md) +2. Implement following Laravel patterns +3. Document following [Getting Started Guide](getting_started.md#documentation) +4. Integrate following [Foundation Integration Guide](foundation_integration_guide.md) + +### 3. Quality Requirements +All implementations must: +1. Pass all tests (see [Testing Guide](testing_guide.md)) +2. Meet Laravel compatibility requirements +3. Follow integration patterns (see [Foundation Integration Guide](foundation_integration_guide.md)) +4. Support dependency injection (see [Container Package Specification](container_package_specification.md)) +5. Support event testing (see [Events Package Specification](events_package_specification.md)) + +### 4. Integration Considerations +When implementing testing features: +1. Follow patterns in [Foundation Integration Guide](foundation_integration_guide.md) +2. Ensure Laravel compatibility per [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md) +3. Use testing approaches from [Testing Guide](testing_guide.md) +4. Follow development setup in [Getting Started Guide](getting_started.md) + +### 5. Performance Guidelines +Testing system must: +1. Execute tests efficiently +2. Support parallel testing +3. Handle large test suites +4. Manage test isolation +5. Meet performance targets in [Laravel Compatibility Roadmap](laravel_compatibility_roadmap.md#performance-benchmarks) + +### 6. Testing Requirements +Testing package tests must: +1. Cover all testing features +2. Test HTTP assertions +3. Verify database testing +4. Check event assertions +5. Follow patterns in [Testing Guide](testing_guide.md) + +### 7. Documentation Requirements +Testing documentation must: +1. Explain testing patterns +2. Show assertion examples +3. Cover test organization +4. Include performance tips +5. Follow standards in [Getting Started Guide](getting_started.md#documentation) diff --git a/melos.yaml b/melos.yaml index f4eeb3b..eada6fc 100644 --- a/melos.yaml +++ b/melos.yaml @@ -13,6 +13,7 @@ repository: https://github.com/protevus/platform packages: - apps/** - packages/** + - sandbox/** - helpers/tools/** - examples/** diff --git a/packages/bus/.gitignore b/packages/bus/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/bus/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/bus/CHANGELOG.md b/packages/bus/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/bus/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/bus/LICENSE.md b/packages/bus/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/bus/LICENSE.md @@ -0,0 +1,10 @@ +The MIT License (MIT) + +The Laravel Framework is Copyright (c) Taylor Otwell +The Fabric Framework is Copyright (c) Vieo, Inc. + +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/packages/bus/README.md b/packages/bus/README.md new file mode 100644 index 0000000..757f4c9 --- /dev/null +++ b/packages/bus/README.md @@ -0,0 +1 @@ +

\ No newline at end of file diff --git a/packages/bus/analysis_options.yaml b/packages/bus/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/bus/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/bus/lib/angel3_bus.dart b/packages/bus/lib/angel3_bus.dart new file mode 100644 index 0000000..536519b --- /dev/null +++ b/packages/bus/lib/angel3_bus.dart @@ -0,0 +1,9 @@ +library angel3_bus; + +export 'src/dispatcher.dart'; +export 'src/command.dart'; +export 'src/handler.dart'; +export 'src/queue.dart'; +export 'src/batch.dart'; +export 'src/chain.dart'; +export 'src/bus_service_provider.dart'; diff --git a/packages/bus/lib/src/batch.dart b/packages/bus/lib/src/batch.dart new file mode 100644 index 0000000..5a2a24f --- /dev/null +++ b/packages/bus/lib/src/batch.dart @@ -0,0 +1,19 @@ +import 'command.dart'; +import 'dispatcher.dart'; + +class Batch { + // Implement Batch +} + +class PendingBatch { + final Dispatcher _dispatcher; + final List _commands; + + PendingBatch(this._dispatcher, this._commands); + + Future dispatch() async { + for (var command in _commands) { + await _dispatcher.dispatch(command); + } + } +} diff --git a/packages/bus/lib/src/bus_service_provider.dart b/packages/bus/lib/src/bus_service_provider.dart new file mode 100644 index 0000000..d892653 --- /dev/null +++ b/packages/bus/lib/src/bus_service_provider.dart @@ -0,0 +1,60 @@ +// // lib/src/bus_service_provider.dart + +// import 'package:angel3_framework/angel3_framework.dart'; +// import 'package:angel3_event_bus/angel3_event_bus.dart'; +// import 'package:angel3_mq/angel3_mq.dart'; +// import 'dispatcher.dart'; + +// class BusServiceProvider extends Provider { +// @override +// Future boot(Angel app) async { +// // Register EventBus +// app.container.registerSingleton(EventBus()); + +// // Register Queue +// app.container.registerSingleton(MemoryQueue()); + +// // Create and register the Dispatcher +// final dispatcher = Dispatcher(app.container); +// app.container.registerSingleton(dispatcher); + +// // Register any global middleware or mappings +// dispatcher.pipeThrough([ +// // Add any global middleware here +// ]); + +// // Register command-to-handler mappings +// dispatcher.map({ +// // Add your command-to-handler mappings here +// // Example: ExampleCommand: ExampleCommandHandler, +// }); +// } +// } + +// class MemoryQueue implements Queue { +// final List _queue = []; + +// @override +// Future push(Command command) async { +// _queue.add(command); +// } + +// @override +// Future later(Duration delay, Command command) async { +// await Future.delayed(delay); +// _queue.add(command); +// } + +// @override +// Future pushOn(String queue, Command command) async { +// // For simplicity, ignoring the queue parameter in this implementation +// _queue.add(command); +// } + +// @override +// Future laterOn(String queue, Duration delay, Command command) async { +// // For simplicity, ignoring the queue parameter in this implementation +// await Future.delayed(delay); +// _queue.add(command); +// } +// } diff --git a/packages/bus/lib/src/chain.dart b/packages/bus/lib/src/chain.dart new file mode 100644 index 0000000..f46dc4e --- /dev/null +++ b/packages/bus/lib/src/chain.dart @@ -0,0 +1,15 @@ +import 'command.dart'; +import 'dispatcher.dart'; + +class PendingChain { + final Dispatcher _dispatcher; + final List _commands; + + PendingChain(this._dispatcher, this._commands); + + Future dispatch() async { + for (var command in _commands) { + await _dispatcher.dispatch(command); + } + } +} diff --git a/packages/bus/lib/src/command.dart b/packages/bus/lib/src/command.dart new file mode 100644 index 0000000..81d5395 --- /dev/null +++ b/packages/bus/lib/src/command.dart @@ -0,0 +1,5 @@ +// lib/src/command.dart + +abstract class Command {} + +abstract class ShouldQueue implements Command {} diff --git a/packages/bus/lib/src/dispatcher.dart b/packages/bus/lib/src/dispatcher.dart new file mode 100644 index 0000000..fcf1ea6 --- /dev/null +++ b/packages/bus/lib/src/dispatcher.dart @@ -0,0 +1,251 @@ +// lib/src/dispatcher.dart + +import 'dart:async'; + +import 'package:platform_container/container.dart'; +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:angel3_mq/mq.dart'; + +import 'command.dart'; +import 'handler.dart'; +import 'batch.dart'; +import 'chain.dart'; + +/// A class that handles dispatching and processing of commands. +/// +/// This dispatcher supports both synchronous and asynchronous command execution, +/// as well as queueing commands for later processing. +class Dispatcher implements QueueingDispatcher { + final Container container; + final EventBus _eventBus; + final Subject _commandSubject; + final MQClient _queue; + final Map _handlers = {}; + + /// Creates a new [Dispatcher] instance. + /// + /// [container] is used for dependency injection and to retrieve necessary services. + Dispatcher(this.container) + : _eventBus = container.make(), + _commandSubject = BehaviorSubject(), + _queue = container.make() { + _setupCommandProcessing(); + } + + /// Sets up the command processing pipeline. + /// + /// This method initializes the stream that processes commands and emits events. + void _setupCommandProcessing() { + _commandSubject + .flatMap((command) => Stream.fromFuture(_processCommand(command)) + .map((result) => CommandEvent(command, result: result)) + .onErrorReturnWith( + (error, stackTrace) => CommandEvent(command, error: error))) + .listen((event) { + _eventBus.fire(event); + }); + } + + /// Dispatches a command for execution. + /// + /// If the command implements [ShouldQueue], it will be dispatched to a queue. + /// Otherwise, it will be executed immediately. + /// + /// [command] is the command to be dispatched. + @override + Future dispatch(Command command) { + if (command is ShouldQueue) { + return dispatchToQueue(command); + } else { + return dispatchNow(command); + } + } + + /// Dispatches a command for immediate execution. + /// + /// [command] is the command to be executed. + /// [handler] is an optional specific handler for the command. + @override + Future dispatchNow(Command command, [Handler? handler]) { + final completer = Completer(); + _commandSubject.add(command); + + _eventBus + .on() + .where((event) => event.command == command) + .take(1) + .listen((event) { + if (event.error != null) { + completer.completeError(event.error); + } else { + completer.complete(event.result); + } + }); + + return completer.future; + } + + /// Processes a command by finding and executing its appropriate handler. + /// + /// [command] is the command to be processed. + Future _processCommand(Command command) async { + final handlerType = _handlers[command.runtimeType]; + if (handlerType != null) { + final handler = container.make(handlerType) as Handler; + return await handler.handle(command); + } else { + throw Exception('No handler found for command: ${command.runtimeType}'); + } + } + + /// Dispatches a command to a queue for later processing. + /// + /// [command] is the command to be queued. + @override + Future dispatchToQueue(Command command) async { + final message = Message( + payload: command, + headers: { + 'commandType': command.runtimeType.toString(), + }, + ); + _queue.sendMessage( + message: message, + // You might want to specify an exchange name and routing key if needed + // exchangeName: 'your_exchange_name', + // routingKey: 'your_routing_key', + ); + return message.id; + } + + /// Dispatches a command synchronously. + /// + /// This is an alias for [dispatchNow]. + /// + /// [command] is the command to be executed. + /// [handler] is an optional specific handler for the command. + @override + Future dispatchSync(Command command, [Handler? handler]) { + return dispatchNow(command, handler); + } + + /// Finds a batch by its ID. + /// + /// [batchId] is the ID of the batch to find. + @override + Future findBatch(String batchId) async { + // Implement batch finding logic + throw UnimplementedError(); + } + + /// Creates a new pending batch of commands. + /// + /// [commands] is the list of commands to be included in the batch. + @override + PendingBatch batch(List commands) { + return PendingBatch(this, commands); + } + + /// Creates a new pending chain of commands. + /// + /// [commands] is the list of commands to be included in the chain. + @override + PendingChain chain(List commands) { + return PendingChain(this, commands); + } + + /// Applies a list of pipes to the command processing pipeline. + /// + /// [pipes] is the list of pipes to be applied. + @override + Dispatcher pipeThrough(List pipes) { + _commandSubject.transform( + StreamTransformer.fromHandlers( + handleData: (data, sink) { + var result = data; + for (var pipe in pipes) { + result = pipe(result); + } + sink.add(result); + }, + ), + ); + return this; + } + + /// Maps command types to their respective handler types. + /// + /// [handlers] is a map where keys are command types and values are handler types. + @override + Dispatcher map(Map handlers) { + _handlers.addAll(handlers); + return this; + } + + /// Dispatches a command to be executed after the current request-response cycle. + /// + /// [command] is the command to be dispatched after the response. + @override + void dispatchAfterResponse(Command command) { + final message = Message( + payload: command, + headers: { + 'commandType': command.runtimeType.toString(), + 'dispatchAfterResponse': 'true', + }, + ); + + _queue.sendMessage( + message: message, + // You might want to specify an exchange name if needed + // exchangeName: 'your_exchange_name', + // If you want to use a specific queue for after-response commands: + routingKey: 'after_response_queue', + ); + } +} + +abstract class QueueingDispatcher { + Future dispatch(Command command); + Future dispatchSync(Command command, [Handler? handler]); + Future dispatchNow(Command command, [Handler? handler]); + Future dispatchToQueue(Command command); + Future findBatch(String batchId); + PendingBatch batch(List commands); + PendingChain chain(List commands); + Dispatcher pipeThrough(List pipes); + Dispatcher map(Map handlers); + void dispatchAfterResponse(Command command); +} + +typedef Pipe = Command Function(Command); + +class CommandCompletedEvent extends AppEvent { + final dynamic result; + + CommandCompletedEvent(this.result); + + @override + List get props => [result]; +} + +class CommandErrorEvent extends AppEvent { + final dynamic error; + + CommandErrorEvent(this.error); + + @override + List get props => [error]; +} + +class CommandEvent extends AppEvent { + final Command command; + final dynamic result; + final dynamic error; + + CommandEvent(this.command, {this.result, this.error}); + + @override + List get props => [command, result, error]; +} diff --git a/packages/bus/lib/src/handler.dart b/packages/bus/lib/src/handler.dart new file mode 100644 index 0000000..1c8cdfe --- /dev/null +++ b/packages/bus/lib/src/handler.dart @@ -0,0 +1,5 @@ +import 'command.dart'; + +abstract class Handler { + Future handle(Command command); +} diff --git a/packages/bus/lib/src/queue.dart b/packages/bus/lib/src/queue.dart new file mode 100644 index 0000000..5d4b999 --- /dev/null +++ b/packages/bus/lib/src/queue.dart @@ -0,0 +1,8 @@ +import 'command.dart'; + +abstract class Queue { + Future push(Command command); + Future later(Duration delay, Command command); + Future pushOn(String queue, Command command); + Future laterOn(String queue, Duration delay, Command command); +} diff --git a/packages/bus/pubspec.yaml b/packages/bus/pubspec.yaml new file mode 100644 index 0000000..deb1887 --- /dev/null +++ b/packages/bus/pubspec.yaml @@ -0,0 +1,24 @@ +name: platform_bus +description: The Bus Package for the Protevus Platform +version: 0.0.1 +homepage: https://protevus.com +documentation: https://docs.protevus.com +repository: https://github.com/protevus/platformo + +environment: + sdk: ^3.4.2 + +# Add regular dependencies here. +dependencies: + platform_container: ^9.0.0 + platform_core: ^9.0.0 + angel3_reactivex: ^9.0.0 + angel3_event_bus: ^9.0.0 + angel3_mq: ^9.0.0 + # path: ^1.8.0 + +dev_dependencies: + build_runner: ^2.1.0 + lints: ^3.0.0 + mockito: ^5.3.0 + test: ^1.24.0 diff --git a/packages/bus/test/dispatcher_test.dart b/packages/bus/test/dispatcher_test.dart new file mode 100644 index 0000000..a931ffb --- /dev/null +++ b/packages/bus/test/dispatcher_test.dart @@ -0,0 +1,197 @@ +import 'dart:async'; + +import 'package:platform_bus/angel3_bus.dart'; +import 'package:platform_container/container.dart'; +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:angel3_mq/mq.dart'; +import 'package:mockito/mockito.dart'; +import 'package:test/test.dart'; + +class IsMessage extends Matcher { + @override + bool matches(item, Map matchState) => item is Message; + + @override + Description describe(Description description) => + description.add('is a Message'); +} + +class MockContainer extends Mock implements Container { + final Map _instances = {}; + + @override + T make([Type? type]) { + type ??= T; + return _instances[type] as T; + } + + void registerInstance(T instance) { + _instances[T] = instance; + } +} + +class MockEventBus extends Mock implements EventBus { + @override + Stream on() { + return super.noSuchMethod( + Invocation.method(#on, [], {#T: T}), + returnValue: Stream.empty(), + ) as Stream; + } +} + +class MockMQClient extends Mock implements MQClient { + Message? capturedMessage; + String? capturedExchangeName; + String? capturedRoutingKey; + + @override + dynamic noSuchMethod(Invocation invocation, + {Object? returnValue, Object? returnValueForMissingStub}) { + if (invocation.memberName == #sendMessage) { + final namedArgs = invocation.namedArguments; + capturedMessage = namedArgs[#message] as Message?; + capturedExchangeName = namedArgs[#exchangeName] as String?; + capturedRoutingKey = namedArgs[#routingKey] as String?; + return null; + } + return super.noSuchMethod(invocation, + returnValue: returnValue, + returnValueForMissingStub: returnValueForMissingStub); + } +} + +class TestCommand implements Command { + final String data; + TestCommand(this.data); +} + +class TestHandler implements Handler { + @override + Future handle(Command command) async { + if (command is TestCommand) { + return 'Handled: ${command.data}'; + } + throw UnimplementedError(); + } +} + +class TestQueuedCommand implements Command, ShouldQueue { + final String data; + TestQueuedCommand(this.data); +} + +void main() { + late MockContainer container; + late MockEventBus eventBus; + late MockMQClient mqClient; + late Dispatcher dispatcher; + + setUp(() { + container = MockContainer(); + eventBus = MockEventBus(); + mqClient = MockMQClient(); + + container.registerInstance(eventBus); + container.registerInstance(mqClient); + + dispatcher = Dispatcher(container); + }); + + group('Dispatcher', () { + test('dispatchNow should handle command and return result', () async { + final command = TestCommand('test data'); + final handler = TestHandler(); + + container.registerInstance(handler); + dispatcher.map({TestCommand: TestHandler}); + + final commandEventController = StreamController(); + when(eventBus.on()) + .thenAnswer((_) => commandEventController.stream); + + final future = dispatcher.dispatchNow(command); + + // Simulate the event firing + commandEventController + .add(CommandEvent(command, result: 'Handled: test data')); + + final result = await future; + expect(result, equals('Handled: test data')); + + await commandEventController.close(); + }); + + test('dispatch should handle regular commands immediately', () async { + final command = TestCommand('regular'); + final handler = TestHandler(); + + container.registerInstance(handler); + dispatcher.map({TestCommand: TestHandler}); + + final commandEventController = StreamController(); + when(eventBus.on()) + .thenAnswer((_) => commandEventController.stream); + + final future = dispatcher.dispatch(command); + + // Simulate the event firing + commandEventController + .add(CommandEvent(command, result: 'Handled: regular')); + + final result = await future; + expect(result, equals('Handled: regular')); + + await commandEventController.close(); + }); + + test('dispatch should queue ShouldQueue commands', () async { + final command = TestQueuedCommand('queued data'); + + // Dispatch the command + await dispatcher.dispatch(command); + + // Verify that sendMessage was called and check the message properties + expect(mqClient.capturedMessage, isNotNull); + expect(mqClient.capturedMessage!.payload, equals(command)); + expect(mqClient.capturedMessage!.headers?['commandType'], + equals('TestQueuedCommand')); + + // Optionally, verify exchange name and routing key if needed + expect(mqClient.capturedExchangeName, isNull); + expect(mqClient.capturedRoutingKey, isNull); + }); + + test( + 'dispatchAfterResponse should send message to queue with specific header', + () { + final command = TestCommand('after response data'); + + // Call dispatchAfterResponse + dispatcher.dispatchAfterResponse(command); + + // Verify that sendMessage was called and check the message properties + expect(mqClient.capturedMessage, isNotNull); + expect(mqClient.capturedMessage!.payload, equals(command)); + expect(mqClient.capturedMessage!.headers?['commandType'], + equals('TestCommand')); + expect(mqClient.capturedMessage!.headers?['dispatchAfterResponse'], + equals('true')); + + // Verify routing key + expect(mqClient.capturedRoutingKey, equals('after_response_queue')); + + // Optionally, verify exchange name if needed + expect(mqClient.capturedExchangeName, isNull); + }); + test('map should register command handlers', () { + dispatcher.map({TestCommand: TestHandler}); + + // Mock the event bus behavior for this test + when(eventBus.on()).thenAnswer((_) => Stream.empty()); + + // This test is a bit tricky to verify directly, but we can check if dispatch doesn't throw + expect(() => dispatcher.dispatch(TestCommand('test')), returnsNormally); + }); + }); +} diff --git a/packages/events/.gitignore b/packages/events/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/events/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/events/CHANGELOG.md b/packages/events/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/events/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/events/LICENSE.md b/packages/events/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/events/LICENSE.md @@ -0,0 +1,10 @@ +The MIT License (MIT) + +The Laravel Framework is Copyright (c) Taylor Otwell +The Fabric Framework is Copyright (c) Vieo, Inc. + +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/packages/events/README.md b/packages/events/README.md new file mode 100644 index 0000000..757f4c9 --- /dev/null +++ b/packages/events/README.md @@ -0,0 +1 @@ +

\ No newline at end of file diff --git a/packages/events/analysis_options.yaml b/packages/events/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/events/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/events/lib/dispatcher.dart b/packages/events/lib/dispatcher.dart new file mode 100644 index 0000000..bbc26fc --- /dev/null +++ b/packages/events/lib/dispatcher.dart @@ -0,0 +1,3 @@ +library; + +export 'src/dispatcher.dart'; diff --git a/packages/events/lib/src/dispatcher.dart b/packages/events/lib/src/dispatcher.dart new file mode 100644 index 0000000..de9349e --- /dev/null +++ b/packages/events/lib/src/dispatcher.dart @@ -0,0 +1,499 @@ +import 'dart:async'; +import 'package:platform_container/container.dart'; +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:angel3_mq/mq.dart'; + +// Simulating some of the Laravel interfaces/classes +abstract class ShouldBroadcast {} + +abstract class ShouldQueue {} + +abstract class ShouldBeEncrypted {} + +abstract class ShouldDispatchAfterCommit {} + +class Dispatcher implements DispatcherContract { + // Properties as specified in YAML + final Container container; + final Map> _listeners = {}; + final Map> _wildcards = {}; + final Map> _wildcardsCache = {}; + late final Function _queueResolver; + late final Function _transactionManagerResolver; + final Map> _eventBusListeners = {}; + final Map> _untilCompleters = {}; + final Map _eventBusSubscriptions = {}; + final Set _processedMessageIds = {}; + + // Properties for Angel3 packages + final EventBus _eventBus; + late final MQClient? _mqClient; + final Map> _subjects = {}; + + // Queue and exchange names + static const String _eventsQueue = 'events_queue'; + static const String _delayedEventsQueue = 'delayed_events_queue'; + static const String _eventsExchange = 'events_exchange'; + + Dispatcher(this.container) : _eventBus = EventBus(); + + // Setter for _mqClient + set mqClient(MQClient client) { + _mqClient = client; + _setupQueuesAndExchanges(); + _startProcessingQueuedEvents(); + } + + void _setupQueuesAndExchanges() { + _mqClient?.declareQueue(_eventsQueue); + _mqClient?.declareQueue(_delayedEventsQueue); + _mqClient?.declareExchange( + exchangeName: _eventsExchange, + exchangeType: ExchangeType.direct, + ); + _mqClient?.bindQueue( + queueId: _eventsQueue, + exchangeName: _eventsExchange, + bindingKey: _eventsQueue, + ); + _mqClient?.bindQueue( + queueId: _delayedEventsQueue, + exchangeName: _eventsExchange, + bindingKey: _delayedEventsQueue, + ); + } + + void _startProcessingQueuedEvents() { + _mqClient?.fetchQueue(_eventsQueue).listen((Message message) async { + if (message.payload is Map) { + final eventData = message.payload as Map; + if (eventData.containsKey('event') && + eventData.containsKey('payload')) { + await dispatch(eventData['event'], eventData['payload']); + } else { + print('Invalid message format: ${message.payload}'); + } + } else { + print('Unexpected payload type: ${message.payload.runtimeType}'); + } + }); + } + + @override + void listen(dynamic events, dynamic listener) { + if (events is String) { + _addListener(events, listener); + } else if (events is List) { + for (var event in events) { + _addListener(event, listener); + } + } + if (events is String && events.contains('*')) { + _setupWildcardListen(events, listener); + } + } + + void _addListener(String event, dynamic listener) { + _listeners.putIfAbsent(event, () => []).add(listener); + + // Create a subject for this event if it doesn't exist + _subjects.putIfAbsent(event, () => BehaviorSubject()); + + // Add EventBus listener and store the subscription + final subscription = _eventBus.on().listen((AppEvent busEvent) { + if (busEvent is CustomAppEvent && busEvent.eventName == event) { + listener(event, busEvent.payload); + } + }); + _eventBusSubscriptions[event] = subscription; + } + + void _setupWildcardListen(String event, Function listener) { + _wildcards.putIfAbsent(event, () => []).add(listener); + _wildcardsCache.clear(); + } + + @override + bool hasListeners(String eventName) { + return _listeners.containsKey(eventName) || + _wildcards.containsKey(eventName) || + hasWildcardListeners(eventName); + } + + bool hasWildcardListeners(String eventName) { + return _wildcards.keys + .any((pattern) => _isWildcardMatch(pattern, eventName)); + } + + @override + void push(String event, [dynamic payload]) { + final effectivePayload = payload ?? []; + _mqClient?.sendMessage( + exchangeName: _eventsExchange, + routingKey: _delayedEventsQueue, + message: Message( + headers: {'expiration': '5000'}, // 5 seconds delay + payload: { + 'event': event, + 'payload': + effectivePayload is List ? effectivePayload : [effectivePayload], + }, + timestamp: DateTime.now().toIso8601String(), + id: 'msg_${DateTime.now().millisecondsSinceEpoch}', // Ensure unique ID + ), + ); + } + + @override + Future flush(String event) async { + final messageStream = _mqClient?.fetchQueue(_delayedEventsQueue); + if (messageStream == null) { + print('Warning: MQClient is not initialized'); + return; + } + + final messagesToProcess = []; + + // Collect messages to process + await for (final message in messageStream) { + print('Examining message: ${message.id}'); + if (message.payload is Map && + !_processedMessageIds.contains(message.id)) { + final eventData = message.payload as Map; + if (eventData['event'] == event) { + print('Adding message to process: ${message.id}'); + messagesToProcess.add(message); + } + } + } + + print('Total messages to process: ${messagesToProcess.length}'); + + // Process collected messages + for (final message in messagesToProcess) { + final eventData = message.payload as Map; + print('Processing message: ${message.id}'); + await dispatch(eventData['event'], eventData['payload']); + _mqClient?.deleteMessage(_delayedEventsQueue, message); + _processedMessageIds.add(message.id); + } + } + + @override + void subscribe(dynamic subscriber) { + if (subscriber is EventBusSubscriber) { + subscriber.subscribe(_eventBus); + } else { + // Handle other types of subscribers + } + } + + @override + Future until(dynamic event, [dynamic payload]) { + if (event is String) { + final completer = Completer(); + _untilCompleters[event] = completer; + + // Set up a one-time listener for this event + listen(event, (dynamic e, dynamic p) { + if (!completer.isCompleted) { + completer.complete(p); + _untilCompleters.remove(event); + } + }); + + // If payload is provided, dispatch the event immediately + if (payload != null) { + // Use dispatch instead of push to ensure immediate processing + dispatch(event, payload); + } + + return completer.future; + } + throw ArgumentError('Event must be a String'); + } + + @override + Future dispatch(dynamic event, [dynamic payload, bool? halt]) async { + final eventName = event is String ? event : event.runtimeType.toString(); + final eventPayload = payload ?? (event is AppEvent ? event : []); + + if (event is ShouldBroadcast || + (eventPayload is List && + eventPayload.isNotEmpty && + eventPayload[0] is ShouldBroadcast)) { + await _broadcastEvent(event); + } + + if (event is ShouldQueue || + (eventPayload is List && + eventPayload.isNotEmpty && + eventPayload[0] is ShouldQueue)) { + return _queueEvent(eventName, eventPayload); + } + + final listeners = getListeners(eventName); + for (var listener in listeners) { + final response = + await Function.apply(listener, [eventName, eventPayload]); + if (halt == true && response != null) { + return response; + } + if (response == false) { + break; + } + } + + return halt == true ? null : listeners; + } + + // void _addToSubject(String eventName, dynamic payload) { + // if (_subjects.containsKey(eventName)) { + // _subjects[eventName]!.add(payload); + // } + // } + + @override + List getListeners(String eventName) { + var listeners = [ + ...(_listeners[eventName] ?? []), + ...(_wildcardsCache[eventName] ?? _getWildcardListeners(eventName)), + ...(_eventBusListeners[eventName] ?? []), + ]; + + return listeners; + } + + List _getWildcardListeners(String eventName) { + final wildcardListeners = []; + for (var entry in _wildcards.entries) { + if (_isWildcardMatch(entry.key, eventName)) { + wildcardListeners.addAll(entry.value); + } + } + _wildcardsCache[eventName] = wildcardListeners; + return wildcardListeners; + } + + @override + void forget(String event) { + // Remove from _listeners + _listeners.remove(event); + + // Remove from _subjects + if (_subjects.containsKey(event)) { + _subjects[event]?.close(); + _subjects.remove(event); + } + + // Cancel and remove EventBus subscription + _eventBusSubscriptions[event]?.cancel(); + _eventBusSubscriptions.remove(event); + + // Remove from wildcards if applicable + if (event.contains('*')) { + _wildcards.remove(event); + _wildcardsCache.clear(); + } else { + // If it's not a wildcard, we need to remove it from any matching wildcard listeners + _wildcards.forEach((pattern, listeners) { + if (_isWildcardMatch(pattern, event)) { + _wildcards[pattern] = listeners + .where((listener) => listener != _listeners[event]) + .toList(); + } + }); + _wildcardsCache.clear(); + } + + // Remove any 'until' completers for this event + _untilCompleters.remove(event); + } + + @override + void forgetPushed() { + _listeners.removeWhere((key, _) => key.endsWith('_pushed')); + _eventBusListeners.removeWhere((key, _) => key.endsWith('_pushed')); + // Note: We're not clearing all EventBus listeners here, as that might affect other parts of your application + } + + @override + void setQueueResolver(Function resolver) { + _queueResolver = resolver; + } + + @override + void setTransactionManagerResolver(Function resolver) { + _transactionManagerResolver = resolver; + } + + // Add these methods for testing purposes + void triggerQueueResolver() { + _queueResolver(); + } + + void triggerTransactionManagerResolver() { + _transactionManagerResolver(); + } + + @override + Map> getRawListeners() { + return Map.unmodifiable(_listeners); + } + + bool _shouldBroadcast(List payload) { + return payload.isNotEmpty && payload[0] is ShouldBroadcast; + } + + Future _broadcastEvent(dynamic event) async { + // Implement broadcasting logic here + // For now, we'll just print a message + print('Broadcasting event: ${event.runtimeType}'); + } + + bool _isWildcardMatch(String pattern, String eventName) { + final regExp = RegExp('^${pattern.replaceAll('*', '.*')}\$'); + return regExp.hasMatch(eventName); + } + + bool _shouldQueue(List payload) { + return payload.isNotEmpty && payload[0] is ShouldQueue; + } + + Future _queueEvent(String eventName, dynamic payload) async { + _mqClient?.sendMessage( + exchangeName: _eventsExchange, + routingKey: _eventsQueue, + message: Message( + payload: {'event': eventName, 'payload': payload}, + timestamp: DateTime.now().toIso8601String(), + ), + ); + } + + // Updated on method + Stream on(String event) { + return (_subjects + .putIfAbsent(event, () => BehaviorSubject()) + .stream as Stream) + .where((event) => event is T) + .cast(); + } + + // In your Dispatcher class + void setMQClient(MQClient client) { + _mqClient = client; + } + + // Method to close the MQClient connection + Future close() async { + _mqClient?.close(); + } + + // Don't forget to close the subjects when they're no longer needed + void dispose() { + for (var subject in _subjects.values) { + subject.close(); + } + } +} +// ... rest of the code (DispatcherContract, EventBusSubscriber, etc.) remains the same + +abstract class DispatcherContract { + void listen(dynamic events, dynamic listener); + bool hasListeners(String eventName); + void push(String event, [dynamic payload]); + Future flush(String event); + void subscribe(dynamic subscriber); + Future until(dynamic event, [dynamic payload]); + Future dispatch(dynamic event, [dynamic payload, bool halt]); + List getListeners(String eventName); + void forget(String event); + void forgetPushed(); + void setQueueResolver(Function resolver); + void setTransactionManagerResolver(Function resolver); + Map> getRawListeners(); +} + +// Helper class for EventBus subscribers +abstract class EventBusSubscriber { + void subscribe(EventBus eventBus); +} + +// Mixin to simulate Macroable trait +mixin Macroable { + // Implementation of Macroable functionality +} + +// Mixin to simulate ReflectsClosures trait +mixin ReflectsClosures { + // Implementation of ReflectsClosures functionality +} + +// If not already defined, you might need to create an Event class +class Event { + final String name; + final dynamic data; + + Event(this.name, this.data); +} + +// Custom AppEvent subclasses for handling different event types +class StringBasedEvent extends AppEvent { + final String eventName; + final dynamic payload; + + StringBasedEvent(this.eventName, this.payload); + + @override + List get props => [eventName, payload]; +} + +class CustomAppEvent extends AppEvent { + final String eventName; + final dynamic payload; + + CustomAppEvent(this.eventName, this.payload); + + @override + List get props => [eventName, payload]; +} + +// This is a simple implementation of Reflector that does nothing +class EmptyReflector implements Reflector { + const EmptyReflector(); + + @override + ReflectedType reflectType(Type type) { + throw UnimplementedError(); + } + + @override + ReflectedInstance reflectInstance(Object object) { + throw UnimplementedError(); + } + + @override + ReflectedType reflectFutureOf(Type type) { + throw UnimplementedError(); + } + + @override + String? getName(Symbol symbol) { + // TODO: implement getName + throw UnimplementedError(); + } + + @override + ReflectedClass? reflectClass(Type clazz) { + // TODO: implement reflectClass + throw UnimplementedError(); + } + + @override + ReflectedFunction? reflectFunction(Function function) { + // TODO: implement reflectFunction + throw UnimplementedError(); + } +} diff --git a/packages/events/pubspec.yaml b/packages/events/pubspec.yaml new file mode 100644 index 0000000..22bde60 --- /dev/null +++ b/packages/events/pubspec.yaml @@ -0,0 +1,21 @@ +name: platform_events +description: The Events Package for the Protevus Platform +version: 0.0.1 +homepage: https://protevus.com +documentation: https://docs.protevus.com +repository: https://github.com/protevus/platformo +environment: + sdk: ^3.4.2 + +# Add regular dependencies here. +dependencies: + platform_container: ^9.0.0 + angel3_mq: ^9.0.0 + angel3_event_bus: ^9.0.0 + platform_core: ^9.0.0 + angel3_reactivex: ^0.27.5 + # path: ^1.8.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/events/test/event_test.dart b/packages/events/test/event_test.dart new file mode 100644 index 0000000..72a75ab --- /dev/null +++ b/packages/events/test/event_test.dart @@ -0,0 +1,430 @@ +import 'package:angel3_event_bus/res/app_event.dart'; +import 'package:test/test.dart'; +import 'package:platform_container/container.dart'; +import 'package:angel3_mq/mq.dart'; +import 'package:platform_events/dispatcher.dart'; // Replace with the actual import path + +void main() { + late Dispatcher dispatcher; + late MockMQClient mockMQClient; + + setUp(() { + var container = Container(EmptyReflector()); + dispatcher = Dispatcher(container); + mockMQClient = MockMQClient(); + dispatcher.mqClient = mockMQClient; // Use the setter + + // Clear the queue before each test + mockMQClient.queuedMessages.clear(); + }); + + group('Dispatcher', () { + test('listen and dispatch', () async { + var callCount = 0; + dispatcher.listen('test_event', (dynamic event, dynamic payload) { + expect(event, equals('test_event')); + expect(payload, equals(['test_payload'])); + callCount++; + }); + await dispatcher.dispatch('test_event', ['test_payload']); + expect(callCount, equals(1)); + }); + + test('wildcard listener', () async { + var callCount = 0; + dispatcher.listen('test.*', (dynamic event, dynamic payload) { + expect(event, matches(RegExp(r'^test\.'))); + callCount++; + }); + + await dispatcher.dispatch('test.one', ['payload1']); + await dispatcher.dispatch('test.two', ['payload2']); + expect(callCount, equals(2)); + }); + + test('hasListeners', () { + dispatcher.listen('test_event', (dynamic event, dynamic payload) {}); + expect(dispatcher.hasListeners('test_event'), isTrue); + expect(dispatcher.hasListeners('non_existent_event'), isFalse); + }); + + test('until', () async { + // Test without pushing the event immediately + var futureResult = dispatcher.until('test_event'); + + // Use a small delay to ensure the until listener is set up + await Future.delayed(Duration(milliseconds: 10)); + + await dispatcher.dispatch('test_event', ['test_payload']); + var result = await futureResult; + expect(result, equals(['test_payload'])); + + // Test with pushing the event immediately + result = + await dispatcher.until('another_test_event', ['another_payload']); + expect(result, equals(['another_payload'])); + }, timeout: Timeout(Duration(seconds: 5))); // Add a reasonable timeout + + test('forget', () async { + var callCount = 0; + dispatcher.listen('test_event', (dynamic event, dynamic payload) { + callCount++; + }); + await dispatcher.dispatch('test_event'); + expect(callCount, equals(1)); + + dispatcher.forget('test_event'); + await dispatcher.dispatch('test_event'); + expect(callCount, equals(1)); // Should not increase + }); + + test('push and flush', () async { + print('Starting push and flush test'); + + // Push 4 messages + for (var i = 0; i < 4; i++) { + dispatcher.push('delayed_event', ['delayed_payload_$i']); + } + + // Verify that 4 messages were queued + expect(mockMQClient.queuedMessages['delayed_events_queue']?.length, + equals(4), + reason: 'Should have queued exactly 4 messages'); + + print( + 'Queued messages: ${mockMQClient.queuedMessages['delayed_events_queue']?.length}'); + + var callCount = 0; + var processedPayloads = []; + + // Remove any existing listeners + dispatcher.forget('delayed_event'); + + dispatcher.listen('delayed_event', (dynamic event, dynamic payload) { + print('Listener called with payload: $payload'); + expect(event, equals('delayed_event')); + expect(payload[0], startsWith('delayed_payload_')); + processedPayloads.add(payload[0]); + callCount++; + }); + + await dispatcher.flush('delayed_event'); + + print('After flush - Call count: $callCount'); + print('Processed payloads: $processedPayloads'); + + expect(callCount, equals(4), reason: 'Should process exactly 4 messages'); + expect(processedPayloads.toSet().length, equals(4), + reason: 'All payloads should be unique'); + + // Verify that all messages were removed from the queue + expect(mockMQClient.queuedMessages['delayed_events_queue']?.length, + equals(0), + reason: 'Queue should be empty after flush'); + + // Flush again to ensure no more messages are processed + await dispatcher.flush('delayed_event'); + expect(callCount, equals(4), + reason: 'Should still be 4 after second flush'); + }); + + test('shouldBroadcast', () async { + var broadcastEvent = BroadcastTestEvent(); + var callCount = 0; + + dispatcher.listen('BroadcastTestEvent', (dynamic event, dynamic payload) { + callCount++; + }); + + await dispatcher.dispatch(broadcastEvent); + expect(callCount, equals(1)); + }); + + test('shouldQueue', () async { + var queueEvent = QueueTestEvent(); + await dispatcher.dispatch(queueEvent); + expect(mockMQClient.queuedMessages['events_queue'], isNotEmpty); + expect(mockMQClient.queuedMessages['events_queue']!.first.payload, + containsPair('event', 'QueueTestEvent')); + }); + + test('forgetPushed removes only pushed events', () { + dispatcher.listen('event_pushed', (_, __) {}); + dispatcher.listen('normal_event', (_, __) {}); + + dispatcher.forgetPushed(); + + expect(dispatcher.hasListeners('event_pushed'), isFalse); + expect(dispatcher.hasListeners('normal_event'), isTrue); + }); + + test('setQueueResolver and setTransactionManagerResolver', () { + var queueResolverCalled = false; + var transactionManagerResolverCalled = false; + + dispatcher.setQueueResolver(() { + queueResolverCalled = true; + }); + + dispatcher.setTransactionManagerResolver(() { + transactionManagerResolverCalled = true; + }); + + // Trigger the resolvers + dispatcher.triggerQueueResolver(); + dispatcher.triggerTransactionManagerResolver(); + + expect(queueResolverCalled, isTrue); + expect(transactionManagerResolverCalled, isTrue); + }); + + test('getRawListeners returns unmodifiable map', () { + dispatcher.listen('test_event', (_, __) {}); + var rawListeners = dispatcher.getRawListeners(); + + expect(rawListeners, isA>>()); + expect(() => rawListeners['new_event'] = [], throwsUnsupportedError); + }); + + test('multiple listeners for same event', () async { + var callCount1 = 0; + var callCount2 = 0; + + dispatcher.listen('multi_event', (_, __) => callCount1++); + dispatcher.listen('multi_event', (_, __) => callCount2++); + + await dispatcher.dispatch('multi_event'); + + expect(callCount1, equals(1)); + expect(callCount2, equals(1)); + }); + }); +} + +abstract class MQClientWrapper { + Stream fetchQueue(String queueId); + void sendMessage({ + required Message message, + String? exchangeName, + String? routingKey, + }); + String declareQueue(String queueId); + void declareExchange({ + required String exchangeName, + required ExchangeType exchangeType, + }); + void bindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }); + void close(); +} + +class RealMQClientWrapper implements MQClientWrapper { + final MQClient _client; + + RealMQClientWrapper(this._client); + + @override + Stream fetchQueue(String queueId) => _client.fetchQueue(queueId); + + @override + void sendMessage({ + required Message message, + String? exchangeName, + String? routingKey, + }) => + _client.sendMessage( + message: message, + exchangeName: exchangeName, + routingKey: routingKey, + ); + + @override + String declareQueue(String queueId) => _client.declareQueue(queueId); + + @override + void declareExchange({ + required String exchangeName, + required ExchangeType exchangeType, + }) => + _client.declareExchange( + exchangeName: exchangeName, + exchangeType: exchangeType, + ); + + @override + void bindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }) => + _client.bindQueue( + queueId: queueId, + exchangeName: exchangeName, + bindingKey: bindingKey, + ); + + @override + void close() => _client.close(); +} + +class MockMQClient implements MQClient { + Map> queuedMessages = {}; + int _messageIdCounter = 0; + + void queueMessage(String queueName, Message message) { + queuedMessages.putIfAbsent(queueName, () => []).add(message); + print( + 'Queued message. Queue $queueName now has ${queuedMessages[queueName]?.length} messages'); + } + + @override + String declareQueue(String queueId) { + queuedMessages[queueId] = []; + return queueId; + } + + @override + void deleteQueue(String queueId) { + queuedMessages.remove(queueId); + } + + @override + Stream fetchQueue(String queueId) { + print('Fetching queue: $queueId'); + return Stream.fromIterable(queuedMessages[queueId] ?? []); + } + + @override + void sendMessage({ + required Message message, + String? exchangeName, + String? routingKey, + }) { + print('Sending message to queue: $routingKey'); + final newMessage = Message( + payload: message.payload, + headers: message.headers, + timestamp: message.timestamp, + id: 'msg_${_messageIdCounter++}', + ); + queueMessage(routingKey ?? '', newMessage); + } + + @override + Message? getLatestMessage(String queueId) { + final messages = queuedMessages[queueId]; + return messages?.isNotEmpty == true ? messages!.last : null; + } + + @override + void bindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }) { + // Implement if needed for your tests + } + + @override + void unbindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }) { + // Implement if needed for your tests + } + + @override + void declareExchange({ + required String exchangeName, + required ExchangeType exchangeType, + }) { + // Implement if needed for your tests + } + + @override + void deleteExchange(String exchangeName) { + // Implement if needed for your tests + } + + @override + List listQueues() { + return queuedMessages.keys.toList(); + } + + @override + void close() { + queuedMessages.clear(); + } + + @override + void deleteMessage(String queueId, Message message) { + print('Deleting message from queue: $queueId'); + queuedMessages[queueId]?.removeWhere((m) => m.id == message.id); + print( + 'After deletion, queue $queueId has ${queuedMessages[queueId]?.length} messages'); + } +} + +class BroadcastTestEvent implements AppEvent, ShouldBroadcast { + @override + List get props => []; + + @override + bool? get stringify => true; + + @override + DateTime get timestamp => DateTime.now(); +} + +class QueueTestEvent implements AppEvent, ShouldQueue { + @override + List get props => []; + + @override + bool? get stringify => true; + + @override + DateTime get timestamp => DateTime.now(); +} + +// This is a simple implementation of Reflector that does nothing +class EmptyReflector implements Reflector { + const EmptyReflector(); + + @override + ReflectedType reflectType(Type type) { + throw UnimplementedError(); + } + + @override + ReflectedInstance reflectInstance(Object object) { + throw UnimplementedError(); + } + + @override + ReflectedType reflectFutureOf(Type type) { + throw UnimplementedError(); + } + + @override + String? getName(Symbol symbol) { + // TODO: implement getName + throw UnimplementedError(); + } + + @override + ReflectedClass? reflectClass(Type clazz) { + // TODO: implement reflectClass + throw UnimplementedError(); + } + + @override + ReflectedFunction? reflectFunction(Function function) { + // TODO: implement reflectFunction + throw UnimplementedError(); + } +} diff --git a/packages/pipeline/.gitignore b/packages/pipeline/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/pipeline/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/pipeline/CHANGELOG.md b/packages/pipeline/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/pipeline/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/pipeline/LICENSE.md b/packages/pipeline/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/pipeline/LICENSE.md @@ -0,0 +1,10 @@ +The MIT License (MIT) + +The Laravel Framework is Copyright (c) Taylor Otwell +The Fabric Framework is Copyright (c) Vieo, Inc. + +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/packages/pipeline/README.md b/packages/pipeline/README.md new file mode 100644 index 0000000..586a156 --- /dev/null +++ b/packages/pipeline/README.md @@ -0,0 +1,380 @@ +

+ +# Platform Pipeline + +A Laravel-compatible pipeline implementation in Dart, providing a robust way to pass objects through a series of operations. + +[![Pub Version](https://img.shields.io/pub/v/platform_pipeline)]() +[![Build Status](https://img.shields.io/github/workflow/status/platform/pipeline/tests)]() + +## Table of Contents + +- [Overview](#overview) +- [Features](#features) +- [Requirements](#requirements) +- [Installation](#installation) +- [Usage](#usage) + - [Basic Usage](#basic-usage) + - [Class-Based Pipes](#class-based-pipes) + - [Invokable Classes](#invokable-classes) + - [Using Different Method Names](#using-different-method-names) + - [Passing Parameters to Pipes](#passing-parameters-to-pipes) + - [Early Pipeline Termination](#early-pipeline-termination) + - [Conditional Pipeline Execution](#conditional-pipeline-execution) +- [Advanced Usage](#advanced-usage) + - [Working with Objects](#working-with-objects) + - [Async Operations](#async-operations) +- [Laravel API Compatibility](#laravel-api-compatibility) +- [Comparison with Laravel](#comparison-with-laravel) +- [Troubleshooting](#troubleshooting) +- [Testing](#testing) +- [Contributing](#contributing) +- [License](#license) + +## Overview + +Platform Pipeline is a 100% API-compatible port of Laravel's Pipeline to Dart. It allows you to pass an object through a series of operations (pipes) in a fluent, maintainable way. Each pipe can examine, modify, or replace the object before passing it to the next pipe in the sequence. + +## Features + +- 💯 100% Laravel Pipeline API compatibility +- 🔄 Support for class-based and callable pipes +- 🎯 Dependency injection through container integration +- ⚡ Async operation support +- 🔀 Conditional pipeline execution +- 🎭 Method name customization via `via()` +- 🎁 Parameter passing to pipes +- 🛑 Early pipeline termination +- 🧪 Comprehensive test coverage + +## Requirements + +- Dart SDK: >=2.17.0 <4.0.0 +- platform_container: ^1.0.0 + +## Installation + +Add this to your package's `pubspec.yaml` file: + +```yaml +dependencies: + platform_pipeline: ^1.0.0 +``` + +## Usage + +### Basic Usage + +```dart +import 'package:platform_pipeline/pipeline.dart'; +import 'package:platform_container/container.dart'; + +void main() async { + // Create a container instance + var container = Container(); + + // Create a pipeline + var result = await Pipeline(container) + .send('Hello') + .through([ + (String value, next) => next(value + ' World'), + (String value, next) => next(value + '!'), + ]) + .then((value) => value); + + print(result); // Outputs: Hello World! +} +``` + +### Class-Based Pipes + +```dart +class UppercasePipe { + Future handle(String value, Function next) async { + return next(value.toUpperCase()); + } +} + +class AddExclamationPipe { + Future handle(String value, Function next) async { + return next(value + '!'); + } +} + +void main() async { + var container = Container(); + + var result = await Pipeline(container) + .send('hello') + .through([ + UppercasePipe(), + AddExclamationPipe(), + ]) + .then((value) => value); + + print(result); // Outputs: HELLO! +} +``` + +### Invokable Classes + +```dart +class TransformPipe { + Future call(String value, Function next) async { + return next(value.toUpperCase()); + } +} + +void main() async { + var container = Container(); + + var result = await Pipeline(container) + .send('hello') + .through([TransformPipe()]) + .then((value) => value); + + print(result); // Outputs: HELLO +} +``` + +### Using Different Method Names + +```dart +class CustomPipe { + Future transform(String value, Function next) async { + return next(value.toUpperCase()); + } +} + +void main() async { + var container = Container(); + + var result = await Pipeline(container) + .send('hello') + .through([CustomPipe()]) + .via('transform') + .then((value) => value); + + print(result); // Outputs: HELLO +} +``` + +### Passing Parameters to Pipes + +```dart +class PrefixPipe { + Future handle( + String value, + Function next, [ + String prefix = '', + ]) async { + return next('$prefix$value'); + } +} + +void main() async { + var container = Container(); + container.registerFactory((c) => PrefixPipe()); + + var pipeline = Pipeline(container); + pipeline.registerPipeType('PrefixPipe', PrefixPipe); + + var result = await pipeline + .send('World') + .through('PrefixPipe:Hello ') + .then((value) => value); + + print(result); // Outputs: Hello World +} +``` + +### Early Pipeline Termination + +```dart +void main() async { + var container = Container(); + + var result = await Pipeline(container) + .send('hello') + .through([ + (value, next) => 'TERMINATED', // Pipeline stops here + (value, next) => next('NEVER REACHED'), + ]) + .then((value) => value); + + print(result); // Outputs: TERMINATED +} +``` + +### Conditional Pipeline Execution + +```dart +void main() async { + var container = Container(); + var shouldTransform = true; + + var result = await Pipeline(container) + .send('hello') + .when(() => shouldTransform, (Pipeline pipeline) { + pipeline.pipe([ + (value, next) => next(value.toUpperCase()), + ]); + }) + .then((value) => value); + + print(result); // Outputs: HELLO +} +``` + +## Advanced Usage + +### Working with Objects + +```dart +class User { + String name; + int age; + + User(this.name, this.age); +} + +class AgeValidationPipe { + Future handle(User user, Function next) async { + if (user.age < 18) { + throw Exception('User must be 18 or older'); + } + return next(user); + } +} + +class NameFormattingPipe { + Future handle(User user, Function next) async { + user.name = user.name.trim().toLowerCase(); + return next(user); + } +} + +void main() async { + var container = Container(); + + var user = User('John Doe ', 20); + + try { + user = await Pipeline(container) + .send(user) + .through([ + AgeValidationPipe(), + NameFormattingPipe(), + ]) + .then((value) => value); + + print('${user.name} is ${user.age} years old'); + // Outputs: john doe is 20 years old + } catch (e) { + print('Validation failed: $e'); + } +} +``` + +### Async Operations + +```dart +class AsyncTransformPipe { + Future handle(String value, Function next) async { + // Simulate async operation + await Future.delayed(Duration(seconds: 1)); + return next(value.toUpperCase()); + } +} + +void main() async { + var container = Container(); + + var result = await Pipeline(container) + .send('hello') + .through([AsyncTransformPipe()]) + .then((value) => value); + + print(result); // Outputs after 1 second: HELLO +} +``` + +## Laravel API Compatibility + +This package maintains 100% API compatibility with Laravel's Pipeline implementation. All Laravel Pipeline features are supported: + +- `send()` - Set the object being passed through the pipeline +- `through()` - Set the array of pipes +- `pipe()` - Push additional pipes onto the pipeline +- `via()` - Set the method to call on the pipes +- `then()` - Run the pipeline with a final destination callback +- `thenReturn()` - Run the pipeline and return the result + +## Comparison with Laravel + +| Feature | Laravel | Platform Pipeline | +|---------|---------|------------------| +| API Methods | ✓ | ✓ | +| Container Integration | ✓ | ✓ | +| Pipe Types | Class, Callable | Class, Callable | +| Async Support | ✗ | ✓ | +| Type Safety | ✗ | ✓ | +| Parameter Passing | ✓ | ✓ | +| Early Termination | ✓ | ✓ | +| Method Customization | ✓ | ✓ | +| Conditional Execution | ✓ | ✓ | + +## Troubleshooting + +### Common Issues + +1. Container Not Provided +```dart +// ❌ Wrong +var pipeline = Pipeline(null); + +// ✓ Correct +var container = Container(); +var pipeline = Pipeline(container); +``` + +2. Missing Type Registration +```dart +// ❌ Wrong +pipeline.through('CustomPipe:param'); + +// ✓ Correct +pipeline.registerPipeType('CustomPipe', CustomPipe); +pipeline.through('CustomPipe:param'); +``` + +3. Incorrect Method Name +```dart +// ❌ Wrong +class CustomPipe { + void process(value, next) {} // Wrong method name +} + +// ✓ Correct +class CustomPipe { + void handle(value, next) {} // Default method name +} +// Or specify the method name: +pipeline.via('process').through([CustomPipe()]); +``` + +## Testing + +Run the tests with: + +```bash +dart test +``` + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +This package is open-sourced software licensed under the MIT license. diff --git a/packages/pipeline/analysis_options.yaml b/packages/pipeline/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/pipeline/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/pipeline/examples/async_pipeline.dart b/packages/pipeline/examples/async_pipeline.dart new file mode 100644 index 0000000..03f6dc1 --- /dev/null +++ b/packages/pipeline/examples/async_pipeline.dart @@ -0,0 +1,38 @@ +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_container/mirrors.dart'; +import 'package:platform_pipeline/pipeline.dart'; + +class AsyncGreetingPipe { + Future handle(String input, Function next) async { + await Future.delayed(Duration(seconds: 1)); + return next('Hello, $input'); + } +} + +class AsyncExclamationPipe { + Future handle(String input, Function next) async { + await Future.delayed(Duration(seconds: 1)); + return next('$input!'); + } +} + +void main() async { + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + app.container.registerSingleton((c) => Pipeline(c)); + + app.get('/', (req, res) async { + var pipeline = app.container.make(); + var result = await pipeline + .send('World') + .through(['AsyncGreetingPipe', 'AsyncExclamationPipe']).then( + (result) => result.toUpperCase()); + + res.write(result); // Outputs: "HELLO, WORLD!" (after 2 seconds) + }); + + await http.startServer('localhost', 3000); + print('Server started on http://localhost:3000'); +} diff --git a/packages/pipeline/examples/basic_usage.dart b/packages/pipeline/examples/basic_usage.dart new file mode 100644 index 0000000..736a354 --- /dev/null +++ b/packages/pipeline/examples/basic_usage.dart @@ -0,0 +1,36 @@ +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_container/mirrors.dart'; +import 'package:platform_pipeline/pipeline.dart'; + +class GreetingPipe { + dynamic handle(String input, Function next) { + return next('Hello, $input'); + } +} + +class ExclamationPipe { + dynamic handle(String input, Function next) { + return next('$input!'); + } +} + +void main() async { + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + app.container.registerSingleton((c) => Pipeline(c)); + + app.get('/', (req, res) async { + var pipeline = app.container.make(); + var result = await pipeline + .send('World') + .through(['GreetingPipe', 'ExclamationPipe']).then( + (result) => result.toUpperCase()); + + res.write(result); // Outputs: "HELLO, WORLD!" + }); + + await http.startServer('localhost', 3000); + print('Server started on http://localhost:3000'); +} diff --git a/packages/pipeline/examples/error_handling.dart b/packages/pipeline/examples/error_handling.dart new file mode 100644 index 0000000..6f8aa84 --- /dev/null +++ b/packages/pipeline/examples/error_handling.dart @@ -0,0 +1,34 @@ +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_container/mirrors.dart'; +import 'package:platform_pipeline/pipeline.dart'; + +class ErrorPipe { + dynamic handle(String input, Function next) { + throw Exception('Simulated error'); + } +} + +void main() async { + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + app.container.registerSingleton((c) => Pipeline(c)); + + app.get('/', (req, res) async { + var pipeline = app.container.make(); + try { + await pipeline + .send('World') + .through(['ErrorPipe']).then((result) => result.toUpperCase()); + } catch (e) { + res.write('Error occurred: ${e.toString()}'); + return; + } + + res.write('This should not be reached'); + }); + + await http.startServer('localhost', 3000); + print('Server started on http://localhost:3000'); +} diff --git a/packages/pipeline/examples/mixed_pipes.dart b/packages/pipeline/examples/mixed_pipes.dart new file mode 100644 index 0000000..0e17a71 --- /dev/null +++ b/packages/pipeline/examples/mixed_pipes.dart @@ -0,0 +1,35 @@ +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_container/mirrors.dart'; +import 'package:platform_pipeline/pipeline.dart'; + +class GreetingPipe { + dynamic handle(String input, Function next) { + return next('Hello, $input'); + } +} + +void main() async { + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + app.container.registerSingleton((c) => Pipeline(c)); + + app.get('/', (req, res) async { + var pipeline = app.container.make(); + var result = await pipeline.send('World').through([ + 'GreetingPipe', + (String input, Function next) => next('$input!'), + (String input, Function next) async { + await Future.delayed(Duration(seconds: 1)); + return next(input.toUpperCase()); + }, + ]).then((result) => 'Final result: $result'); + + res.write( + result); // Outputs: "Final result: HELLO, WORLD!" (after 1 second) + }); + + await http.startServer('localhost', 3000); + print('Server started on http://localhost:3000'); +} diff --git a/packages/pipeline/lib/pipeline.dart b/packages/pipeline/lib/pipeline.dart new file mode 100644 index 0000000..9b73f9f --- /dev/null +++ b/packages/pipeline/lib/pipeline.dart @@ -0,0 +1,5 @@ +library; + +export 'src/pipeline.dart'; +export 'src/conditionable.dart'; +export 'src/pipeline_contract.dart'; diff --git a/packages/pipeline/lib/src/conditionable.dart b/packages/pipeline/lib/src/conditionable.dart new file mode 100644 index 0000000..ce796a0 --- /dev/null +++ b/packages/pipeline/lib/src/conditionable.dart @@ -0,0 +1,16 @@ +/// Provides conditional execution methods for the pipeline. +mixin Conditionable { + T when(bool Function() callback, void Function(T) callback2) { + if (callback()) { + callback2(this as T); + } + return this as T; + } + + T unless(bool Function() callback, void Function(T) callback2) { + if (!callback()) { + callback2(this as T); + } + return this as T; + } +} diff --git a/packages/pipeline/lib/src/pipeline.dart b/packages/pipeline/lib/src/pipeline.dart new file mode 100644 index 0000000..37d9d68 --- /dev/null +++ b/packages/pipeline/lib/src/pipeline.dart @@ -0,0 +1,241 @@ +import 'dart:async'; +import 'dart:mirrors'; +import 'package:platform_container/container.dart'; +import 'package:logging/logging.dart'; +import 'pipeline_contract.dart'; +import 'conditionable.dart'; + +/// Defines the signature for a pipe function. +typedef PipeFunction = FutureOr Function( + dynamic passable, FutureOr Function(dynamic) next); + +/// The primary class for building and executing pipelines. +class Pipeline with Conditionable implements PipelineContract { + /// The container implementation. + Container? _container; + + final Map _typeMap = {}; + + /// The object being passed through the pipeline. + dynamic _passable; + + /// The array of class pipes. + final List _pipes = []; + + /// The method to call on each pipe. + String _method = 'handle'; + + /// Logger for the pipeline. + final Logger _logger = Logger('Pipeline'); + + /// Create a new class instance. + Pipeline(this._container); + + void registerPipeType(String name, Type type) { + _typeMap[name] = type; + } + + /// Set the object being sent through the pipeline. + @override + Pipeline send(dynamic passable) { + _passable = passable; + return this; + } + + /// Set the array of pipes. + @override + Pipeline through(dynamic pipes) { + if (_container == null) { + throw Exception( + 'A container instance has not been passed to the Pipeline.'); + } + _pipes.addAll(pipes is Iterable ? pipes.toList() : [pipes]); + return this; + } + + /// Push additional pipes onto the pipeline. + @override + Pipeline pipe(dynamic pipes) { + if (_container == null) { + throw Exception( + 'A container instance has not been passed to the Pipeline.'); + } + _pipes.addAll(pipes is Iterable ? pipes.toList() : [pipes]); + return this; + } + + /// Set the method to call on the pipes. + @override + Pipeline via(String method) { + _method = method; + return this; + } + + /// Run the pipeline with a final destination callback. + @override + Future then(FutureOr Function(dynamic) destination) async { + if (_container == null) { + throw Exception( + 'A container instance has not been passed to the Pipeline.'); + } + + var pipeline = (dynamic passable) async => await destination(passable); + + for (var pipe in _pipes.reversed) { + var next = pipeline; + pipeline = (dynamic passable) async { + return await carry(pipe, passable, next); + }; + } + + return await pipeline(_passable); + } + + /// Run the pipeline and return the result. + @override + Future thenReturn() async { + return then((passable) => passable); + } + + /// Get a Closure that represents a slice of the application onion. + Future carry(dynamic pipe, dynamic passable, Function next) async { + try { + if (pipe is Function) { + return await pipe(passable, next); + } + + if (pipe is String) { + if (_container == null) { + throw Exception('Container is null, cannot resolve pipe: $pipe'); + } + + final parts = parsePipeString(pipe); + final pipeClass = parts[0]; + final parameters = parts.length > 1 ? parts.sublist(1) : []; + + Type? pipeType; + if (_typeMap.containsKey(pipeClass)) { + pipeType = _typeMap[pipeClass]; + } else { + // Try to resolve from mirrors + try { + for (var lib in currentMirrorSystem().libraries.values) { + for (var decl in lib.declarations.values) { + if (decl is ClassMirror && + decl.simpleName == Symbol(pipeClass)) { + pipeType = decl.reflectedType; + break; + } + } + if (pipeType != null) break; + } + } catch (_) {} + + if (pipeType == null) { + throw Exception('Type not registered for pipe: $pipe'); + } + } + + var instance = _container?.make(pipeType); + if (instance == null) { + throw Exception('Unable to resolve pipe: $pipe'); + } + + return await invokeMethod( + instance, _method, [passable, next, ...parameters]); + } + + if (pipe is Type) { + if (_container == null) { + throw Exception('Container is null, cannot resolve pipe type'); + } + + var instance = _container?.make(pipe); + if (instance == null) { + throw Exception('Unable to resolve pipe type: $pipe'); + } + + return await invokeMethod(instance, _method, [passable, next]); + } + + // Handle instance of a class + if (pipe is Object) { + return await invokeMethod(pipe, _method, [passable, next]); + } + + throw Exception('Unsupported pipe type: ${pipe.runtimeType}'); + } catch (e) { + return handleException(passable, e); + } + } + + /// Parse full pipe string to get name and parameters. + List parsePipeString(String pipe) { + var parts = pipe.split(':'); + return [parts[0], if (parts.length > 1) ...parts[1].split(',')]; + } + + /// Get the array of configured pipes. + List pipes() { + return List.unmodifiable(_pipes); + } + + /// Get the container instance. + Container getContainer() { + if (_container == null) { + throw Exception( + 'A container instance has not been passed to the Pipeline.'); + } + return _container!; + } + + /// Set the container instance. + Pipeline setContainer(Container container) { + _container = container; + return this; + } + + /// Handle the value returned from each pipe before passing it to the next. + dynamic handleCarry(dynamic carry) { + if (carry is Future) { + return carry.then((value) => value ?? _passable); + } + return carry ?? _passable; + } + + Future invokeMethod( + dynamic instance, String methodName, List arguments) async { + // First try call() for invokable objects + if (instance is Function) { + return await instance(arguments[0], arguments[1]); + } + + var instanceMirror = reflect(instance); + + // Check for call method first (invokable objects) + var callSymbol = Symbol('call'); + if (instanceMirror.type.declarations.containsKey(callSymbol)) { + var result = instanceMirror.invoke(callSymbol, arguments); + return await result.reflectee; + } + + // Then try the specified method + var methodSymbol = Symbol(methodName); + if (!instanceMirror.type.declarations.containsKey(methodSymbol)) { + throw Exception('Method $methodName not found on instance: $instance'); + } + + var result = instanceMirror.invoke(methodSymbol, arguments); + return await result.reflectee; + } + + /// Handle the given exception. + dynamic handleException(dynamic passable, Object e) { + if (e is Exception && e.toString().contains('Container is null')) { + throw Exception( + 'A container instance has not been passed to the Pipeline.'); + } + _logger.severe('Exception occurred in pipeline', e); + throw e; + } +} diff --git a/packages/pipeline/lib/src/pipeline_contract.dart b/packages/pipeline/lib/src/pipeline_contract.dart new file mode 100644 index 0000000..2b45e7f --- /dev/null +++ b/packages/pipeline/lib/src/pipeline_contract.dart @@ -0,0 +1,9 @@ +/// Represents a series of "pipes" through which an object can be passed. +abstract class PipelineContract { + PipelineContract send(dynamic passable); + PipelineContract through(dynamic pipes); + PipelineContract pipe(dynamic pipes); + PipelineContract via(String method); + Future then(dynamic Function(dynamic) destination); + Future thenReturn(); +} diff --git a/packages/pipeline/pubspec.yaml b/packages/pipeline/pubspec.yaml new file mode 100644 index 0000000..92c1efb --- /dev/null +++ b/packages/pipeline/pubspec.yaml @@ -0,0 +1,19 @@ +name: platform_pipeline +description: The Pipeline Package for the Protevus Platform +version: 0.0.1 +homepage: https://protevus.com +documentation: https://docs.protevus.com +repository: https://github.com/protevus/platform + +environment: + sdk: ^3.4.2 + +# Add regular dependencies here. +dependencies: + platform_container: ^9.0.0 + platform_core: ^9.0.0 + logging: ^1.1.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/pipeline/test/laravel_pipeline_test.dart b/packages/pipeline/test/laravel_pipeline_test.dart new file mode 100644 index 0000000..0fcdeaa --- /dev/null +++ b/packages/pipeline/test/laravel_pipeline_test.dart @@ -0,0 +1,258 @@ +import 'package:platform_container/container.dart'; +import 'package:platform_pipeline/pipeline.dart'; +import 'package:test/test.dart'; + +// Test pipe classes to match Laravel's test classes +class PipelineTestPipeOne { + static String? testPipeOne; + + Future handle(dynamic piped, Function next) async { + testPipeOne = piped.toString(); + return next(piped); + } + + Future differentMethod(dynamic piped, Function next) async { + return next(piped); + } +} + +class PipelineTestPipeTwo { + static String? testPipeOne; + + Future call(dynamic piped, Function next) async { + testPipeOne = piped.toString(); + return next(piped); + } +} + +class PipelineTestParameterPipe { + static List? testParameters; + + Future handle(dynamic piped, Function next, + [String? parameter1, String? parameter2]) async { + testParameters = [ + if (parameter1 != null) parameter1, + if (parameter2 != null) parameter2 + ]; + return next(piped); + } +} + +void main() { + group('Laravel Pipeline Tests', () { + late Container container; + late Pipeline pipeline; + + setUp(() { + container = Container(const EmptyReflector()); + pipeline = Pipeline(container); + + // Register test classes with container + container + .registerFactory((c) => PipelineTestPipeOne()); + container + .registerFactory((c) => PipelineTestPipeTwo()); + container.registerFactory( + (c) => PipelineTestParameterPipe()); + + // Register types with pipeline + pipeline.registerPipeType('PipelineTestPipeOne', PipelineTestPipeOne); + pipeline.registerPipeType('PipelineTestPipeTwo', PipelineTestPipeTwo); + pipeline.registerPipeType( + 'PipelineTestParameterPipe', PipelineTestParameterPipe); + + // Reset static test variables + PipelineTestPipeOne.testPipeOne = null; + PipelineTestPipeTwo.testPipeOne = null; + PipelineTestParameterPipe.testParameters = null; + }); + + test('Pipeline basic usage', () async { + String? testPipeTwo; + final pipeTwo = (dynamic piped, Function next) { + testPipeTwo = piped.toString(); + return next(piped); + }; + + final result = await Pipeline(container) + .send('foo') + .through([PipelineTestPipeOne(), pipeTwo]).then((piped) => piped); + + expect(result, equals('foo')); + expect(PipelineTestPipeOne.testPipeOne, equals('foo')); + expect(testPipeTwo, equals('foo')); + }); + + test('Pipeline usage with objects', () async { + final result = await Pipeline(container) + .send('foo') + .through([PipelineTestPipeOne()]).then((piped) => piped); + + expect(result, equals('foo')); + expect(PipelineTestPipeOne.testPipeOne, equals('foo')); + }); + + test('Pipeline usage with invokable objects', () async { + final result = await Pipeline(container) + .send('foo') + .through([PipelineTestPipeTwo()]).then((piped) => piped); + + expect(result, equals('foo')); + expect(PipelineTestPipeTwo.testPipeOne, equals('foo')); + }); + + test('Pipeline usage with callable', () async { + String? testPipeOne; + final function = (dynamic piped, Function next) { + testPipeOne = 'foo'; + return next(piped); + }; + + var result = await Pipeline(container) + .send('foo') + .through([function]).then((piped) => piped); + + expect(result, equals('foo')); + expect(testPipeOne, equals('foo')); + + testPipeOne = null; + + result = + await Pipeline(container).send('bar').through(function).thenReturn(); + + expect(result, equals('bar')); + expect(testPipeOne, equals('foo')); + }); + + test('Pipeline usage with pipe', () async { + final object = {'value': 0}; + + final function = (dynamic obj, Function next) { + obj['value']++; + return next(obj); + }; + + final result = await Pipeline(container) + .send(object) + .through([function]).pipe([function]).then((piped) => piped); + + expect(result, equals(object)); + expect(object['value'], equals(2)); + }); + + test('Pipeline usage with invokable class', () async { + final result = await Pipeline(container) + .send('foo') + .through([PipelineTestPipeTwo()]).then((piped) => piped); + + expect(result, equals('foo')); + expect(PipelineTestPipeTwo.testPipeOne, equals('foo')); + }); + + test('Then method is not called if the pipe returns', () async { + String thenValue = '(*_*)'; + String secondValue = '(*_*)'; + + final result = await Pipeline(container).send('foo').through([ + (value, next) => 'm(-_-)m', + (value, next) { + secondValue = 'm(-_-)m'; + return next(value); + }, + ]).then((piped) { + thenValue = '(0_0)'; + return piped; + }); + + expect(result, equals('m(-_-)m')); + // The then callback is not called + expect(thenValue, equals('(*_*)')); + // The second pipe is not called + expect(secondValue, equals('(*_*)')); + }); + + test('Then method input value', () async { + String? pipeReturn; + String? thenArg; + + final result = await Pipeline(container).send('foo').through([ + (value, next) async { + final nextValue = await next('::not_foo::'); + pipeReturn = nextValue; + return 'pipe::$nextValue'; + } + ]).then((piped) { + thenArg = piped; + return 'then$piped'; + }); + + expect(result, equals('pipe::then::not_foo::')); + expect(thenArg, equals('::not_foo::')); + }); + + test('Pipeline usage with parameters', () async { + final parameters = ['one', 'two']; + + final result = await Pipeline(container) + .send('foo') + .through('PipelineTestParameterPipe:${parameters.join(',')}') + .then((piped) => piped); + + expect(result, equals('foo')); + expect(PipelineTestParameterPipe.testParameters, equals(parameters)); + }); + + test('Pipeline via changes the method being called on the pipes', () async { + final result = await Pipeline(container) + .send('data') + .through(PipelineTestPipeOne()) + .via('differentMethod') + .then((piped) => piped); + + expect(result, equals('data')); + }); + + test('Pipeline throws exception on resolve without container', () async { + expect( + () => Pipeline(null) + .send('data') + .through(PipelineTestPipeOne()) + .then((piped) => piped), + throwsA(isA().having( + (e) => e.toString(), + 'message', + contains( + 'A container instance has not been passed to the Pipeline')))); + }); + + test('Pipeline thenReturn method runs pipeline then returns passable', + () async { + final result = await Pipeline(container) + .send('foo') + .through([PipelineTestPipeOne()]).thenReturn(); + + expect(result, equals('foo')); + expect(PipelineTestPipeOne.testPipeOne, equals('foo')); + }); + + test('Pipeline conditionable', () async { + var result = await Pipeline(container).send('foo').when(() => true, + (Pipeline pipeline) { + pipeline.pipe([PipelineTestPipeOne()]); + }).then((piped) => piped); + + expect(result, equals('foo')); + expect(PipelineTestPipeOne.testPipeOne, equals('foo')); + + PipelineTestPipeOne.testPipeOne = null; + + result = await Pipeline(container).send('foo').when(() => false, + (Pipeline pipeline) { + pipeline.pipe([PipelineTestPipeOne()]); + }).then((piped) => piped); + + expect(result, equals('foo')); + expect(PipelineTestPipeOne.testPipeOne, isNull); + }); + }); +} diff --git a/packages/pipeline/test/pipeline_test.dart b/packages/pipeline/test/pipeline_test.dart new file mode 100644 index 0000000..ae67501 --- /dev/null +++ b/packages/pipeline/test/pipeline_test.dart @@ -0,0 +1,106 @@ +import 'package:test/test.dart'; +import 'package:platform_core/core.dart'; +import 'package:platform_container/container.dart'; +import 'package:platform_container/mirrors.dart'; +import 'package:platform_pipeline/pipeline.dart'; + +class AddExclamationPipe { + Future handle(String input, Function next) async { + return await next('$input!'); + } +} + +class UppercasePipe { + Future handle(String input, Function next) async { + return await next(input.toUpperCase()); + } +} + +void main() { + late Application app; + late Container container; + late Pipeline pipeline; + + setUp(() { + app = Application(reflector: MirrorsReflector()); + container = app.container; + container.registerSingleton(AddExclamationPipe()); + container.registerSingleton(UppercasePipe()); + pipeline = Pipeline(container); + pipeline.registerPipeType('AddExclamationPipe', AddExclamationPipe); + pipeline.registerPipeType('UppercasePipe', UppercasePipe); + }); + + test('Pipeline should process simple string pipes', () async { + var result = await pipeline.send('hello').through( + ['AddExclamationPipe', 'UppercasePipe']).then((res) async => res); + expect(result, equals('HELLO!')); + }); + + test('Pipeline should process function pipes', () async { + var result = await pipeline.send('hello').through([ + (String input, Function next) async { + var result = await next('$input, WORLD'); + return result; + }, + (String input, Function next) async { + var result = await next(input.toUpperCase()); + return result; + }, + ]).then((res) async => res as String); + + expect(result, equals('HELLO, WORLD')); + }); + + test('Pipeline should handle mixed pipe types', () async { + var result = await pipeline.send('hello').through([ + 'AddExclamationPipe', + (String input, Function next) async { + var result = await next(input.toUpperCase()); + return result; + }, + ]).then((res) async => res as String); + expect(result, equals('HELLO!')); + }); + + test('Pipeline should handle async pipes', () async { + var result = await pipeline.send('hello').through([ + 'UppercasePipe', + (String input, Function next) async { + await Future.delayed(Duration(milliseconds: 100)); + return next('$input, WORLD'); + }, + ]).then((res) async => res as String); + expect(result, equals('HELLO, WORLD')); + }); + + test('Pipeline should throw exception for unresolvable pipe', () { + expect( + () => pipeline + .send('hello') + .through(['NonExistentPipe']).then((res) => res), + throwsA(isA()), + ); + }); + + test('Pipeline should allow chaining of pipes', () async { + var result = await pipeline + .send('hello') + .pipe('AddExclamationPipe') + .pipe('UppercasePipe') + .then((res) async => res as String); + expect(result, equals('HELLO!')); + }); + + test('Pipeline should respect the order of pipes', () async { + var result1 = await pipeline + .send('hello') + .through(['AddExclamationPipe', 'UppercasePipe']).then((res) => res); + var result2 = await pipeline + .send('hello') + .through(['UppercasePipe', 'AddExclamationPipe']).then((res) => res); + expect(result1, equals('HELLO!')); + expect(result2, equals('HELLO!!')); + expect(result1, isNot(equals(result2))); + }); +} diff --git a/packages/process/.gitignore b/packages/process/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/process/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/process/CHANGELOG.md b/packages/process/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/process/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/process/LICENSE.md b/packages/process/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/process/LICENSE.md @@ -0,0 +1,10 @@ +The MIT License (MIT) + +The Laravel Framework is Copyright (c) Taylor Otwell +The Fabric Framework is Copyright (c) Vieo, Inc. + +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/packages/process/README.md b/packages/process/README.md new file mode 100644 index 0000000..757f4c9 --- /dev/null +++ b/packages/process/README.md @@ -0,0 +1 @@ +

\ No newline at end of file diff --git a/packages/process/analysis_options.yaml b/packages/process/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/process/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/process/examples/basic_process/main.dart b/packages/process/examples/basic_process/main.dart new file mode 100644 index 0000000..8415927 --- /dev/null +++ b/packages/process/examples/basic_process/main.dart @@ -0,0 +1,36 @@ +// examples/basic_process/main.dart +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_process/angel3_process.dart'; +import 'package:logging/logging.dart'; +import 'package:platform_container/mirrors.dart'; + +void main() async { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((record) { + print('${record.level.name}: ${record.time}: ${record.message}'); + }); + + // Create an Angel application with MirrorsReflector + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + // Use dependency injection for ProcessManager + app.container.registerSingleton(ProcessManager()); + + app.get('/', (req, res) async { + // Use the ioc function to get the ProcessManager instance + var processManager = await req.container?.make(); + + var process = await processManager?.start( + 'example_process', + 'echo', + ['Hello, Angel3 Process!'], + ); + var result = await process?.run(); + res.writeln('Process output: ${result?.output.trim()}'); + }); + + await http.startServer('localhost', 3000); + print('Server listening at http://localhost:3000'); +} diff --git a/packages/process/examples/process_pipeline/main.dart b/packages/process/examples/process_pipeline/main.dart new file mode 100644 index 0000000..7950162 --- /dev/null +++ b/packages/process/examples/process_pipeline/main.dart @@ -0,0 +1,37 @@ +// examples/process_pipeline/main.dart +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_process/angel3_process.dart'; +import 'package:logging/logging.dart'; +import 'package:platform_container/mirrors.dart'; + +void main() async { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((record) { + print('${record.level.name}: ${record.time}: ${record.message}'); + }); + + // Create an Angel application with MirrorsReflector + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + // Register ProcessManager as a singleton in the container + app.container.registerSingleton(ProcessManager()); + + app.get('/', (req, res) async { + // Use dependency injection to get the ProcessManager instance + var processManager = await req.container?.make(); + + var processes = [ + angel3Process('echo', ['Hello']), + angel3Process('sed', ['s/Hello/Greetings/']), + angel3Process('tr', ['[:lower:]', '[:upper:]']), + ]; + + var result = await processManager?.pipeline(processes); + res.writeln('Pipeline output: ${result?.output.trim()}'); + }); + + await http.startServer('localhost', 3000); + print('Server listening at http://localhost:3000'); +} diff --git a/packages/process/examples/process_pool/main.dart b/packages/process/examples/process_pool/main.dart new file mode 100644 index 0000000..f8f21e4 --- /dev/null +++ b/packages/process/examples/process_pool/main.dart @@ -0,0 +1,37 @@ +// examples/process_pool/main.dart +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_process/angel3_process.dart'; +import 'package:logging/logging.dart'; +import 'package:platform_container/mirrors.dart'; + +void main() async { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((record) { + print('${record.level.name}: ${record.time}: ${record.message}'); + }); + + // Create an Angel application with MirrorsReflector + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + // Register ProcessManager as a singleton in the container + app.container.registerSingleton(ProcessManager()); + + app.get('/', (req, res) async { + // Use dependency injection to get the ProcessManager instance + var processManager = await req.container?.make(); + + var processes = + List.generate(5, (index) => angel3Process('echo', ['Process $index'])); + var results = await processManager?.pool(processes, concurrency: 3); + var output = results + ?.map((result) => + '${result.process.command} output: ${result.output.trim()}') + .join('\n'); + res.write(output); + }); + + await http.startServer('localhost', 3000); + print('Server listening at http://localhost:3000'); +} diff --git a/packages/process/examples/web_server_with_processes/main.dart b/packages/process/examples/web_server_with_processes/main.dart new file mode 100644 index 0000000..1559db1 --- /dev/null +++ b/packages/process/examples/web_server_with_processes/main.dart @@ -0,0 +1,67 @@ +// examples/web_server_with_processes/main.dart +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_process/angel3_process.dart'; +import 'package:file/local.dart'; +import 'package:logging/logging.dart'; +import 'package:angel3_mustache/angel3_mustache.dart'; +import 'package:platform_container/mirrors.dart'; + +void main() async { + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((record) { + print('${record.level.name}: ${record.time}: ${record.message}'); + }); + + // Create an Angel application with MirrorsReflector + var app = Application(reflector: MirrorsReflector()); + var http = PlatformHttp(app); + + // Register dependencies in the container + app.container.registerSingleton(const LocalFileSystem()); + app.container.registerSingleton(ProcessManager()); + + // Set up the view renderer + var fs = await app.container.make(); + var viewsDirectory = fs.directory('views'); + //await app.configure(mustache(viewsDirectory)); + + app.get('/', (req, res) async { + await res.render('index'); + }); + + app.post('/run-process', (req, res) async { + var body = await req.bodyAsMap; + var command = body['command'] as String?; + var args = (body['args'] as String?)?.split(' ') ?? []; + + if (command == null || command.isEmpty) { + throw PlatformHttpException.badRequest(message: 'Command is required'); + } + + // Use dependency injection to get the ProcessManager instance + var processManager = await req.container?.make(); + + var process = await processManager?.start( + 'user_process', + command, + args, + ); + var result = await process?.run(); + + await res.json({ + 'output': result?.output.trim(), + 'exitCode': result?.exitCode, + }); + }); + + app.fallback((req, res) => throw PlatformHttpException.notFound()); + + app.errorHandler = (e, req, res) { + res.writeln('Error: ${e.message}'); + return false; + }; + + await http.startServer('localhost', 3000); + print('Server listening at http://localhost:3000'); +} diff --git a/packages/process/examples/web_server_with_processes/views/index.mustache b/packages/process/examples/web_server_with_processes/views/index.mustache new file mode 100644 index 0000000..cb29244 --- /dev/null +++ b/packages/process/examples/web_server_with_processes/views/index.mustache @@ -0,0 +1,39 @@ + + + + + + + Angel3 Process Example + + +

Run a Process

+
+ + +
+ + +
+ +
+
+ + + + diff --git a/packages/process/lib/angel3_process.dart b/packages/process/lib/angel3_process.dart new file mode 100644 index 0000000..1965d4a --- /dev/null +++ b/packages/process/lib/angel3_process.dart @@ -0,0 +1,7 @@ +library; + +export 'src/process.dart'; +export 'src/process_helper.dart'; +export 'src/process_manager.dart'; +export 'src/process_pipeline.dart'; +export 'src/process_pool.dart'; diff --git a/packages/process/lib/src/process.dart b/packages/process/lib/src/process.dart new file mode 100644 index 0000000..4049683 --- /dev/null +++ b/packages/process/lib/src/process.dart @@ -0,0 +1,250 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:convert'; + +// import 'package:angel3_framework/angel3_framework.dart'; +// import 'package:angel3_mq/mq.dart'; +// import 'package:angel3_reactivex/angel3_reactivex.dart'; +// import 'package:angel3_event_bus/event_bus.dart'; +import 'package:logging/logging.dart'; + +class Angel3Process { + final String _command; + final List _arguments; + final String? _workingDirectory; + final Map? _environment; + final Duration? _timeout; + final bool _tty; + final bool _enableReadError; + final Logger _logger; + + late final StreamController> _outputController; + late final StreamController> _errorController; + late final Completer _outputCompleter; + late final Completer _errorCompleter; + final Completer _errorOutputCompleter = Completer(); + bool _isOutputComplete = false; + bool _isErrorComplete = false; + + Process? _process; + DateTime? _startTime; + DateTime? _endTime; + bool _isDisposed = false; + + Angel3Process( + this._command, + this._arguments, { + String? workingDirectory, + Map? environment, + Duration? timeout, + bool tty = false, + bool enableReadError = true, + Logger? logger, + }) : _workingDirectory = workingDirectory, + _environment = environment, + _timeout = timeout, + _tty = tty, + _enableReadError = enableReadError, + _logger = logger ?? Logger('Angel3Process'), + _outputController = StreamController>.broadcast(), + _errorController = StreamController>.broadcast(), + _outputCompleter = Completer(), + _errorCompleter = Completer(); + + // Add this public getter + String get command => _command; + int? get pid => _process?.pid; + DateTime? get startTime => _startTime; + DateTime? get endTime => _endTime; + + Stream> get output => _outputController.stream; + Stream> get errorOutput => _errorController.stream; + + // Future get outputAsString => _outputCompleter.future; + // Future get errorOutputAsString => _errorCompleter.future; + + Future get exitCode => _process?.exitCode ?? Future.value(-1); + bool get isRunning => _process != null && !_process!.kill(); + + Future start() async { + if (_isDisposed) { + throw StateError('This process has been disposed and cannot be reused.'); + } + _startTime = DateTime.now(); + + try { + _process = await Process.start( + _command, + _arguments, + workingDirectory: _workingDirectory, + environment: _environment, + runInShell: _tty, + ); + + _process!.stdout.listen( + (data) { + _outputController.add(data); + }, + onDone: () { + if (!_isOutputComplete) { + _isOutputComplete = true; + _outputController.close(); + } + }, + onError: (error) { + _logger.severe('Error in stdout stream', error); + _outputController.addError(error); + if (!_isOutputComplete) { + _isOutputComplete = true; + _outputController.close(); + } + }, + ); + + var errorBuffer = StringBuffer(); + _process!.stderr.listen( + (data) { + _errorController.add(data); + errorBuffer.write(utf8.decode(data)); + }, + onDone: () { + if (!_isErrorComplete) { + _isErrorComplete = true; + _errorController.close(); + _errorOutputCompleter.complete(errorBuffer.toString()); + } + }, + onError: (error) { + _logger.severe('Error in stderr stream', error); + _errorController.addError(error); + if (!_isErrorComplete) { + _isErrorComplete = true; + _errorController.close(); + _errorOutputCompleter.completeError(error); + } + }, + ); + + _logger.info('Process started: $_command ${_arguments.join(' ')}'); + } catch (e) { + _logger.severe('Failed to start process', e); + rethrow; + } + return this; + } + + Future run() async { + await start(); + if (_timeout != null) { + return await runWithTimeout(_timeout!); + } + final exitCode = await this.exitCode; + final output = await outputAsString; + final errorOutput = await _errorOutputCompleter.future; + _endTime = DateTime.now(); + return ProcessResult(pid!, exitCode, output, errorOutput); + } + + Future runWithTimeout(Duration timeout) async { + final exitCodeFuture = this.exitCode.timeout(timeout, onTimeout: () { + kill(); + throw TimeoutException('Process timed out', timeout); + }); + + try { + final exitCode = await exitCodeFuture; + final output = await outputAsString; + final errorOutput = await _errorOutputCompleter.future; + _endTime = DateTime.now(); + return ProcessResult(pid!, exitCode, output, errorOutput); + } catch (e) { + if (e is TimeoutException) { + throw e; + } + rethrow; + } + } + + Future write(String input) async { + if (_process != null) { + _process!.stdin.write(input); + await _process!.stdin.flush(); + } else { + throw StateError('Process has not been started'); + } + } + + Future writeLines(List lines) async { + for (final line in lines) { + await write('$line\n'); + } + } + + Future kill({ProcessSignal signal = ProcessSignal.sigterm}) async { + if (_process != null) { + _logger.info('Killing process with signal: ${signal.name}'); + final result = _process!.kill(signal); + if (!result) { + _logger.warning('Failed to kill process with signal: ${signal.name}'); + } + } + } + + bool sendSignal(ProcessSignal signal) { + return _process?.kill(signal) ?? false; + } + + Future dispose() async { + if (!_isDisposed) { + _isDisposed = true; + await _outputController.close(); + await _errorController.close(); + if (!_outputCompleter.isCompleted) { + _outputCompleter.complete(''); + } + if (!_errorCompleter.isCompleted) { + _errorCompleter.complete(''); + } + await kill(); + _logger.info('Process disposed: $_command ${_arguments.join(' ')}'); + } + } + + Future get outputAsString async { + var buffer = await output.transform(utf8.decoder).join(); + return buffer; + } + + Future get errorOutputAsString => _errorOutputCompleter.future; +} + +class ProcessResult { + final int pid; + final int exitCode; + final String output; + final String errorOutput; + + ProcessResult(this.pid, this.exitCode, this.output, this.errorOutput); + + @override + String toString() { + return 'ProcessResult(pid: $pid, exitCode: $exitCode, output: ${output.length} chars, errorOutput: ${errorOutput.length} chars)'; + } +} + +class InvokedProcess { + final Angel3Process process; + final DateTime startTime; + final DateTime endTime; + final int exitCode; + final String output; + final String errorOutput; + + InvokedProcess(this.process, this.startTime, this.endTime, this.exitCode, + this.output, this.errorOutput); + + @override + String toString() { + return 'InvokedProcess(command: ${process._command}, arguments: ${process._arguments}, startTime: $startTime, endTime: $endTime, exitCode: $exitCode)'; + } +} diff --git a/packages/process/lib/src/process_helper.dart b/packages/process/lib/src/process_helper.dart new file mode 100644 index 0000000..5166698 --- /dev/null +++ b/packages/process/lib/src/process_helper.dart @@ -0,0 +1,21 @@ +import 'process.dart'; + +Angel3Process angel3Process( + String command, + List arguments, { + String? workingDirectory, + Map? environment, + Duration? timeout, + bool tty = false, + bool enableReadError = true, +}) { + return Angel3Process( + command, + arguments, + workingDirectory: workingDirectory, + environment: environment, + timeout: timeout, + tty: tty, + enableReadError: enableReadError, + ); +} diff --git a/packages/process/lib/src/process_manager.dart b/packages/process/lib/src/process_manager.dart new file mode 100644 index 0000000..f2d48b6 --- /dev/null +++ b/packages/process/lib/src/process_manager.dart @@ -0,0 +1,148 @@ +import 'dart:async'; +import 'dart:io'; + +// import 'package:angel3_framework/angel3_framework.dart'; +// import 'package:angel3_mq/mq.dart'; +// import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:logging/logging.dart'; + +import 'process.dart'; +import 'process_pool.dart'; +import 'process_pipeline.dart'; + +class ProcessManager { + final Map _processes = {}; + final EventBus _eventBus = EventBus(); + final List _subscriptions = []; + final Logger _logger = Logger('ProcessManager'); + + Future start( + String id, + String command, + List arguments, { + String? workingDirectory, + Map? environment, + Duration? timeout, + bool tty = false, + bool enableReadError = true, + }) async { + if (_processes.containsKey(id)) { + throw Exception('Process with id $id already exists'); + } + + final process = Angel3Process( + command, + arguments, + workingDirectory: workingDirectory, + environment: environment, + timeout: timeout, + tty: tty, + enableReadError: enableReadError, + logger: Logger('Angel3Process:$id'), + ); + + try { + await process.start(); + _processes[id] = process; + + _eventBus.fire(ProcessStartedEvent(id, process) as AppEvent); + + process.exitCode.then((exitCode) { + _eventBus.fire(ProcessExitedEvent(id, exitCode) as AppEvent); + _processes.remove(id); + }); + + _logger.info('Started process with id: $id'); + return process; + } catch (e) { + _logger.severe('Failed to start process with id: $id', e); + rethrow; + } + } + + Angel3Process? get(String id) => _processes[id]; + + Future kill(String id, + {ProcessSignal signal = ProcessSignal.sigterm}) async { + final process = _processes[id]; + if (process != null) { + await process.kill(signal: signal); + _processes.remove(id); + _logger.info('Killed process with id: $id'); + } else { + _logger.warning('Attempted to kill non-existent process with id: $id'); + } + } + + Future killAll({ProcessSignal signal = ProcessSignal.sigterm}) async { + _logger.info('Killing all processes'); + await Future.wait( + _processes.values.map((process) => process.kill(signal: signal))); + _processes.clear(); + } + + Stream get events => _eventBus.on(); + + Future> pool(List processes, + {int concurrency = 5}) async { + _logger.info('Running process pool with concurrency: $concurrency'); + final pool = ProcessPool(concurrency: concurrency); + return await pool.run(processes); + } + + Future pipeline(List processes) async { + _logger.info('Running process pipeline'); + final pipeline = ProcessPipeline(processes); + return await pipeline.run(); + } + + void dispose() { + _logger.info('Disposing ProcessManager'); + + // Cancel all event subscriptions + for (var subscription in _subscriptions) { + subscription.cancel(); + } + _subscriptions.clear(); + + // Dispose all processes + for (var process in _processes.values) { + process.dispose(); + } + _processes.clear(); + + _logger.info('ProcessManager disposed'); + } +} + +abstract class ProcessEvent extends AppEvent {} + +class ProcessStartedEvent extends ProcessEvent { + final String id; + final Angel3Process process; + + ProcessStartedEvent(this.id, this.process); + + @override + String toString() => + 'ProcessStartedEvent(id: $id, command: ${process.command})'; + + @override + // TODO: implement props + List get props => throw UnimplementedError(); +} + +class ProcessExitedEvent extends ProcessEvent { + final String id; + final int exitCode; + + ProcessExitedEvent(this.id, this.exitCode); + + @override + String toString() => 'ProcessExitedEvent(id: $id, exitCode: $exitCode)'; + + @override + // TODO: implement props + List get props => throw UnimplementedError(); +} diff --git a/packages/process/lib/src/process_pipeline.dart b/packages/process/lib/src/process_pipeline.dart new file mode 100644 index 0000000..449c708 --- /dev/null +++ b/packages/process/lib/src/process_pipeline.dart @@ -0,0 +1,50 @@ +import 'dart:async'; +import 'package:logging/logging.dart'; +import 'process.dart'; + +class ProcessPipeline { + final List _processes; + final Logger _logger = Logger('ProcessPipeline'); + + ProcessPipeline(this._processes); + + Future run() async { + String input = ''; + DateTime startTime = DateTime.now(); + DateTime endTime; + int lastExitCode = 0; + + _logger + .info('Starting process pipeline with ${_processes.length} processes'); + + for (final process in _processes) { + _logger.info('Running process: ${process.command}'); + if (input.isNotEmpty) { + await process.write(input); + } + final result = await process.run(); + input = result.output; + lastExitCode = result.exitCode; + _logger.info( + 'Process completed: ${process.command} with exit code $lastExitCode'); + if (lastExitCode != 0) { + _logger.warning( + 'Pipeline stopped due to non-zero exit code: $lastExitCode'); + break; + } + } + + endTime = DateTime.now(); + _logger.info( + 'Pipeline completed. Total duration: ${endTime.difference(startTime)}'); + + return InvokedProcess( + _processes.last, + startTime, + endTime, + lastExitCode, + input, + '', + ); + } +} diff --git a/packages/process/lib/src/process_pool.dart b/packages/process/lib/src/process_pool.dart new file mode 100644 index 0000000..67b323f --- /dev/null +++ b/packages/process/lib/src/process_pool.dart @@ -0,0 +1,62 @@ +import 'dart:async'; +import 'package:logging/logging.dart'; +import 'process.dart'; + +class ProcessPool { + final int concurrency; + final List _queue = []; + int _running = 0; + final Logger _logger = Logger('ProcessPool'); + + ProcessPool({this.concurrency = 5}); + + Future> run(List processes) async { + final results = []; + final completer = Completer>(); + + _logger.info('Starting process pool with ${processes.length} processes'); + + for (final process in processes) { + _queue.add(() async { + try { + final result = await _runProcess(process); + results.add(result); + } catch (e) { + _logger.severe('Error running process in pool', e); + } finally { + _running--; + _processQueue(); + if (_running == 0 && _queue.isEmpty) { + completer.complete(results); + } + } + }); + } + + _processQueue(); + + return completer.future; + } + + void _processQueue() { + while (_running < concurrency && _queue.isNotEmpty) { + _running++; + _queue.removeAt(0)(); + } + } + + Future _runProcess(Angel3Process process) async { + _logger.info('Running process: ${process.command}'); + final result = await process.run(); + _logger.info( + 'Process completed: ${process.command} with exit code ${result.exitCode}'); + return InvokedProcess( + process, + process.startTime!, + process.endTime!, + result.exitCode, + result.output, + result.errorOutput, + ); + } +} diff --git a/packages/process/lib/src/process_service_provider.dart b/packages/process/lib/src/process_service_provider.dart new file mode 100644 index 0000000..c762c94 --- /dev/null +++ b/packages/process/lib/src/process_service_provider.dart @@ -0,0 +1,24 @@ +/* import 'package:angel3_framework/angel3_framework.dart'; +import 'package:logging/logging.dart'; +import 'process_manager.dart'; + +class ProcessServiceProvider extends Provider { + final Logger _logger = Logger('ProcessServiceProvider'); + + @override + void registers() { + container.singleton((_) => ProcessManager()); + _logger.info('Registered ProcessManager'); + } + + @override + void boots(Angel app) { + app.shutdownHooks.add((_) async { + _logger.info('Shutting down ProcessManager'); + final processManager = app.container.make(); + await processManager.killAll(); + processManager.dispose(); + }); + _logger.info('Added ProcessManager shutdown hook'); + } +} */ diff --git a/packages/process/pubspec.yaml b/packages/process/pubspec.yaml new file mode 100644 index 0000000..b837bae --- /dev/null +++ b/packages/process/pubspec.yaml @@ -0,0 +1,25 @@ +name: platform_process +description: The Process Package for the Protevus Platform +version: 0.0.1 +homepage: https://protevus.com +documentation: https://docs.protevus.com +repository: https://github.com/protevus/platformo + +environment: + sdk: ^3.4.2 + +# Add regular dependencies here. +dependencies: + platform_container: ^8.0.0 + platform_core: ^8.0.0 + angel3_mq: ^8.0.0 + angel3_mustache: ^8.0.0 + angel3_event_bus: ^8.0.0 + angel3_reactivex: ^8.0.0 + file: ^7.0.0 + logging: ^1.1.0 + path: ^1.8.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/process/test/process_test.dart b/packages/process/test/process_test.dart new file mode 100644 index 0000000..ab3a7eb --- /dev/null +++ b/packages/process/test/process_test.dart @@ -0,0 +1,80 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:platform_process/angel3_process.dart'; +import 'package:test/test.dart'; + +void main() { + late Angel3Process process; + + setUp(() { + process = Angel3Process('echo', ['Hello, World!']); + }); + + tearDown(() async { + await process.dispose(); + }); + + test('Angel3Process initialization', () { + expect(process.command, equals('echo')); + expect(process.startTime, isNull); + expect(process.endTime, isNull); + }); + + test('Start and run a simple process', () async { + var result = await process.run(); + expect(process.startTime, isNotNull); + expect(result.exitCode, equals(0)); + expect(result.output.trim(), equals('Hello, World!')); + expect(process.endTime, isNotNull); + }); + + test('Stream output', () async { + await process.start(); + var outputStream = process.output.transform(utf8.decoder); + var streamOutput = await outputStream.join(); + await process.exitCode; // Wait for the process to complete + expect(streamOutput.trim(), equals('Hello, World!')); + }); + + test('Error output for non-existent command', () { + var errorProcess = Angel3Process('non_existent_command', []); + expect(errorProcess.start(), throwsA(isA())); + }); + + test('Process with error output', () async { + Angel3Process errorProcess; + if (Platform.isWindows) { + errorProcess = Angel3Process('cmd', ['/c', 'dir', '/invalid_argument']); + } else { + errorProcess = Angel3Process('ls', ['/non_existent_directory']); + } + + print('Starting error process...'); + var result = await errorProcess.run(); + print('Error process completed.'); + print('Exit code: ${result.exitCode}'); + print('Standard output: "${result.output}"'); + print('Error output: "${result.errorOutput}"'); + + expect(result.exitCode, isNot(0), reason: 'Expected non-zero exit code'); + expect(result.errorOutput.trim(), isNotEmpty, + reason: 'Expected non-empty error output'); + + await errorProcess.dispose(); + }); + + test('Kill running process', () async { + var longRunningProcess = Angel3Process('sleep', ['5']); + await longRunningProcess.start(); + await longRunningProcess.kill(); + var exitCode = await longRunningProcess.exitCode; + expect(exitCode, isNot(0)); + }); + + test('Process timeout', () async { + var timeoutProcess = + Angel3Process('sleep', ['10'], timeout: Duration(seconds: 1)); + expect(() => timeoutProcess.run(), throwsA(isA())); + }, timeout: Timeout(Duration(seconds: 5))); +} diff --git a/packages/process/test/process_test_extended.dart b/packages/process/test/process_test_extended.dart new file mode 100644 index 0000000..ab82810 --- /dev/null +++ b/packages/process/test/process_test_extended.dart @@ -0,0 +1,102 @@ +import 'dart:async'; +import 'dart:io' show Directory, Platform, ProcessSignal; +import 'package:platform_process/angel3_process.dart'; +import 'package:test/test.dart'; +import 'package:path/path.dart' as path; + +void main() { + late Angel3Process process; + + setUp(() { + process = Angel3Process('echo', ['Hello, World!']); + }); + + tearDown(() async { + await process.dispose(); + }); + + // ... (existing tests remain the same) + + test('Process with custom environment variables', () async { + var command = Platform.isWindows ? 'cmd' : 'sh'; + var args = Platform.isWindows + ? ['/c', 'echo %TEST_VAR%'] + : ['-c', r'echo $TEST_VAR']; // Use a raw string for Unix-like systems + + var envProcess = + Angel3Process(command, args, environment: {'TEST_VAR': 'custom_value'}); + + var result = await envProcess.run(); + expect(result.output.trim(), equals('custom_value')); + }); + + test('Process with custom working directory', () async { + var tempDir = Directory.systemTemp.createTempSync(); + try { + var workingDirProcess = Angel3Process(Platform.isWindows ? 'cmd' : 'pwd', + Platform.isWindows ? ['/c', 'cd'] : [], + workingDirectory: tempDir.path); + var result = await workingDirProcess.run(); + expect(path.equals(result.output.trim(), tempDir.path), isTrue); + } finally { + tempDir.deleteSync(); + } + }); + + test('Process with input', () async { + var catProcess = Angel3Process('cat', []); + await catProcess.start(); + catProcess.write('Hello, stdin!'); + await catProcess.kill(); // End the process + var output = await catProcess.outputAsString; + expect(output.trim(), equals('Hello, stdin!')); + }); + + test('Longer-running process', () async { + var sleepProcess = Angel3Process(Platform.isWindows ? 'timeout' : 'sleep', + Platform.isWindows ? ['/t', '2'] : ['2']); + var startTime = DateTime.now(); + await sleepProcess.run(); + var endTime = DateTime.now(); + expect(endTime.difference(startTime).inSeconds, greaterThanOrEqualTo(2)); + }); + + test('Multiple concurrent processes', () async { + var processes = + List.generate(5, (_) => Angel3Process('echo', ['concurrent'])); + var results = await Future.wait(processes.map((p) => p.run())); + for (var result in results) { + expect(result.output.trim(), equals('concurrent')); + } + }); + + test('Process signaling', () async { + if (!Platform.isWindows) { + // SIGSTOP/SIGCONT are not available on Windows + var longProcess = Angel3Process('sleep', ['10']); + await longProcess.start(); + await longProcess.sendSignal(ProcessSignal.sigstop); + // Process should be stopped, so it shouldn't complete immediately + expect(longProcess.exitCode, doesNotComplete); + await longProcess.sendSignal(ProcessSignal.sigcont); + await longProcess.kill(); + expect(await longProcess.exitCode, isNot(0)); + } + }); + + test('Edge case: empty command', () { + expect(() => Angel3Process('', []), throwsA(isA())); + }); + + test('Edge case: empty arguments list', () { + // This should not throw an error + expect(() => Angel3Process('echo', []), returnsNormally); + }); + + test('Edge case: invalid argument type', () { + // This should throw a compile-time error, but we can't test for that directly + // Instead, we can test for runtime type checking if implemented + expect(() => Angel3Process('echo', [1, 2, 3] as dynamic), + throwsA(isA())); + }); +} diff --git a/packages/queue/.gitignore b/packages/queue/.gitignore new file mode 100644 index 0000000..0b4272d --- /dev/null +++ b/packages/queue/.gitignore @@ -0,0 +1,10 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock + +*.mocks.dart +*.reflectable.dart diff --git a/packages/queue/CHANGELOG.md b/packages/queue/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/queue/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/queue/LICENSE.md b/packages/queue/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/queue/LICENSE.md @@ -0,0 +1,10 @@ +The MIT License (MIT) + +The Laravel Framework is Copyright (c) Taylor Otwell +The Fabric Framework is Copyright (c) Vieo, Inc. + +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/packages/queue/README.md b/packages/queue/README.md new file mode 100644 index 0000000..757f4c9 --- /dev/null +++ b/packages/queue/README.md @@ -0,0 +1 @@ +

\ No newline at end of file diff --git a/packages/queue/analysis_options.yaml b/packages/queue/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/queue/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/queue/lib/queue.dart b/packages/queue/lib/queue.dart new file mode 100644 index 0000000..585829f --- /dev/null +++ b/packages/queue/lib/queue.dart @@ -0,0 +1,75 @@ +/// The Queue Package for the Protevus Platform. +/// +/// This package provides a Laravel-compatible queue implementation in Dart, offering +/// features like job queuing, delayed job processing, job encryption, and transaction-aware +/// job dispatching. +/// +/// # Basic Usage +/// +/// ```dart +/// final queue = Queue(container, eventBus, mqClient); +/// +/// // Push a job to the queue +/// await queue.push(MyJob()); +/// +/// // Push a job with delay +/// await queue.later(Duration(minutes: 5), MyJob()); +/// +/// // Push a job to a specific queue +/// await queue.pushOn('high-priority', MyJob()); +/// ``` +/// +/// # Features +/// +/// - Job queuing and processing +/// - Delayed job execution +/// - Job encryption +/// - Transaction-aware job dispatching +/// - Event-based job monitoring +/// - Queue connection management +/// +/// # Events +/// +/// The queue system fires two main events: +/// - [JobQueueingEvent]: Fired before a job is queued +/// - [JobQueuedEvent]: Fired after a job has been queued +/// +/// # Job Interfaces +/// +/// Jobs can implement various interfaces to modify their behavior: +/// - [ShouldBeEncrypted]: Job payload will be encrypted +/// - [ShouldQueueAfterCommit]: Job will be queued after database transactions commit +/// - [HasMaxExceptions]: Specify maximum number of exceptions before job fails +/// - [HasFailOnTimeout]: Specify if job should fail on timeout +/// - [HasTimeout]: Specify job timeout duration +/// - [HasTries]: Specify maximum number of retry attempts +/// - [HasBackoff]: Specify delay between retry attempts +/// - [HasRetryUntil]: Specify when to stop retrying +/// - [HasAfterCommit]: Specify if job should run after commit +library platform_queue; + +// Core queue implementation +export 'src/queue.dart'; + +// Events +export 'src/job_queued_event.dart'; +export 'src/job_queueing_event.dart'; + +// Job interfaces +export 'src/should_be_encrypted.dart'; +export 'src/should_queue_after_commit.dart'; + +// Re-export commonly used types and interfaces +export 'src/queue.dart' show Queue, InvalidPayloadException; + +// Job configuration interfaces +export 'src/queue.dart' show HasMaxExceptions, HasFailOnTimeout, HasTimeout; +export 'src/queue.dart' + show HasDisplayName, HasTries, HasBackoff, HasRetryUntil; +export 'src/queue.dart' show HasAfterCommit, HasShouldBeEncrypted; + +// Support interfaces +export 'src/queue.dart' show Encrypter, TransactionManager; + +// Time utilities +export 'src/queue.dart' show InteractsWithTime; diff --git a/packages/queue/lib/src/job_queued_event.dart b/packages/queue/lib/src/job_queued_event.dart new file mode 100644 index 0000000..09b1301 --- /dev/null +++ b/packages/queue/lib/src/job_queued_event.dart @@ -0,0 +1,70 @@ +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:equatable/equatable.dart'; + +/// Event fired after a job has been successfully queued. +/// +/// This event is dispatched after a job has been successfully added to the queue, +/// providing information about the queued job including its ID, payload, and any +/// specified delay. +/// +/// Example: +/// ```dart +/// eventBus.on().listen((event) { +/// print('Job ${event.jobId} queued on ${event.queue}'); +/// print('Will execute after: ${event.delay}'); +/// }); +/// ``` +class JobQueuedEvent extends AppEvent { + /// The name of the queue connection. + final String connectionName; + + /// The name of the specific queue the job was added to. + final String? queue; + + /// The unique identifier assigned to the queued job. + final String jobId; + + /// The job instance that was queued. + final dynamic job; + + /// The serialized payload of the job. + final String payload; + + /// The delay before the job should be processed, if any. + final Duration? delay; + + /// Creates a new [JobQueuedEvent]. + /// + /// [connectionName] is the name of the queue connection. + /// [queue] is the specific queue name, if any. + /// [jobId] is the unique identifier assigned to the job. + /// [job] is the actual job instance. + /// [payload] is the serialized job data. + /// [delay] is the optional delay before processing. + JobQueuedEvent(this.connectionName, this.queue, this.jobId, this.job, + this.payload, this.delay); + + @override + List get props => + [connectionName, queue, jobId, job, payload, delay]; + + @override + Map toJson() { + return { + 'connectionName': connectionName, + 'queue': queue, + 'jobId': jobId, + 'job': job.toString(), + 'payload': payload, + 'delay': delay?.inMilliseconds, + }; + } + + /// The event name used for identification. + @override + String get name => 'job.queued'; + + @override + String toString() => + 'JobQueuedEvent(connectionName: $connectionName, queue: $queue, jobId: $jobId, delay: $delay)'; +} diff --git a/packages/queue/lib/src/job_queueing_event.dart b/packages/queue/lib/src/job_queueing_event.dart new file mode 100644 index 0000000..35fc590 --- /dev/null +++ b/packages/queue/lib/src/job_queueing_event.dart @@ -0,0 +1,72 @@ +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:equatable/equatable.dart'; + +/// Event fired before a job is queued. +/// +/// This event is dispatched just before a job is added to the queue, +/// allowing listeners to perform actions or validations before the job +/// is actually queued. +/// +/// Example: +/// ```dart +/// eventBus.on().listen((event) { +/// print('About to queue job on ${event.queue}'); +/// if (event.delay != null) { +/// print('Will be delayed by ${event.delay}'); +/// } +/// }); +/// ``` +/// +/// This event can be particularly useful for: +/// - Logging job attempts +/// - Validating job parameters before queueing +/// - Monitoring queue activity +/// - Implementing queue-based metrics +class JobQueueingEvent extends AppEvent { + /// The name of the queue connection. + final String connectionName; + + /// The name of the specific queue the job will be added to. + final String? queue; + + /// The job instance to be queued. + final dynamic job; + + /// The serialized payload of the job. + final String payload; + + /// The delay before the job should be processed, if any. + final Duration? delay; + + /// Creates a new [JobQueueingEvent]. + /// + /// [connectionName] is the name of the queue connection. + /// [queue] is the specific queue name, if any. + /// [job] is the actual job instance to be queued. + /// [payload] is the serialized job data. + /// [delay] is the optional delay before processing. + JobQueueingEvent( + this.connectionName, this.queue, this.job, this.payload, this.delay); + + @override + List get props => [connectionName, queue, job, payload, delay]; + + @override + Map toJson() { + return { + 'connectionName': connectionName, + 'queue': queue, + 'job': job.toString(), + 'payload': payload, + 'delay': delay?.inMilliseconds, + }; + } + + /// The event name used for identification. + @override + String get name => 'job.queueing'; + + @override + String toString() => + 'JobQueueingEvent(connectionName: $connectionName, queue: $queue, delay: $delay)'; +} diff --git a/packages/queue/lib/src/queue.dart b/packages/queue/lib/src/queue.dart new file mode 100644 index 0000000..2233816 --- /dev/null +++ b/packages/queue/lib/src/queue.dart @@ -0,0 +1,396 @@ +// lib/src/queue.dart + +import 'dart:async'; +import 'dart:convert'; + +import 'package:platform_container/container.dart'; +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:crypto/crypto.dart'; +import 'package:uuid/uuid.dart'; + +import 'job_queueing_event.dart'; +import 'job_queued_event.dart'; +import 'should_be_encrypted.dart'; +import 'should_queue_after_commit.dart'; + +abstract class Queue with InteractsWithTime { + /// The IoC container instance. + final Container container; + final EventBus eventBus; + final MQClient mq; + final Subject jobSubject; + final Uuid uuid = Uuid(); + + /// The connection name for the queue. + String _connectionName; + + /// Indicates that jobs should be dispatched after all database transactions have committed. + bool dispatchAfterCommit; + + /// The create payload callbacks. + static final List _createPayloadCallbacks = []; + + Queue(this.container, this.eventBus, this.mq, + {String connectionName = 'default', this.dispatchAfterCommit = false}) + : _connectionName = connectionName, + jobSubject = PublishSubject() { + _setupJobObservable(); + } + + void _setupJobObservable() { + jobSubject.stream.listen((job) { + // Process the job + print('Processing job: $job'); + // Implement your job processing logic here + }); + } + + Future pushOn(String queue, dynamic job, [dynamic data = '']) { + return push(job, data, queue); + } + + Future laterOn(String queue, Duration delay, dynamic job, + [dynamic data = '']) { + return later(delay, job, data, queue); + } + + Future bulk(List jobs, + [dynamic data = '', String? queue]) async { + for (var job in jobs) { + await push(job, data, queue); + } + } + + // Add this method + void setContainer(Container container) { + // This method might not be necessary in Dart, as we're using final for container + // But we can implement it for API compatibility + throw UnsupportedError( + 'Container is final and cannot be changed after initialization'); + } + + // Update createPayload method to include exception handling + Future createPayload(dynamic job, String queue, + [dynamic data = '']) async { + if (job is Function) { + // TODO: Implement CallQueuedClosure equivalent + throw UnimplementedError('Closure jobs are not yet supported'); + } + + try { + final payload = jsonEncode(await createPayloadMap(job, queue, data)); + return payload; + } catch (e) { + throw InvalidPayloadException('Unable to JSON encode payload: $e'); + } + } + + Future> createPayloadMap(dynamic job, String queue, + [dynamic data = '']) async { + if (job is Object) { + return createObjectPayload(job, queue); + } else { + return createStringPayload(job.toString(), queue, data); + } + } + + Future> createObjectPayload( + Object job, String queue) async { + final payload = await withCreatePayloadHooks(queue, { + 'uuid': const Uuid().v4(), + 'displayName': getDisplayName(job), + 'job': 'CallQueuedHandler@call', // TODO: Implement CallQueuedHandler + 'maxTries': getJobTries(job), + 'maxExceptions': job is HasMaxExceptions ? job.maxExceptions : null, + 'failOnTimeout': job is HasFailOnTimeout ? job.failOnTimeout : false, + 'backoff': getJobBackoff(job), + 'timeout': job is HasTimeout ? job.timeout : null, + 'retryUntil': getJobExpiration(job), + 'data': { + 'commandName': job.runtimeType.toString(), + 'command': job, + }, + }); + + final command = jobShouldBeEncrypted(job) && container.has() + ? container.make().encrypt(jsonEncode(job)) + : jsonEncode(job); + + payload['data'] = { + ...payload['data'] as Map, + 'commandName': job.runtimeType.toString(), + 'command': command, + }; + + return payload; + } + + String getDisplayName(Object job) { + if (job is HasDisplayName) { + return job.displayName(); + } + return job.runtimeType.toString(); + } + + int? getJobTries(dynamic job) { + if (job is HasTries) { + return job.tries; + } + return null; + } + + String? getJobBackoff(dynamic job) { + if (job is HasBackoff) { + final backoff = job.backoff; + if (backoff == null) return null; + if (backoff is Duration) { + return backoff.inSeconds.toString(); + } + if (backoff is List) { + return backoff.map((d) => d.inSeconds).join(','); + } + } + return null; + } + + int? getJobExpiration(dynamic job) { + if (job is HasRetryUntil) { + final retryUntil = job.retryUntil; + if (retryUntil == null) return null; + return retryUntil.millisecondsSinceEpoch ~/ 1000; + } + return null; + } + + bool jobShouldBeEncrypted(Object job) { + return job is ShouldBeEncrypted || + (job is HasShouldBeEncrypted && job.shouldBeEncrypted); + } + + Future> createStringPayload( + String job, String queue, dynamic data) async { + return withCreatePayloadHooks(queue, { + 'uuid': const Uuid().v4(), + 'displayName': job.split('@')[0], + 'job': job, + 'maxTries': null, + 'maxExceptions': null, + 'failOnTimeout': false, + 'backoff': null, + 'timeout': null, + 'data': data, + }); + } + + static void createPayloadUsing(Function? callback) { + if (callback == null) { + _createPayloadCallbacks.clear(); + } else { + _createPayloadCallbacks.add(callback); + } + } + + Future> withCreatePayloadHooks( + String queue, Map payload) async { + if (_createPayloadCallbacks.isNotEmpty) { + for (var callback in _createPayloadCallbacks) { + final result = await callback(_connectionName, queue, payload); + if (result is Map) { + payload = {...payload, ...result}; + } + } + } + return payload; + } + + Future enqueueUsing( + dynamic job, + String payload, + String? queue, + Duration? delay, + Future Function(String, String?, Duration?) callback, + ) async { + final String jobId = uuid.v4(); // Generate a unique job ID + + if (shouldDispatchAfterCommit(job) && container.has()) { + return container.make().addCallback(() async { + await raiseJobQueueingEvent(queue, job, payload, delay); + final result = await callback(payload, queue, delay); + await raiseJobQueuedEvent(queue, jobId, job, payload, delay); + return result; + }); + } + + await raiseJobQueueingEvent(queue, job, payload, delay); + final result = await callback(payload, queue, delay); + await raiseJobQueuedEvent(queue, jobId, job, payload, delay); + + // Use angel3_mq to publish the job + mq.sendMessage( + message: Message( + headers: {'jobId': jobId}, // Include jobId in headers + payload: payload, + timestamp: DateTime.now().toIso8601String(), + ), + exchangeName: '', // Use default exchange + routingKey: queue ?? 'default', + ); + + // Use angel3_reactivex to add the job to the subject + jobSubject.add(job); + + return result; + } + + bool shouldDispatchAfterCommit(dynamic job) { + if (job is ShouldQueueAfterCommit) { + return true; + } + if (job is HasAfterCommit) { + return job.afterCommit; + } + return dispatchAfterCommit; + } + + Future raiseJobQueueingEvent( + String? queue, dynamic job, String payload, Duration? delay) async { + if (container.has()) { + final eventBus = container.make(); + eventBus + .fire(JobQueueingEvent(_connectionName, queue, job, payload, delay)); + } + } + + Future raiseJobQueuedEvent(String? queue, dynamic jobId, dynamic job, + String payload, Duration? delay) async { + if (container.has()) { + final eventBus = container.make(); + eventBus.fire( + JobQueuedEvent(_connectionName, queue, jobId, job, payload, delay)); + } + } + + String get connectionName => _connectionName; + + set connectionName(String name) { + _connectionName = name; + } + + Container getContainer() => container; + + // Abstract methods to be implemented by subclasses + // Implement the push method + Future push(dynamic job, [dynamic data = '', String? queue]) async { + final payload = await createPayload(job, queue ?? 'default', data); + return enqueueUsing(job, payload, queue, null, (payload, queue, _) async { + final jobId = Uuid().v4(); + mq.sendMessage( + message: Message( + id: jobId, + headers: {}, + payload: payload, + timestamp: DateTime.now().toIso8601String(), + ), + exchangeName: '', + routingKey: queue ?? 'default', + ); + return jobId; + }); + } + + // Implement the later method + Future later(Duration delay, dynamic job, + [dynamic data = '', String? queue]) async { + final payload = await createPayload(job, queue ?? 'default', data); + return enqueueUsing(job, payload, queue, delay, + (payload, queue, delay) async { + final jobId = Uuid().v4(); + await Future.delayed(delay!); + mq.sendMessage( + message: Message( + id: jobId, + headers: {}, + payload: payload, + timestamp: DateTime.now().toIso8601String(), + ), + exchangeName: '', + routingKey: queue ?? 'default', + ); + return jobId; + }); + } + + // Cleanup method + void dispose() { + jobSubject.close(); + } +} + +// Additional interfaces and classes + +abstract class HasMaxExceptions { + int? get maxExceptions; +} + +abstract class HasFailOnTimeout { + bool get failOnTimeout; +} + +abstract class HasTimeout { + Duration? get timeout; +} + +abstract class HasDisplayName { + String displayName(); +} + +abstract class HasTries { + int? get tries; +} + +abstract class HasBackoff { + dynamic get backoff; +} + +abstract class HasRetryUntil { + DateTime? get retryUntil; +} + +abstract class HasAfterCommit { + bool get afterCommit; +} + +abstract class HasShouldBeEncrypted { + bool get shouldBeEncrypted; +} + +abstract class Encrypter { + String encrypt(String data); +} + +abstract class TransactionManager { + Future addCallback(Future Function() callback); +} + +// Add this mixin to the Queue class +mixin InteractsWithTime { + int secondsUntil(DateTime dateTime) { + return dateTime.difference(DateTime.now()).inSeconds; + } + + int availableAt(Duration delay) { + return DateTime.now().add(delay).millisecondsSinceEpoch ~/ 1000; + } +} + +// First, define the InvalidPayloadException class +class InvalidPayloadException implements Exception { + final String message; + + InvalidPayloadException(this.message); + + @override + String toString() => 'InvalidPayloadException: $message'; +} diff --git a/packages/queue/lib/src/should_be_encrypted.dart b/packages/queue/lib/src/should_be_encrypted.dart new file mode 100644 index 0000000..348ad79 --- /dev/null +++ b/packages/queue/lib/src/should_be_encrypted.dart @@ -0,0 +1,18 @@ +/// Marks a job as requiring encryption before being stored in the queue. +/// +/// Jobs implementing this interface will be automatically encrypted using the +/// configured encrypter before being serialized and stored in the queue. +/// +/// Example: +/// ```dart +/// class SensitiveJob implements ShouldBeEncrypted { +/// final String sensitiveData; +/// +/// SensitiveJob(this.sensitiveData); +/// +/// void handle() { +/// // Process sensitive data +/// } +/// } +/// ``` +abstract class ShouldBeEncrypted {} diff --git a/packages/queue/lib/src/should_queue_after_commit.dart b/packages/queue/lib/src/should_queue_after_commit.dart new file mode 100644 index 0000000..d6da8d5 --- /dev/null +++ b/packages/queue/lib/src/should_queue_after_commit.dart @@ -0,0 +1,22 @@ +/// Marks a job as requiring to be queued after database transactions have committed. +/// +/// Jobs implementing this interface will not be queued until all open database +/// transactions have been committed. This ensures data consistency by preventing +/// jobs from being processed before their related database changes are permanent. +/// +/// Example: +/// ```dart +/// class CreateUserJob implements ShouldQueueAfterCommit { +/// final User user; +/// +/// CreateUserJob(this.user); +/// +/// void handle() { +/// // Send welcome email +/// // This will only happen after the user is actually saved to the database +/// } +/// } +/// ``` +/// +/// Note: If a transaction fails and rolls back, the job will not be queued. +abstract class ShouldQueueAfterCommit {} diff --git a/packages/queue/pubspec.yaml b/packages/queue/pubspec.yaml new file mode 100644 index 0000000..f251ac6 --- /dev/null +++ b/packages/queue/pubspec.yaml @@ -0,0 +1,25 @@ +name: platform_queue +description: The Queue Package for the Protevus Platform +version: 0.0.1 +homepage: https://protevus.com +documentation: https://docs.protevus.com +repository: https://github.com/protevus/platform + +environment: + sdk: ^3.4.2 + +# Add regular dependencies here. +dependencies: + platform_container: ^9.0.0 + angel3_mq: ^8.0.0 + angel3_event_bus: ^8.0.0 + angel3_reactivex: ^8.0.0 + uuid: ^4.5.1 + crypto: ^3.0.5 + +dev_dependencies: + build_runner: ^2.3.3 + build_test: ^2.1.0 + lints: ^3.0.0 + mockito: ^5.0.0 + test: ^1.24.0 diff --git a/packages/queue/test/queue_test.dart b/packages/queue/test/queue_test.dart new file mode 100644 index 0000000..5c9e0de --- /dev/null +++ b/packages/queue/test/queue_test.dart @@ -0,0 +1,317 @@ +import 'package:test/test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:platform_container/container.dart'; +import 'package:angel3_event_bus/event_bus.dart'; +import 'package:angel3_mq/mq.dart'; +import 'package:platform_queue/src/queue.dart'; + +import 'package:platform_queue/src/job_queueing_event.dart'; +import 'package:platform_queue/src/job_queued_event.dart'; +import 'package:platform_queue/src/should_queue_after_commit.dart'; +import 'queue_test.mocks.dart'; + +@GenerateMocks([Container, MQClient, TransactionManager, Queue]) +void main() { + late MockContainer container; + late EventBus eventBus; + late MockMQClient mq; + late MockQueue queue; + late List firedEvents; + + setUpAll(() { + provideDummy(EventBus()); + }); + + setUp(() { + container = MockContainer(); + firedEvents = []; + eventBus = EventBus(); + mq = MockMQClient(); + queue = MockQueue(); + + // Inject the other mocks into the queue + // queue.container = container; + // queue.mq = mq; + + when(queue.container).thenReturn(container); + when(queue.eventBus).thenReturn(eventBus); + when(queue.mq).thenReturn(mq); + when(queue.connectionName).thenReturn('default'); + + // Stub for shouldDispatchAfterCommit + when(queue.shouldDispatchAfterCommit(any)).thenReturn(false); + + // Modify the createPayload stub + when(queue.createPayload(any, any, any)).thenAnswer((invocation) async { + if (invocation.positionalArguments[0] is Map && + (invocation.positionalArguments[0] as Map).isEmpty) { + throw InvalidPayloadException('Invalid job: empty map'); + } + return 'valid payload'; + }); + + // Modify the push stub + when(queue.push(any, any, any)).thenAnswer((invocation) async { + final job = invocation.positionalArguments[0]; + final data = invocation.positionalArguments[1]; + final queueName = invocation.positionalArguments[2]; + // Simulate firing events asynchronously + Future.microtask(() { + eventBus.fire(JobQueueingEvent( + queue.connectionName, queueName, job, 'payload', null)); + eventBus.fire(JobQueuedEvent( + queue.connectionName, queueName, 'job_id', job, 'payload', null)); + }); + return 'pushed'; + }); + + // Stub for enqueueUsing + when(queue.enqueueUsing( + any, + any, + any, + any, + any, + )).thenAnswer((invocation) async { + final job = invocation.positionalArguments[0]; + final payload = invocation.positionalArguments[1]; + final queueName = invocation.positionalArguments[2]; + final delay = invocation.positionalArguments[3]; + final callback = invocation.positionalArguments[4] as Function; + + eventBus.fire(JobQueueingEvent( + queue.connectionName, queueName, job, payload, delay)); + final result = await callback(payload, queueName, delay); + eventBus.fire(JobQueuedEvent( + queue.connectionName, queueName, result, job, payload, delay)); + + return result; + }); + + // Stub for pushOn + when(queue.pushOn(any, any, any)).thenAnswer((invocation) async { + final queueName = invocation.positionalArguments[0]; + final job = invocation.positionalArguments[1]; + final data = invocation.positionalArguments[2]; + return queue.push(job, data, queueName); + }); + + // Modify the laterOn stub + when(queue.laterOn(any, any, any, any)).thenAnswer((invocation) async { + final queueName = invocation.positionalArguments[0]; + final delay = invocation.positionalArguments[1]; + final job = invocation.positionalArguments[2]; + final data = invocation.positionalArguments[3]; + // Directly return 'pushed later' instead of calling later + return 'pushed later'; + }); + + // Add a stub for bulk + when(queue.bulk(any, any, any)).thenAnswer((invocation) async { + final jobs = invocation.positionalArguments[0] as List; + for (var job in jobs) { + await queue.push(job, invocation.positionalArguments[1], + invocation.positionalArguments[2]); + } + }); + + // Stub for later + when(queue.later(any, any, any, any)).thenAnswer((invocation) async { + final delay = invocation.positionalArguments[0]; + final job = invocation.positionalArguments[1]; + final data = invocation.positionalArguments[2]; + final queueName = invocation.positionalArguments[3]; + final payload = + await queue.createPayload(job, queueName ?? 'default', data); + return queue.enqueueUsing( + job, payload, queueName, delay, (p, q, d) async => 'delayed_job_id'); + }); + + when(container.has()).thenReturn(true); + when(container.has()).thenReturn(false); + when(container.make()).thenReturn(eventBus); + + // Capture fired events + eventBus.on().listen((event) { + firedEvents.add(event); + print("Debug: Event fired - ${event.runtimeType}"); + }); + + // Setup for MQClient mock + when(mq.sendMessage( + message: anyNamed('message'), + exchangeName: anyNamed('exchangeName'), + routingKey: anyNamed('routingKey'), + )).thenAnswer((_) { + print("Debug: Mock sendMessage called"); + }); + }); + + test('pushOn calls push with correct arguments', () async { + final result = await queue.pushOn('test_queue', 'test_job', 'test_data'); + expect(result, equals('pushed')); + verify(queue.push('test_job', 'test_data', 'test_queue')).called(1); + }); + + test('laterOn calls later with correct arguments', () async { + final result = await queue.laterOn( + 'test_queue', Duration(minutes: 5), 'test_job', 'test_data'); + expect(result, equals('pushed later')); + // We're not actually calling 'later' in our stub, so we shouldn't verify it + verify(queue.laterOn( + 'test_queue', Duration(minutes: 5), 'test_job', 'test_data')) + .called(1); + }); + + test('bulk pushes multiple jobs', () async { + await queue.bulk(['job1', 'job2', 'job3'], 'test_data', 'test_queue'); + verify(queue.push('job1', 'test_data', 'test_queue')).called(1); + verify(queue.push('job2', 'test_data', 'test_queue')).called(1); + verify(queue.push('job3', 'test_data', 'test_queue')).called(1); + }); + + test('createPayload throws InvalidPayloadException for invalid job', () { + expect(() => queue.createPayload({}, 'test_queue'), + throwsA(isA())); + }); + test('shouldDispatchAfterCommit returns correct value', () { + when(queue.shouldDispatchAfterCommit(any)).thenReturn(false); + expect(queue.shouldDispatchAfterCommit({}), isFalse); + + when(queue.shouldDispatchAfterCommit(any)).thenReturn(true); + expect(queue.shouldDispatchAfterCommit({}), isTrue); + }); + + test('push enqueues job and fires events', () async { + final job = 'test_job'; + final data = 'test_data'; + final queueName = 'test_queue'; + + print("Debug: Before push"); + final result = await queue.push(job, data, queueName); + print("Debug: After push"); + + // Wait for all events to be processed + await Future.delayed(Duration(milliseconds: 100)); + + expect(result, equals('pushed')); + verify(queue.push(job, data, queueName)).called(1); + + // Filter out EmptyEvents + final significantEvents = + firedEvents.where((event) => event is! EmptyEvent).toList(); + + // Print fired events for debugging + print("Fired events (excluding EmptyEvents):"); + for (var event in significantEvents) { + print("${event.runtimeType}: ${event.toString()}"); + } + + // Verify fired events + expect(significantEvents.where((event) => event is JobQueueingEvent).length, + equals(1), + reason: "JobQueueingEvent was not fired exactly once"); + expect(significantEvents.where((event) => event is JobQueuedEvent).length, + equals(1), + reason: "JobQueuedEvent was not fired exactly once"); + }); +} + +class TestQueue extends Queue { + List pushedJobs = []; + + TestQueue(Container container, EventBus eventBus, MQClient mq) + : super(container, eventBus, mq); + + @override + Future push(dynamic job, [dynamic data = '', String? queue]) async { + pushedJobs.add(job); + final payload = await createPayload(job, queue ?? 'default', data); + return enqueueUsing(job, payload, queue, null, (payload, queue, _) async { + final jobId = 'test-job-id'; + mq.sendMessage( + message: Message( + id: jobId, + headers: {}, + payload: payload, + timestamp: DateTime.now().toIso8601String(), + ), + exchangeName: '', + routingKey: queue ?? 'default', + ); + return jobId; + }); + } + + @override + Future later(Duration delay, dynamic job, + [dynamic data = '', String? queue]) async { + return 'pushed later'; + } + + @override + Future createPayload(dynamic job, String queue, + [dynamic data = '']) async { + if (job is Map && job.isEmpty) { + throw InvalidPayloadException('Invalid job: empty map'); + } + return 'valid payload'; + } + + @override + bool shouldDispatchAfterCommit(dynamic job) { + if (job is ShouldQueueAfterCommit) { + return true; + } + return dispatchAfterCommit; + } + + @override + Future enqueueUsing( + dynamic job, + String payload, + String? queue, + Duration? delay, + Future Function(String, String?, Duration?) callback, + ) async { + eventBus.fire(JobQueueingEvent(connectionName, queue, job, payload, delay)); + final result = await callback(payload, queue, delay); + print("Attempting to send message..."); // Debug print + mq.sendMessage( + message: Message( + id: 'test-id', + headers: {}, + payload: payload, + timestamp: DateTime.now().toIso8601String(), + ), + exchangeName: '', + routingKey: queue ?? 'default', + ); + print("Message sent."); // Debug print + eventBus.fire( + JobQueuedEvent(connectionName, queue, result, job, payload, delay)); + return result; + } +} + +// class DummyEventBus implements EventBus { +// List firedEvents = []; + +// @override +// Future fire(AppEvent event) async { +// firedEvents.add(event); +// } + +// @override +// dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +// } + +class InvalidPayloadException implements Exception { + final String message; + InvalidPayloadException(this.message); + @override + String toString() => 'InvalidPayloadException: $message'; +} + +class MockShouldQueueAfterCommit implements ShouldQueueAfterCommit {} diff --git a/packages/support/example/service_provider_example.dart b/packages/support/example/service_provider_example.dart new file mode 100644 index 0000000..26d2b44 --- /dev/null +++ b/packages/support/example/service_provider_example.dart @@ -0,0 +1,67 @@ +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_support/providers.dart'; + +/// Example service that will be provided +class ExampleService { + final String message; + ExampleService(this.message); + + void printMessage() { + print(message); + } +} + +/// Example service provider that demonstrates the basic features +class ExampleServiceProvider extends ServiceProvider { + @override + void register() { + super.register(); + // Register a singleton service + singleton(ExampleService('Hello from ExampleService!')); + + // Register an event listener + listen('app.started', (req, res) { + var service = make(); + service.printMessage(); + return true; + }); + } + + @override + List provides() => ['example-service']; +} + +/// Example deferred service provider that demonstrates lazy loading +class DeferredExampleProvider extends DeferredServiceProvider { + @override + void register() { + super.register(); + singleton(ExampleService('Hello from DeferredService!')); + } + + @override + List provides() => ['deferred-service']; + + @override + List dependencies() => ['example-service']; +} + +void main() async { + // Create the application + var app = Application(); + + // Register the service providers + app.registerProvider(ExampleServiceProvider()); + app.registerProvider(DeferredExampleProvider()); + + // The ExampleServiceProvider will be booted immediately + // The DeferredExampleProvider will only be booted when needed + + // Later, when we need the deferred service: + await app.resolveProvider('deferred-service'); + + // Create and start the HTTP server + var http = PlatformHttp(app); + await http.startServer('127.0.0.1', 3000); +} diff --git a/packages/support/lib/providers.dart b/packages/support/lib/providers.dart new file mode 100644 index 0000000..1d3c8a8 --- /dev/null +++ b/packages/support/lib/providers.dart @@ -0,0 +1,6 @@ +/// Support for Laravel-like service providers in Dart. +library platform_support.providers; + +export 'src/providers/service_provider.dart'; +export 'src/providers/deferred_service_provider.dart'; +export 'src/providers/service_provider_support.dart'; diff --git a/packages/support/lib/src/providers/contracts/service_provider.dart b/packages/support/lib/src/providers/contracts/service_provider.dart new file mode 100644 index 0000000..5891f1f --- /dev/null +++ b/packages/support/lib/src/providers/contracts/service_provider.dart @@ -0,0 +1,30 @@ +/// Contract for service providers. +/// +/// This interface defines the core functionality that all service providers +/// must implement. It matches Laravel's ServiceProvider contract to ensure +/// API compatibility. +abstract class ServiceProviderContract { + /// Register any application services. + void register(); + + /// Bootstrap any application services. + void boot(); + + /// Get the services provided by the provider. + List provides(); + + /// Get the events that trigger this service provider to register. + List when(); + + /// Determine if the provider is deferred. + bool isDeferred(); +} + +/// Contract for deferrable providers. +/// +/// This interface matches Laravel's DeferrableProvider contract to ensure +/// API compatibility. +abstract class DeferrableProviderContract { + /// Get the services provided by the provider. + List provides(); +} diff --git a/packages/support/lib/src/providers/deferred_service_provider.dart b/packages/support/lib/src/providers/deferred_service_provider.dart new file mode 100644 index 0000000..06f5151 --- /dev/null +++ b/packages/support/lib/src/providers/deferred_service_provider.dart @@ -0,0 +1,20 @@ +import 'service_provider.dart'; +import 'contracts/service_provider.dart'; + +/// A service provider that is loaded only when needed. +/// +/// Deferred service providers are not loaded during the initial application boot +/// process. Instead, they are loaded only when one of their provided services is +/// actually needed by the application. +/// +/// This aligns with Laravel's DeferrableProvider interface which requires only +/// the provides() method to indicate which services should trigger loading of +/// the provider. +abstract class DeferredServiceProvider extends ServiceProvider + implements DeferrableProviderContract { + @override + bool isDeferred() => true; + + @override + List provides(); +} diff --git a/packages/support/lib/src/providers/providers.dart b/packages/support/lib/src/providers/providers.dart new file mode 100644 index 0000000..6b37883 --- /dev/null +++ b/packages/support/lib/src/providers/providers.dart @@ -0,0 +1,11 @@ +/// Core service provider functionality +library; + +export 'service_provider.dart'; +export 'deferred_service_provider.dart'; + +/// Service provider contracts +export 'contracts/service_provider.dart'; + +/// Support functionality +export 'service_provider_support.dart'; diff --git a/packages/support/lib/src/providers/service_provider.dart b/packages/support/lib/src/providers/service_provider.dart new file mode 100644 index 0000000..2b19abc --- /dev/null +++ b/packages/support/lib/src/providers/service_provider.dart @@ -0,0 +1,271 @@ +import 'package:meta/meta.dart'; +import 'package:platform_core/core.dart'; +import 'package:platform_container/container.dart'; +import 'contracts/service_provider.dart'; +import 'service_provider_static.dart'; + +/// Base class for all service providers. +/// +/// Service providers are the central place to configure your application's services. +/// Within a service provider, you may bind things into the service container, register +/// events, middleware, or perform any other tasks to prepare your application for +/// incoming requests. +abstract class ServiceProvider + with ServiceProviderStatic + implements ServiceProviderContract { + /// The application instance. + late Application app; + + /// All of the registered booting callbacks. + final List bootingCallbacks = []; + + /// All of the registered booted callbacks. + final List bootedCallbacks = []; + + /// Create a new service provider instance. + ServiceProvider(); + + /// Register any application services. + @override + @mustCallSuper + void register() {} + + /// Bootstrap any application services. + @override + @mustCallSuper + void boot() { + callBootingCallbacks(); + callBootedCallbacks(); + } + + /// Register a booting callback to be run before the boot operations. + void booting(Function callback) { + bootingCallbacks.add(callback); + } + + /// Register a booted callback to be run after the boot operations. + void booted(Function callback) { + bootedCallbacks.add(callback); + } + + /// Call the registered booting callbacks. + void callBootingCallbacks() { + for (var callback in bootingCallbacks) { + callback(); + } + } + + /// Call the registered booted callbacks. + void callBootedCallbacks() { + for (var callback in bootedCallbacks) { + callback(); + } + } + + /// Merge the given configuration with the existing configuration. + @protected + void mergeConfigFrom(String path, String key) { + // TODO: Implement config merging + } + + /// Replace the given configuration with the existing configuration recursively. + @protected + void replaceConfigRecursivelyFrom(String path, String key) { + // TODO: Implement recursive config replacement + } + + /// Load the given routes file if routes are not already cached. + @protected + void loadRoutesFrom(String path) { + // TODO: Implement route loading + } + + /// Register a view file namespace. + @protected + void loadViewsFrom(String path, String namespace) { + // TODO: Implement view loading + } + + /// Register the given view components with a custom prefix. + @protected + void loadViewComponentsAs(String prefix, List components) { + // TODO: Implement view component loading + } + + /// Register a translation file namespace. + @protected + void loadTranslationsFrom(String path, String namespace) { + // TODO: Implement translation loading + } + + /// Register a JSON translation file path. + @protected + void loadJsonTranslationsFrom(String path) { + // TODO: Implement JSON translation loading + } + + /// Register database migration paths. + @protected + void loadMigrationsFrom(dynamic paths) { + // TODO: Implement migration loading + } + + /// Register Eloquent model factory paths. + @protected + @Deprecated('Will be removed in a future version.') + void loadFactoriesFrom(dynamic paths) { + // TODO: Implement factory loading + } + + /// Setup an after resolving listener, or fire immediately if already resolved. + @protected + void callAfterResolving(String name, Function callback) { + // TODO: Implement after resolving + } + + /// Register migration paths to be published by the publish command. + @protected + void publishesMigrations(List paths, [dynamic groups]) { + // TODO: Implement migration publishing + } + + /// Register paths to be published by the publish command. + @protected + void registerPublishables(Map paths, [dynamic groups]) { + // TODO: Implement path publishing + } + + /// Laravel API compatibility method - forwards to registerPublishables + @protected + @Deprecated('Use registerPublishables instead') + void publishes(Map paths, [dynamic groups]) => + registerPublishables(paths, groups); + + /// Ensure the publish array for the service provider is initialized. + @protected + void ensurePublishArrayInitialized(String className) { + // TODO: Implement publish array initialization + } + + /// Add a publish group / tag to the service provider. + @protected + void addPublishGroup(String group, Map paths) { + // TODO: Implement publish group addition + } + + /// Get the paths to publish. + Map pathsToPublish([String? provider, String? group]) { + // TODO: Implement paths to publish + return {}; + } + + /// Get the paths for the provider or group (or both). + @protected + Map pathsForProviderOrGroup(String? provider, String? group) { + // TODO: Implement provider/group paths + return {}; + } + + /// Get the paths for the provider and group. + @protected + Map pathsForProviderAndGroup(String provider, String group) { + // TODO: Implement provider and group paths + return {}; + } + + /// Get the service providers available for publishing. + List publishableProviders() { + // TODO: Implement publishable providers + return []; + } + + /// Get the migration paths available for publishing. + List publishableMigrationPaths() { + return List.from(ServiceProviderStatic.publishableMigrationPaths); + } + + /// Get the groups available for publishing. + List publishableGroups() { + // TODO: Implement publishable groups + return []; + } + + /// Register the package's custom Artisan commands. + void commands(List commands) { + // TODO: Implement command registration + } + + /// Get the services provided by the provider. + List provides() => []; + + /// Get the events that trigger this service provider to register. + List when() => []; + + /// Determine if the provider is deferred. + bool isDeferred() => false; + + /// Get the default providers for a Laravel application. + List defaultProviders() { + // TODO: Implement default providers + return []; + } + + /// Add the given provider to the application's provider bootstrap file. + bool addProviderToBootstrapFile(String provider, [String? path]) { + // TODO: Implement provider bootstrap + return false; + } + + // Container convenience methods - these are extensions to Laravel's spec + // to make working with Dart's type system more ergonomic + + /// Register a singleton binding in the container. + void singleton(T instance) { + app.container.registerSingleton(instance); + } + + /// Register a binding in the container. + void bind(T Function(Container) factory) { + app.container.registerFactory(factory); + } + + /// Get a service from the container. + T make([Type? type]) { + return app.container.make(type); + } + + /// Determine if a service exists in the container. + bool has() { + return app.container.has(); + } + + /// Register a tagged binding in the container. + void tag(List abstracts, List tags) { + app.startupHooks.add((app) { + for (var type in abstracts) { + for (var tag in tags) { + app.container.registerSingleton(app.container.make(type), as: tag); + } + } + }); + } + + /// Register an event listener. + void listen(String event, RequestHandler listener) { + app.startupHooks.add((app) { + app.fallback((req, res) { + if (req.uri?.path == event) { + return listener(req, res); + } + return true; + }); + }); + } + + /// Register a middleware. + void middleware(String name, RequestHandler handler) { + app.startupHooks.add((app) { + app.responseFinalizers.add(handler); + }); + } +} diff --git a/packages/support/lib/src/providers/service_provider_static.dart b/packages/support/lib/src/providers/service_provider_static.dart new file mode 100644 index 0000000..be0bdbc --- /dev/null +++ b/packages/support/lib/src/providers/service_provider_static.dart @@ -0,0 +1,11 @@ +/// Mixin that provides static members for ServiceProvider +mixin ServiceProviderStatic { + /// The paths that should be published. + static final Map> publishes = {}; + + /// The paths that should be published by group. + static final Map> publishGroups = {}; + + /// The migration paths available for publishing. + static final List publishableMigrationPaths = []; +} diff --git a/packages/support/lib/src/providers/service_provider_support.dart b/packages/support/lib/src/providers/service_provider_support.dart new file mode 100644 index 0000000..15920a3 --- /dev/null +++ b/packages/support/lib/src/providers/service_provider_support.dart @@ -0,0 +1,87 @@ +import 'dart:async'; +import 'package:platform_core/core.dart'; +import 'service_provider.dart'; + +/// Storage class for service provider state +class ServiceProviderStorage { + /// The registered service providers + final Map providers = {}; + + /// The loaded provider types + final Set loaded = {}; + + /// The deferred services and their dependencies + final Map> deferred = {}; +} + +/// Extension that adds service provider support to [Application]. +extension ServiceProviderSupport on Application { + /// Get the provider storage instance. + ServiceProviderStorage get _storage { + if (!container.has()) { + container.registerSingleton(ServiceProviderStorage()); + } + return container.make(); + } + + /// Register a service provider with the application. + Future registerProvider(ServiceProvider provider) async { + provider.app = this; + + var provides = provider.provides(); + for (var service in provides) { + _storage.providers[service] = provider; + if (provider.isDeferred()) { + _storage.deferred[service] = provider.when(); + } + } + + if (!provider.isDeferred()) { + await _bootProvider(provider); + } + } + + /// Boot a service provider. + Future _bootProvider(ServiceProvider provider) async { + if (_storage.loaded.contains(provider.runtimeType)) return; + + try { + // Boot dependencies first + for (var dependency in provider.when()) { + await resolveProvider(dependency); + } + + // Call booting callbacks + provider.callBootingCallbacks(); + + // Register the provider + await Future.sync(() => provider.register()); + + // Execute any startup hooks that were registered during registration + for (var hook in startupHooks.toList()) { + await hook(this); + } + startupHooks.clear(); + + // Boot the provider + await Future.sync(() => provider.boot()); + + // Call booted callbacks + provider.callBootedCallbacks(); + + _storage.loaded.add(provider.runtimeType); + } catch (e) { + // If registration fails, remove from loaded providers + _storage.loaded.remove(provider.runtimeType); + rethrow; + } + } + + /// Resolve a service provider. + Future resolveProvider(String service) async { + var provider = _storage.providers[service]; + if (provider != null && !_storage.loaded.contains(provider.runtimeType)) { + await _bootProvider(provider); + } + } +} diff --git a/packages/support/pubspec.yaml b/packages/support/pubspec.yaml index 0b62651..ab6b996 100644 --- a/packages/support/pubspec.yaml +++ b/packages/support/pubspec.yaml @@ -1,15 +1,20 @@ name: platform_support description: Protevus Platform support package. version: 9.0.0 -# repository: https://github.com/my_org/my_repo +homepage: https://protevus.com +documentation: https://docs.protevus.com +repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/support environment: sdk: ^3.5.4 -# Add regular dependencies here. dependencies: - # path: ^1.8.0 + platform_container: ^9.0.0 + platform_core: ^9.0.0 + meta: ^1.16.0 + collection: ^1.19.1 dev_dependencies: lints: ^4.0.0 test: ^1.24.0 + http: ^1.2.0 diff --git a/packages/support/test/providers_http_test.dart b/packages/support/test/providers_http_test.dart new file mode 100644 index 0000000..8db365c --- /dev/null +++ b/packages/support/test/providers_http_test.dart @@ -0,0 +1,129 @@ +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_container/container.dart'; +import 'package:platform_support/providers.dart'; +import 'package:test/test.dart'; +import 'package:http/http.dart' as http; + +// Test service provider with HTTP functionality +class HttpTestProvider extends ServiceProvider { + final events = []; + final middlewareCalls = []; + + @override + void register() { + super.register(); + + // Add a route handler + app.fallback((req, res) { + // Record middleware call + middlewareCalls.add(req.uri?.path ?? ''); + + if (req.uri?.path == '/test') { + events.add('route-hit'); + res.write('test'); + return false; + } + return true; + }); + } + + @override + void boot() { + super.boot(); + } + + @override + List provides() => ['http-test']; +} + +void main() { + group('ServiceProvider HTTP Tests', () { + late Application app; + late PlatformHttp server; + late HttpTestProvider provider; + late int port; + + setUp(() async { + app = Application(reflector: const EmptyReflector()); + server = PlatformHttp(app); + provider = HttpTestProvider(); + + // Register provider before starting server + await app.registerProvider(provider); + + // Start server on random port + await server.startServer('127.0.0.1', 0); + port = server.server?.port ?? 0; + expect(port, isNot(0), reason: 'Server should be assigned a port'); + + // Wait a bit for server to be ready + await Future.delayed(Duration(milliseconds: 100)); + }); + + tearDown(() async { + await server.close(); + await app.close(); + }); + + test('routes registered by provider work', () async { + expect(provider.events, isEmpty, + reason: 'No events should be recorded yet'); + + // Make request to test route + var response = await http.get(Uri.parse('http://127.0.0.1:$port/test')); + + // Wait a bit for async handlers to complete + await Future.delayed(Duration(milliseconds: 100)); + + expect(response.statusCode, equals(200), + reason: 'Should get successful response'); + expect(response.body, equals('test'), + reason: 'Should get expected response body'); + expect(provider.events, contains('route-hit'), + reason: 'Route should be hit'); + }); + + test('middleware registered by provider works', () async { + expect(provider.middlewareCalls, isEmpty, + reason: 'No middleware calls should be recorded yet'); + + // Make request to trigger middleware + await http.get(Uri.parse('http://127.0.0.1:$port/test')); + + // Wait a bit for async handlers to complete + await Future.delayed(Duration(milliseconds: 100)); + + expect(provider.middlewareCalls, contains('/test'), + reason: 'Middleware should record request path'); + }); + + test('multiple requests are handled correctly', () async { + // Make multiple requests + await Future.wait([ + http.get(Uri.parse('http://127.0.0.1:$port/test')), + http.get(Uri.parse('http://127.0.0.1:$port/test')), + http.get(Uri.parse('http://127.0.0.1:$port/test')) + ]); + + // Wait a bit for async handlers to complete + await Future.delayed(Duration(milliseconds: 100)); + + expect(provider.events.length, equals(3), + reason: 'Should record 3 route hits'); + expect(provider.middlewareCalls.length, equals(3), + reason: 'Should record 3 middleware calls'); + }); + + test('middleware runs for all requests', () async { + // Make request to non-existent route + await http.get(Uri.parse('http://127.0.0.1:$port/not-found')); + + // Wait a bit for async handlers to complete + await Future.delayed(Duration(milliseconds: 100)); + + expect(provider.middlewareCalls, contains('/not-found'), + reason: 'Middleware should run even for non-existent routes'); + }); + }); +} diff --git a/packages/support/test/providers_test.dart b/packages/support/test/providers_test.dart new file mode 100644 index 0000000..8fbdebe --- /dev/null +++ b/packages/support/test/providers_test.dart @@ -0,0 +1,236 @@ +import 'package:platform_core/core.dart'; +import 'package:platform_core/http.dart'; +import 'package:platform_container/container.dart'; +import 'package:platform_support/providers.dart'; +import 'package:test/test.dart'; + +// Test service class +class TestService { + final String message; + TestService(this.message); +} + +// Service registry for testing +class ServiceRegistry { + static final Map providers = {}; + static final Map booted = {}; + + static void register(String key, ServiceProvider provider) { + providers[key] = provider; + } + + static void markBooted(String key) { + booted[key] = true; + } + + static ServiceProvider? get(String key) { + return providers[key]; + } + + static bool isBooted(String key) { + return booted[key] == true; + } + + static void clear() { + providers.clear(); + booted.clear(); + } +} + +// Basic service provider for testing +class TestServiceProvider extends ServiceProvider { + bool registerCalled = false; + bool bootCalled = false; + final String message; + TestService? _service; + + TestServiceProvider([this.message = 'test']); + + @override + void register() { + super.register(); + registerCalled = true; + _service = TestService(message); + ServiceRegistry.register('test-service', this); + } + + @override + void boot() { + super.boot(); + bootCalled = true; + ServiceRegistry.markBooted('test-service'); + } + + @override + List provides() => ['test-service']; + + TestService? getService() => _service; +} + +// Deferred service provider for testing +class DeferredTestProvider extends DeferredServiceProvider { + bool registerCalled = false; + bool bootCalled = false; + TestService? _service; + + @override + void register() { + super.register(); + registerCalled = true; + _service = TestService('deferred'); + ServiceRegistry.register('deferred-service', this); + } + + @override + void boot() { + super.boot(); + bootCalled = true; + ServiceRegistry.markBooted('deferred-service'); + } + + @override + List provides() => ['deferred-service']; + + TestService? getService() => _service; +} + +// Provider with dependencies for testing +class DependentProvider extends ServiceProvider { + bool registerCalled = false; + bool bootCalled = false; + TestService? _service; + + @override + void register() { + super.register(); + registerCalled = true; + + // Get the base service + var baseProvider = + ServiceRegistry.get('test-service') as TestServiceProvider?; + if (baseProvider != null && ServiceRegistry.isBooted('test-service')) { + var baseService = baseProvider.getService(); + if (baseService != null) { + _service = TestService('dependent: ${baseService.message}'); + } + } + ServiceRegistry.register('dependent-service', this); + } + + @override + void boot() { + super.boot(); + bootCalled = true; + ServiceRegistry.markBooted('dependent-service'); + } + + @override + List provides() => ['dependent-service']; + + @override + List dependencies() => ['test-service']; + + TestService? getService() => _service; +} + +void main() { + group('ServiceProvider Tests', () { + late Application app; + + setUp(() { + app = Application(reflector: const EmptyReflector()); + ServiceRegistry.clear(); + }); + + tearDown(() async { + await app.close(); + ServiceRegistry.clear(); + }); + + test('registers and boots non-deferred provider immediately', () async { + var provider = TestServiceProvider(); + await app.registerProvider(provider); + + expect(provider.registerCalled, isTrue, + reason: 'register() should be called'); + expect(provider.bootCalled, isTrue, reason: 'boot() should be called'); + expect(provider.getService(), isNotNull, + reason: 'Service should be created'); + expect(provider.getService()?.message, equals('test')); + }); + + test('defers loading of deferred provider', () async { + var provider = DeferredTestProvider(); + await app.registerProvider(provider); + + expect(provider.registerCalled, isFalse, + reason: 'register() should not be called yet'); + expect(provider.bootCalled, isFalse, + reason: 'boot() should not be called yet'); + expect(provider.getService(), isNull, + reason: 'Service should not be created yet'); + }); + + test('loads deferred provider when resolved', () async { + var provider = DeferredTestProvider(); + await app.registerProvider(provider); + await app.resolveProvider('deferred-service'); + + expect(provider.registerCalled, isTrue, + reason: 'register() should be called after resolution'); + expect(provider.bootCalled, isTrue, + reason: 'boot() should be called after resolution'); + expect(provider.getService(), isNotNull, + reason: 'Service should be created after resolution'); + expect(provider.getService()?.message, equals('deferred')); + }); + + test('resolves dependencies before booting provider', () async { + var baseProvider = TestServiceProvider('base'); + var dependentProvider = DependentProvider(); + + // Register base provider first to ensure it's ready + await app.registerProvider(baseProvider); + await app.registerProvider(dependentProvider); + + expect(baseProvider.registerCalled, isTrue, + reason: 'Base provider register() should be called'); + expect(baseProvider.bootCalled, isTrue, + reason: 'Base provider boot() should be called'); + expect(dependentProvider.registerCalled, isTrue, + reason: 'Dependent provider register() should be called'); + expect(dependentProvider.bootCalled, isTrue, + reason: 'Dependent provider boot() should be called'); + + expect( + dependentProvider.getService()?.message, equals('dependent: base')); + }); + + test('singleton registration works correctly', () async { + var provider = TestServiceProvider(); + await app.registerProvider(provider); + + var service1 = provider.getService(); + var service2 = provider.getService(); + + expect(identical(service1, service2), isTrue, + reason: 'Should get same instance'); + }); + + test('provider storage persists across resolutions', () async { + var provider = DeferredTestProvider(); + await app.registerProvider(provider); + + // First resolution + await app.resolveProvider('deferred-service'); + var service1 = provider.getService(); + + // Second resolution + await app.resolveProvider('deferred-service'); + var service2 = provider.getService(); + + expect(identical(service1, service2), isTrue, + reason: 'Should get same instance across resolutions'); + }); + }); +} diff --git a/sandbox/eventbus/.github/workflows/dart.yml b/sandbox/eventbus/.github/workflows/dart.yml new file mode 100644 index 0000000..21b7ff6 --- /dev/null +++ b/sandbox/eventbus/.github/workflows/dart.yml @@ -0,0 +1,54 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Dart + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + # Note: This workflow uses the latest stable version of the Dart SDK. + # You can specify other versions if desired, see documentation here: + # https://github.com/dart-lang/setup-dart/blob/main/README.md + # - uses: dart-lang/setup-dart@v1 + - uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603 + + - name: Flutter action + # You may pin to the exact commit or the version. + # uses: subosito/flutter-action@4389e6cbc6cb8a4b18c628ff96ff90be0e926aa8 + uses: subosito/flutter-action@v1.5.3 + + - name: Install dependencies + run: dart pub get + + # Uncomment this step to verify the use of 'dart format' on each commit. + # - name: Verify formatting + # run: dart format --output=none --set-exit-if-changed . + + # Consider passing '--fatal-infos' for slightly stricter analysis. + - name: Analyze project source + run: dart analyze + + # Your project will need to have tests in test/ and a dependency on + # package:test for this step to succeed. Note that Flutter projects will + # want to change this to 'flutter test'. + - name: Run tests + run: flutter test --coverage + + - name: Install lcov + run: sudo apt-get install -y lcov + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 + with: + file: coverage/lcov.info diff --git a/sandbox/eventbus/.gitignore b/sandbox/eventbus/.gitignore new file mode 100644 index 0000000..3d34218 --- /dev/null +++ b/sandbox/eventbus/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ +coverage diff --git a/sandbox/eventbus/.metadata b/sandbox/eventbus/.metadata new file mode 100644 index 0000000..0bb64e4 --- /dev/null +++ b/sandbox/eventbus/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 7e9793dee1b85a243edd0e06cb1658e98b077561 + channel: stable + +project_type: package diff --git a/sandbox/eventbus/.vscode/settings.json b/sandbox/eventbus/.vscode/settings.json new file mode 100644 index 0000000..52472e3 --- /dev/null +++ b/sandbox/eventbus/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "codecov", + "devcraft", + "shouldly" + ] +} \ No newline at end of file diff --git a/sandbox/eventbus/CHANGELOG.md b/sandbox/eventbus/CHANGELOG.md new file mode 100644 index 0000000..5302c51 --- /dev/null +++ b/sandbox/eventbus/CHANGELOG.md @@ -0,0 +1,67 @@ +## 0.6.2 + +* update `logger` dependency + +## 0.6.1 + +* [Add] `allowLogging` to control logging (thanks [@hatemragab](https://github.com/hatemragab)) + +## 0.6.0 + +* **[Change]** fire `EmptyEvent` after each event to keep stream empty. +* [Add] [Logger](https://pub.dev/packages/logger) + +## 0.5.0 + +* [Add] timestamp for each `event`. + +## 0.4.0 + +* [Add] mapper + +## 0.3.0+3 + +* Downgrade clock version + +## 0.3.0+2 + +* Improve documentation + +## 0.3.0+1 + +* Improve documentation + +## 0.3.0 + +* [Add] `EventCompletionEvent` +* Improve documentation + +## 0.2.2 + +* [Fix] `clock` dependency + +## 0.2.1 + +* [Add] debug logging + +## 0.2.0 + +* [Add] history + +## 0.1.0 + +* [Add] distinct + +## 0.0.2+1 + +* [Fix] GitHub repository link + +## 0.0.2 + +* [Remove] `id` of `AppEvent` + +## 0.0.1 + +* Initial release. +* [Add] `EventBus` +* [Add] `AppEvent` superclass diff --git a/sandbox/eventbus/LICENSE b/sandbox/eventbus/LICENSE new file mode 100644 index 0000000..c560cf3 --- /dev/null +++ b/sandbox/eventbus/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Andrew + +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. diff --git a/sandbox/eventbus/README.md b/sandbox/eventbus/README.md new file mode 100644 index 0000000..4c8f4bd --- /dev/null +++ b/sandbox/eventbus/README.md @@ -0,0 +1,98 @@ +# EventBus: Events for Dart/Flutter + +[![pub package](https://img.shields.io/pub/v/event_bus_plus.svg?label=event_bus_plus&color=blue)](https://pub.dev/packages/event_bus_plus) +[![codecov](https://codecov.io/gh/AndrewPiterov/event_bus_plus/branch/main/graph/badge.svg?token=VM9LTJXGQS)](https://codecov.io/gh/AndrewPiterov/event_bus_plus) +[![Dart](https://github.com/AndrewPiterov/event_bus_plus/actions/workflows/dart.yml/badge.svg)](https://github.com/AndrewPiterov/event_bus_plus/actions/workflows/dart.yml) + +**EventBus** is an open-source library for Dart and Flutter using the **publisher/subscriber** pattern for loose coupling. **EventBus** enables central communication to decoupled classes with just a few lines of code – simplifying the code, removing dependencies, and speeding up app development. + +event bus publish subscribe + +## Your benefits using EventBus: It… +- simplifies the communication between components; +- decouples event senders and receivers; +- performs well with UI artifacts (e.g. Widgets, Controllers); +- avoids complex and error-prone dependencies and life cycle issues. + + +event bus plus + +### Define the app's events + +```dart +// Initialize the Service Bus +IAppEventBus eventBus = AppEventBus(); + +// Define your app events +final event = FollowEvent('@devcraft.ninja'); +final event = CommentEvent('Awesome package 😎'); +``` + +### Subscribe + +```dart +// listen the latest event +final sub = eventBus.last$ + .listen((AppEvent event) { /*do something*/ }); + +// Listen particular event +final sub2 = eventBus.on() + .listen((e) { /*do something*/ }); +``` + +### Publish + +```dart +// fire the event +eventBus.fire(event); +``` + +### Watch events in progress + +```dart +// start watch the event till its completion +eventBus.watch(event); + +// and check the progress +eventBus.isInProgress(); + +// or listen stream to check the processing +eventBus.inProgress$.map((List events) => + events.whereType().isNotEmpty); + +// complete +_eventBus.complete(event); + +// or complete with completion event +_eventBus.complete(event, nextEvent: SomeAnotherEvent); +``` + +## History + +```dart +final events = eventBus.history; +``` + +## Mapping + +```dart +final eventBus = bus = EventBus( + map: { + SomeEvent: [ + (e) => SomeAnotherEvent(), + ], + }, + ); +``` + +## Contributing + +We accept the following contributions: + +* Improving the documentation +* [Reporting issues](https://github.com/AndrewPiterov/event_bus_plus/issues/new) +* Fixing bugs + +## Maintainers + +* [Andrew Piterov](mailto:contact@andrewpiterov.com?subject=[GitHub]%20Source%20Dart%event_bus_plus) diff --git a/sandbox/eventbus/analysis_options.yaml b/sandbox/eventbus/analysis_options.yaml new file mode 100644 index 0000000..67016e9 --- /dev/null +++ b/sandbox/eventbus/analysis_options.yaml @@ -0,0 +1,224 @@ +include: package:flutter_lints/flutter.yaml +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: true + errors: + # Close instances of dart.core.Sink. + close_sinks: error + # Cancel instances of dart.async.StreamSubscription. + cancel_subscriptions: error + # treat missing required parameters as a error (not a hint) + missing_required_param: error + # treat missing returns as a error (not a hint) + missing_return: error + # allow having TODOs in the code and treat as warning + todo: warning + # allow self-reference to deprecated members (we do this because otherwise we have + # to annotate every member in every test, assert, etc, when we deprecate something) + deprecated_member_use_from_same_package: ignore + # Ignore analyzer hints for updating pubspecs when using Future or + # Stream and not importing dart:async + # Please see https://github.com/flutter/flutter/pull/24528 for details. + sdk_version_async_exported_from_core: ignore + # await + unawaited_futures: error + avoid_print: warning + always_declare_return_types: error + unrelated_type_equality_checks: error + implementation_imports: error + require_trailing_commas: warning + avoid_slow_async_io: error + use_build_context_synchronously: error + sized_box_for_whitespace: error + dead_code: warning + invalid_assignment: error + + exclude: + - "bin/cache/**" + # the following two are relative to the stocks example and the flutter package respectively + # see https://github.com/dart-lang/sdk/issues/28463 + - "lib/i18n/messages_*.dart" + - "lib/src/http/**" + - "build/**" + - "lib/**.freezed.dart" + - "lib/**.g.dart" + - "test/**" + - "example/**" + +linter: + rules: + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + - always_declare_return_types + - always_put_control_body_on_new_line + # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 + - always_require_non_null_named_parameters + # - always_specify_types + - annotate_overrides + # - avoid_annotating_with_dynamic # conflicts with always_specify_types + # - avoid_as # required for implicit-casts: true + - avoid_bool_literals_in_conditional_expressions + # - avoid_catches_without_on_clauses # we do this commonly + # - avoid_catching_errors # we do this commonly + - avoid_classes_with_only_static_members + # - avoid_double_and_int_checks # only useful when targeting JS runtime + - avoid_empty_else + - avoid_equals_and_hash_code_on_mutable_classes + - avoid_field_initializers_in_const_classes + - avoid_function_literals_in_foreach_calls + # - avoid_implementing_value_types # not yet tested + - avoid_init_to_null + # - avoid_js_rounded_ints # only useful when targeting JS runtime + - avoid_null_checks_in_equality_operators + # - avoid_positional_boolean_parameters # not yet tested + - avoid_print # not yet tested + # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) + # - avoid_redundant_argument_values # not yet tested + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + # - avoid_returning_null # there are plenty of valid reasons to return null + # - avoid_returning_null_for_future # not yet tested + - avoid_returning_null_for_void + # - avoid_returning_this # there are plenty of valid reasons to return this + # - avoid_setters_without_getters # not yet tested + - avoid_shadowing_type_parameters # not yet tested + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_types_as_parameter_names + # - avoid_types_on_closure_parameters # conflicts with always_specify_types + # - avoid_unnecessary_containers # not yet tested + - avoid_unused_constructor_parameters + - avoid_void_async + # - avoid_web_libraries_in_flutter # not yet tested + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + # - cascade_invocations # not yet tested + # - close_sinks # not reliable enough + # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 + # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 + - control_flow_in_finally + # - curly_braces_in_flow_control_structures # not yet tested + # - diagnostic_describe_all_properties # not yet tested + - directives_ordering + - empty_catches + - empty_constructor_bodies + - empty_statements + # - file_names # not yet tested + - flutter_style_todos + - hash_and_equals + - implementation_imports + # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 + - iterable_contains_unrelated_type + # - join_return_with_assignment # not yet tested + - library_names + - library_prefixes + # - lines_longer_than_80_chars # not yet tested + - list_remove_unrelated_type + # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 + # - missing_whitespace_between_adjacent_strings # not yet tested + - no_adjacent_strings_in_list + - no_duplicate_case_values + # - no_logic_in_create_state # not yet tested + # - no_runtimeType_toString # not yet tested + - non_constant_identifier_names + # - null_closures # not yet tested + - omit_local_variable_types # opposite of always_specify_types + # - one_member_abstracts # too many false positives + # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + # - parameter_assignments # we do this commonly + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + # - prefer_asserts_with_message # not yet tested + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + # - prefer_constructors_over_static_methods # not yet tested + - prefer_contains + # - prefer_double_quotes # opposite of prefer_single_quotes + - prefer_equal_for_default_values + # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + - prefer_for_elements_to_map_fromIterable + - prefer_foreach + # - prefer_function_declarations_over_variables # not yet tested + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + # - prefer_int_literals # not yet tested + # - prefer_interpolation_to_compose_strings # not yet tested + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + # - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932 + # - prefer_relative_imports # not yet tested + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + # - provide_deprecation_message # not yet tested + - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml + - recursive_getters + - slash_for_doc_comments + # - sort_child_properties_last # not yet tested + - sort_constructors_first + - sort_pub_dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + - unawaited_futures # too many false positives + - unnecessary_await_in_return # not yet tested + - unnecessary_brace_in_string_interps + - unnecessary_const + # - unnecessary_final # conflicts with prefer_final_locals + - unnecessary_getters_setters + # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_in_if_null_operators + - unnecessary_overrides + - unnecessary_parenthesis + - unnecessary_statements + - unnecessary_string_interpolations + - unnecessary_this + - unrelated_type_equality_checks + # - unsafe_html # not yet tested + - use_full_hex_values_for_flutter_colors + # - use_function_type_syntax_for_parameters # not yet tested + # - use_key_in_widget_constructors # not yet tested + - use_late_for_private_fields_and_variables + - use_rethrow_when_possible + # - use_setters_to_change_properties # not yet tested + # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 + # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review + - valid_regexps + - void_checks + +dart_code_metrics: + rules: + - newline-before-return: + severity: style + - no-boolean-literal-compare: + severity: error + anti-patterns: + - long-method: + severity: warning diff --git a/sandbox/eventbus/doc/pub_sub.webp b/sandbox/eventbus/doc/pub_sub.webp new file mode 100644 index 0000000000000000000000000000000000000000..8e13702aac1179e74d9195fd9aebfbdd950fbdc5 GIT binary patch literal 16548 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 literal 0 HcmV?d00001 diff --git a/sandbox/eventbus/doc/video_presentation.gif b/sandbox/eventbus/doc/video_presentation.gif new file mode 100644 index 0000000000000000000000000000000000000000..0ef19815533e43ee4b6c00d4b873394dc5cc28c3 GIT binary patch literal 1887898 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 TG``P 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


Lm^#^*u9@KSLw;r9<(^F3y9H>H_PO4+?0N2Ra? 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 z zr%fs9!iyp-b}%dbuK8=F6eE2D?uO(yzV?^@7GV+stn&FLSkT?Zb#Cf>jG-U)4H@vWYTUVz@{cE>DmpYJAcEnY#P)GN*}(v=d?auU4P@k zhbIZE@w2}O;zf<`?u@udCzF~Fyd8lIGLmC zq$r!3x0*js1C7C4!>5dc4D8WAvY+a;se8!0EYMyple~4?{Yj{ClAK+si{PpPJ~9>} zvDrCq`pa$w7<-!$^GE$rk8Jg?Y_WY)32&*$^Ol_B06%!W9X=tR-%1|GYrNMi!nyG*88REP zqu=@IvDb|(erHB#z1+5JI^_%?_8p4cwkG~C)+Ff1y;|okl2fIRXVmXUmr3P z@ltHQUP`2JoOh9%WR@g?834U6!NodC4q?CkKnmW`$PYRF31Rd++!EHL>ZGtsWYrn* zjz_!VF8i}?H`%0La^Q(f$F!@z6^1b2=v{MWUcolsyW}Qo|JzxjYf&D*3OVtfk#54y zbV`}^g${0yOPr2Z>MQ&u+I%A!PmoX+<6D5>LgX!~_YBO4%qVv~`bnmDoYFR!P706a zgjB*k-jWqq?4lV>k#SwaSODn+dIicZcAK`qxVlsqL{kWDH^)LBVzecroPS=)5xGXg zC^Q~?!U>j&awt)JollbEEep}(EFM>C9|=Y%7d8Ol;JZ*KbLF>!y2OB8j!H_F-vt$kl+WI z0%6cl-nv^DG?*50BHDMs1NS6`Ga}Lw`(wKIs|!Rl26M6?xJ>O+>o4%Vq9H8*kaDG- zwbEO*=@yyh;h8`WFsu8rBp?0~!v1Y^Hv@96gCtuEw?Tx7z$Cjw&z=^@n@#fqdCq5@ zTmx45!*@$(ITrm(e4iQv9aJfZh~KB%`By?2 zYM3S$qEYxr$d$&&coheiu+JU!A%J=V|FEEHUh#v(GwSClL)wC~+V7fbq4^pu?99z* zmAY)eDwugc1^2N8ISH z?}>Bj*L3s~)B79gD^$0Rsxr14Z-q9cqvKWXzrJukR$8^aJ4=PGMEmfEwvLSM6>6a& z-<9cXNFRRLydaHM{OG` zv}DX;DD1xO&%5Eeb%K;|3XDzH`@`#d8pJy-3){&ImJ9DosaCG3@|YYxL47hm$J8_ z9EurTYw|d1lx98{0M0&{txT71gNYK9W%xq|E-oovV9b;VMi>guR?LPOWVINz3>$H( z5qYs7`uxf^LW+466XSm4{FbC3vQ^L@%7F!SEfw{WI40ux3gILp7x^n{5i1 zZONEzYnbgAoBee(+r4kL7i6{{Z+4Jlc35h5)M7>*Hang*J6SWMQE6rX77S1j1Cqsn zH8Btq44o5(-V+0ThJhtu7+zr*%P>r>80HZS%Nz#2j$u8!t?v;g9nT2$#h0KVB?3{(%y2bfp3wahx1wl(iS<4HWmP#g;7o9AXJuOw9 zS*j*jUV3GzR%WT*YN;_|sX1qPdEHX$*b>cRr7dWsBWra<(@NLG>Z+5Ko~PBdXIA8F%VOg!Xmd-}#zoV{)x_qulZ~6Fjr%hjj|7`LuWas? z+1zWjxj$m#IcMXwZu8*S#+$|Vp`fjgtnDLBTVE5~$4<6>p0-b(+4?8gK7C~yP-Yw0 zY8y0S`)tlOc-=PS*cQiP7b<8MCTkb2X%}H)7wKdd>*{b=57qWZAD0^U=v-*HfLo7T>y_(V8;kQb`whJYIlRD9KK*c|#lNi)+ zPi~l@Qkg819z1yPtZg6X0MX9hJGL@$#V~pdQ{O~$xHayIpJ56aIXc4%>3&IXI7&U9 zVffl*ryG!;Us$5@@~=?HXNh}de+GFv`$pENo8&HaOfGLmi1 zVu(9as(G#oLnNT(-3~PSiZUqQMf8S^zpFjLzooy5jBkj-jyCn% zTvnPaZo!X{sw#qhZ7D4-;c*hgUr|IyzZRS_c2v20vVr1Tt|8xWpQI)Rzl+{*)gSEa z-%!%^sL2eA!A^GOuSB8oK9U<8x`!JS`!Eexk40iPs;~jo!r?JJEyh@gZlVn15NLeL zV$>pG!-hjqqF<*$Mxp`HqUI5`L#|m;s)<_kt6AIH89q6of)aN?DO8`jHBib9D3R*Z zv<6Dw@o8Hd?Cm}og$(u%gVL$Hr^8UA5IIE|pQ<%EIhm752z@%0K7HrpWanfIa(Y_8 zXaE|6fPMv`BOJyq<=9`5*A9lrRz@RFBAXU<`*l{4mB_&fyfu7fSX=zL#IAahYKbqI z{9wGzpaFS^M^~e_=Z4;=uWMF#n>4+WRxY1w_J0W;t7(6G zY5XXk*mg|R`u=(7wOM=H@zL)_sq^|B$S0w!{*m8t5F5HMuz2PdJi?uGi5!lIi{y*o zu(7iS!f`mLwt{OWoz4x;(_2w7w*BwuVq?1>aWZejbffs;5zY)kXRO}F$o?vP>l{h7 z3{Sd9^{@y`q^6>A>JmlydV+Uh<}pTk=iXTfK`ONIcA)EB^rE$WPUo(dUi_J9#DzZd z(xV`j`zFXK_8tCgC6ufg?eYHCD=sc?RHFax@>#3!sdIR|ce?K_zp#^{!e@J#*9YI= z_4v}xfDE+p96-WmXnu}Vz(??P*wk`iJ}6x`0o-G|Qe0ZMvQolyo0d0N06G?yC~f$M zqJ>OeclQfi?_2#BMGKEE+_H7(Q(j%GCV_gnvOn3}Td$pRbGYjeuB2C17iZC%Q9+gy z^K#?LHS&7qS@u&-KmI59bsWc5?WCj7z|49}ak_MF(@FY8uiMLTjSWkUCA>G0S!IpV zg}5fO+08LNsolflUb@-Kr$F57Lq*GMX&uJj-x`pF%9stx)URy~$@j@@59j8gw?|Ze z3y3o+&y;R|L_=BfKI(9L?tIceTedT%Eh>y*gdj(DCai2nc-bsD#A-h~K3TtLCoP>H zsrNLzzK?y;;$Ygyb3D-(`E>xCUr0D&PO1XxE&pHUFV#CwR>$ z>5csbJbPyYI^l}f!Ou`z)8vnu*o}kVz8RaWB7_XD!wJXS^23$V`i;ZYiaxocHHbYh zdA#O#xq6>Iwe{!^@xpAcmOl9mb+iAbdJm=bD3`iT+HRtvN3T6N{yXLV;dpoU$)Dpr za`gF={l$z2CkIRKKb#z{)rV+`F+JQgw4_KcCh12se4w2S4_r8y-mQSr==D##4JvRj zWAZ(v_e6R%iXw9m0dm$O)leuN+Y#a~A0eqR2e#kl2j$D# zYRpVCUF`y$>Hh_kL5KCxhg}KD@s4^T(xFZBr|%xCAOodkZmq@W<8}Knv9F4p+436H zT9V1JR*(_o`z1a>|4krd0KgEE*&{h$7Vlx~Vwn30EGuuG;2po9XFRQS{s3s5(cS@^FSHtch-qqkD}r1M2pba1SwhbfuN z?Ak_oUHk2Gy=mc6!gt^s{lLxyZ1?Iz$_X+B(#%XrU@}O&Wgio&> z*W{2f#GZH(B;)R40VSvi6Ua94A|A!a_i%>UBb*c>iA{ZUpUfN0cm_G;3V#Ob)G0Vr zEg6i+wcRqd96cyZddq1>}~a1#9Mg3d!`LyF_+$ZsveOD^OpL zKP)4H5MK^S5i}23uLoae{$`cd(<8M-uIM=VS#V1)U7U^ivP+I9TXvo9#xt%ZUkAAo z%Ji_fq!F@0pz)NV31>{7Twr#;M1F5b_)&)`E- z)pVheuIGgBOY`DR7HHsege^}91qfQaC@k8rjlN7a%TaAaagRUJSCgmH_x&R3hRMuS z$Oyf{Z<6{zP=D&~{S+%jc&(&Q+{~A!M_s=&<%Q z>DDO-E!SC-0YhlsQxH9}lHUNVjHk8HqI0-pS z939B*XVx_-aCv>GzuOwRx-}#A?J_mk>BvD@f z3HJW>+%obT2W=Sugmv5-C#s3ba_a*`Wbty)pH)vO(W(r@$os6WQ?C>+nY%p`%#-Hs zcIgGGKLkXKpM(RD2pGITej7G(_{u-FME9)XT4;FG2q<~c`0SfMMgDWb>Gm%^nd|s6 zcJ1PnZHK2>*u0a;?4_(lM|xXd{62+c{t2k(0`>c0;wJ6&k2O$CLXHO}xyQ8MWNpjfKS7 z)%-eUI2vgAJzJl}z0QaK2y7Q{ReYSqaytZn^cOJF{fOtOrs6Z0P;}FyzDZo_M1%xS z=m2x<0nNJ95a4T;#~Pyc%oK3+sd76KUMY%<>BFxfN>vmS?CeNWJJw<+z|ZH z)|yl3A79uX5kY=>DhH{+S9%C@vih_72DcYetlnlBX7iHOVsCPhX`WI`F3Otq1$&Dh*O)7daZP!8#(Hr7uJs z(!NAji(X2}-~{Wz!u=ioUX#kRW`D8ol^}TsX%#92i!Hu@P2%C)#jyT8T_4hhJ*^1* zFm~g79s7x8DAfGsW9ZEkx99mVHA+u(Z+gf!dmI-%GC=jYj^%St+nc)3=fY9(tqq#3 zk6rw@9SU5WEUd0_E`o_*JU5=pKjjuCk&{jfG!D^TOX$rb=nUe)l6RuBSCs2VQS9 zRD1u(Y9KYVTQvyEmM)3LHi|hHy}0U%1x7htzy64>E}eZd-FE)63=}Ek+7>@FlXez#S9IrbPjt!$iJ*=v>9i6Djf7nTQ)&zHCk-03xuEj#%Ug z$AkEDY@aXDO${J}E<*oY=YUIaLcCvag(l5kM=Od00`mbd4}Q~Bs0_~PV!vZ#D{pS+r-?5_jW;4!VczZs$nw9LtQ{aRr8Jw+kf2!h)!4T}HRYRiDo7Gq zlx`?+Df%Wz{(8oAQRhSNEh1f_7(jQas34%YFsrz@SoIK}EY(z8!B-ED;`<;&-!rK^np5k zdWZM{z+VAUuYfpI&<9q)vMU&yE0||0;71h*{z^9WN)CrguE0v3>`K1oN`aZmGe?yu z{wfjmDlvyDiNGq!>?*0#w8NPyxuYt1{%S?_Y9)tiWm;ghYIe0+bG61y_2r{#G=Ghb zdX26_jb31les+yvbB*y#jph-=3^?rf%{@L{b&GkVu^}$E=xYK|=^@a$ChN!@X znCynQ=7#v0hQy-=Jbz<~dSjYHV|rj?W_Dv%b7Rg-WA0HSfxqdEdQ-kbQ$b);VRln- zb5rR|Q~6O-1%GpudUK6Kb6sF_Lw0jhb92i~bK6lfk-w!=y`|fsr8lspKf7hHxn+2! zW%Q_J-;j}{-a6sXIvLnHmEAhs+&Vkc`t7KdOyh6+q29LW(Do~^Z7I8LrMYcwrfuV> zjl$o)rQW{d(7qekzMtKG*xXK?X+Jq?KOIa0X%Hc&3E@FRSPqe~g~&Whgj0zKfeto} z4i3i-uAmN{oDRO04uRQ@GXnB3BJUCoE>tQlD$^yDJAK};^CBPRL)E`G8tOki$)>CLb-&!D#54{{!`p9Rn`KwKV3 zn7NP3=X6Sd!F{bK1;FD+?!2VaxrAmg#Q_pfUC*fsqO-8`D6ne<;EDWDjWGkv8_0

zFL>HE9=1>BNf3YoYLIv`x2@Fl05w=w;E*8$tK`{{Kh>e!3Qr>|2zeB!&B7b%1RL?t zvx$Of_>)T90hou2KLDKB#e`GL%;TWetXuJH$T6BjjR$=Cj9{IIU2!$1M71O60< z4D;w{rrhW}*M2DKg+d<^hN!A1IcIh2#NRNioHkTL6tu?JQ> zm~yD`yR%qGHdbxc#yt> ze+;-YMF7V;=o<_DmjFN71G8kochBFyxYCR4r9-HSU5q1>s zNcsy_#Uh~q2Of_Hl4AvaVBujDB;KPxj|~fDBI}?)p)E#L8xrHuugS(AV?cL@5l385 z#U5}4Jm>@yVM#+yW;$FHj)Zz3BH(e(dk;U3ywV4Us+52`4uu|8Kbg}CITHy}+3Zm5 z2JMAILdds{&$~o;M9~_qt1@AN449ZO+)_Ic5Fp)kFb;h*uWJ~D${kJ z(V$ZTQ7r-P!)qb{w}n{9DX#rYk<|6L@u8$)mkk%X0nyTa@cuE>QX8C(g{LxOP~`xl z9SSl(6hs0Q+rpnmfFnpC1s1IDtv8qnQoeCYudfaA2fjmwhmch2Z;pen{ zL-8Qplb}Ra8wv|LOqtiNL;xYcwBtxeY=f!i*WvCqB+WY_K337Ea~~ zr@ezb5y|2K5=RjVBJh<%p+Rhz^(fqwMv?*m8QQxl28_>i5_SW0_y&-}g3pCk6WHLa zGKds#FXix*DYsQqvpv|AdvW$wjRt5jU=aWSHv=D@)PCBdvg;Xa&*GxiQxVQEUZVT0 zDar$FzBggc3o;ELb}G;t%rVD+pY8 zE&dPNzwL;b#P6`99wNnAVdtwr;ihn{X<-E-*!K`viTn4zZHqZ01XnM|Q1%QvjVVnOBms{PY{Fv5f)X8Y z<1^K!MEM%FKZgPLPBK-IJ2}>i@c$o?4bE%@xCpp2zB+(UC@Ndi@ zftkZ{Jo;p4_$cD?L+A+raGFGfQl1bPkl`H|F93M%f@R3uw*!AQ1}um2>A@$SAQ;$9 z8g9t+4kAG*Zt&GJP%~cO8h=1Bi8J7IVKHWOX+IGjQVGHXa6u1PGHoavf3k=VY)6O6 zup#ku`hT+^5@{*u@Qsg&pPd+xiMtP@VnHW}5Zg4Epwh==3Q~Y2WO@?PKmEq%yPfrLsS*l2TlhR5QsM$hY<|%HD@A9TJD7SD9B{=_o|1#^TuEm0q(wnK=%z}xG@z#_Qd57=2-eD zJOt{$UWzyk08kQG!UZm20#;)~WN3&xhhXV=NU8@y0e{z!EOIUldXxmN@`FRM9H$*M z5CDoAe2z}*p=@q_eRtK+Ug0lq+Y6|;xUU1Y=@{WqHTsxWs^ey}??q{){TsuSX4f2P zbKbP+&cYKF1Ecw>>BjyU>nVQka2#ZCT@IG6N+lR(#VtssX^_s-j zR(siWsIG%tuEGNcLb0u`qvF+w2ad`$S-MWDjr9+l)bID{I&1!?;MHb3<#kCA%|=R{UY!-svK|^0O~Q^m$TuM1bWd> zAtZhTs-?^Bp~>p9h$yhcIrqGS<((0QeipYBvI#!4+K!h#dA?}iLUMhv1+F>#ky;nN zJBJ|8qPQsb(ZPu3)kl{u7ZLgLyV4IH%BPf_dVm!*i;4+H36c*A-~1I7KtyFnE@$3C zx$IfzSzg7?T}-oxD*`SCZE6*Z%TqElg@4n-a)oitxxNNNV~jEjJKBkAB1vNR(jy0U zPxX^6!MVctPe3@_cv32~#@h=^$o2+P3kDCmt<-5_mTQlFxL$4N#P{zvO)kTz{bOT| zyWxw>OxH8$-b=7&(NI_DzZc2{=?-~`a0wzl56_W)&wU%jOeBQon}JQjv&5try`!{0NZiR}?~o%k780mQ7#0Jz1*OBxnj#WRfAlMlIN|_y;Ilc8U5hX};7Ow_@`i zy06NXeZBS}cfnp`DwHY^=ulamf)uDe&bJ|uktJTVTvx`u!;YwV9?=_GAdUrfSKCKy zGiy@FT!B`%rESR$96$dc?dO+V%L~7j8lPYI^L@}V{a>-diPj$66R`NHn>c*g2{5FU z%9qg&5uc(6SO$)V$#@kX1di+dWD}v>0Tl-qrb8l^*6z28;2k4nC1#Pb5_L@k0h*xK z3ksiI1`X;Zhl$zCGGF&BUeu(c#W^p4jA3Ga4^ahsCx*^v#(;n+L_Sj*1$B=tapfNb z4IT!vpa39ABLWSKZgE{U3}f7fMM(*FphNW}_v%DWDZJq?CsJ_3_=_vNwlafcfg7`t zA?e6`b1!;^z!XHW6q#w`Ld$?j6+sD|o-)XeD><}KsK3ckaW|bD#gVtX$Bc)Vr{2N6 zoNi%$0F}5N3a>{q6|)o8*P=kncwW^n<2_@AbJ`Z=e)z2 zUm&Ocxa*%>U$FhP^Xud&0l>3YUYq)AJ-;0-6Gr$gpEH(Ag)ZOspr@DPD!Xzb>_;_YN>sHt>AhN(mTx@@`hE;$5$ zayg=p2yDbE!Nif7e5-LZBQg!LJxu&QqDZk`WfSd5?&@P=IXe?|61+%8C$^TNlZe?>IU7Ra0hCZ_ z4xS1#lSh{Z^kD4R*}5ziZ;%2EXA2*Oky*&Q+I^z(B#3F{|H`y%5}tIzxR+T#SO8Ia zaT^TWndK9}U6d0gLQIWWcUXcMJW<4hlEHGVpB@6PGe3$g8W>kwvE2Wc4#16byQWIX zRLV1L2srBuREoir(7*%yJEG_yA8nMEHs*%fd&sehK|w)crh!5j2>)+TlJR(udrWju z{%fWLu?M-x!-Uo?XWkrO=NWW#>z*#5z9Itw?W{vu3Bl#SI*>6UT8Iy00|&sf9}owl zbY2)(p99fvY-xa?ZLnSuFAWf?;^&<&@>XEoP{dly;KBDgtNCnJ7e`0<6g)lv0-#GM z==pJ3i3dgIU?bz;f?4F^L#8G6Z6|ocqs|q|&k|}5~apv$E z%?f-cl+Uih%HE6!sCDhW;^6$j6CU_qNIF$Wy9b)n1O+HWxE{_bTYoj%9w6~8g_ka`ypX6VuV`gu<;>s>Dvj3o*y*iJBzcyLf&kKpe(co}9V#c(k~sc7%S0El|v{H6^|0VF+xZt_&+rp%VFYpi~e`nAa3isC^^)bS04oJ%%Fxa zDBw*R0Q%J9dg}bf{*D>KmBl1C(<@`M%n~6K{hZ7brd%V9-w5JVVSa3F90Mo zDs$x|6~fgG#8w3!_Gyn#7gJo)Pgsl!9998okhB(ctuIt<4Z7)O6kpK3FF<;^W8E# z-Lg<1>_2~?Qgo`5a7NAJ|IVvq9{HO^1P0i0 zCK#@RH=~LoKn>^_vT9g6N{>??=y06`sU1M<<(?;_jaXo*&gW@dvoo)UfX%Ql9?&8E zKciLwsNMl%Iy1bD2XwKGpPfLM$&IibcD32YC8x!cH5Qt3<8GV4L$sfm(-;CV_kS~?7~uL=?J0Nc;ru;rj3E_jNbwk6DyCSj%0 zGF>~}X$e!M?VWduJ2>bp{Bo7m82vcIhz4Mz>)LR}wG8TZtV>o4&!1q-pz+|Hi7MFJ zk|*si)8=xUDtK-)ax14my6mF156W%PE(;^We7_uLsKbzV*f{Xpv>vw~qgA^z%G+(u z@CD^8u*n0W+b&C55Kn9a+#Yac;Hm%mfwE>3k13Ktd$Q9S4incSP1Aeb=<-H7#{EZy ztLYWhtOsxSK(Eh_Hm2%&?3_clOnW_ScV~6!r9IZ8@s5KuX)VcheLtJ z;{=c;wqN?=d`X+iI7{L3bg<{(6gDx&LbllzdQw9AgJx2%o|_2w_i=^)055GlN%vs$gSVQ!WZe6&|u&Yw~{O*=TiV zT=bn&d8nsyLP49y%QV(Izo}Pxlu}RQ%r|?Ets1l%GcW8zAG3$9P4({)zOPLdl*M39 zf)8IsKYX>&nybBBFV(H5d^b~jwzK$PjhyRiYjfT~6Hh*I|F7*+e5&K$d*8=B9T)pI zWoqMlDYBrkUdy^`Y@puz;*sYtgYi2%6CzLhK6BodDEYojn3!5jun>6q;iK)PLl1o- zv-yPndFe@GlpnT57ry@ zBbag4`|S~B=Ak2y$lxbk{FVK|OD~-~q`e-ddA_^#{@E>WvxMLuK|XiQgP!;txx_aP ziJV+(cQ3i&Z+dAQa%i%~>-pk&kFtNh52cFdyMmiIBi{5b@0*ELsv;A2y54_EeSh%N zCyc>|%dkSL`3bxJ>0h_L{C@c5Prt0iC!hBI3C&=ihZ{Z(C12#M9(5*GO~m>Mp5%@+ zXJ9Xm%nJKoT$sM(8w8_%m>mheZ0?QNAN_vi^M{Adyq~S(R$h(cmEfn=)9HEytU!H4aaWY)^Gk$)Vy8NynW8RL;1X8 z!@N_+yz{`k%jCT4;=J4LygPisLv+DYX~D~I!P{=Z$8W(mYQZmQ!9QmqpnTzQ!$M%k zLeRiM@Z`dg#f6Yv?&0SmNpvw(X)(-jG2Cu3!f!D$YB4Hl@mS7cbot`(hQ*kU#S;UI zv6G7@7Z*?ME}n)jkwur{l$PQRmlEuj&iE}QMlB^JEuGC-N-keI*RYh*v2=c5DRpuw zZE@+s?ov8@nIgJORa(w4T+Xyx&hlH%j#|!1TF%W`&MRNeZ&<$Av3zM@xnOd+aB;b4 zcexn8LK9snQChjo?eei(DfL?^i&`m9TDh9DQo$)-xz?~!*|BncV5Mqu<;LPl_3lay ze3dS`TC22r({Q!UZnfTT^;XnsL(*zv&T3QnYIDPCOULT%fz>;ct9KVy@9nPMhp#b2 z*IJd<9vH5**{!wvtv!rd>quJrFK4Z@eC<)g+T)J3Cj)C;lWR{G*PiXJJ%_I|Mc2EP z)_V-sd+pZy{MP%U)(4W-2Xoek%GX~stPgjrzZ_T}nOuLhxc+)~{SAC$RCMF5(#DwK z#<<4K_Z;Bk-6g|5s zmb;0&x+&hcDe>Q?RZvn^%&82vS_qm#wZQU=6Iz|b4$_WF&w*J{|nVl@7tK0bC zZIk~Jr0;D1A4g{%4%Pd=@!4lE7>s>s$d-ML5Ht4d`@Ux1vhQTZE`*R>V+mQZFGU$k zNC-(teUMNgB75fR_xtOd>v^v0T-W*IJm-18pZk8@^5hhS{sZOX1C^^r9`hki;82w; zcc`XysBU?v;c=)LeyEjls9kV)r}j{%`%riEQ18>B{^p^<@u4C7uMzWKV}ZXWa(_*= z{+e0-HTU>y;o%m`k{IWS2TcEw{4YqRJ9K0WNH={T)EcTx+u-;<)S3C{4a*UYCy4F@ zE-@M^^CU^s5`SCn==Qav(-)yKwMXs+VU}9kR3toZ3lBR<@vIFUF~U;`5^f(SdVYFD zMf_{cB4^kGh8h8oCnH#4$l~(2QD8+kjW{6Cn>nS zpvzvo;$C8Ie-A_uXcz$5eg_0k!=XK8A=3DaV~D6YA>=~}6$)EKdzO}U%@6@FNR13W zPPCT5)1ZKv|3wU19N_?w;FjY$T0D&)5NQ-9eFBemM5c8=dMbx^fXf+Lol#AvKs*6- z*(ZWqkyoLbNFzMQ79IyUj?+F?M8soO{!;ZEOFl^o^*DPfWc8fZ0Z3Z^@xT9FvP~T&i-kPyB3Q$ z1|aZ)cnH+!sIDN?fee53U+gvch_v^>EtL}wcyP_A{5;v?Jh9-3XEVY2+5v1Y!7coJ zRxb7-EbQ7aAiJ5s-Fl3}CtCZTL*!56w(#k;8MwW~9mBY$`cQn~Uw_O%JdBn{&q@Ld z0+*xJ-wxcsWy6>csnG;U92j|~AY+7=#Ak`#sn3 zP@bX0$@4Ifv4KFT>qNv6dfG~SCna+7(Plb@+|81%%TJHDP*KuH4u^9RN zwb!O>mi30XhaIb6r~c1D;7%R`OSXr5Bft-5lYKE;B_ECF!!TYD#2P93txhI(S5MhV(b z+^4Fn(4@y|Y-{>YvmB{qTHdHok8RvxyLY3ovcNH(wWiSJk#$XxM`aP68xRtZA`pAZ zVr@@uxnm0`eVT@L6Va%_gMdBj6fhu?{Kvga_|C>B*ZcJ&9i> zC#=@8R4|o0HFz!I8^yKHYAcKD>l@mZ>Kk6Kn$1~f)-wrcw#ASBw7%*Fvo~o@3i(uZ z*PCrOwbKc+;3&Tq`{ap&+`RncLQm^EKiw^9>iQh?xhY_HgwnTN?uA*?^T2w|&(>WO zpPxHV#@qVfs#g_6yx!eS$^qUO(B0|y3c6~OfEnys2Ab# zeZ%Zh+B(7>yxcl^ErFwL?0T+U+gpLE(zbEo_T{#B;zJzm6Ve~-+9&0{m9|eQR_RH; zR{?W&Osg^2cg$#AFYB1q71)vfV5mms?3^<-weS3B=~C7?e@mdR^OIu&XV=0Pg?GOe zJgUmNmV7KDn3Tua?8H8Q(h>f>9R97WyPr%VYSZ5K1Vqr15zm1n0{hf3rxEM(@Srs| z;d`G96dhiCH~JPb3gjLpz1Sp2aDho>>6Zg4>C&Mj745?Dc&0Z(en%>L7r}T~_qD6V zEgakR<9k2&nyi6o3rY<-dQHU$3b}5WJ*0cvS?Cu^?%x-zV9UeABWa*e&`4Flx~1auFBe?Y>L zk2Xp0uM>h>rj8e1;VM*NzhcQp=cAOqP#lFb9{NETb6ie*1%6zKH$pr)QQjJ44)f*n zFD7F62b7QK5@Y|Ej?pyzQ9kv{#^AOqOt%X1DMR-3MMcIKj0k9fOYj5R9G*QVY$CP# z?`wkEAT*^BK%<&A{f7DgC2zYrOQmEcEVn}7aumc#FDcNA(dMY-=~v(xPVFm#U>*xF z%TcUfQQV-6oomCY_ukm)n@&dS5E7|<@z4&_>wLm#t%G}_v9f&?xV;56B~56mVymMSgzLI@_O#WnNz8{GFnI3{))!vjCvqn5W`04z9&J4FDwMQNi=? zi+fR!ThRT<2>RA|g`EHP$F1r%oxfACkBu`#aU1b2$7d({-equ!)V9|A?toK7!T_lc zsCfsjA3XRdV&Q~kDxE6i;k?nEcV~coq&2p8K?AC41QbEU2lsBdZ0@ERp3V3_70nzt zi=R>UyuSkIYOlQ|j54DJfT+5tJZ`pI50$jhqQEC`^eppK^qLII(U6zYB>EkYxC&-B zs#7x#qyjNzXT!J~J{3v;oOI|z-~FLQ%HTDm9?3LEh34N`-7+|NTbTvk;z1U!$X%UK zQsG^^oX9!M`pOFPb+<{X20y~b#n4?S@K%+J3m(dXcA|%q@H~}ot=Dl~Ad$=sX*G$3 zIP?lwOoPi*U`9zHo?egt0^kYHo=+N)dSvBp;0W6*bXggn-Za7{1LAf04_MSRWNCMBMV~)z50sK)&`HJ!cfT5_w zpBAVo%7sr)@u`IUu$dQ>3y*`X@bR#TlCQ<8M}5R^%Z^l!J|l`GsLo=ADRfUD=+u=s zFU1KU*9!t;%xDzcInASOPy3FJ+=vv+)Um8+7HCNX6jMQ|URtH{rUJk$_(3>~NS+hB zPy>??18~Ub%8ig?@T4gODbWJ@z_$vpcap%%2BiF}ukO&CmrAHT>-M_b0ZV$e!SbTw zMKJdQ;H1GDgc-0PQax0@FW^BoaTSClK?SY$fNl7A0bb|uJ7OBV6oc`ts&n2Rw+61m zjQ~S+3mD;jJ$eVFx2y>Yb97Qa_&dFvIhe6m%fOy*ML^19rxk!FiPT^_o4^uM5mzn* z0Nb{`I5;BCxAKFUB5Pl;2!{8=Nn^#GM!&2%FrzFaRRkqqhXsqfW@^OAFpX8Tcfm(2 z+~(AU+*Odl4ZLU9#8GHIrPXmm>)5fFR@)a|Dt&iyf~{r%6&m<(208GhEPV>)i) ztGkg77nGt}$^=p)iEyYDkj*nlMX-a8(&_~8;Fr+%$8E$6+U}0~vPPQxF&K*N@67^e zx&+3U#eno7P_ucrq6TEBK;T4-0ZD=&FMjv3XsgoJ`}QuKNEuqCCb-_rb`(W9&r3Mr zI65$_XeDMpzWeKxr6X$<{qjFR*Ay2c)xMmtx;~Bnx7#3D31o_~q-x9G1JobQ1RIsB(i;GtF|=@x3H0D9XJCHdKex#OCFN(=+xK3!fmKf2o=NH` zQl#1g5}*}h@g~lIC6PV5$!mL+yAxkR1yjW!G2$dK7)klqn{;ZjA{HV_(k) zu&Q;8NlI73&$NaK9bomeiYvNTa4bCWbA=yXg2Iua*vT^6<^oMb-C>+;!tTp+M!0cB zq!n~FEdgU#M+n{KV6c z@CX2b*BQXTYw!Cnf%Opu6RJe~J2Qh5a59u2LL?oh;w#e1<^^@Uov;){JXH%eyNIek zFzY2F4^Q#8TYrWZpP31?n$gZKiC|&l)TBd=5nw64_09FsNf4U&2`*ovtkmN z0xV-$I}-)41Z)Kk!UPcFh{rkM4)sD{8KeSkwT=X>6X>nn)(Xt#kfudB{5Xa$mB zf~&rZ!xd>Tl;|^*gg&|JXSWhV;+`ga`GG|PfcXdt&1r^WjwJvu!HO^21XqEm1T6nk z6G!IZ7F>n(sg>G{9#nNd8M?WzLWx)ap2RM+4tXm|& z7^qkYM_FVfE;2_UOJ~D4ZOxg;uv$_5H!ECwuFbcQ3N^4R_{eimz~uFiNth{)<3GJJ z3#%?#zweta_6+i6k8j!MS}ZdCG5fF&P?f;c$%?*rdHUE(gW+O*6M)7g{RF^JSGY^~ zLu6vi!23e=tO$N| zY1Ds|$U()rSz}K?eI@1c#Lo_shN+2h*HkQhgrn=1`2zWQm5J)Cn3QB8KnONP88x7S z{qQf~*T3cWDEh?aEp-zE0zf0jDlcC(f74Rir}OMr|9FNja-4E{F;?FSfqxszy^R&Q zNq{ad^mKGN8wY71_gB+OP$ShBYQVH4AYuD;ltw?u_igd^`0`uIg{d9%@Qw^k za*xQnB^ptuG-b~%Y~LGfkLpf~uPSy8?MbN2-ZtnH`Nj+9y?irWzC9}?I_i|@agu~M zxij@z2cw{2b)z2UmkHAtc2)!W|iWcYj_1)b0Jh(Fgc_0?3 zV~_Cp{OHbNO}rERFcdkMyw;@Jl4gf~Fw2uDfNyfl8!s$XE8Bha`iYD_E9K{=+@}(?yT*0 z@(z%9|JD(VDLbppSHuOPtx510C0eOk!^+=OEUP3b># zKkd-FcxU6@$pi8Fu}8orokI+Ps_yquMC~b8B9I%$k&3;=^#-U^K*5+ofom|>`i;X3 z^kw=3sP?|FsD(Z7Kx-JA>4%LO8gauGG>?LToJWCDWzLSI4R6itftP82zVQ}JCs>k$3lfykqa3Ja%64~sD zE8H_CaqRqjYs2}5))vacDQU*?9Az5F_(YGX^AWPyT ztj37q4Slf?I=r|J$7pl|m5s|xW6{!}kJx^7wx^N@3i#4cPY>Y^ti|z3bJL-$(#)mg z@~jE96zz;AW4}7*QsPSAU^?Eq%A_nK(uL9wE>SK(UK{}U6`to6QS2p-$<9gp2po`1 zmJA9|cY;%+fzRq5aP0##>&`0$>Gzn38q#VMW_NG1iT{G2r^SSx=#XDzybH&|i4w^* z8Sms>WKKN?RQL&0%T-zwd6z+k;?sYQGMxT#+T8FZ76cfM3UyddOkt;|T<;muwm$^= zVYnOEiJgD0-YPY1!IX4kWHmvpJaIiV1JhEj8_*&Fc^~ur zf#pWG*(hW1FkT=p|G=>xiYbYrl(jV=1VxW@HYd!vbS)lLVwvV>u02{Uk)=6WkR?*E zSuibC@GY%*;$1-js*X}-sv)E;H40xsejW)ELgG+LR7a{a7=^kk(j3Xm01&y8%FD3o zC2O-e>JD~YCqb~r2n7;V$m^!TC5=2Ec}k&4zf7XwNF=*PJh1M4IJ~TX$e7FDF0eJ?Q~z zY>N9p<;kguGL zBt(q^_!o`j<=vN+?<-;>oLi42x{tAX`QH>$$>S9t3dkb`6w?euE1rWTl^*QwZ5#v7 z0JWYb1qMUBf%(gb1uGLXbXIg3kmWM?c*SmA)8RBrN?fVK)yzXH>+L z8vd9H%~(#dZR)@Ysus38Xv>aq&iMpwO{q*^7={VBJsU0Y64fiBB2})mYL$#hm26Fh zCIk!a8{^dLs<{3FxDNfIa6YJ_PbLdKO@Bf2yA(Z=X|(E>X!Scw^g8wHB^~RqK3?Cqy!ugXqlX5Sb}K}| z8KRT$RdCRU1)3=7CG*!`U>uAGWzyQWmqe>kE4N>LybiGm|Eschb4;CfmNJ{*K^N`F zhf6(m_Qv0(DK?@bxTw~+zV>JCo^XcX^X*7bt2?s?ucld0Ktio>R@H;}ZPidK8G%Ha z@NNA~*x0>ywZU1hqiU@Q+rZ|~yXhJ9`f1sRv72N)ng3S9<1hX58Ex_z$%8+DPleQO z`4lH^rEN%om_tS@8C5ET+aKxkqpv(CQa*tOg^`7M zHw1FcRlleLHxo<5`o~#hfBW>mgQ!STk@vusYJUR|za%#NlTNNdiMr7JZ@-S2L(;yk zH}H^+Wjc2K$^X8o1R_CC?c<69II$74a(j-r1UMbPSx>gJS_&<go0B88ed>whH1hnOt*_e zygt+#*IL|``n3wUiVSwjz#Vy1HUw_YzbXm$|F54A*LQyU-{!ka@&Bl&Y)^+a-c@K7 zD3?Y3Eqd=k=U963;_qzuUrr?1KPF=D>rAa>e|c>5@$dYHPeS2pggAi{Z+RmC40ZtV zPcS3_DMY48U^>Vyji`(uG!4$Zj89_xbLQU%k(@9ZqQ12~tycB(7ci;x9z_Gudmocj$7jJJG?PlWdp_-IrhNYxp-IM&-T!dK)w`&OW$T7-(r z-&m4DkWvtvLk3&1NNQZKLYhuUz7_c}@hk6Q6erTr16DGWumVDxtvsbCrS~UH-`_q> zG`STYWVio>nuZkk*gCH<3o0uoKhUpuo?$k7=SGuRg-R~3f8A$Lh=~5)?#piwuAJ$W zht>geaPwXyPY@oY&}lYr?bXz&3CK13t7J5(NF$~FRvH0j!n;-g%;2gr+(?-S5QS=N zr}>iCv!;2{=Ahb~D#vQZ_S6Ao@!cs+H}KJOP>^c8h|i+mr!V0N?CTP->*mEZe>;ANZFSx2{K|mY7J{jyS{(kiNS9^|5Uti+|OkG@va?@6G}Yz6`ST7 zM9$d%>*?mZ((my!Lj79~hDcAW^kng6MBiH~o$F3tR%ZqLk~*IH>o8iTc48WwF<}W4 zz@?P0m*@KhbkRTM9)0o4lyiqILiNMQp4fLZJl${Bv7TYkxylwTKxU*9Wl!5X>}7JL z2#FMXdawe=jd68DF*eMs4+LP`p#O@J63_P3eJM?(Qf2u8ieTrKC5iyjh=}BL_-WVQIE2m({?=%%_ z+<#3e5ChVMde-~P4ajd2WPg7T#l%`Qck12vW9#T-eKxVf0K${CKDDs&sY{Hm<(x*_ z_56d-Kn)$&vvZJ`*>W%2s~;DC#wZ23xae(SS~f544eorOaKBc*BSsCmToSnRbZP#s zU6+pfr|;+f*~-rJGy&Px+TF2*6=59^%Tmc_(G1cb$;EPUfFAP?3q+A7WFrzVP(m4fbyT%4V; zJ-@g+dm${yU2}8+s=oji9!0gyUCu+#E-xOpO~7l;C@M}P`j6w=CeG#|!ZpV?Z^{Ht zUWjyD1P!c%YR-9{Unua)uytJoj2wy8Y;(0;2tB{JJX#lfegP^!Vr#otS;Fl0kUZs` zki_Zn`o`B=L>O`FXn6%Gfmu16UY41b5R@S$IxXv@zMjL%U;-5M(D%j)=MqU#LDex6 zN?cO%NQ8u72bLd+jl!?1B1K3c7>SnYFbk*R@zRj-m9=Fjbu6un)htu1M*y5Tk?7i*cn#5(Mh>@Su zyYli}Ez^P`!(#P^mzNi3Q^?CH2-ow&vsuXHEHY?h8&r95d3ktwH9iZuH?n;;1p!qa ziq&6mJ-;}cMGDnl2-P26eHI8ZfK0)m-9j8lKrjf|jkQz^rJ%0slxnwDzDZ}1_Ff)q zts2e3s6F7g(^ma9SJ1TH?k)ZG^2ZV`_e?ll}?#XXZ^Ehz3x(wAdRgHv(YGA|A77T~cJF@Z z@czE^rG&8&+Ytk%;?iTOs~Ae9Wp%@!p&G$sLPckKD zPKk(0(*}phmz}>pwYbEEe5l3L#knskG>Y_g|NigZj}xdtU(bG{ALP*u+pv>+Uq-8R zpIq(>uB4bi9@k90>OC%m4wA_}Bo4WdWOw~o$M>&aVcAluH7Qdqyj zbV2IY^R3+Hv59i-KfV{p7X>^)@QrC-B@|B}Hi~__er%My(w87mAW2@EWf2?C1bi9f zCGf@3Frh7CA`@F_DTb|nt1{!}PeHw86h@;U%fkD|(?a+9A2p?6KY!E`lZAfPRX_Ir z`K+#{{%3t-*Uz5~EhA*1UyU{Vk6D_cRbkA}seeRqX1q43ceD#6K$!3LgLHk{*y++) znoprrJF2rsRy!RF?hQL#%VEEEx>tg_u|4Zow3-*Rr473;x2L=fd-q0!f7kt<^7;Mh zWTWBt>x(1dkJ*HIK}! zp4`r%n*6tm!#Oj{%&a+ckEXvfCw8K!dD|4xqX{QVNC3S{ZPU?`Z}-m8=YUbsV~ ze#c)THk*#W#vGG(j{n2M#ZFcdneUyfrV2biS<8^yJ^7ZcC3d==XL;}Rd!fhk(~Z*b z-P28Cir7nyeGxOQ+lKkijb2rC@1BLoF|5-lH-EZ!zSFa5;JFRXZ#w@?GBk(dLVJdy z_QnJZ%|LK8B*Ur22eY zyhfFFW%R!;7)LI$|6c+SkNtPS@cEr!c0a&IGZrATG9OYyf+_5A-*FmbM4XT)ZL%>G zm?fy(*Z|GAJJ{Fe30y0+K76r?X0rW}*2QtwzP?rx8B2g_YY!RkU+4Q=MM>};8|tw3 zN@l->g^({(hPc@FQ?>Of=?lix9Zsj@+kGn0WhcXHPCM@ArIk$La=jw=_S2n^RV<_0 zBT~it8J>DoY@fzPZob^l49KYB*wh|XSlWLWF;T^JJU05mc|XhHR~3d3*4|)Got~iQ z%H@@U(p2E}evrXCFn%Pab+g*xab7ildQe|70xPt4ViUsB^VVc{ID)nnfMk~%(xV>+ z3tJc6R`6nonf`O*h*WqZ{6(%Vi#mnCEr5vmqvt&8wKOi-I9$f59LHXeAt1mF*VYX{ zIsCbH)KY^>juZf)X8gS)HlE(ZgE9l!B?Yq+qhy|T+@PhIs^ zipY$ zie7GS49HB|N8O-%KJxc@$KV>bsCPDYty9eNUxP2rqT*{N2$v0GqXn{I;bR>mm%W*f zT1y!4mQ1sc12yFii*7!mFBH>-cKeNZbOpC!x_;CHVWNwE*Rc4JQ=|j$%QrngLB3q4 z|Gg$+E=B+q3JnxkO?Z3nIO~=#wsq9%KUWvQgHcOWrIh={w?&BY@J1l?yIDN_&6Om| z%vIo(6ba&rwTmISpxDlFbi6GDGwQMATm>guMhnK}onxWbuZKq`P| zP~zv34eJ#U$Qlo!(aYJaCxI}p7BSnBuv>aXa23EHQ2Q+FJ9!yc5G0a*3EfRd}23)YA2?(fb~58h#bMq@h|kkVCZN^AV+1CH&|+{TkGdrNbAZ(e*=A32es-a z17@ur+iuLnwV*UfJjXQvpATn9rvA62*+JG@0ww#^Zd@lEGJgL?k7%+zO`UIULvB@H z2lf{|_c4CvvK6i7N`&%AOD9i$zS$fDSj)ng`zF%HY$M4fdOWciN+^C<1Re+~bil|j zG*eN`dW#cl;DEhn8cqudT+?%2M=J@6TGU(SjDN283p8RS8upuv%zzF?@o*-mB)An| zTHXkc;Q&!(W~5`XYKymRWi4}8Cih?;qOV!fGIIxxja64BY62rVnHAv=Bb`awh?=_w{?#M)d&M6HVR^_0+~)OzaypxT96XV0Ml6s zks{us#RKIr;M!b$P>Zifg zcNE+Kjt^ffaBKtA&Cm?ao7}f9yd6j(7M7g|EF?>~zs^fcW-YqYmhiW_@KIzDv=X2u z;aIp>bh{EMzXx#NDyqK4&1w<-w5S*z50YPjuGJK`u$Ht%%B!c{=)6_ZV{QDxOJzk4 zReO~4IPZ?iDcz7Y9rNP#zpk`$iFR+S>6IvQdeg+UtgX)F>Ga+PGR=4%c{;a#knNMs zm8#9!A)9Dh7BPJ2%9>;?Tjt5Bt8r})E(HUvNojPz8jJmGz31{Ve-C3d!%Ln8c`wT| zPIXvcJ}ZA+>woHr(n+vF&*a#H!|R|%tRL}CF3!!#`X9W+n&*Se_ravRa@dk+frQdu z*(=BqxatQ={ToGVmswXG9p+8(NM7asEVZ*!7PmJRf&z-?-j7AV0)!qwT&trO0I6uKAzKWK$1Q>$a6>D@b@%reGr z>JR~x62%fp&v=~St(*1uaRx&b}y zOKTTp#Vv`bPe?XuNd|M*Vd)a?1Vz*C1Mc5M&Ag-wgVIj?Y?VYHvhj>1gOG~aR)E?PP_H4sd!_8?c;Tt6|yJYGrnwU z0w}7OeyJyviH&V>Ka5NY63p>H%VlvohX5(teHos5etMElnVpq{s!~AXkF~DH>+Dlh zl3|_FKRWIWWsAJcLht*D7w4+em6}-6-L)WENoF~x(_`ggzO&j3Cuj!bRK;Aa;FU8=dz{8tbf-!nFz8bgd9M- zSpm`ZWli+Ux{{ZL@r7JYMfK+|TiAQs6ni^td%L20drEp=p7TZfU~n&b89wy(bN3lJ zcaeMwhod5&S|pQnmDmVadsSiy_y7$!5Df`FARnl^v4 zUrnB~j-1OnFl2r@?c+19NQ+Kr|zoxi{EKHr!oC3o46yQT**rp(zNWqQbJj1SntqT#TTvMDuqJc&MK0;I-m+^eQ4r*6R3^nZDiL zRpfSN$&u2WWPwc%htT!1g_L$u&JJI`=pw=8LoH|~DW|)ziFF`}?mu|UXR22T1(C0V zOLF+=N+%bIqA|{+3u?eQcx&>o8|~)#VjFimbfCgCr5x?4Eq^<}-&Q+K-tQ~Z2c#WC zd-aUOT4we4Y4_fw-)GO+Q)G}5_&l@k zS>MH+myX)c{9+YCvFA{;j;A*HLi86>M848Kn? zrt_apP^^I*D)qRMH77!9$?iKZSSf=JD+q3G9OF`kmE%_>0#yZDhOhGg8dE{+Mvxm+ z|Lp)A5p*sZ*>m*eH&ocF$r3~So^Mzy-p~aAm{)*JT|mn0Po@&E7%R!#pMisO;ACUv=nyA_=q-UI^t~irp#x0``oEt%TRABhKk|$us zJas=uCVaBmW+h9%FR9?3k-bjVk{L%Y{#Cc~OTU)=z091wvoQ3FXqFWB???PI(|)zH zLXx>(yjC7NYsZZq{NOxP`4HQn@k%_h!+zZp`+kXdB}NE7Q0bpGaTL4F8KI(2&;QJS zo0{%<=aGw{mS$Pd`YYyaXuZFq#p<_dgWL4-SQEC}A8$xH3Pl`Sx_yL5BCPc3ZEm}h zr$0(@gCq1$9$9-)WPr-WP79x$O1_x)WY!sLJZ)kBWbJ)=7iaMu?b(YslTC6n<~+4( zm7>FcpDl;Dge3-L1Dc3$5t?FSc68DD%Xi+o^}{`ueCUh9g^zY!^&W&?-5 zov6Fbm+Wc!vz=CJMIoX^m%0=vGK7ZLYI+5i2>J4Fs9<_kEtQVXpxSC?O(TO<_TKu! z%r~uUZjFb$*0bw(@@|+vcU_$2(+!v03A7uVzWzG-Cix>rs`REoIa9)=l65e@S_Jta zEOrs?Je#L(zShocc-^d)E1=tyzDNr-XVy2I<^bGOg)JGMQ6-@TQhLWr+$ zd>(6NW7C|k3*9?M&=C|4LsfULv6X#3X?*qk;U`so#H}{hf-o{JM-q16Fqd@0#10TJuP!>P|z!Z z!M3!HO583lP?OE4V_);JD~l=+g1X9Dq>k9*iI0l{tl%>?7{*2kQCmPQLBl?E7~nEz zB_3>4xYH}xd-z9JVhDZkl6&^NHWdz$M=)iwv3L#;9ykT+DO9Mn5k-H^1sf`#A0E8V z-AJg!h>4qEM#ypXAt`VyyPsaNIzm;-P~sry&_qxAqnRG7n2|Hs&!$?$0SOT1yfZ3YM zEJuw|`Ovj})Aly~L%Kz^Rwdg*z$>*-v0lD#>YV%|j6ewf)K;aTc)9XdnGf~K7zjW_ zBk){cP5g2m@rvHTZ6F+Coy;C)Whh(qZ6F@;;6w`#LmYWm-DCKP1F|;W{h_?68q%4r z@N?SIkmBc_s~bCQPbM)WE_Hzq7o|OD@j?Cmi3c%ZBy|3?TI|&?xLkUP1ipT) zZWcoZ0eaLW9$krBfm{+8;#<_D8A%_!e}~rT8e`!H41|{(n;E6mG{nVN!QtZGiE42| z^>O;xc#^=(F?+Q6L=+sUJvWVExb+BY$?7RO_F7k6{SFKm_3ay+aR>!~*8QwICndXL zFRr24!JRX*Y4-7Off93Nb2!N;i~j6M6+O&ea$bKzp)9`6IX_dyxQLlje~l5D(p z=`sbc*Pp0k@TX~dQiJ*Zb0cX^1bq`<2K0tKZ=58A+OZ}T^?cja)Kcbap=T8u#buo7 z#@tT?KBR-Z4rx$*baZyP+ScV^(95-{9&dY=5d_HDdC(z1mIG zFH+ZT!=#{h-Az39RM!b+S~$e(E}0pr=gMzd^v=~?y6jZXQ`5BgL$$kX6FE}f*WI+_ z^SZm-t5f}eWYf}bydJkEBMm}oOv`?`dMJK5HHa87EkCICxV;l;7_(veSkt!`L%ZBFwx_jnCUSGs>)*-~5@b zo40A%nOU8tdA;dVZ}X-o^G0{`2HWr6maoptTawKiUHE*gC!;JnYRsE_+SMnXW!bl3-W>hi$MN5pB?)HHlECNdOdV}C%x}?}?&j;ldA>jv?lF zk}dnb@%cwiMmrqVSibt@<{$m#+~H)z^7X+}|Ja>q$BPZi{`2qtasSR80dOl4m_L9( z9peNMuo|Fp4@ls=a6)KV4Kh4*p$-_P2{Y>HV|g8rEPLUMN|EQ~;zFco#H`gQf!+u! zQ>9s7tUc~o7!pek%=C+K;n=hqRon>7ioI~bz^%vB_=9pXV_bO!$kuOl-Gg$=E?fn* ztjA4jg7TYU+(bOA-`Q>i6}-A|lSr|iaN(D>lki;=o9US-7sXL?5z@pz5@CESq+*qH z{9PpWje~+ZX?uGSh#>)^cV{8%ddVtObC8*|c<^QG7P!oMvW^gf^OOL{2%MGYav3nX z;{obgXA?8d0De6zJl;;>LvfdYqTZw@T)Seb(xEeeg+#-^!t=3kL#AQV`p0)Cp6Q1* zq0PEO00J=zQ-8Co`PkN*0X4Zu@erg~>9p!4yzsGe>Lx*QAE6p>U}$WBoL1tup153V3QA_kf7 z2c$m1t0RJNJWfvp81&$PZBsljwM~rH5oj z0{T})P$ghHJ(l~!R2%yTk?Y?!t504`rz;;;36yQ&;4fzi?uFE7ec3WKRQQGdlH17J>U_3<9D&=oeT+E3s z`QJfS+(nXO+}Y+e@_D$*!OnZ~k6snvc0cg2AC%Ysedsl6t2f977~k`%`#j}yFL2?P zT$f@$QzV3Q@Ae8icKy8nXK??|1MtT6fpzIC8*E zQvx=%5SurRyQ2dX5=?!?fS~aNE;6LjTp3T0xzu+3M^vvbe3SvDD!@|J3x{be;Hh98TS>+^N z9D`%%z=1RR#TVkmQ6t~jM<_7_%DOj(dnw*ABP`jPDydf^1G*e)s|R5E(viQq>Z|RV z;(A&deFNL+AQ=%288Zq?(<-GcJbU)5KWYd|(?KgpE`J6AJ3M%Nkiv2T(yzmFrULcl zfve}BZQ&&Pxs>w{@U-eN^8M))2CFd^D|HtoAj=AXW`RIC4UgMP39TCuKN(ZmO5q&C zb0UTe>&Cw4YBM9%J$>)c;0fX_nm%^$SS$F-2UQ_nHD}jRWPlcAbwHVi(5(jQ3`Xc_ z0}ZU=4Ysw|PPGIZ2LtSeKSl$YTY&6^i7Hr7;zdH@MZ5{ih{?(ulWF+KP+y*UQo-Sf zp>~2eMumAHL1qtZ?4+wLPvF!BGN%G*v`LbU@X+=kOcW3xB0~scpy@&N(>w`hjl<;&J5q%ws zX(pg5^+R#g3f$HMiCdm&p!&I4 zY?aA}<+@;oA_hss*t8PVFQLk_XhafIKJ=Bc2((fl2FTK&+i{Y2sl2@wU2-P;L0_6- zh!OJX!9N4mt7gm~p;0oSv>hc(dBX_#K-%NeQJ>`LS}3}cES=cTlqE-55uA3l8U&F0 zg8Jz}DCXl``!Q680jbYuh`K(M*{BBuplCs4hQo0uOh2GhLSIceYAb-apr8Q|sEc%M z3nG0yKB@?V>U2GM>~6A?D*fEGyI*UxwS9fL{V6@O1&^o0_tTBM>0zf~HAEuEPV$)I(b`=?W!)!fpm02iufM z$8%|F9J&>Op$zGjZEXl&*-!fj4PR-q7DbofSTq;aC=Y+gPQD$x5{e&$9?=8r`Otvs zPCXQFHOMzV>+DD0M-x~Xb#k>(&sPxv<9p6Z^DWy$%tEOzWl42TeYABH;K^&KG9GTn zXRZ@a{hxLQby0)*nFj@sfa4Lzd?R-7=w?FKErQp0L&iZ$yMpyQD;z_a@J5qGi{8Un ziyM#?QLRK&S!-JO9vF?vi2K+ji>Jw#kTyeT3Ymah=COd?&dJ(G)_OQ!F573)30aY= z=W^Oky}AYQ;(hMZBfg3Uc8HnE6uP1-RPJdV&J~K`LT`O!s&PAQS`BuwT>^wP+xwZq zYc%J;?r)o+_Ci;EjR=>EG>M(^yN6xO3EO`BQTMQ=kJ`%a8(F|Q9BdtgR#yR)exuDI zJ-=t_6YCt)xFZPOEu(VjY(zi=ryF zf=Duy_lEX7xbN*cn`>fT^Kmx{z2Zg}Lz7Fh-d_ z!#XOM6fj~@LJckPGCS9+hKgWXT64}Z)>V7S5g@ogrU@IcB!VhLh`ffI+PbsnnU(=g zVERWjn_GRhr=zq)5IOGCV7>ie2ZqNoy9!Jjh^nvG_Axn(9)Ir3xk09UKX8x&e{i~0 zp4zi>iRnmm5LLFGvUK=!twTN&>B0y9g!IVsEDsJl65fJ^ubH9zsH2otL9?|e&L*ml zxt;BMP7ksX1;~@BDw$AuE_aO~T~C>3+5948`A+zcQMtQ-;V^{09;(F|ke*S$0304x zRBcEZv^Fy|ZJCB$(6&C|)cNYd0W(+A?v++2EPszI0!M|g>@)SP9#P*DXg`w zI)8@}Ubd!Mdqgr_`sp$nFdYGaMA4xdG`t4%K%gFi3WM=pYiNI$H#~S{;XF0L`QZsb zi%)Z!xd@tHI27_MQ+01lQR~jzZDH15V`Z(wMQz_>X*(kqK)o7>txy1 ztjbnOIS3pAjLns=2G1&?C_hcTTbd5aBua1E!KO__zLs( z@T|?6ug&z}#1_EdRG3$U41tOcgwZn}Yb!$x#z2^L1V4^+Dx_PpbyNp!5W1Rm;;56B z-<0Kqp8kERzpLrFGY49ZJU#i&?-VwmeSq#M@qd+K`fK$bPvo9+;ihLU1-v{0*M`6> zs4r-l6X84qm}|tVF@G;Jnv4MQ?v}i}%dISvIrnhP^>Uh~7fp`?9>hlkJ(ycay&l|i z{l@3(q0i+L0LD0vL6KHoS#463R}g2GWY@V z9Ox!xcv|B8VKx#2q0PZp*el1!JlpKAKK}(pztAxoqYSzG?8e=UxVuU$j&E7>P%!g+}o*j88S3;M=(V{8A><#lot8353epMDHus5KM zUN1h@5X*^J8XD(i6HNv%s56KY?CJcgs?bLsQ8@Tnc))8S>-zduh) zwg)Dj(tUy@dGZOc^Cz-(lg#W|o|~ zW4YJlrk8Ol23N+1CpWjUH(4cXdrxg?Pt|gHk`L6KI2dv|RzWMYOAA54;*XW;Z{anwM_%Wv>1!JS8YV|?FtUiU|5 zw!zik>lrbbpG}IJjcpkgSFSEe@nCEHk<5sLU;Iy z4X1|MGj?72EjF4N?*0C@#4*%(cKpMWs}sMM>RbXckC~h~zut6VX7pXfrJEG7DEy~; ziuw+Iedyf6-1Nl6$tQu$OW!OIs<_K!^RHj#HZWEii}1|2B&BAelOot;W{y(c7`5(( zXd}xbsl^6)sQfHDdOPdze%AI{(Wbba*_NMB$>?iMsu%q6n-ljeh&HqD!ILaj_`val zMAb@?r}NwO1;hHacYfSb1qQp@%(bIT3%WRq@1 zyQ?UGu`qvjO2~!L8ugo@YSo;xqAyC8>m{8#fn;pfsXI60jTcJdzU8@OaS~Y>ba}^( z8xi}=ajT9Zs?CkHN^c)Pm7Mo`wc8#%4O4mnf%Q?c zIOE{u+jb9nefGhf9t$HMygF#I{qedl8`&j?OMLRv){$=S+c)0Nf9_=M6s%J_QkKIZ zHU-q&OIx+a6SnFQ3I3~geza~!(eEEET45j6#z-Gn_c1u4t@|wS zd(Zs$oM#H5A8tO|yZEcAs9|xk!|a*0@b&6&v*r1HXPzxDEhat-70o?^$_cfh|5PRZ zw;l!TuSbD{pdjzS4M0?Tl@*;D@?=cB>}=~oM65u=Uk@)BT)OFP1uEtUon4O&RKPJN zuFlWIH#=u*KZw4z9=*ws4<)0{-5bgMBpx0eZ@-P%PVLgj`2P0oYs<{{p0CBePT<#P zn`ZdhykvMou1xX`Tvj01y&y)N$T7b+w>G>#E+uQfjm<8XYh9n_^z$Y|>u2oJ`|8Bv zz3ag^3X)3%BbsK<*U#F8-wS#r&MSXn#~E>cGJ->b(>SKW}@ zhm4w!s+rfmyC8dOp|=QRznGo-GdJ0(aHV>xa7yfag^3M)7gyWA@EU}L3cDMe{345h zi21Ky2lKO2m7@d!M?qM+NG5N7c1avq(g|aWdb&F?d9(Wy`U)EcmwOS{8fU@OQ8;r{ z+_z?7VX^yp{qkE7kuCCjHnlQ)9G*SC+^yhOJG8toKih#=ZU@`jI~UqP#2sJlx&huW)9#`z4p)hi~7@%N6kbxTafvPy;o1`c&ai>$TxrUc)&&STuZp zl;g}a6_k;s!w=LSoGs=}kw0^#Vf@PT@%ERU zK(-iB_*brIe_1c}C=i9xm;Dtj+Fv$H%?co2jL4q>vS*}b#XmiY@8ZQ4^8blP@#uC( z#((2cRF=HDWu2mRy#0UlC_*vHu3PWEdq8fAS$C+a{C$Pj>$2k=Rrdy-P`jI}oKXyEM@c9|_uSZeM{nEse-}cv|_}0SSd???x=701kV%OW%R*t+b`F}l%j(od1 zX-l&D>e#2Qza9mTv0}qtkK$Wv%C?i;^)=H!`BIO<{%P%>vHpq+pZ|Ik6N08#$p(jp z`uXYM*LN?)ke@Ej3BQF$;GZ=tEs7!@b@V)YCXxKDd{CuZ76KYdtwick=no4RxC0tr zmEJEi~fC@3#Af976$`%jPJXMV`+$j_V9e|i)?!v!q0e|i+dx7Y`?Mv7AZt4GoP zd2M03kCrO|e;86)Ts2zeB&Q%DLF691^||XPS8|MZuYOj=>3+q6);QPjcI~!@t!j72 zA9d=FjaTpwZ2MK&=X~MUW8?3W=CV7`v5998q|~DTm3)PbsJ|YCtikwycoe>qFO<)hPrg+B>rvpNw5M9PWc>9gip!_k zNiwZd9h)3CP1~o+I_>H-JaoOn{OZv7u83QK!fF0$nUxAC*k$5OukFCQQ?CUzvVW{I zZI|*e&WX*QZwFqr_*;V^+h_aFWL%tm@AaQO3WLkbofohBFTM$#`_xI3@EeH-!qX8J zD};@6Uzmrd=FD4u6j}C1=FlOstiK+`3C~axIHT#=Xy<*6#zX$heg*H%EcQzRCF34% zf0}svvHQy2VGfr|;yh!1)qi_?;@D}5_P|RsDf@s?%UXJk9^7M{((C_J(0D z`d5H)(9#WNt0HtGb1IX|KU+Is~Jy5li~^$imhL0 z9h;1C?JQjVr1gc)jmcP#O}ttSEc_SkJ7E(F!S z8n)C#3pS*#ePK3wel=?76)a@@)|2P&axq!B<2n7eR29+p|75*j>Ut3S>mQ-lvHhUN zfhwTJ+yR_8A=ytV@t^6BXgquN@+Q4pv(=Dw)s!WbmHENm6DpQfxP=Q*XY^vWZC zmDa6k`nj6Ye(%FUphz6m%d5>Pi+@vI@A%;}|90DFF6P3`autsYw~u~Pxcs20{nIRF zGZe+*lv7{GZ~h`jbMKGk4nb%;k`%sHm@L2NcfDia)57c%-pc!ws6&HaRpzQ&?e1U6=otKA zJXgby|J`9^0} zjCdOJkmjz2YR9Gh)V(2JjCXRIpC0<*bJ)Y^%A@`Or?U4kCvCr}42WJDc0WwG-uZ3) zqNs(4dBl#g9on>ZzSY|PQL>rE@oPG3F1`n@#6Ec8H3##!#L8~eF=wH##Qt%aOV_A# z-NGAg!sGJuc4Nl|7T#8OKfZsxYwX10!aE+OiW_A&?zwicztz6#QAXGJIg`cr{Ddm0 zxAM!!eepwocU9Gsu3vt^ivt48lj;_`-&b-L2Z!yS)V}Nb9ZBTd9#aEaB;>h_Z{?&7b?J=HG_x+fEY z#ozGQnpP|OspK5-kcPyerro7`D!oqposd}5dES0HdtlHvE3>8RdiQi_&%U2~u(kXs z`$C`w!n=M}yZ;D=+ zG)%J3*AHzln{Pd`JeA%P^4%bDz6*Q8X1cn?EG&QY<^&ZmA7+|3_bj}vTmExzf;oQP zVev!L@@#d_)8E&7fJ%%nRSUagJ{^;;=Nmr;ogff6~&FV-`AU^=zT{ zS=h{zo~7Rx%oYU?8YH578^Wd%!xx5o!WP~=Se{C}DHdFkY}O-FUv*gjbf!Szt~~l) zE*Wjcg?Zu;x74Kr!amZu78O2rmW#!Rs5oVsoFPq$NLB~Zlrw26)ifLnX-j~5QK;&L zA+VkBDj_zKO^2OAsgOZu0?zDuNa48~x4;o%HiR3w$I<%LS5(j^42 zJRR-C1C)8#>|tu1HLFe(jrEE)5k;ALMaQsM3jMM2C2@)+(F{=>1{EJ^$ZABQ^3QvlL3Dr+@Aua5UHi<=*?uLG8=PhI4V=b zAEl8> zM6+R<5l1rPyIJwhta#61>JkrCX-GGYLimcXYCOP%l8o92fxSZb@_-qZ&(3J*ht{OE zMl3N7oy*4HN+OI#Si@9?SdfxljY0E3TQ&qOWIr25yRji7?2OQP7Tqv|HP0T#p+nlh ze0&mFMBU4ZruWD0d5=kgB&$tbo#Vm+1PN*cxCx%2-iGk!(eJKK*=3ZGFq~rFiXGvi zk|@aQLR73E{q;NS!9b=ViS;#@Np7l{7t36OwZRSQJ&C#( zxVGpgT#ZNfBBaag#G3E`Ne~nxq@Rh7_4j7cSgga|Xk`*ihg5Ki53!{}xAGw?+3;LQ zUSmJTZ=RZqLvJOajd0i{Dn`sh4Gx1Q0${BWK842$ys;yEtRWW`#)g}7VfK8CEbEqS zb)Jz1b{3DlP#SAXEI7pl4rgITIE8EGseDnMoplOqO;c`9!o_oa#4vm>@TC-S97S7JRn{o zK<1JPDpz#If0??cQHRnSfE-f&Yg;jlC62qSew0S}(41xE{jEH0Qx z0JF$osG!)219+H(poiff`%%HT8`F5m+PYYWYW6d?@=cE_jIU$kc>qHoV{TH3Xw35D z0scIMiXd%;Pdd(sy|)#8lLRv%01Hasc^}J0M4-=IC23D zALT`Wp68)PcqnBK5+X5yD+^)qLWsNo;wb z2RlGR0f68@qqiYKd2}rj$A^vnZ33ck2xoq?im>^HP&S?n>f)&Y0jfiUTS+fT2+v_0 zqDFe*Oom~&FboA6yMV=xqpeDBUqz=C1(&zY)#(rbXB0{;GmLOlEt?~Nkr&|dLU=N@;|31yEQA151ci#g5&$d_c2cVU-$f=e^G zTtFEJn{`Pj1RkLXLGFUInsAVMkcQsD-aSN^zJvm3N-vMju5%*ZNq$tCQM`vwd5iIl zF;&KcLpR!@5C#;EC7yHJIem%{p_s)?9tDaGpxS~o1uh(I3lHGeV(@T)f-UlmjO&n& zETcs#pfd025)s*c0b;<%Om2gOQX6zgfDi9gfiZR;AA1Oo@S?nnXTLi`zONY#1;~l= zTsUD*jZYv1NrbOq11iMQg8DQwNVnIT_+z!0@AX;x_XHjY#b$A8eaR?!5_Fxo?~iGP zgD7fPh)(CDow-%lLSVLR_$eYM00+-8!5Yo+6!0=fJ5Y%fn0j7$BK~fh3C@5J9+Zuq z!__4cpmp`_3S2BL=jv(6-Q1J1&rg!u0SYo9^dDdNJahK_EggU% zPKFR%xRsy3$cBvF_;T?*CZ8fD@(l>^(1@C$-2m<;K$WQ&G#AiJ zfT|AU1_i-(@gXPJUyUH}Erc6>LaZhg&=6wvg;+CwyIFK}lJbX^(OTHyk4{2JGKa24 zM$&Av3*O$bTg%j4D;?Y|{HBC%YJ19$${kd~TKJS~_F*z>v3}mUjF`u09Qr0P_eC2v z5Rz9b(JbO=Vhsb!e(|tkLdMHAZAWUQk3G%B*}0Px88;%3K)~(}MM0@3HU*IIVK+$` zE3#5|*R?olGOz^r5j@Rm_{`}SULrxT{(E6j* zK5mI!`inY#6+JRb$Y=Gl^kwqDx8<-{MI&6yte`z{xjm4G+|Pr^3J{7!@GKX37J@D$ z;Cvv6+0Ybr$#+f9K8XP0OF%{9qb_BRo$45S`uonG=8bNpx00VI0;%vf=-j5IUQ3e5+X3Wr$XM8 zwQzB>0w3W|sQX?$0kl@kgdoz~A{+xFI{j|zwZ%nh(o)?f53`c2F2!wl7A;pAYr@J+ zCjvhS*fkson;k+o#nFhiK4N*8g~OjJ&fR638oxAwxiKY;j##@>&s1}-am zEe}6f?r0EVG9hF(xMC7qBVB@bIn`5#Js>5 ze(YMw(K5$^Sz2x1&))0Wu3{U}5ZZkE5!Y*>H?E;`WnmY(mkg7BAFtoK=g0SfcM~Uh zG&okxqhENc8L{h(hHII^(~!gsR(A}HuIz118F_V8qvp}M)|{P*=^inUy!+A|TrhcV zdgor3smp6iQiSIk)g;5-a!=j#%&jlWW7SU#4%G**+oNUhY4G13MP4=U#oIMH=fotP zEv%1{U*1I@#X+?lDe5Obty&5eO@8kwKKXh1#hy9&^~RQ0de+zd^(Z3QrxT0-c_)fF zV(m3yBSX!a^c=lK)h2GwES<6sV=^P$huf!c*;4MP+-9EK5vR-hSG!-E+^>B4-yVhP z)xOJC>w{+|t?&$mE7o$F{3z=!DNa{x)N-y(*=XEKy>d|NZspWL?TWrDhjjksQCzjv z?a-UH)qCx9)lR=Oq?xV%E%mCs@mS@wz3KG7JPHRQO!3-2`Sok0EAp1|N3R_|u-1R( zu(W=5&GF#2$N%sst{t&A`7?8bv`^9B$??$cKTb|Zj`|;UcK82t)b(_lzw@yRkN-G( zTz%v3aw7Q89~Ux1F~HR`cK58*qqwcO|7?!`tee&ZE#R2X-TldK7b@NaxGO*WKI=|t zQoQbQrDOM;$FQW|q#=jS;lhxP6FI-w?=VcKWFV6Z^pR+dSA`Hpq_#7A1s}!kF>;wrmT?Hq-Q= zbJve+n14-Czhih-zrh-HDx0x7``FGB_H)nVr^DZFZV2NLBUkI-OX4Lf1h~^)?j#z(Q*rWt*lq`o_hlU!7f#|6?v=mt(P-64787>EOg8K&lU1Az{17n zD-8T8-;HaFSFJ{rHnI18mZ@ z7>93{hP!w59Z&q=P9Vy{?0U{bp>377{2Cv)e$!!-z4CBO_*>RT855?mC1dn`lWNU6 zE}rr=_#||tMzM^or2^Py`SZs{1kww?-n$~-;`c-1io*}+$RV->+2jP#7N5QnY~!)H zoB$}r3Dz&~V$pOAuzKaxl?;&;Tz}YH^@s4_sYT?L!EZ!-18LvbsxPJ*yvUY^mb}JnyB;?6I7463>Qjzk~JJ*)ECfH+=@4EN2bqCMU4dWn2 zWT{6HeufHvOQ5Ore*FH{YmZVV54>2?G!^4zWvSL{WftZ#4LlPrUko`AD!&We*# zk0QY9gs%xpaXp1*%>5##R!v+H$%TzQ)XjWd^nVPug>lQ)?ufNmo5y^7D`u zI9Q3iS5edZs>?FC7=?rf9RtT-A8)HPKiehtq8FXE25q?F()JlV7F0GzlmaI4gQ@gTVAdi}?b@2lT0NYPhuBs}wr`1VJ!Zg|U$Gb^eV#6`C_*})*Sa}nvB z^|f*RzB{waKNOPRicg#%x6FzI1AMm8KnLAy(p$t&oq}~ zYevKf$7{i&a|bS#Mlfd&{tRW!xWQEwJ&9 zF0ENijC#%v1ltBgz0c3=%bM9AR%IUjYGQKwc?=lXwBTMT%6YZ8_(97tcbwHDF8(8) z=u+Gm)A#lHj@~Nk?FIALwE4<3nrTc-{lyNYAl>VqsN?T`pL6xv^ zgcK6T%r7r2BC;3#9t}yGcC+2!LbrmnV+SOUOKGbVyRwEjY-3{o2XX_3s5V3m7$W|T zBeLQ=o=Zc*CB#6ksjIVUNF3g@mh)SKXp1Ap_-Gs}Z>H3@`qhso_wvb+reN-Hm>Q2y zCRUFV1C8-AseIY>cqzE84l7D`R&CHHzNn5k8n4RPe*IG&H!@XRc~I&P?H zlt1_Ze`1JJ#?zjCgb!07{%A<$8}jshlzomBDb(_G)Of4O!}@`)RaN6N4Sg1On)i~2 zYO73HGlG%;{EtzNZ)K*RF5DXkK1*RZXZh8bK-y1t~(}={jbb5t+2N2 zZ@aGj@jsbse9Wc)JLdX`LDb6K_Ydako!6(D`|oz$|21>{+phb|Tsv+${DZkpkA40J zbA=!@{2x_@rHkytLg0Uw|_8Kw&iN?p(H7D9ZI&< zANk8%HNU4iIsav@_rFI19)H_){}Xe4e@5}NHJ+C9|C_n~ckQ~$x9<}6JpM822`w8L z9ecn-Z1cUwS$Uy6Dnj+{cx3+evGRzOrvGNH|EXQ~m$_EhkzSb1p)6k#)eT8RjiHx| zc`NYE!f3N~REjL>s1W)bfmfiU)q~S-eW7bk@vNXXnYxXj6$!r+Zlx!%Fqu&(-|450 za-tnDQ7FW0SPv%MN8)p-Q84-Hy2*}SBm9+ik6db_8D3nm&m_f(M(8BgRqeCA>APi@ zhWG~ox?z){pb@iNO?uH{?h=}P7_j54+Pw)?$>_EHiCeKIfJ%I^%DMPrZs#0d)}mvD zHJ7M}H)JzD1j^5~q4BDcqz6#Ew$K6Q)IWXo6X|xW=HZG;$VfChdsfHTZ~5A_=AiNA07PJGxXB4PxG&2bNYc4vcoe7R8bt1_w6 zh*zV2rrwAmbMtQ4i!0*kyLluks#@M@&oux1gRGfN<0R6b4^cPWT8zWrmx~OpOgznq zxpnE*iq{Wro?ZO?TA4wd3pS!G{bjBah%5&Jl{db&hC)Sc>HMLQao))x(AH*uLynqzNNH(rR$JHc$qkq-x3yf{Y-FyOuT$=m8g^~g zxEMCGviyvUOaJrf?^78(r_C!bvYN;$$x(at?&xN;b)GYx&f>@2(JQv;@;Nr0J*0B> z)UhZuO#o8>Y~Cp~vAV2`Fjs&Y8CaX9GKodc7+iRp}rW zsq%R6A`-ccf46YcXdH9)|oyQ4u-krJ`Dc9Sad#VV|y1Q=g zDj2Ssiq~O#U-Y273!kC-c>CLLQcrn3a>_zMRLOWI`k|x5@z*!{X#P%xh{!z_XT0ieEy z?qSPc$Vf3exmOLLXzh39G-*ExZ&3NC*$!#3(dfoC^6{p$?v-^V$|2N?R2 zLc+ti^S0l7egzOdn%*+lk)gBjR@v^WQ=G{cO^1o)eY~3{6N$T&_)oI79UtF6oZKZ@`5if-#sKX_&^_NOzX*4wY@W&Mg1aF>Vm0U8fhK8`n-FZ+EJ z7FiO}c29o+(Vu@423G?+eFNO>o?FchCUpQWeFy%(FjuAMXS;OnUB#4Zk9-ty71XaV zu0FX+mJC%_wfB?y+}0FowY;q}7Q76nI=L6Xs+!)L9x)iu`_cDxm$}#!M}#f8#w>qw zPTafQ_CoeZx9;w~ilbwtM=ta`x4f;WSibk`MAlgMjUD~>UVKhY+~eZfH~0R(XReD& z6I5)y0O=rlzIIv2a;X2R)FXOnvOLL7tRGT$m~VGqp33a0|6$NG-yOU>&A~n$wsKhL z%~_r)ad(f<~s0i=DPT4ae0o1Z4gE|h`+9th*}*QrZRfOKTIU^{KSTt zVuz(scgaG3Ps8kA<{B(n6kwl8L@f@>Q#lgxu*0*3cRkCqb&@4v;xqA22g$;KWLebn zYuJVgq%vNjs z7?rNsPuCIA3CavzLx!F!LqCvVn8`4%W|;Of_KFxpWu}E8(^5M35y-U8WFD+$+V(T; zMNE=%gri}ElWT-?V1#RC#IfoKkN$`gq6o5bq^Duz8P~{j{o&eykv`TM-Ws@z)sei( zNczSoikJMgex>WfD%&z6gRAKhZq&CYbayJ?MnR2`S*$=-OeQO?niVU_T){#`M`=XI zyGAE?MP~*^XJV#3RgpuI{p;y9$YvOmqM3GnGOkm zxTwsY*GOC-v8Q-gBu`q4h`;j?i;)(|*zg1#N?{F3LQK+?{!^9|!)Jw#QDH<1Bn*$8 z=U}&HVW-K-^TcGetmJua@{UsMG%jUVX|np76a$HOvQ|xs;rkS$`DC+^6w~)9`fjNf zL8+E*DZAa0C%8yW95#ceGR8)^lMq@Ih&>(=hsQC6*f;?wAwvAAuEB6Q-NF(_U_KK{UqFK?&(eJd#=EmQx*+Q=63ougPifPQE^$k>G|-(u6zmRb(lUyda1c1*J!YOAjtFxkx4l z(B#K|xsEOhg5(i$?v7+@qH{k<-e=P1^H`o@!P-cX!U5)*yfk@&(?KubwcAg^-w())5mFVotYjVD=DX6k3c>F%&>3oh# zd(K*|eAR^lhGxpv(hPR=%@!M#ZT<0D{4|LWF&IdPJ;WT&0`}t2_5zS7gcZz(t~i!0 zrsM=>r7UpJsX~mLOe(Q0ML#-u8ed>+gGTb8szmgmH7O)5L^dALj!qfUEVMqB63m0z z5N_{{E}Cd7xSWNZ5FqvV2z4!$ZPi%(JT`{{*+7K_Rbw7A{xuPvOxp!|e2`Qtq7 z5*~4b11=G;LlQ%58ZLjAO-^+iCYXbsAYd7s6b2u?K!CWB5VAaIv1TEIjdg*5QvB%y z0oQQQ3<7F*Rz4hk*LopY6%X5iN2>~xr#Y!Q(b-e)Gkr_36O^094>5~)5GDXSOOjR` zPE(r4stAi$)~3#sVx`#GMF_m|hWSH~E)=*f52WDBc4}tM^RQEbWHBD0%f_ssCd3^> zhfx7{9F zyDvYm$A~a{2$}`~S0xgdjGP5g)vuv{=}FJVciRY-Gdrgn%ps8O(-W5=y@S3I{sI zgPoOPa1J_70Mnqt3^_HqiwHd;QkDYGAwPCq0Uq0iRmB0x!kU6HFXju|MPXOP`gQij7`73HKNqC?t2TjzThzG}nzyb+9B|ydt5k1vdcQza(fx($5H!fO_f{w-)Yf_6_7Z5p+x@69+ z4QS9=2udjEG3oR+zs?K~7Pq7Ixah7-REB`(CO}G)z#tc?%|o9RW{q*Ap-9+P3e-!; z%fMA=5+I&b;7HB$Hm&AgK?Sy14@U-~)cd1kl2Ak}>InZq~^{xV#C%gGcP{WU>Ig}@T=^;u4Fn4nCz4JylnnF_lkAt<45_przFu}&ab2&M6)Z=g~4X5!S1uN^poaY8Q@MIwd z$!jqaLOqGFXbNA8G@yj*sfY(p@e$G!5*vh|85iy)#CqR*O<2yb9prz`L`e^KMH6_7 z_*W7(9Erz8N%n@t-p#&XbT^w&UwsJa#(kr(G6Kt{UU zxo^6_69h;Yp*~r<_0|pz7L?j@k-BX78Ujj{GIC9bC@>y{3E-vOC|x{y4G-$VL7bqp zPz2H!00a_{K?IF)5C|WXqe5-|L$0hZZnb?y*y$CbTM-dk>+uj$! zH^kE2$|T*`U~&nvE!8Qwv>F3DNkMO?Lbi}W>0}Fv0$W8w2kPX68hz!Sf^C#g!Q5b! zn-I!h!g?-1GfIcwv=8$%?;2~)Y&Yr%abrI;p3y)jZk;bve}8u}FMl#CKdUyS;zQ1t ztk-ax1hZo)r*pu4I0zK?Mk0hb3Z-k<=*<%7Vd0k{bW!k$EMOI~vmF&jN^*}L-hjLH zRQ2=Ayi$bwpGPq%_l-o8VF?yDODhj1-`4sQoK>LaR%VBtzoMDHy$6#<1&>3ZZ%=?P z+t7Y83yydQfd_q>mBAYM#l4IMC~4x-G}vVbh-(bNhPBL3mquq;KETo?DF=HVR2y|9 zphfC64-RceeXKHZV17}j=EVXIO@Kh9jCnVHsdP9pm$*<@Rxl+Y$c*#vT>8-LAcmbH zA)eVKNd%=^sg1?TVNc8;UutravWvc(lpHMQTZb=P8z~T*6)t0O3p3x>x{^*bFpx;C zE!JGQIF$`|AAGZ-iM8gDES?)^Z)p}YcXACupu1Uk=C&z8naD%V_#G2DS{wm`gfqr>jUH8 zOLxCm|J~!ru5Vrx3nX-K(?|TMd?r;kJqy`dS5=e(08-(ho#IXanQ`jn+NAVf08m+Nl}Q^ zEpv#eSlBz#a??I}St1(S@oY&(mGTTKy^9k8_%*f}xbY075xD}iNHTLB1!#~4h=m30 z_4^6<%IaO34cunfq5TT~iMiHCgQ(@5r!?hn{AI4!!EM%?)ahTL>BmZFo8&oOkF3;l zidf*t2T|k8*=tkU>gmR(SN(0*{e!v6AJXa(N42XK)D?8;yKOqPX+r04#pB$7_UVrB z`dn6ziIlmLELQC9<4Y#q=2qBhNn@3-(yS>n8&c$qD)qK64qe%5w&P#SwXe^#V3>jJ zwA_6(lXOvYMNCnDwA25RxgM8=@ja#OI=6FD=K8+Fk+@pQTp!OK^ZmhpK$(AJ9lOzcZNs=_i7_!AANywfgNzy1=k~Abuk|s%#ZBMc_l{6R(ed7DE z&&_qtx%R%!Is3ZKTEBIEXD!PgYOPxSnfK%MyqgZ&{L}k)`sGy<)BE}NE2I3Y9@~5g zmkM2vM%27+@Qk?iHuq@c6>;g8$ojFaqX!zkOnf;Yz%DwoqETs8?@)WFT|!h#!SH)S zEgH)ByLC+7+wU!{BN7g_?{qakWn52r`#pqt565)w2z*DF-%5L9=-f;g@cD-85|py}jiZMLPJf;x=n>OgGB#z?-x})j1(=lM&SjxY4U4TaN2N+L zh>;Yt%LH+snfJ*cXRcX-{Ozq<^~WYun+S_^R`W6}>p$N#HVWN*91M!Ml|1jboL| zP-?vt=zHSX?2GgyEZN?rI6%G*wE1Y(rtUnig2pm5QAz!R6lfGm$rz2sJhpK% zj~L(aBRMawY!76@SgEJ64wa-kyHZ zgaiJ;wXz&U@%?5_@x@yQEKveP@8SO2gmxHCyCd6>+mGK~lK&IT+>2XRHsJsQ#-}H; zp23f*JZ%ym+gakxL10aquyiRf*kWG$e0;1$!De5Hv#U$EFW%S3=X|2V#Wo~B4Tx?o zYkUX$K}1=nUv?D0<#KDdz~1Vyz83d^p~*@a9DG@_XsPP7V_y9k-q!3djb+aafC6|(OCz}d!#ifNROzE2R?pL=hYUFT3$%_0YDf}An zj<3L&2Ot653^BZ*cyfN?t0T9^uD*w{`Cp>$jCY9Ie*Ov@qz(?e?TybYflj~9?|?PZ zdW}zX4i8H#jtK|H;Ny?s@>1tn$vx(zc~JL!&Jw44&xrkFZ)|Cq8F-UP7x*;*es-^h~EFqS_*Q ztubrh%LL3QAHts;!o*K1=1gOgB%?5*N=_oW<1mr|ou0;|PZBwDOs3p8w%H)I8N->F znTCMCUF9hY&jjG#1JYBOL#i;At^5*n2u-4ZG1}NZ}6ZpVOTiWmQF8j<+C_2GrD9nnJ<@?%ED|+~ zAu5U9FRE{DE1Zyvyh)IKy;#K_8aR-bLmwK2+Nw$Yz2GP;>20+rXFxn2=uF-&T19z*nSe(-Kxf~vY!v`d6xgc@v&WaRroebPw4}_f{FX&S+h|x zZkF0R@~GH}-{dIB7FazpdkCLXP=OaTIj-hgjI|dT&=d)4opoT1*fV z8Mk@LepM&yR6OO>gj%Liv;0MXcC{1AnoY~=+i#g8zfHvS~@l*~sbl zWtS_bKU5%VWgqzumwp+l{=-^X<(J|5$zf!zjIa#;t(5K8@q+2Mo9!cZKb^#5a6@;0 zdYNxO(>E`UN9=re>+{SP>BD9B4jWKhoG4>YHxa;*`jGpM@&#$eW?U5S=j)LtK^~f1 zYrWf2Y)Fx;M-ebY#bALS$)`stP>klD6XOC>F9fTYtWy{#|1?3{I zopipnGljFV?Sjf-;eCT?>2E8(f1R?G-%_?fVbEgZyQNi0l+Mi=qc@V2J2|G`;n^EhlJTE=OnI( zooR8_u`m}=d~Y~>A?i%lO>T(#k%nySAd2s!R^PhOGyIH87JD~5_U{?Zt!=xs^zfs{ zfzycMOA5Ku?6$;P@%dKbH-3*k>_*e|)om%?3^*e7vwK@Vm>XB4l&;+_cTdj<9!!3! z6pdfI%$c{z$opJ-fDI}y>LxXq#NWJH>JIWte0%M9{=)j-$dQypHjBdJ(CUcC)X1vAOAEn zJ$VnM!eQr_c#0;*FXei6bfN-%Y-l zm9ING@C;`{3sOq9btXB8-m%&)kV)NWQiw=0rTE2APS4`p0rBe+-VhI}xZG68W}E39 zC9Fgq0GGa`I!e$g= zp-BTd6U$#PMqDXqzI*{r9*7njm_X=3v^N13Gv>hx~_m;^DNcrIDP+9E4KxEoIut%@jeh)gbY7$?sr>+>O1 zyfum(orxx^c{5E5dCI^BGzF%|B=H*ze7|>}RVIq@y@oD0pw<~Z3Nqsp`fQ#!9CWUv zB_F2;jP=LNI#n5lQZZ0v{^f+M`?vYkp1MZl5EoG95S7f3{ zZ-CB_L%UaD_w$eXfyrz!hQ&nL(hlrqCaT;zoJhke)`s9vY-cl^EfaG{l%ntqw+RI} z(}E4cd~F(GBoW&fb48Uk%D`=-GcZZ< zN{7R?f#j!`06C4g`xXVq!|wz`1P{^TRYd<(%GKIKTPXNM)G^Ej@^T6r7$N*D*{8IH zAej7amV)0TB{zjq7SSjUw{*u5$<-CL7(^$gQUdo9ych&M@Z{5SO#T?AV ztmI)3Z`4vAiUCHED7cOMQ^X`h`pTZ=#mx!`R58XJqIgj8_I!X;1t8`=(oWhc7{ykIi5b7g7%GFr{qak&~%}DB7{Mv;azK)Nx+yCp;kmbpW%4$eY&9G?a;?%qisWCuO%yoPe`*OjZE76s%C$$!Zd(flZ7logE zRG{0Ki-=jee9R(d<{hIGCq#f54I^a$Yp8^4w#3~G;9KNA%VW39j-MthKa;llzy`Nm z#-r${)Cm0Y1D$>c?r%7UODdfAj6e`!G)vK*T-5~W@$;v00(}V>8me)UJVqt%2Pxac zY2NeBF``i1N0fqB+P8$N0bSvVV38RU^J8krgNHk|(a@MAY>PxQiVEmg0e8x@r9`#h z3G!C6khdWzcemm;Q`6adwRV6P6u01%pGC?UCljCHjH~v{$M0JnmSWShV>3wcCu;li zu$VVdCr64+j98gA^K4r8c<8d|=_SoCFl?vN3(qd?bG;a1TG~7ggxINBic7bS0Gs1W zADqp>M}_RxI#a(@nKPwbPx0Y86R=Jt7}aZTOzdva z{zQ7kSe<6Q8?cfA9HbJasj)X#QS|uu%N(NeJHiWp{?=0&VRYOYDQ>AadASE=g#ha& zAh9P+pte+);3& z!|x!r3K=QWIBCjjzE$eK~^NU4^ojdNX-Ng_-#!f@Tvm7EPH|%U|=wcCX zaK5IlFCmE%>PsQGp^grHI8PR#T%`5m-_;7uP!I|mOC^u-aU?#V3Ejhm-xJE~zn7n| zvTO7=3ekl%G3i%#zHX$A)EHZ6CGKeQbGo?lyC(ep5DPt3^gmh%cNRHSZJ9e&^?!or z<;gFm0Q>5uwmJX}UGUWw$#6Z;aB=zAv!yr3;e;EXksDNOW(EDy+kpq>ji-T#sY#Cmg1r)zc_CTj|R;!BSd9z{-7Szi>nUvQ~IGcU9->C+gF963xW zrcGj4L(>y;$0&U6)WkH5gcFe46mpUR@+A2If`MLeSR^RUp$jTW71d&ZC$*>2bz@}N zIUwAoFCg60P!^OLGK# z54v0~>MpVM_W}8l^e`W49$#$ZKVVOyTUQHOGNHmzae50+qna0@2FbW4dG*qq9#MK2 zT?R`k6+z@GHSx<~3ON8GCn+SifZU@d=DyFR6p*aK+`(!t#sDBm2IQQDd>|5MQNJUc z@c29PUp-Z&dt?9hRJC%~-M>0jEsQ_(zX>OpCO}~J6W$-f2~V)AJg@$Hg%hGEJVukk zwqGrTBQ~los}~La{zAB4IaPJdZtJqI>I(aKt#+{dW2L&KF$G(XUt*E-z4HE{lp}gq zEmC|eb{J|0*%q8q?x@`6QfLE7vnaE{v`@D%&bt5%*<|BKthn@}A;=VdlM8(=U-J3b zSm(wij+i%VJ~w=MbaB}|)a!@jhUr#yX`^)Hpk^cSe=3CAQk@w-%2@bt$L6)b+a05i zs6P#|ps~)2DX8V|!snwgQD0DeJA(dvY?y|zixHUyC5b#AbA~%Mxjo6h1yGE}Uz8t; zV!!Y^tbdLOtOcE%6hfuA&cMre{S1a}Hh${Htv$c*X4u%GRi(>bJ~7}gfoBi0RTyNp zwJ5LU>fv|=6A*)$4dpWJ{V9OZF)VcY^P3MNyO%kRwmrXnXEdQ`)nLh&t;-%`PtI(< zd+FBjws+WviANf4-ibWA6Z`b^8t0;){_d%&d++tH6TOE&f1MPkUgtLAui5kE5+uX= z;r*?rYENI+Epzm6nZI`S>mLi@HtTd_RSRbEMAe!X_akPBg%D~4Wz9Ruq=cv0>muZ@ z!ab0P4RFG{*(yyhi~4SV?_1+Vwnk-1Yy&;s;D-mRpB||+xG<(Sz<&=Z_UiJTKe5+;^2!5`AVUc&m2cyvK2+>A5x4 z@5)_xvzWjSW8b5c%OHY>h@~sz5jT}NYqyFxcCrhUlVvW8kU}_rS+UNOGS^kD&obj> z7eVDK?ry(Q2zSMEugCNJ9$BgFlPg|_Tb~zA%PvF8<+N0f&SKs1GWSj8-e+4oOYO!H z-L2f`vd4>Z|M7CaC*{7kT3=Mg|9{|A<=l~Ma9987f#hE)g!^Bgs&a=8B+VB;A?1O9 zmXM*;mWSTFOL1+U05`LoZ6t!wtLfBWNfq9LgvMi$1567FP|+}H)HP^3@M#xH&qqMQ zRo&Oik!F#(Mi0`aER7^cU?XFfio&b=2BFL#J#2_TCQV&yM@w30RzluPtvZEE4n8ie z#V+?tQ%e*j8*e_c%zY+8zm%4m+{q)&3ht9;qLLO{_|6*6rag2NTcpD5BaQf~QGf*o z%?sXM6;|g>TvM`2?Yt_+Oe*h`T9(Jt!FE#B!|%_CnWQBXDu;5D z4YgTr62DRrzJ7J@2P?)%26v$( zi4dXnQ8)TViVekug1Zf2iB6m(rD6s8tl52CV@P$;fLPI1{v`df0BzGr?|&OI>ByH# z9&-fXgqcv~hBVcnO^ithWkDYp!)dljuPsq3YfI@U(>A8E?PQIUOL!Nq+XU#r3mj!2 zb`jIQSw)_VDHeUokn`~RX>|uAMrkVcjml2Ub?VVH!cqC#&l7p9hXf>lPAaHS*J{;I zq%zR}nz&Bqp<{@Eg{B27VRhUTgNL&e@)}7i^6u-^h}kP-cU6`PSftvbuIA?^lo9T_ z3s?$qA7E@$b$txPy!reAzKd8-lMGqNN0hx2UZtCb&6NVWOOgm^!zG3`!}0kp{@_bD z_e+~2-hVW?Jw}(_pM_-Lz*>n@i#!vh-)i@@F!)_46)p97zL_pC3De|*Apu6hI zGS-HP@TY@GJEP)^lJ1@bL-l7wgKEaMZ#r902Y_(zgO0>2JDL#2AJCSfgnW2Lq zWe-uOC6^Q4&54wA7&@uZwy80Gsj+dXae1lnwW$f+sfqGbrcN5mjGpYLy}~c;U=kW6)?>jc0? z`VoQ=lOaIwsmbt+3e68eEvLi~Re_@@AVz$$yG+AYJIZ75FwqF>K_x^o(5tp(zKRP~ zL=!%mMzoq`*`5khd=tM7%ABs%IGq=|%9OH$fk&^-vh$-v@EE%hXX05d<`rcnAGH|_ zI&OMu!*VXt!ly09V@{pYou_e6cnUv)HeQ|Wm=ttQf>OPb?d(KXUlf@aN?AtL7dj=l=KU))UDo=9e65^+;j01qM`V7)e#MaQj|cUkpHT{<5Wt* zhC<8b+=nL$S5+0ZO{tkq71}L7?J6nkc(3+sUj82``R_;g|7_?8t&m-AgBM2Ms(lY5 z%<6UeSv!lQs0jEw0Q#JvrxUPQtgyeyg_t;OcW%1u9o+T?Zs~!uI^aWho4KDE?DzeXL9XyW=-$>?5S!wtPSo=U$nIn!mbnk^g{ zgY!D!!d}=abD*xZ6UQ2=kiuWv0q1<#t1)fkCB()e|DS!scK`{SYj{7fKn`!ty~;i%i67mj+Xyo;qqv1&A>@<$%8mD*C;wnVLJX&!xo+(1W(KufumGaWsMf_SRER*(^QYvkzV0^DJi`Q8} zN8oq>mN2-zq&QwogIL7?^b0g8v!iR-Kn}jmK}B+D4?Wt~B(oOT4iL~vdp|(Tz-pmM zwLr`h#KzU9_4B&h#hn>+2V;Ra11t+?cF9E4!XaO-EZPbr6^dfZhxoNQLlUWqB2^+0 z>G- zd_x1dB8gn&oLS%6FLLN-nh?RXQE^aFGp)84!FM}OUJopBW(i4|B9R!Xt^K7NJza)R zpL1{^pp4Kk0?LS$1D`(U@|d2MVbT!?4e~?T@2BJp;;&M2`KbQiQt}}q?q5;z`rk*% zq--DjZyGv4wIri|D?`U-9a<9ZFAN>}Nco)ZzsS&G{;{Ikpv-0a4}<>w%2j`i@LNQk zoug!rIZD26`Ee+D`P$!z@c(^7$A7O)w>PR(am&zYR@-K;^FV9wkammiuhgbn+!`8v zOnqoE)@J=OeC&zsyNa=P`^llPrx3wXCUVh^kUeu>bPcIZU-e1$oaSaZ-s!U~V*G{Q z-fQDs0f#@0zoe)BYHj*tZ_LYx$sgn1U7PGnn4JAI`4f|{R4!&~N6O!%Evl6FXRI2Q zzva3uof^oQt4+__TRAmYczAf~9WQn1|AC?7FDZH1jC|nifte}EKMz>s-l*s=W$Co>@T-K4D)G`}kaU6Q=H8^1 zFJ+r~UQpcjOKmz5;lDuI>waIiN6NANrwtu{s7?P@Q*!=jPT8*-I>tYyu4N#G4&zFL zap|SsP05eiW9!DwOEWIpzuWLMzGtjR-genx^3m*56AUsiH?`MMbAgD788bxbo6%<; zi8x(v4I*kEI%$5;PPOSY7zdqDY#J?n_(3u0uA6SSK#>w~QE9yUlG_NTgOhy$XD%kp zA233nsq|T9`9rFn3&=bY04gmJHO`~Nf0Juf4NfwWfkAPy61x$Nbr0S0u|ve_erqrr zhaz_}lJJF0lFj)K&WPXGf(T%O7G`Lf@;M3cMf^VfwxzF)C@7uNhI<4bqlR{|$dcX4 z`cfzWw;)ZMl)F?tLb%q8nS$5TTIwC)u4X1;;(<3+5w{8R>cJ$f?gbTu+XMw$Zpz{| zXMWz+$MZ0BK$l^p@D&VmQknMFo8`YTv~iE{r+TndEl^6|aG6?}VH8{p5-g)RDa9Ps zqW2_|(0)!@d@hp!tf;~!-FMXcF6;OJ^Y)XwQ-w$iMGoFoO#$%dWD&vzgt#+T9Ar^Dl7bs?i=k_*^}S~)Mw0FzijyE+r+n7W z3GKm4Novb$*|FNpb=Igy-BzH0S$tm&CBU%s<~>?{Vx5~xe#g$fi%N=SP2@xnYaU~y z?B}2ux-z>X$5=L77tj!$f5a-?^7^Xw1DvtK6KXp$dy#qQkc|b0H}pdHE|n{sx_RLy zOR|2A-J(dz*u_Pg_AU4XJv;M1*QV3c3~w_o4()VQ1#1oXvuZ# zbVv~PwJ9cI-`VTBzC#8_7q+S_R*0u#D%1`=dK$T*`uyt@bs`GD@~wC`Ppa9j(YP4A z6-zrL;(W~hvhbM!j-K#{yyP2TconmeLh~0glD3a z6>Mrf3eR)T&b+OmovHQU|43Qw2^nHmvtm~kolb7yRc@H&+dMkpO@3=Pfi>})+F%zS zOpkqo+rho<j7q{cz5rf6yr{@(kI_)f*u8*kRSlw`cAKp zF;CKI195tq6XB{JzBj#~kA@qrC@6|hi#*>D_tB=hH=r=b*hc8Bu18&ae;m|JLo2~z z6dhr5nr&9@^W8 z*jfpPzb@JW4bB=R8;id;MaJup2>;QlK)_v1VSSLRYZO7UH*zBUACcyOxveHHBF*{D zNpsQ$V9j^07DeA)U+~U3qZ8qd`lS@*TsY*~Fai`vS=Kk_`w-~BV1R~P;OOnih?~;u zV=&T@rOA9X_;F~W1xRdx^FFyJRJo;$au@;+rxS_T8=NY&ThAC+i%?LFN!nu9$>oFLU{ITU7>{ARQtRa%a zKg(d>a@pwkh$dUYYJxl8!@9?M6jCNCd*I08PAW@?h&DAd@Q+^+-A1Et7*@-g#Am_? zI~X&2;dVTj*x5b^tFVU@GvThUuu2w;(1c<(@>oTT-g7{KAO=DfvJQ$Bvm1F5BQN3zYm{tpJ)C!ynMH6LUXor}h3z~8u-h|kO z$#)<@bGX6c@j2iG7eXHY1`KITjj+QGtT&@_b8`^7v7myyF36rEEu(_<_Mkl{hnovk z^z)G3FrSjhNzUx4tAAGIcK=3LgsJ^d`8d90(mo7tqs8l49NZNergpzJVl!Fll97c3G4vetjoO2u@3#1}! z?)#j19Knq_)$SJ<8J$z`U<~K?L&wG}+^<5%bT;~Lp+mDj=dYk6qIJ*zMw;vMRAoXM zf9ee@KzaSU^@c47%4VYR^k3@@+gE~Bv=%Y{k9)%uf8IJPLR{p_ytZgn*4OwYhuy`0 zXRL(TH|HWxRPevi#tL13QxxmxRNWaOar)<7HJKU3KimYUb{&q{N@2_1>ke<97qct6l^cP3Bk z1li?WI2l#uVicd3GPAB&=aN|vHGj)VUCu>yWS9qw?MThcS@wyS>b^0oak;(+IiA``*ep#Vw)Z@%&R)Y50D8okB1_<4ea1Y7v_{9t-qgdtdX{q2&>a#`_|g<~+Zix!ErtZ}nL2D={tsW% z-S35AErz-brA$b@gWGW&Oad;3I<1vfF_*{|+}>{#q8Y$UHsUstW`#)#pp=Z9+VLIo zRPs^^?lbGKg%+|*%mO(^@B$^=IXA5vv@9EYhW+GIziXKHZbSzfTTOs9l$xP2JaIRfyyv#Th}1ET!8UXe8>-5kG<)9!6$|7h zj>A=(S@zjy)V2$4R$FDCt>>kfpZmo{zDgt6%5(ct8je0KRRM>4?b7q!XJjJ>4}M`Tp2L2je>9qOcLOM&dwx0;`7ULRB4@q7UQNK@5= zX}GQH3Vzahgil`PL0&-T;Wl zGmNq;6@T(Tp>gW^Lp$z+$qI#y3QA1OEkXxYCqMu!7h&#v8>kxmVHKcXOPKeeDh27v zP}V+4P-F3vjF`JH>(d$=P7Fr|J_iYwl>3f_jAR@nMh~B79(l@0(zI^;Ip8d@6sJm7 z19&(o>b@iVhMXi>pcHJ2b)bv=Y9AgmcKv*a6wJlyA&&iV`E>_Vkf~D3Q+#3rzgZl# z#W;bE+Ae*#7LG!xAfq=0n>X0oZp0e`ARqQF>Rpi3{dxwz_yp#6 z$}LLhAlTQoE@)ZWqCR|#a+$#fHc8XJ?@WOiB}d)m|k_fEidqj1mgoCyn=gUzjj zSq-p%CA>7g9(ndBHo%+?7||LUx`s*zVSF-@$b|ii28z1i(w3o?J|yBfi3kVjEl8+T z_I=-+grWG|)J&INejlu!If>y+VOW!jtcl`&SS1Zsh!P9v5&{9N2~4go-xEVD*r zn^zxe1vcA2!907&7%Hg|mxVFQ%mu-L_4o{lEu&k5%|jmZ2n&>ZP&?D-Ub6@|1bh4W z@`N9z+0~9II z>=II*sKSndz(s`>wWe0q-9FGN6PY1ta<)j83B{F3y}b1%rsZDjW)ojQUp|OLJZ*FG z0?j}KQi99!koPn4-p+01#ocJrv4M0I!J>YNFFUQ!hMsN#+Onl4d_hmY7(tuPayo)1 z;&d>lUpl89XwZY%k}?vc!4R7n3lP3A)1%hPL`D4~3B*)Xq{_Rg6a$c6JA^#T5d|dF zSP<)>H#{we((8G-%s@M;2@C2er`Gg}LTZHwE`{-W+lQo?9w6OM&%3s_)Bvm*kP2G{ z;_`b%?RjZ!q8^zjlmhW(ytZ_zsJ$K`2!}iwLNo#FYBM5OCKKgbfpQ^zqJ@gkQ)!nJ z(I(Qw;vtz7K?dZ(k5B-D2FQaSksJP?HGKGm4iE}JNZ}V@VosYt*a4xx-!DUC5`L8k zK6I%3EfI_xo%t&w*z@~ji134W;%~_i@%=!O>c5c;@pG=`JR>w_A>+^Mt)|sPoU%3d zUy>^|zj|dY(Wk587qedd#D|YAkBB*f>&;qU2KKa=7F^J5wb}n>f4l4aU7j6t>#hHE zuJqT5;G^IEW{nlG`yc4cw~1=eBgY~{@Yn0D{~?0^5W$~wrBjx1(qtr8YC0fClXv|d zv)(^O1b;B=EgOBDqEdR{-hkUW{b}u>4@j~DsS%wqdKTney-dn{sAM6+X?P}GRJ&WM z<0{Qm?JT`0O>@@H;j+o@)|U+LZX^NG&plC23N#(Gc68m@^U*RxDUYC9!^c^8?kaZq zLCNLBhAg9SBL%OY-7I*zTW@=6URg%G?^rKoAyX5VcivS}YvAH6EgG?-wTu0?v_7vZ z-D;^%#Gr?xSjH8oOBDUIfOqjPZ_1N#^J^cj>5EFa?RALnW;wKdpb_zqTu}Usz=SVI z7O41EW^dZ)ep`gAaCl>=SqlX?D!mdFrQ|8fA?0jZ%A(m$9?A_g-GAUi&r3CR1H-bW zJ^Sg*P)p=_+FhQ@wigZ zPVC{7d$0DmC+pX14ywpO^-?}(T{bx@5@`~)>Clv^{zjAVpK_(zYTxN^#t9rat;do{ zXFMr?Sa1DPuC&YKsFL2E!hvlK+Lh589SX?$3_8jo&28@wo~NHqufxu#U{U@Q@}2A> zvyYRlfSiKLZ@EigAj0)Lo9sVd)96cXWg-q`)vK*&+{2ia6vt zph#XYA5x-$_myDPZ2{M{tLwVl*Wl-OoN{<$K<&2P_B4GccsJXiGdGlA1u@P2P^b^` zk5!HPBTkZRw5Eh;5}?M>O%v3S2l;PTZiy$ePURw1mw(alKCd@T+UBF z_UQU1Tx^*H_vG*16MT69ZfL0Iq-SCZkla3SB)ht}sPOAEg^<+CT9FkEKf!yFN|5*q z001k_O@-7?TQi^bx44{t0e6-GNbAb>Q_UWE?{D0wG*9frkgd5DLan%`x{QkI3E05F zMExs=F|Gd^dZnc$ zenFvlTE)v5xVgE>=+GnI@}ZYwaOsUs^_)qW5V%@?nO@u*S~2LH*^PL9o*)^Q7Fp)q ziR@N5ET=6&FrIvOyj9p7mS685ongd!+5YrVZcVRo?m#RnXMB9DtEf}8yL=)kn&y(YaEj;M_!EeEy7ksu$3z? zw`L-bD28b%?gs6QThb z7fKu!7=oo0W_8&0Uu=cIvwRYu&P)&kL3Vlc>y=H;|;XtP;SUk)V^ft3R z6S|Opw?%4O2Ko65eB&g&p-d|dFDI}U$;#N8v?Vm~=yA=19biI(h@Lt3xD~c^vm#4m ze0q8AT)f7;PTb1pY6XDEqdFrp4tcbz@IRU3A*Yz(AE^|FD z$YuWbzp*!F{rXx562$r2H@2p6>R-LFBYxi-+w=B~pC8Y4x7aUF{)?;oyvTpMtGf*q zA{zb1)m_CY4P^ZvU)|@dK9LWd5UWplknW$>I))A+YaJG;wFXx!QZ`$B3{P48TWcM^ z$LdqK@1}|yJZJT(@VlY4*Hh=gf2=FGQ+QKj^_O2)q2iKY{udhs#~^@h$gDHrpg>=_$jN0m@13XLOoAD!W(f>%Cq8R zY`$WeQ)m)!^GY&A@<_9UlkrRB5cS-vjgBa!4Bg#4a)AHhxI9|Py1S7WOnH{5rw-tp zkhwwr{N(5#$__Fh9E{#_M^_z)(rI$^7X$O;Vw@Vp0{j{C@9Rz&`sF2uR7nY0DmPI_ zAPkDKgsWx?;k1z%GY*)fCc3anlfl|Vc(&!l?9v}{ab-!NYbXR0`UQX}!Dz(sUfbp{ z@rx)zV)RYULIJ31$z>X*Z)YwUs=2kzU4U*9la!1NG9trFc?!> z>I%PNk`@o8;|DPTP|)n8Uk=(UzSVh{ZI}iD4y8j(1tL#0iS0?-Ef8Nx`JHikq=W)I6IFtE8t5H z8)<6Lqx{@rR|1n!>LoIW$A2n>X z9DKS5MByyBz*2_Osy7B{ccWf$Y;w>f5(RzF?Foj;zD?W{YTKk9=@|wwb(75QV>1L8 zB^Q_g%z`ML0Z5T38}E9U!)m)kCu$M}xTRDGV=QJV#3T(`A7A{f;;FPXpjblWH9h;x zAn>$`Db7DVUaJ;GUe%jKjuh6-AC1cT-Y!^qEYr?!6xqk!Sb||w?(Aq=N~yW}^%JR; z@ZwGT*~&#h!?U%ieeWBzd85C%){*+SV!_i~{x>sAPTx!L&%5wnYaO3AJU(5t_|VF) z@3;K)c*Bx}ai0xihUGN0iTn*&@$lNAvzWJz@~& zj&D5PIjh!V@)R{(h~Yj znbvt~rsL#qXc&J)=O|;mok(6gg5HZt-Zz-+VWvJY$v&r@;U+LUt9q!i@rFyx{+uJ zcizEUeS9nu9xEy-6y+Cw6%jF*aOcB(#EgU_>33C+KYArUbZ@k>@+u-*m^%lw3R}!W zG7d%ULwrY$r+?DRk_4CbA!a9xn!V)RAf4{#?@UUn8$rSpfpIy3*}b9~>^2zI3_d zNqf7ZcSYAI{OR-OqN3^{7(UrB^}M6)em~qQgI~UUR@Wv@?0`KY3lSP3q)s0GVY2_{ zcbsN8`<^VLMebcGBV>(ZS%XOO0ts>GawJHr0g{a9=;)l77)PjQ5QfLbhqCK>k*j#e z+>YMV=%@^nIfTzg5)%`O$i80woZqRWE>AC3=2gqfhztni)pxZ^g z)4CLr@u<2sOy}IZ(ja;wEr683%js+*sRSUEl7qqljX20u%M$?{65duQhB`WHqw9on z(SXZRcb|9&pC<|A$#nC1E*zZ)}c^lrM;fNB;FQ6 z5T@9cj=&ntf1tFqH#R7szf{L7*d6gK$@{=zo)AH*@-lV7W=6R`EBcx*yD`jO4=++2aY&1-HA_RHTOJ%GEVW5pCf{NBAZCqbL z2frHhqYL>%-4*V2?agyBhiv56JBLC@HvmFI2m~QygwW7jVF1#~kp26a=yB%KU)LS1 z{u>jG8*%=MiGHu{@cb3_H+6>~y`=U3Ub@3t8dH(_7rH}m5{{tvFVh|NoLTwtnne(O zNo9R;oNM@9{ElJ;OvIcM$#<^LGPZXAO_BdxpQZ2b>9hQG-NDUbr1^=%#*qgZ+cQR5 zQunouJY*dqjsC}p^l;gK;t#*oXPNN9&5?8BTQ*oafi&1$%2)5q?f~Srq@Q**yp88iR}sdY;{P@gXg)ZPb;3&$10d3={nB zQ$!G3pO|!UsXob|NrbX)b3%uk0bbu-!G;nC3}!_S*XFePl;{o^(5`JV2;`xx%|PXt z&{7o!jkAP@DxcvI*2;{0k8{Tjz1EgHc9<6^6hi1j0w*0QYDAn2z%Tdjo)^>dDxb$YEL;jPS~q=k(&rrN`h!VX%*io;N< zLiK%YpvcS_D?(|Am=~1JJ82}|LCT0+eo%XmtSzMmgp^(&J3>stD2l0D@y2k6JNjS> zmZBox&6%v+=&5lyHEkr9|$j7uEaiCCrk-SDk@vpXY} ze=ADG9EFJCWdgMjI@83*iRe)VB_2Gz>u0Oyq;Ek!%ApN!05S0(6Qdy%JU1c+W47=& zeTNSBRBpCKtuZ90%5sS+ph$jr+XLVyhv$mQa4d z2u&T>P14YD`VLn`u+;gX=kS(t!=Yzb#WEv93$e2!iJoc^+=xO6-IPn8=r~DEUr(fC zu!tKer4J1N?zY$7okCgCjxN97d3pOGK2uYOHJq}oMH9iSpqmi3F2u9>-H{Y>fD>pq z>prCv$T&%~1>X`k$2DC5S=tHEz_>LN?Fv$`@NQtuBEgDG0V}b&K@3Ey{&l2f`LN&Ba!rP1ek?pXpK(B#EsVr z(fa%Y7&U$}z@_7uX9ep1ClLtTx$Ka;{ibt*IAcK)G4ubi_wLb9#tYm3J@?#m<?y z&MJpdl1ep6rILn(Bu(X%q*0WR#`(-ROJb7Hd6XncLy{zoLp4d7gd}N5LegLy(qw*j zd++yo-{*byvwqLo&wl@T*8ayDYt28iX3e_4*Y~=v&vmz9tB5+@aP?0TEEgtB9*+Bc)L)t#Q4=$XFT)Rn zU(IcqJ3J$$Zywv8iM(0$pDq}#I{Eua!|R-;v)U^LwmjL_dKXNZ%OiJgzGInmv$t(8Lshs;G-8VAM=#_m;DZpm?vLJrJd zoOD26d2GGMDaT~9vV+Kd&w|2alhqzxgcMpCDIm{1s4DrWaZ31%QmA@tG(kC3J=LNv zC2>$G^IYl)>(u{>T>48)>l_->+6#eTisSvMV-?@!9gFQfQsMAkl3f&<&O%kpvnvqV zUwG9$r4=DKT|2Wr?4G@`+=Zr@Yo&Em=XA(43~hWA72Vvk+b%mN&pG#v*0J2Ms2Ey8 zb?q{_`yXdfIvPRI`PQUFC-^>SdMT->WuOvr^NTXh5$`(akD}U84fS?PqLDe~lTw_R zl2~o1%rNJ#Xek!JZ8yxKS z%HyGalSM>{bD`Mt*5}a2B2z~XeRjWCJRVy&g);jUuSiw~T#C;sK*M9TonkO?_)7Ii zeSQ5iej}Xs>up=xmtT^A!ftdmUi4cs{7XVe{b^@o0%!j0>FMt4>;3ql?NG6#Z(P#X z)7{e2{HGm|HQP5Vo}ChRylqC+P|LGMR1l$O_12a~Fdj9DW}2EBQIuL=r`Wl$83p0j zH*-<6KWU?eZ-FqZnr~gjQAhaJIeDoCB9y-G!4Y1`=!6|VHy2-Bb9WCiLItzse<4H#I$LM*AKAo#MvJ^!C3imx>MlV_V!k{@=-^f3Pk7 zzbvF=6EjNs-zGc6>E2Wlbxt1XT))&A8M|2L-Ef7%wWYW~8VVUrKI zEYW@}{(od4mC5MQl-}-Ov?h?m>iUP`w`Xo1p~%ZP6uFQ43zQl87_xqXh5S}>#0ZTD z@y*ed!Z-DT27;P1YrZ`ffJgER;xPl*Hcs*u1Aw$t-P*#vNsSQ_N04_0RI6F=v8K=3 z!N$wX`p?*R0&h9yeEn^g_oc+?J7~{37n>FjU${A6S^gLeOTGB8Jyzp>@%~rCw5;N` zj<9oDZkpfLWNu83m0;HUC*5|sJQNQ|8Wg=}@Mvcu$&8Kx?w|a&_wxHUh6FS0vM`qG ziR+y&R<2Rly0Z=kvg21$0fh};Xfkv8jyFdqwZQ`epuH&0I8}%_fW(v9M1&>M)JmBf z(K}twZ{HI~rQu70?;v|bEZ9Q_oEK&;bA-MBO7&u*+zcM?$YI4&dH6Lmw0Ra(`&C{v zfWeH13Dkt!huTY89Cl!@ZTdJox9-s~>Q)&$cCvCR0LE3t0VULgdFlD3L&s$!FZcG~ zym}!oV-SY>mJz>P zp9k%#VnOOGFq>A zWT3|DUeJbH!87GVT`Ft&;M%u`Qq9!$5dx0SX;Df#>hicGa~{IOB0}tD5c5qvH4gkK zGKW;T?!1DI%fYFY72yT|S)YPL>4&Hv5+O574Q;huFPC+R;Pq`a1M4#D=6BHJ z)RglYfF0Z_hL7%7(@8leXB#OpD)t#u6n+?FMs;c@=A9sZ>H5r zYtnb#W;0vu2(;-iRrUJuXz1&IKlpw%Gkr^~W7gfM66%wm_Ti@J;Cr;uijcDQ+@{GD z7o!Vn&XIzIF#Xp|t&e9!B(sNE&X`O6U7w?s) zWKfjs!;iB=v1*-3AJzV=ak@WzX*x8ANs%GSUHmAyEtXuod>-whXh*%lEjyBt7If`e z{^}&bn#1W{i3Q;WZ|dtSaJ#RV#}=)OdSRG1;k?ft6*E@(BE>yXSx=@Z=8T1|=~eH3 z&ApM?X}2BirJz0#^MvpB?;~i}rKq?VEx^n>HOP82Zfj`(MUA43mm?vGw+AHge96nt zzuw(~_TB!GnwGM8?=e(GpaC_#h?;Y+Bx%LXU%vD?q&y%Vy?d+a$LC*?ho2>=^-}y! z5?q0rQYG6?HadDo@!!u(O-(GwnRK}%AV<6g%@g(ZL>aDB231Yo%}O5E){Kr%dR0rz zBPy;GS2Q#}l~0>8z9#PcDlRU}Mol2lyT&r34T&0Y<%kX)@*to7_VVpJw2%{8GfqtI zK9tkE@XXiB%8JT4Nna(DlXJ-=YY=-uqLtQG-PGOO+|)Pr6V*uN8`F$(j^Hh zdr+eYNbdYQ&7Z}wHqgFgcjmQqv$bPTlj+_ zj(#<-I<3(>Bk#z3d+(B&=ElzYb(HRo3OARa7}GXJj!B0qO;wI5?xUzK)1Q?Lnkrg% zPYLw2n653|jl~94 zLfW91HhiU|vZ^SXpJ!@p?NZYnl~&L#5LHca!WvCR>}le`WYj^P>u@tHd(`R77P9n!U0LOgMR_Zo)%piAI+inYa*Dp!s#pN*mHif2VhJH^V;b`Umn<+FjP6v6@ zRqs?~IpgL%L@O(IdGP*j&w5p#-aF6qWb=KR)_r5xwpjl2$XRNsz75ENDQ2TGex3hQ z^@(7#vhpu-*1yPEf0vxqYWs`%bVcZk9d#cMYd@Cz$NAEK-#QAH)<({}y(;l&-XfhR zXqXAq4&=v?Ku%(G_jOM4`xFgFK>|3a13XFeV!+jzOFKEhqP!I1C}4Yf&XY6Eh*z^k za7rHT^1t+NZU0&SCQ<}|NKpdGdNwnqCA$#&3PW<_Wu~C0>F9ZbngbMkiq`$yMF?S& zVixJvK!T?8Z@lCCGns81WlnO6QNedodx)R1sr5o;vD;*^Yy0qi=^KZ)QIoeC zlv&CmW^!p^gQgSC*X8yyc93oG?S1!`o5|SNE@cNpQS_9JbNP7QaD&#UpkYg&0{J!x zDlK}reD!`BW))S4Uom6l{o=xD1q&UpYbJ#VgYV;{%*m3Q?!K!dMPy9_3U=pjy!naw z4!u3swWR7>p-Mq}RM2E)KJJ@ekU$HdoiZsAYAvO1RjwY+h^=ancOOh} zIg^%y3+vT3ac0pBM41W%3f?HMZVT!lD24TEZFC;pKY>YEs9s0>X^f5RHH0uFaj@}B z3Qmz4uQjrWx1YUS)0UE;iS)u-^M>P}n}3>t&FZD<@icV?X7L~ZI_K4y?x8SBs`CkC z#2itk131}4l9U0O1#Rdn&PGirJ|_Aj;sK*A_YJ9a(MM~#*Hk5F`cW~k%UB#vpR&N6 z&_GD$e2S$!;G?{N=ryRN!cmu!r0lI^TUwk-KL<8rW0OBs_YxcHR6GHmEL8|#mE-W{ z2k+iKF#b+{Cbu-|3bR6K#BkQ&8f1{1mFNAsI zIIqYL*7LZ5?{~LBojNX7&<}TPL(Wf+i|B#hM)*}GxmC$q4)k$lmQ&IC0=Y}hJ|xiMV^Pj(&c zN8ZoCn~ zrDH#@Y)#VQsab2lh7#k(IIZXF=f;M5$)Ddg;1!v53yZiIAdDt^)3M@51Bg|xxb{nk zkCn=MBPp0{KxVNq0J1o^wS@dn(w-Rm5rh!e88;_BxQ#M(H+EL37f)u(tYhOh@o;OI z_-%`053WWB>{xO|c+w1cf`eBs!s{_{ejVY&PL-@la@Gw}1Q5SaACY^`%u2$oKz!#{ z#W8gD=@}!7^^vnGxTS(fgBg{xDrB9aec28OMIDEsgsmS`IlB!pL22MRiCa5WHt8p1 z$mPHA>t@qgzlD+bhy{rBnUs~T{Z*Ix~ z_k^fa6`Pq9``(mz=hS3lJ$!KLo_zmZiw~sT3R9Nq?%u!#=drPizocfWE1$I9ttY}Z z99#Im<_@c`TA+=73_5xyPes%)xtE3y4`_nj2(OLMk;=D``$dS zQ^s+7esSS>G~ZIDef8q>>-^oJi0czV`W=4yDu1V!)~C0`?P)be-ld*4eUn-@czT_? zJyho0tDj-`=JdzZjJ2!ja9PHPvC^n|<^}bPYuhq6`)AHnDb4Dq|5t3TzwpWaIvpg& zq%Zn$SKP99+d+oIX+M32Cxg8R; z`4kfqg%+OB-csYIslxJ_oSf{sy2tV{ljf8C1|Yg-MiM1`(u$$rm^8; zJhX>YI*1A|Q9YDVj;``_w+LrQIg(SaB?ANfV-r*3<0Hf0hU1&WQ%%so$c)@2@zj*K zufMTFpa^9aT2xPocj<%qt!tWe@WCHLMI&lH~~n6blo?f<)um@bm|f*LKF<3M?po}r8dE#qM2b4Cx|y=(9g2J~Qk50BH-6&dINwt*hcJcia%Tw?B~J~h}3r4I^QYJ%FjX9q__Bi$B8 zzPvOZpU-V8V!(+rZK({t27|-2*l1~j#_`ewgI%T6m_54d+?>tXdFItTI};PmI!gBF zC03ir7p=}E4t8144rQc^`ukx>y}Lt5FX#;L)0HDo)s4Lf5FsX`$eO{c$YO{FXDT^0 zd|qR6Tl0*75x^fIFgl6G`lv*#D5q751$-i9<2qYnjNs6-?%Ez&WidM_gDyAU$U>LK zoBxMT_LuV0Uy^`-B;Q})$A2VW^WQRnsILXe{ZW8uWh(hEX+iM6v2uM1{JYXF?LSJp zwY{nT&gNSDk4d}#Wpn9i&?ssDHXQ^||EJkp{u;`N8T5B;u1aeRVQ%K_KYcprkIhxw zN2us3zI}3iLFKo*i}q0HwmelI-*Z_(4x zdsFe=1#zmC(A}2y$O;(ox(|AzfLCr-j9>vft6(p8Vy;`~x(v_6Wz9 z0V<_?2jf%;5#-Pr)fMyEae*n1+FxFAxP9t(yeeCm7~8#-^m^?Mn8JOdqWqxhp2~8Q zLP{cqLcy$_Nl`GF?{?ROf!VS4PVi*4Lj*4YznN3NLb4iIqO4LgIZ4E((lND)@2YYR z{7@@m#X(3X@6}GG6MBUuTZOIMNx1F*^Y**RDGEU)<1CTdy7E~4+- zt9jd4W^+hs_RVpJW-Zm1Ycrm!q*2}F5@}L7A{~S?gphW{XRTt*3C9|jkN4KOzgl8R z!(L(mu@sK1b84JYyioR`MflYtJ3S zIA{+qUM+)_sLNO+JLknyG&E6LjkVVnk{+0rQ{m{&y6(d?b2*FCI5h(dVTULVnvX!C zMlRPQN{NcZKG4t=l(C)(l{+NFXhXfiu&Fq5*a4jOrH!9l$5?op4lXUB9_wOkjKt6d zAre}fwQ~Y_kGy}0IuF1~H#}^TrzR*#gt+Ov6xyf)v?L5zFhOI!D2pdYNgBRxd5+&w zNh8iL;MD0(mp%w>ITu4H(B99irWvsUqSk1x_)Yb7f51ssaXqkNKf-5R*9!Tu$D#A! zU7K@nP1Rz;E`L9I#;OC~7gBW`TpePjRi@tGG(Jcn{# z*9=_uc$;7tJYiKfWF9Fun{U#t*~zGrvn`9myWSU@hA-Q(iH1F)!GZ6lY~EGk4bAhQ zVD*g6MuYF3Wmt-}7VrW2N&wTW6uZPC*b0ZnN+phyKOa3)9{KYuGC7ZBCoyUPXmdrR3C;8Pw3}|2E~3^1v;UgK7fzf&nfK z8Xf(6JX5k{EhdoobPMLDOLM7HWyTR~kkc3`S*j&9-2!$(89v@g2lNH7KN@ zwpZeKL)7|PviS7W_0|~;?<%`PQ5_?alKLSqYy#~&u}a5Z{*ZM4l0=?wGz=(dYj1VC z&|g>2^LQk&xIQHpC3ZO9wj!zRMUTX`aMqVES;-d0-5*C35&5KXY}PMs+tfzZD;qo8 z`1nMXlhen`#+F^29USieDEvT-?w%YUITDernb21LTjE|iEq8V{tw++*)JQx%J5`Ua z!gQlKKaoT-J~4@Qgm#=CGBve;62BFWNKoGg9Y0+b(-?Sv20g?2@+5t|!oc#rppr2- zaWc4e79AKxr3oruf~u!l(6rX<&*SC&@@XTZlQUrY$iP5vS67=~Y5(v*zjtweNcqU6 zK0%2Wjc-hwYU*@!RaaJI80#AF1=%evT)Q;3@kWHoY3#dDaj1`mijU^z8cHSah!KNX zE36fx2k)9A2(5%f8yV#kiv?`4kjc%0NBY>MiMv|`%Imz^S||nGG-r=~V-l_TS)*M^Uf(!vyobUU@(vX>Qj%!_ zeH>#$-(gc)fJn&g5?m2;9AivED*1h_H3O}k89YIRM@`?1fEpxfE3_SH%4=%s)Yavw zx(xR5nzPe8n_BoBV}@N?#idq(_=3@3Pj^LHXXOQ>fj&NwK<#es>}wMDbfS1Nlu#@l z=tDiVKjh-Bj%Jio{8vAytE27DP)Y{6o+9xs?MDSfK=}x2wEgJ|C5uCG)g!0`Y-(!$Z}>rfe@P`m5%(YcAlAPV4gaVgG-iwYPyL{D-kSeOevmuP z#8}AsKl~siTi_(_|BWBCQ0nr3X5&Z)rZNeCvTtj? zajt*x3UYszRBHaUr1GyNl|BDyHqP^!mC2ta71BzrNB`7pT+I?{!g=ZIr=q~Cl945c zL83ZiE`bAXCeZ$`y-`asr{Mh(GvLBD#vB8RX5%SS?)a<=6$Sd6Z`tfk+Y??PzM&g@ zYsX>ll=B_pLZkb)Y!4Ri&Fd52+mF9Vn4@3v3H+-c9^8`xNqfMC)u!?$hdUAXZ!>;-Z){oZc&8)b_R+OIn_8lK`*zDIXF>T1nWy?15B_hYMkT-v1_j`wdqy>tAi?EbF8j`D|(ef``o z?t9ysb8jLK56u^16TAnm0?}JRn2XgPp+I6@p9}!RQS-KH4p&))wT~Sb%gL?zy!md# z^W{BL<vZkZs~^!0ACjr*LUOgF+4QR@SwjvWI#o*$@TIVBoJ+HbBth=5otzlAFrs6m{zu%dHwM-yeGFeDJgC96! zMba9{Xx=mP^ppILB&Fl-W3><8sN{@Y@RaM>y1u&ggxh%HqQ}P;YtKHq4Bx-8==YJ` zyIfwS<^@gog~I;jo8}XLUa=w?vO(Lu^O}^dl;=H_#Yf+yAa)WY)L)EW3<-%# zSyP4icLsOAoPIYTSoh$G=43fHS z91TZiol3eeaLJ?VTBAq<*&2ykr@Q&(bkTFg7#?PMA|Ss=;H%7E@Z>&t+4^fZmC&gTIrva5b;&ivA^=_j{=LT>}wH#m~=Xvo=VCqBy%>`UonM=bM*=y@&H`4?oCI<#) zuoymV!k-LyYe7!?Fj|(xnY#3l-_cFkPJP3;pva+#wAvlkPiDrO$RO~7SZU+L&BOr!~ z-6Mic5nv^q+|R=Aqybx);97OOIvWo$KzTMeBmj=lz?qw|U`m36F%|(pn1)}4z%T-? zMEAgeL@WX>5P%FCUY?EDqeDB{;Bhvzfsh!@06sb$$;$Cnu8jOJ;HtI6@1bgFv7@`4 zv;$tt!-x@pE`Yxyu$Cy?O9UHH@I*FHwhr$tgsj+6ydZFo2)io@))A1x09=3wK0(DV zK|onHAQnb?Bj6?h;7!5KOp_r2DRC{HzK#3~01q-jYX(jiA>+AN*+T4Q8rF~tXtUsp z*5oA&>^xS~81+<{C8!MG1||4^IPI}n5EPps^;bA4uUp8Wt0Bf=WdKuQt@q2e|& z!PU&9ARY!1;5LfLi|AOqfT2Uhsx#3^S4dt2dWc99YzQyH%5X8;8CdilXDbKvqG5M% zfGH=e9YTf}BuE5PmS*Wvv5IVXGXpZB;@3&(SVam!lYUx}bsBhx(Gg)yIRJx(-2ea! z1g?tojM23rtvTV|&oca=`jL%qDi$&SM#m2i#8< zW}Faa;Pc^Qh?iL4KcpNrKIp4z>E<+miB^N=QGv}AtPusbf(g7$!EE9}VbeGxYOXR3 zIGc)>vAh^19ST^=0Hg?3of{)Vg{)9+2>Zh6r5OErWIay$65f?jnIxJBu%TcL8CYEg zR*K@(0pQI;z)(a6*cdGyX2CJ65fhllgf@#{4Po}v^`4$bQ+-lWNAqAA3N%8+i$%aM zE;9IZrw$=Bf6A@@K5G#J+|I>P0a)P{V0s?2aXVR$Ns?#5YBoS10)7SXVYhNOs=*#~ z@=~;ti(s(=&Iu;|Ejv%j1c)O1^!k{|7nl=V%qEts4Ttj}43rU(8A9w5AnEOfXj(Xc z2sldssBI}`FFj34zqq~7H?1(ko8nVfvE$kdfa74yMPwNY8FVKRq!_o4%9+e*w+TzP z<1|dyF|54kl9BNAHW7J?0IN>H268}a3MNpHy^M;-2uL1WY_y1Mihw)mX9n1y)iFjG z6?_?rryhfd9C-YEmL7w2NSIYK3+r;Bc^qulAheWn(o_Ja0fQA|Q zihY0Krk%_=N4?`3M2FqM^kX8xf~^(hVue z&Xkj+N=)6-Q)9G@7019$RPrPXW5a?URbk&fz*(IKe5lT=S@4($e~f~ETm-ukfQaqs ztEs2PD1>M(c9jtF=>n|ixjW}Y7oNPp?BaMynR$txh3~`i2lzK{Te?@@+9A6bNvOup z=aoioKm5tTZof=uOJV+(FC-5DbD}80iG^9p%Qd#fTe2~05FlCrq*Aet=&48u_HRfE zXI19laL#ndNdUP67<3(5Pr!Dg!OG}NHakp*7q*mzaT1Z`&x1eM=r8}lb^v$e5!5sU zZlhwi3jo)Ppa%nR`UdI=Fb8Nj9J4rTsk>v2m*UM3(j-~q7hri&Zx;tzBm#@SdWeki z_3KL;a^j|GB-2obudIE=PG>&T$v>FU@9}|?NX>V)YtH>gvfuU%2uX6kNFE40Er36B z9kX%xFk!56p-ZjU1}PPqjS*@fIBFJorE~mW8QC%xD`fL57|J#B|S9? zb`cx;ea^2Bx`kL)&)5X;PiExh1`j!&FnsQ^xMQF5)BziOkcO(i;Nnv|)e{9y^$IDM z>@5R5RG&>Fa2S(xGpV-qqKC?Q&lvAgx%MZwFY1Mu@P?MueMamo4Lp}gc%C;KhmwQe z4Y=<*_Q+-6grU?aWMXaov+cfO%g8NXJ@D&&?Lu4z9HW#|j@@|{Y5tOaYX_uC#i&s+ z=n@#Zz$?nX=^kiZbf8u5fQ#;BzvaJMDR){8 z?zBFaE^l4)s&(b}*bUJ&OXc4hYMxlX(~~8{%b+{yU3AJUexHyW%mb8Y5QGqpGf9Wf zoQo}ZgLTK^x#THcyF}2=_}zZ!I9b9b96H|Nak=C0_jZrd9iG42eZRLKIo;v9;vMr& zhr4`-|HqEd-yO$Zp>KE>edk@`<_-)6=fVca9K4{LF6F>vI?0>@6>q{U=RkTCayY%c z&z3=E1HlxeLqI-Eg{$dZH$IY!H^apryGlNG707=mlmBq{dsk6(SJCAUw;p$uANWwS z^TT7!ZeDa(RrH5vcRoD0(=pwvSgB-!b zk?9|kSR`{s&tP=V*H@%(r%5BHdq&tjqboj*-RYV5-7|Ihllb_jN%>DhnxAGif07*U z`ElSAuJjXO?$himQZS8h>h}w|NwVWDxYmjg%)=dH<6Kze4+rc7CFH)%Ju}q4MRo+; zn7$c0esKm_ucuFcuFt@&Pd0phfu@52q_6Uf zuYPV{Ge|>WD+kT=(er~}-2C1!y&@SlV8g(kWZHl8h;s}cb~-m)lrcQ$<8Y^Rm|Kg! zh;j6cx#Rb(^vdwvjM}=F-yW2H8xRiHUl|@*Fv8UeEN`hTBYl%HYos*i$7*yf7vyFb zu!>$Y#HRb#?UQm{ZE*@bU7VB>*5#%Kcf*8zqi1w3J;{ZoY|;d0ls@)q-0jCy%rb=e zW488(r02)n+z&uo1a1*Q2SsqKh;UUzd?Hd^I3RaW&GEM=P+?3_TTS`knEKVR`+csV zg=2@xc2LN+0V88a>gWnYf*u7Uu^HDU(=`BaKNpK^1b`*HarZL1h9KHQaK?)<;ifSD zOBdrPI*b)@P06aj+Hge#!~9}0g9==}eqj0pe)e1aB%DJz33 z!kz6%JgSb+9WvLmq3j zeUyW{e|7E0d$^9bEtZ+>)*DE#%U8O-kbD^x=@OtP*JQVHCS6@!Tkpt}ZPmJ!jPt1e z*-^XQvt+b%Lh^cAvX6#K_kgrj@dsnBr9Yld^uDXY)s1s8HSl&bn4S9-Q;ObaPycFBc~)S6Py1Gwri;d~ z{)An!M*748<35_6DW#BSFeMfw2B4FWqNY(=juDU7WWg6V3i|lGZa%|^QCQ)d*vcsw z<)p{=GY}dth+-cxGSe;WF%lTfXH>`YB(sA-6~Z2yRO3Qg_P`&Ivav3&wbdfNf+niu zMP*Rb`*?}AjI3-*b5Wb69<>Aw?hNK#69~}TcXUDK51Xr14((*1Na48-^u?bB`k(Ah zi`-lbG}j_G+XA7t?{gi{Ec&*LzhS$gB@3*%oVo;p(lS>**WFwjS!5n$U3Ts1DfKnp z-Tboa&oe1o(=@i17rZ#Dzqi=+Mfr`Fxzxi=m$u(4e09+{aJc)$y_>JE(h`W8HWfwx z_g(w_;`ZCl_q;z2+Y4zJuqsV+N9Df_2!7v*q{4+W#&7O?d=xe@{PE?3yPuxy?3ELD zm8}#uq$(|UYpyE${M<&{+R`iU+Pfe&iZX6~c<<|L&Ih|W{56i#D%D*nZm+8Ee|yJ0 z{Ib?~_TZiORe|3uw=mbxY$d~F)lJtg|Ay>8dDtyaIrC%%1p{p5*M3c&h87NqJWj3ek3 z3FGC~4GI$wOa0zNWk;{xB=sXjy~!FOgS{z~Wc|KW-5jsJllp~4eQ5@jgMFu{&-6d1 z8+CYnK5aZuw8%|yyT_hPh4Tat&rPbw`p;PF-RjS>T{qN!mTtMBLuQZTu`lQJGpGn` z;u-fPmyvu@#}q45f7bL+;jMuSJFdO>-*X{H58wEB>+6*$LxRQ=`oCYFp>(@gqs-WeZ7{6#n!2CvCD;ludLD-XG5EwsQ7 z<6HFb=xX_9%o#0owfyp1n7RpFEnoT27F{jB3I%tx)$`ER^1#Lvh?1=^_1#A1TBSQ}j}m)%Zb$qqlX z-_W0DwJ9Oz{C{V){NR@(6M}|eJM-6@jDBxXwz|8S{(enG!rphGPkzsk`T`$sXRXq; zupM|5IADyB{S7r>gb!orTL_r^2*Og=tplOR+?_-jRwrL> zW$rxKm*M}V+6=Q;8Ix>(RAM>bT%z_WyLsx=!ia)a?Q7V0DB)xuY?_7%6Q zyW>o_#;Rc&h8fa4q16nV5Hmu?dJTh!ITr;0_hOxHSVKkP%y6U^vhjHVrwdYsq!^4$ zf+r8>%EWGpVWkih7Mt;j?=MU#7%E#Qny}c3ghZANwI5I@rNp_Aa429Ht2K89-`&F? zGX`#4HzN)8?zVkRa6w8Vr|0du z7exk@MIu^Zk%AU044$wW+ zR8#7lYf0a=>TQ;3JbT$9m-go><_Jc0q!$Y_RwDs!`drgWf+6srz; ztEXO(ZMCw+j+Ej3m6pkj*Phv9p*>!7bk)_+R-ZlTwyRYN8^V_5JN5>xs!67Qaz(r| zCFqaEd2+`yRvrGFK&PlMmwJBf>*@2EwzosBE)1t`{;6WYaXgYr3*YcvB+N<>AkR2&}yCTKRT<@E_qMoyw`8E@NyuwtcI6r{s zpLke9mq&)G69^{89_AX!uiWah@!RPM3h7k%hJ(h3MbgWl&S=;12?fkf%;ia1e>A0R zcnzuwtu$1cPQ-VQV2$o7)E)5n#HBaYu3EuYq0FwjF_&=v=Y&PkMH`G6&xIqm6H+|O zc1dupxmXh7T=MZuDp}neK$!(9a-5_+@d4cvD(31UUgCoka^VeIdi1#Q7OHPaxv(hYAQQ*@gV>y z{Jj-gIFoFFm|+&>)j_5JK~Ka(`zt)wjO|Fe8E2;h zfgB?ZDjc{3S}MYtP{`KLkzbaGIUO*e!a7tLWhS_uD-+3qKPFj(3*dX&in>Re(yp0X5rj{2Z9_THkM-^3S~JO)m~$b=;P)_N&)HSq*?Yh3vT=hUw5E!MUA< zf$@AyCCyy}kkLV8gRxt|FSe0fj5iM}5?ULuK#2(6IppkNwRdY7_9r&Z+KiSaB1arU zwzt8KVoP`oqsYPOc&H_uM?S5=${yV@FDyHtHN&vXG`a!6F*8GhS>7ysIvvTRs>z8w zVv`k;dFRV%XQtL?gH+Ik3bPhnFy|4%XasXEhQ`Djh`?(W$6+2|v&e?U#98vt2;X+G z@-kT9dnZ3DQwR!Cg}5t7s}z2FoPT$S$)6_g6X3_G8D8cD zl&9U;j=yvdTP?5#9~>l(!HYOBO$5&}$rdb3)&{IP6^v#(j~$D+C??<7hN-%N>ne!a z^*s7{fvlnk?7C%r`s z=EGI>`K0Xk-9GdugWg+-%&;(rA$ZF&J5J;2vO+ttQOE}GU48-n*fLWI4?-VlCIILJ zaKQGHRb@W=a}W^cci8Ftnx>71hkfvI*H_=S^NJ5Nv{BIE9Q+CR%v%%dOFYrJ#%EY; zr*ZV4J`)#pi(GPzED~XKc*m3G-!zlP-3&`Qp5a+Y&G%8Q@}KM9@m6iVTSVcDtUc=d zBJRMB;UhOED(S1MZ$4|h*{NiAE5f#+z;9<-T<4nD=04KWNxLp1zq-U=arUjXVZ~ys#07| z+&K-9Rr&t;*NUHRw0o``*xPvf)js8ShdsYn6j+Xx{w%xo!h6Xri<0gTe`6K9?o{V) zNB@xGJ?m_u>Km0N)Nbvvfh=e?sSfn%XGOmv%4{&?+d0tuHct<{4-388MpShK_+wA? zEm`0y7O2fBG*bX=d1M_~NG7i+MjDJ`1#X$uy{-P?o{c|f!NQMnl4H5COAw5NhgIfb zOVH;u4b$)tUk(t$nP50Gp;g&}0gxq(@GWKdvn;&2up)|=v8o+bq{3X~JEk8hcgLMN zzyJ;j;MY$vD_GzH3Wf>c+^IwbF5v(NcY=-2R>nAO%eUAaZq34nGcoEkSp^|PM-myL zGmI~ldEb;RDX@+RH0w+>XXC?IhD&q&?@Yop0nP+5cjDl*x!0`GCZH@vjYrTfGE$}z zw-mxL=O5PkC`U5!;hg-H4+Cr#$(|HgQ`eI%h)@_OOUjhVZsLI;;tc{AThD_BXhfBiT15lpNCdN8fO~-8G`xva-S^%nv2jCg}RN+N~@T-Lp;nX9_Bg=?=E75u_C3E zidg|pj*SbW#=3BFo3|rj0D;a|GBm~==D@3riOPugS&Hm-w)rO4XC`&}7qeM7s%13w zV7Lh5(2ZL!gi@#=QFI!628TngL1rG?56iAFf!B+$y>x)kj0x_jeJu5Pmad^xpi5R~ zT^3Gbs+q?}DP%=1i+j>#*EGRY2<~-NW+Rw#YL;|E6y5@oHi9_D_X6@04{qdC-SZg{={yfg4VPUci_xvm6xsEiU){$pH&nO z7ux7=*rnlgG&tq4sSf$H*!1}^$b?F^-S}!aO7U%)-pdQG-bcNVe^eY6v3qt{>81Bg z!>>-*GKco+7GQ-UW4`UZfgL-Dh51d(I^}NP)+-tDz56(AZ*Ei=Rzsk=Q{lbsF6ZZ^ zm(>dy!*^6ZDm?2dmW@Ql6MTkTY*(q#AG>V6qv(U*Z0Gw;pfAPjoN+-uD;H!q2%^&T zL`{`z-_H|{DAlBusA(<{rQPZadaIrPc2)3ey!-XuiQ;bivu=F<(UG^65q`HCcMN)) zIxMs6RzC4VwRPEiRKccBzPHeaOz4&|J z?oQnhqsPe5qTNfr>ZK^}v0YZYJ7RA#F<=!n;4s@^iQ3)#s({s}auXwVCe1JWVytxE zQSeSLrywWr)OEbi9WTYGpPx;?Op-qis+C+jw8tzncEysE&^_zhO_$ZVB%~l4 z(%-^54qt}+n-%ROoZzFmA>q7`sm1`VYG|NSXhFZ}SVAb{fl`sw=t*w(@uL2a&mVVc zd^N>y-rRruwi5>~qsH!KUFz`BSwppbB)=ql(N38&&IfKOvYl?o)jj7uHLzx3oU=3Y zXUNyAAd$dM9U3x(L8MJlAU!&%Wat!Tk@L~xL7psV!_20 zFt=|(FxH%ADUVoe4UXvRc@mS~xpXv0sG@GXrnL-XyC!YYgo%S}xcvq%ZX z(eMk{cpOFM0M7$q5VGii5(V_u9({{%&o{2 zk;H~Dm&`SnXy`&w$UU;ny2=whGs5-P%+)_YBmTAPO1!8z@;sWS2n0y z{-~bhQ>W`sg-c)$;P7-*!NjhDo`}0UKY+141#hPcNcx2iX*-hz7W!=%(Dj3^Wp~q%V=;;%`{M zMkV1#ihn9W4M=;|v(t%cr8k%%vdmIHA8c}r)ApB;xH}R@5|TxfJxYTz04O>}#sp|_ zAi*6_aadBn=!OgHxUW~WYr4<^w8VEwjnvR=ry>W&V8QthQ9j$ILjlzHwRC*Apa-6H+GbTA1V_Ti znt?IXVE_|Ea$IZcgcbMHD4HZMe!P&~t(=liSq&d~_361a>$qjDAnhJ zble>0)jIVD%B&r=vrv)-VF5)7WaB$KKiZm0`OU4uxLI35w81I_Gx1zQ=D5EDubB>% z8U|QkLOr*1xwoe*eg8D}_7m|D=dTL7ud>0q5(g+B7$2Sw?!J*X=AmVFYY`WI-M;!hhY}V=LP%FHVsfBJ+7~(^J|_C+$p-_6l-6r8_6G>}QpO^m#?lY-9UklMg>*$M=?__YM+B#YYLdjc)dg_f=fin&Fg@)xK z4QP|@>5|wB#EM;F0GYlxpu0mV_nu#GUg^lXSgcjkB`)ma17C^S-$S`zW8N_6#qqT| z!S<9}Og18b#}5TFc>QI$WT{~}s)83`SW=-k5$Yo!@G4B!gU@8;+U$$m<#IM2;dR47 z<*e!Rm*?5B0f#Q%{uLN?^L1j-k^4(qO^O!jS3E>_w!GDfeOGdUnet}mmFr0|_Yg#d zT_|>Lnk4pau+PhPyY|M1y8YfeUzS!#)RQo>ayMRs?<6KHMb30*ggET3i8T3&olNL1 zcT!R4>}HA+EMDajlb0vp#Jr{desw2pDPmks$VdIQ)B98QJE-RXZ&>TZve)MD-Z$^s zHs`1KrAD4VoA@WPsi7ipi!@z|-aXl4l8>p;haZSd~3jHs3EeG267Yw{p zpUhykhUHf0C!=eSX%nE}Gv|$cNcF~pcl#?|=~e6A?!LObvvM!xZde5?zN(>=1lL(8 zj9jyjT#N>DpP#({;@Q#0owai@6)xY?65a$Q{Yw}QuS~ywTTL~&*CyIl{bz^4onDXP z0i_4d+JiOKv7Ls$TDK>~C8mYPx1B|=^vU1;Z-4LG7s0<{(qE>>K6$yR41WLATbHoM zI<;?(RHo%xMN}HS{`%?ZxYKC*--B;6GS>e7mSzBN91=8J&Mbu_ng`rQ9`pAecONRJ zDWHpVw8!|fRQwYEu{#kYOVLPj*%|>k3ePP)DmK_YfUys6#X(UmSOt+&$ zkFJtlJ!L<>aXr+9VbWW5uP@KECqU7D>Z8W9p>8DRK^}Yp(}iCO+ft5bOyU1It8#G> zqweU*%cSfhE2cO*=-tSWu!As1#MKq8I_PXLlzfeu?=%ugcBF~qnGz6Ql&QOL(%uyi zL5(SNMFV^%o`TZ10D~cpc@P|_A7&mlO-xw%sNu}vy7JGPI4;v{_GP=u!b#BhV@h)8 zV{T0wdYu_;JYarRn&KXH;3id{1SX7=vv8{%B-oM;U2fS(5Qjp+G5txugh<-d1aUW< z?qk5-cxKVgQAcQx-_VChBN^^;x69K6+F=p)aOi6=E{XFB)AESsEZ` zVp`QhXkU~C&7aaeggWnf=cnxN@smW)Dj(JX33ubI35cCD*fm&P)_Rewqpy27;CZUw zt@FNDvrV~pI|&zAP~TwJ10fiYK*nzQFbBSq2D@K|;1*Vc>+wz!J7G`6&=gV0aCu7! zM~alN2=FNFS#V^+ERlGf41_u8P9DeL~=jQ%N z!gn4~j$Pn4QLzk6+FMBwoQ--L++&VTFNQ`-EgOieQMxJlv zqkOTTD86n$GsA^%#bw|Gn+k5MA7eD|3Vl)QJ+fX{mxG2<#MI-%2ac_?3J*kw`6_58 zgJ4tYvg}C_5Ile0MnKZ^ac6*uV%Tb65EkK|r;~=i>Yf}k&EdV#-IUyAdj#NowaP&z z5M&O8cN9CIWL`ArC0uk*KQv;zPfkkhvXx_*OvjOsL?MK9F9xEo83w&jx>rR`(pW*M zBO8y{qv3ZqCLz3gpj^AfcqfLovBQ;~(|z7WwEQ zvo@2ei2d2Ms}v-HO4{~xMW|8m6HaUeUQxlF+%=A71CHrx%S-E zPhQOxy-GZvfBNRr^w@%fdp>F;xj~J0$pus6in3=r&m5qF83rslH|86t0u?mhR1Dvq z+{?p+ZiM$u5y@U`SN3zvq-mvYV!Q&$k@piW%_MH8fu8)g7T@F)JRZ`n_9q74^{wY+ zY|}|BC|_@}aLOaULB7$izyNP{FYA2R>C~~}>BQD2|8BSGR8L-eVTml2KkzM8le9Az z`RjG_Ru#98NN?4udqM6SF+5=4(^_(mQ^>*_2f|~8-7Ofe>)|7vp?^0!Zdx?7IpKRR z_w~DjOT95y+3D43UxTHo!zS~oc|Y&Xr+u-;ZrW6s*C5TGKuE78=_(#S_oe!e67m{x zGt=+LEdp95=gy7ax`zk9sJy#+XLI^^XKWqz!OYNd`}b&t1HoUn|4!Q5s!?uxs3U_= zV3i|$)V4Q&PP?*Qy@^Kiax0?`JqUS0I1VV#^jx-g4-&>=6t|<+) zqYOwIq;X;@Z>yatm?^5!I5!~V$rn)CgKY1P)GUy>*D@bYuF&qF;md7V8T~SQ4%y=o z4JMk7VLpwKBT7S_#PW#(EZ*vj03hT&@^pd9QMr^DDterbfYxL{7qoSdmsGag;}2P0_Z%*387}JlL$6@1E9Kafo=nOz z`?Sc$L|wG|id~oIxsTYwZ~eN`s_E^=eAFG|&lW~>96Q^Pm|vY3S&6W^3k%DaCuPl3 z+0c3G08;~DER2d*-Z5Gf*3PJ&BkBp2HyuM*tP`40UuCxqOVzD*+ zEh>_;oF+N&VaSK3e4HS&iU+jC87c?>9FM(KoSVqWMg1(q4YMhE?ASPvESv-H=iylF z@@X(dm^l_6qQ;VjSA$mf#JkNs62j>S`?zrfrG@Y%%vaAHasy(k<4kM)I%QrGw z*{Dyab}${jR(o6hr$?sla*r|p-P{W2=Tc~|MxqcD0Y(LdBJsTBrn%Ur3zUdbIpCd^3QR*t^2r^}U6$|8#f2e) z3;;aTEh``*QE@i8T-pW?46E7=+*Mz;|otr*<+RNx84lN~Eio7rRRif6%oC_9nO!Is{ zwsPEuA?7`hAXBb2Td8{z2xRBc(HnKdmr)~a9`4;|{GsN|OcbxwT4H2l0GKb|(I|OU z=?u2a0@kG>aLHCVe0Iow4%iuNKsB&t1HlPy2(18f7N~jFNQnnqy$68^J^f=5tsTmj zb?<;>py%D8^5qs&29^W-%e#ZsjSXC7@gM>fEZu{k53gGeFhxxbscN{ZJQ<5fMGu;S zPP4LJ@77(%I@6lQ$p|PgrJda2UqBs(z^AWf_iicM4CAQe2vx|Q2?4^R**u@!CxlhBpa zEOa=xi3ZLh`_|q4n~?A$YcQzcdj4&xk1li z7JA@d(nn&7)1Ix0hObBE+lOCES^i|WnSov)Jv1Nb1=_IQ{ zoNE(5*I^1LR*X#m6m2)`V4 zsPHV|jqHfL+-8}4G2jg6_*;%Ncj9N{QpygF)o$$ZN_~G5afy%&2>AeN0n) z-3q*c7rf0=oB)EygoV>_`A!Cwa98MwrZ_SDuI-4yhm;mgp+>gp36T+a5^9CO zo#B7l#-Q}OU|R~m;Se3n-~-}0zLpR$7QzT5s1Ku$D1oM|?5||9r+1y!>Tl5EgD5d- zH2iJ`$t{?*wM$T{do$nr6<7hDJss(PXtvKgF84SeY&j&8F#kOEAB++M+w*5<7t7Ud z7&OrCddst7xF}W)hAA1LKWTD?VXV5?=aM#dwl`HC?^TVR$6BU3opsY_n8)X4;dMPT z8Di~pHjK{Gkk1H75D~_1syuwwJ_;fv#lj|O5AEcei_p!|$B2#$^uw_O2qjWc9>dWf z)nb#8CS;T#3DD5o*HPHU>#TamH@dYf&a2{H(LV7{${w5+lBxy4@?<`(wwijW&rb z>R6ZU3Qq;$PH_){G$sv65>fl*7OjWg_nPHJdN}?*hhOF%kAB<7J!v^B8Mv4HR&M;5 z+Qa+z1K!rn4OIEs2!9^d*4?I{@Y}kwE%$^ad1~aLRDG5_KS(>tsFhvsGXy2zE(y|# z6N_Ps*IGo}%EX_?^Z!1(rBYwhfuIk~)IC3If9a#fqCMe@s9TkR$6t9sjB6@Li3bm% z|BUg8RkN9(c1G>^_*Mo*OtE(uTv#bAw?>p*i{a6s0K(^AZ{vCIWoZKwY>uu?| zX_D4yn?|a05AfRZUqgPYLwgsh%d>R6VmdRVB|nXC)EV_f5f4!tfFXGDm|v%IkmRmq z_B~Xwg^;ZZKmXrrSa|(5pPgx=*VD)LqV4h&r4@OFZA7c@29rI*Rl_I;-C3n~yY*<6 zMjIF$Vlz%oz>anYgPgf)5sm~)IrF^2RJqj-f5cz!%HkM~-&t6a5J;?N|3Gm+N1E{; zrvJ`Z|Klh;zUOMq8oXO+_N@8Ne?dEP*x-B6ybN%X1e>?7OrI>3OsCEteOjg({yuNS zT(8$wj;5EFFDYhdbIPHmMv*rt0`BruTR5ivlsXBwCfd>=5ZV?q&NGuiSugmf?Q${3 zhZYT9HM&%8j-FjK9BT5q;C1!T(uOxz0`JCsn_b#C+#L3#)cEi(qtRQe6zYV<%oQ|4 zYAG4a^{5Tf(ba_`8a%|56YOiNA48=W1%}+Ag}fCBlB;54J>GWw(&wweNvj>J@?=q7 zIKlDS9Lh4gc6(>t+O{kw2jjWn8wUrkMgQIUef(b1&+p&J@z^V zmHg?sEzRK*Vq8bOSA(Mg-Sg)He74A9VeJ<-S-ay))k%+tN8gK_AKg{T9=v{3YO^lS z{r&UD52-C1^i<^(Q&T+uGI*$t#H52`S^k**k}fA_J5xZ!DGElPB!NREI2p-m_}lQ{ zwEi3@Sl148oYLY1#Y)>bXr#7WvQE*q*;bw69eF}u{@S*s5547yK z8c2p&*4Xpkx)k$Wnw@&8L4E#)dj<`KR(~SAk5cn1QmbSYBtiQ{9l8t zr=y$Qf7_4lshhHftz~j9>&;+A|2ahHfsQv#V7*RCd+OOJ+5Q_(6p34Pi_c11o9AvA z(gb_f8x_l7SpL31gT|3V_l@tqOZ{uyI-zb3rt5#BW#yISTlrkERFs*ut-pi@txu#W z1mpgR7_hud0g0FOKEK-u;qc_W)y;jT&#bpRH^01-?o4^n3x`O@B`;z5lFTfc?W65_44#4; zuBpzB8P7P~)Ixu0kC@N90S0lhtYsS|NQkX|*r&ZNo}|aN8qR=ofo>%E6e~4a++nNJ zWq^#&8E&`ukpB0dg_t8h(?WBYZg`ojGb#g@MOmkNjDi2r%3eq#=y{&G_jQV`9c&Lw zIXTaH;S8mHEGyZ-uDq^Cs5Hsr!_F4BAu{Pyy4D$MCJmY(ZQqF*)0qux6L)K5STFQ$ zeAMo9gX!1*Sy!t_uw7!a|AE)SxbA)C_(tV)#(P)Y6F>USX4w3hx%}wiGo$Pc%n?d= zv0(12w)FL4UcjjDiH9fkca{E{dSY82r4%c8^?nhm{jmN@4!CF2NYA^pXGj7eX>k@`&@8y&enFa(y=D{W;3Q? z`Rs>(HyZ64#?M6)9hh-AOS|rwOhnG0)7+%Rc|&dViCu0l;L;nLMm{wh*J~jT+TEsU zr|vusbLii@7>i{7%g!+}BWYZ|yW>73;)H1#@l|u~BlLf~?Cq;MB#5Cied{#k$B4_) zy$i)p3ofRr4~aiVDPMxUn$NB)?M~j%`U zrQ&P+3GY3o6QWE?lL+pJhoB~JJKJ;|mg5JF1Yc5Z2=jByTyAxO7to-c1$37o1y{p! zuSx^9mcRm=m60K++&yc$r&p$);h7S5MEs4qKhO4!G+VrU)r@gj5DPow4K`50F}f@9 zdd~J6yedsuaV6o*-Ax9l+2N-yuTOuRSZ>j_hYJDOo=ng!TGdV)CIS0Zo-kU!DM5GF zmhef4oYxfIdC`vaupdm=7b=WAl1(%+)O&9S$QT#c5pl!sKHu@jsk90KMvpzlhAma) zpE12s(C20_@#Hz9>8tKDhy4t*%rhkmx38a&d5d%F$TakE-smP7x0NjM(5tQ_Y5Tj& zcJmxl18wlD6nkeJm8-T&Qi%G<0c~Qj4Hr2uEqRE{t>#Rdo-ny{p&c4-dOV!kS4H-8 z=7T(ve83_IBGc)joqD-k%Z&xb16kH^5m$b7VvqGO-5}>zF=ACsX1r{8Y9B00f8k&(w~9;Xh_E-|kBrYHz6 zHrSF*QK|t1>`Zf|B9pB)M>lzmhReUu;r;ILlY*5PS*~+N-(yeTAAf|Vm0tjFCrKf@ zw8C~VvX}s&fcz%VQlzL-m(xw+fE{}vS=)q~fl&#ev-2mp?sIfSBRGW6L4qp9 zyTg;HY@kE@vb3EPQ5@-s`6b?V^tz9S%rby0<;fiLelY9z=$;=H$o_5(MP4p)VHJw! zmc4|gdTJ2ave6u56CEAKcS!mm{(%Cx;=V|Za9cmuW(p)D19iYW7Rc; zL)Gh?GirM)cK77pOBd3Fqmfc<6B#ASWfYtN-VJaHlYlyng`pTX(CIT5es2N}scn2xXpe%JzB>W^t?gG^qK#aO=B!HJR4 zt6yNWa-sW(U8@k=0=r{Za9_Iez{2;+l=bnZStN81`c$p$kb$_8@SP5 zy`y6U9|qJ;F)5sjEU#eeT67j5$E0acL{~rA%VId2BqBW2eSM2&4Gm$z9R^~b{y>8X zs}(c~2S}5`(MDvOt_qL#D%ueKJEOaT=Rm-Z+Qx&>vwKbi*Q%Z%<0qZMmvXkVYnRE{ z3TquqRqK2ANv6Z~zrL*%)PXVkV<|@yR zDul-qD=cLwM$dEr5PB#qV8$L3&%yU_%MeiH;s+*A`DQW)gc2Ek6X~q7@8yl$7#Duk zB(0~QIf6YtWeYW88UVLI*HT4BOqnlpHwaa@P3BGV4jGJd z2ebfqtNB8y@r5;dUH$nqJ>7FA3k*H~WR6`vCsZJDoIv1%jE=TxJ63OK=xXPo z=1~H)xP>YTjSOe(qZ^1Jwq56G1{KQWH~2q1YY7_@_~KjM!GcAvB$+?=VYX{A2V2WG)}haj?;4{K%=b589xxT& zb(=G?e_8ia>Re2hE)?9+=gD5=ZGOsc62YdV5bI_yZmWUDJR1DKqxc@i)@NARK=||u z$|lbl?v``4>y+75AKk0G%$fn0Mo(|P;i|)+7im{Ust?fSQCy+;W!&S3X3<$kgZ5+} zqaD*4Am-*OsKV=4PV}AX^WG|LgFL-U^_va_QcxR%WkNp5`?U??w2H88r`71p++CiN ztP2^RUsjvpC;=FafJ^^@z13xS-Z3wKp*A?|DAmmG1@+pG4NrSI>ua?P=9XU49e7y) z-msrvQVT8t)0^Pw-Guqs;>{awZoPc72ze^RLpHmZNJi`WdIhCKTuS7D_xGR3;r;jB zOS^o-x!G6un+LU9vM}X^{)U50pN(GD(o$IVSAy1n(}3q4ZKmlt17+RI7)6CqoioXPiHm)8u*S=LzpTwFFFoXn zaf?^t35Vc)UhT{$H#QjcJ-*U+%_HEcoIg|8nmTiVy@81Dkewo}(twKsp?p^exeAKI z14w3Wcb(_b6a+i$uaX10XI5g}gXpj5vT)xMIz_ir6UjF^XBUVPB=o82Zj0wvMz0x< zZT5KG^Yl17{LQu~jB$3lDM*ZBImtS}ljbDp+4S$t^?!b-;GP#0 z{}3MoM~vWkxWnUp&^ga)fb4(Tb+Xes?{Rs)%hQAdV<_2&G3-yT^O~w@1^r|DyWsL& z<8tpz;JMB4Eid`FEIaq?gtD&0_$NsUJ6)AzCTH!;OpwDcu2zZjVMu;6Y-@<;`AIX;UKBP7s%FsgwU122El zgfbL*P~%u-mpp0TS&ACKxK*j>MN?hulNo1dw?9Ty%U?69#r|#~N=+LjN}wFD)KP}y zW`d^eKFgvt!?UN*-3SAA@`J}RKRAuI6gR@N>3G!4Y0U9Tv)A)oJAX9thkHUz&-LQ1?Q+inA*EUB)AkwwXOz@)wdFw8oN_qeN^8*;)fqAo}1PCMD{^SvlyC+PL-%p%(4B5H8<&d;_;PRb8 zS5M6KLyzTrF(a#&8Pfjr`=Jh;lUKNM*dC>8VfsYRChP;JEDIOILd5BK=iOE=+TDFB zYL7F1Se#Ntnw2n5ICW>=OAHA;Z4=>*X=ht-PFsHR9O0jS`nkDfLF%n;dW6y1;AIp& zHa!hbXyUVcrNJN=4YmfK%{4h$-OMxh%F9 zTM@G)`SNVa<+ITRQrB`_D|_@x>s>c4uA!|->K<3x#WIif7540T8^tP|2=|1^I;-pt zs3;h3Iq+NvO%n#?yoo4RA+Nd~+L6`#q0+m(anqa-xe5vmR3Z--=~s7%chP74cgY3S zhZnNFp1L_#LW9=qQ<_@uEY_+UK%oU~ce~&)@j}z}zw=$vP`0A~8%=)(mEY?OWHIpB z0sf%K!5rgZ*(p$7K0dz+fAXTgiq+Vui#PqezG?m-f(tz>se-x#)A=! zhcg?dE_;i^D0L8PR5l3DVKR8W^NI0S90-gNP`N*Zb-K5+?c=C^vws+Z7X5~Tm3L^VYp(Cbs?1*F=Y117rBRHVq2XD3U)0}D|nW3jg@k}ARn*#;1pzuSxl1pW#YW1z9_^t8Fs4$0o ztfAknhxa@|&>{ z%sTsg74uYFq}Msus;vosaEE*@dSCSO-PR%9;0)nWjpDyVBIPS&p{pzUGavYQZWJm@ z;t^7h3|GLZ#U_>ZpxBa_=I%Nfm@_$yymEIy%O=_3R}{1JqhYp%!ci7ad9s8YV0(|2 z+&QIq5T1-uH{dBJbP}bwf2V1&A0KT^!|Mf3OERIxr@emXEdQA-%Gh#X-#b$1jiaBQ zRaqphX{N@{3|`!wyFqZ5mvK}LM@r|G-Ou>WgL~dAeWIbWX|1KUr<0i!ATe04ov+)T zjKfP;zsl#Mt>Ne}2X|LXY zX_%)M`806m>l?rnkwE3!*`=H(ImnmWkR}V6)a8Tb`S0V8o<9q0>+$N&lC+se)4KGjE{e0`lLwVl<1f6swP>R`rCR)~=7w ze`==xCp5>%fX_u}8!S5!9kt}L!JD0w>u5E~Jn;lysE;PlS|=49kMG#<#{KvM z3%|5aphCGJ#o_bA^u~5`5k-^qPx)7 z(A=hVYfBaW-Il$)7Wb+;|L#sdYuvSA4kBfVqaQ|4al7)3%TP7Df5PmGvr)~&5xcxwDe^Jiav zs(M7x=L3v4f`o*o{w}yKE=YS;CSZS5(D$lOgFkgUD13;?)3K%oLU6?EPer$#ThFfr zC0{A&3;sFfjVLbG6x!WIV{(gTTC9F!iiM6W>&uxkS7GLkJ z{rBr#261iqQ*G_qpKp(d($%F8wbHeJQX(6K69Wi;8iau2Abi#dio-OR4T_5{6GILC z>GC0{Otm4g?6zS#@&qc2jGKTn{OzzcsBA-@3Aun_JJpA%9MiH1g-CyUjrXYBZ9@}E zDZ}=}HB=rQH;KykchDiA^BF#qn5tn1eH-*i&$3C}MgN@}L(r!Jh9*_ohIg8rKo^AK zKH_`*9k$t7w;NO`9+^k8v;gL zc0a^aw3K}^iVScKdXK4W8~U^0g9kjuo87TW~ zb}_*Ha0vG7$k6AlZ6oeSPhhJja9=EY19ly&!TvYn^TldpWLMHdY|VVx7wee-kK^yL zwJSqkY*t1*GS;vHkn%JQ5y;FW;OY>*({^g3%v>8>J-U3_!7$MCR0ys??e(iw!NO&l``sGyM}9`E6+0X zrGY*T1m%ki-&wD!QJ)Jo%9lLLXMHXP`d$uEz8vs+)~{{U_xcItE1}9?{d)ubZq_JY zjr9E*I5O&Y_o4E&*z&J?W&(HLf3JK!<@MK)mC@ag)|8t$%5yA4kbfsZr6u2YE=+CA z|A~#tjgs=YeTG2+&q7pgR=u7(uCD75{k;*g7W83FrB$T-JtjYB&qso4Td(i;xT>)|Uu;zG4U~V6zZew! zHAMCP$m{QkZDYYdPN=p|e2PBY9Tf7jM)kpr?~l}U`;fkO6%Xj&plQatLEx_4O*WRa zg?2GPy1F(bW7=O0!qB#44la?$KqxruV{O< zZmF4XS9FT9SE_trcHZ25#w}xXuugWVX=m^uuiDX}x|+qtPyN#w5QycuqG@@a$i+F zTs-%rfxxV^+EE&kaB1(mS;l%L^7fI0E64sLuvCw~?Yy>hZtspsmoMEWW&J{f4`B$Y zi$9=V#LC3POnkPyTeD-G%c%@gZ_S1VEPmuZOA4JssvTf5FYHnwX6??mFoq>#mRaP#opwe^IJ2VYB7 zGo~JRBn-H|n_(iY!KmWD{~n|xJevWfUoC*I7yu=|+_A(QOZs4Pk>Ibr!sALpKq|x6 zr)gpHq)k72j;=Z&e`-^II$!@uHJRnVSatmIlN19nZJxbl^3UK0vBu;NJmQITDhh!T z;6g${A#~+366p7jl&ON>sn>M#ei+2`YtM!P>ET2cUA98-k7fr^LC)MVk(4qK|2PYl zJg|8`!lHSxh9_6oyts)u)9*1eO9o6s;mXrDtD_LD0>rRbdHt}ykC|%oOu8vdIaxyV z8NM&MzCt;bWKd2&Em6%!5OWZ#)c9x7~g@Tef2=CZQu*rAK{QhJIzx$j;`Fq z0>y-tx*$)J3Bmq$@kQYZuXP(%&&P5V}{R9xr z@5mGs32~HE)l5(kKy2tr{j7!ld94pEgkK<7LX5To6@Cs)act4@63uxbzs{1C=dNqz z2p~Bu&HW|>gKP6OFBVoOR0ZEB^oj_6rI@dw@WogV3-qmY*RS`cdJrUj=S!VfQx(JF ze+JH9zF&i0n2-B&{dXc&c?|^f6BGM{3NCEu6#!;MgIbaFAI)RD>B>H#_}kmQ~F1vSnpMY>;88dg7=b;?nOfU80p%qd5i{KtApmS$$!3m zz@ev8o3&?){|P*F9b<`j)B=erVNEDovB{e52rHpnTpT_ft*Tq}Cv5X4ug%!aB0|uh z>Ti%q_%40VmWjZ#)eME5Knv?i4(39 zkxkDD2`I5*=)~JN@yL~EW&f5B{+`xoFQ_vBOO3WUR;T5)S<@9XoEEJ+`$IeSav@t-PYB#@avJ(^`EC7Y_ch_+t6swMbFe&Veh3Q}47ru8IF*_rjeeL<_L(C8ls zhGBi_7nq9*Elsy9QF!vjr5U^}+D%d0%AXiYk7~b{DCYB$7d8VBn0Le_>Z3l@TB(MtwM{NQ!Vi>EWpXa;3B83&uyYfH70V_aMTEQ)0_M#e(K z@2MPlXPS%|3t=OVof6;Bt9AUMShNk%aY*4 z=(kP3LPK8=zyEyi^%@K>23?T+d4t^Z`vT~3!qcbb$7Z+7>zWUq{0$<$Yd@&DfYVGHCnb%@>OewO2%svo z5Uc?8hAmrh*HucElLcUxej(Ji27Y^~5?%s&w3JbX)8_jeF+TXa-`s`1uy*OyJCZ8U zw0XPkt#zLfjN6Pb60V>~Fqa8ywJ`V{Z{=B#qQ3=5D$92Hdi&_PV=_KK`p5C={WRu8kqsa>5bq^&X47|0=u(yqF&W9}Et2Qae zaiErOH=b=K#MPlEZ$RQmd8VR7ta!gG3o!-Ahdj^jwFKe>a`kNa8Ud<534TUMsHe&K z(ID^fxC4nYS8m4D(v(IQ{Z-kPZRX(D*9p8KE;N~)Q2aw7SzGA_Dj*^9IXkbiBFR{2 z<0{_ZE>>9`S^<+(RY)+f`1E#vqunC8C_$>RH~~_3v_VYt!efif)zQLmbKsY(uyD5k z6+r@V17yK(pr0!v559G}7zfYdf0p_QvEP9G;IAyW0?eR=TFy&t-3AqDoHs+MbIRtKeCOC)Qr^Ta^w$PAL&^ZqFbUQy6eliQofYq&;oC9* zEas-Wv`&jvS2lQznC4lo_yQwK%5!g(D-DqG`s0BXpJxE__ZD4YLQDk>vQH>p2dVps zHHx<;^YsxenAif7`iWIgLgH{j;n;FvCXlYmp0){9UKKWP;V722$vU&iMgoGu7_vw* z&nuBHyjhRVKeDl&5XY{~_eaJHOZNkSgAmHPtA4;w_M~ELE-N-&QAH^c;U+{6i#7hO ze`6z1BLR*}1v#^hJr~NpxEnT>pgc~p(jPwgFA=ex++FY->MW4u|04cccKQ&2Y%=pz zn>_6scBb5teWCAi<~=+{2#O(n^|?;CBJjQ%h-`WV-3$QJ?tvHIrfRjyO^#;Gr`BAq z_&t6Wn)O%jXyy9dpyNWNB4HtRed4sWpa&I!mw%3U$}3{(P0sQ*rNTO~fuH77FhbdW zww%-}>B}48d%s`){~eWy1F4MG4bK?^%psx*DapJlDVw)nr@|vQNcP0maQZ3MF)^I~ z=9=egj~`VE8oyj~D+m7-E`&E+fl!d z{aO{jCj4sCSUw6OmLhXItIx>nJq1soyctF(_vw$Ua-XzCnVAa1_CUjhAWe#B%8Lfai9gZz7iY0jIs+ zoSsWkema8o6L_m0f!k@3&j}zbk(?|I%6hkZODr4{KVe0an;!6sX6=@WHmcH~(kb?< z-7HaH{r#hfPycL!X$rtpvTUFTq)A#2cLP+8fDU*mU!frbE!|_qq!bYB@uGW5$wp-} zEb2C-f5Cl*Q(##48i!Lk@lG~}t@?Tqi!-AnoF4qgdbM3S=&E48xw%fhjbQZmpL%*4 zwOSiqYP5Ue?P#dclg;|NK90ZZa4wv&(NOE|SDSi&X3E4mejOOqEE|dQQvMaH^dS~s zXRP{*^Q*OgQ$Wc%m>Kqc3+~OlM%`5$3S(eomVYkzX}guGCL5q~fF1!Tl?`kVD76bg zSH!Bc&Dd*&BM)25)n0r|kJa@o+1|Ub@%Kb_MmuhJi?T~7>L~jABebTp?Wfkqx``&m zAG*!`XTLk6gC{{V16%%R&ctZ?iimHplz;u34lXJ_UzmiT#5o}gh*wDB4W#^|p^Zw^ z%Ilj%0}GsMo4ntXbhS)1I{wGnokv6c|Bv6FjTze*`_9;R4V7eT?7Qq+(vW12D3WC` zWoJl2Xh`-wNutJ#!_S_Tbj%@@6Y%5UC+6$-yhfaZ*!dE95b(ZJ)Za1rjWUoO;TP6>fAMVdjE0|2 z;(uWhI#m^(m(M<8l1&&hzvMT&JaD#rq*nFT^nN*41u+7KiqcF`t(|@4|D`R8=|bJy zo6z;yj+6`a^Bs|YPX02fHIO@TOaj`eYK@D%VS2v!+Y%+686ciIes4VT2ab`$%^{!k z?R#wX>Era=ooB>~+%qYsnkOo{@k|!-iUFus=-JZC?;Qfvr+!ZOKQ5EIFTZS*DR#a` z4O1TnT|LZ_u2%|~vdni2(-vYptsE=Sj_2om#&nOxCEM5-{F_Q#B(uO^?!EmK{OHg zx@H0E1pW(|d{#~8;z@|!3!TrT=W~{Ec>6ch(-OnBwo>9@&m{w=<`UfVilP~PD@xK$ zeJjg~q4oRp!x=F>%72w^wC9%*buN;Aw zqvJWBbw66J*ECPMQT-IXCJzrU)0sy|__Z#kn+3l4QIrzc7JqLB4N|Eg8v}Mnkacf3`7>pkW4OZ|IL-<5h!x=#Y=u3i3`?Mp!Yu_QD8xIa<_EIkMl=|es@=t95Sr((L7{C^$hoTRiPa*si{}S>KGOzf8}a1BA`p z{%8^Q_3pQ{u=$AXk+5%}*E@RZZvL)XW2cD%Iz!=ElX_r&$WrT4r?=Jc(m6=Ty&t)^ z>h7%+gw*NO6;Du65kE_wS*ovbNCxfy(a3+Sb)lQp_npvon=NP>kOe%+F?4zzen%7{MIa&U;$L1?HhD(07X zC*w@0&=bYJ2!SPCj%5JWA&~?G&vbDskQ1#GiygQ8ikYs#x_Ji?%5P?jSVG3qUCIB< zO^aD$U_D62;6#0e61Mo5Wq- zW1SzF_=kd}NP#!~Msn<#4`~w{j(f(2mNv4H%gd6AJ|5tZ&Zv1lRR|Ud(<(Ut}=X!H^53`1rHIjpXU( zs`Kg5PDJfPUC$&D)~$U5QW=>!k8Jd$ZaCPv!aLegJ5ZgQS3|a#;jXjKen4fJOc- zqfn8ucvXWK+;&Xw*ugqs)2a7LfS%d;Ix&vZ86(-q#6CehhC#A55UR4{B6}*%V>SSZ zJEJfUxK|344Qx!grdh|&3;;^Ph=>vlD+h!Ct|#gM5Lhg#v6Eg5snd1Z*pwKG0lpZ3 z@LL_TLRNKbFQ4vSa(jz~yIvfm@?u%oXMutZ3s^(=ZG8k8#?-(Ll>qGd_1bx|>+7=` z@pc)u`U7QGF#rjfCUFE3r0TT5<&Ted025T1oEF}o0-K+Uu=og43wC+boPazogLG^P z1c>MxI-XJ#Hf_#>fnSZtC=SY7@u02laz1a6gQVN9@|~o@u9D3O2|yHRE!*#Ai4o~49pWAAA{XRg6Jev1MuH{7;~0yG46?9hP-lT{ZxI{|9;yq8`beO|Iuh>c4|gOTox zs^r?A40OLU_<@XmtqB==V+e_$w)V<7qSv(QkqZooui>S{2Z_&Yz*j-9hpxeY<@(76 zl}>{rZjIsSmI*>k4Y7jczZuB65IQ3#w5QnZYpMSER3?f3PDCgs-t#Q2TgEK)i)VpV z^>L8%yl>^|OI)w7=}tU5WgWSex90FERx8_z zjeYLVdXAG;`%`kn`*m_$HSU231;8AQp$~XM1>fFb4SwyO3K^et&s5^|VcWTo;zRe4HN~HD3c7tQgrBFrjw@AV4Pg zF5;BP1h;3an9+aHz*@hU4zcEsId2d}Cm(Z1pb9BSML0HKBI-f~qI;RBC<7DGt3h{+ z91Tplif>G>;#nCo!H)%McLnAXjgprwvcFq!=vuZsc6ya*M8z|<^msq-y^J<6dr{2z zJ@;~BG5;TLfmumDWFFtgR{$+XHhNy#H~mLi4CZf@oocNe8$=b;Z?N@rTF_ewJz5w!mMsK()YT30&$lt_Eaq#u{qN=3F<)+34n*ZOXj-Sz#4tvmDCC zVgCr~?zDQ&A!|(F{jO^vP|!cm(rwDT_4||bUW;q5uHNv;O-Ra3@=;wV%}x86o52uh z0m^%1lJ{8FE!8J4uQKoHfOYOb-ZO^$V%hxXCiyQILS9_YudK|k9>`aEB|k7`SS$PV zrO8v}37^I{qE)wDUJX3$_({9eu)jtYWQ6$$?mz8IDj49CoPH#Djw}bm>%=`Tm@p}v zdLz>L)5jDGt`CAlSlw>$DO`{(TKdUDW-stU(|HFydO@VO-tkB36z$4B`!!%t_<>I6 zZa|?Uor+W9{?BJr2Eq>?D(i<2^cQ#JHu==%=?F}Ngn^%I?b8tMAczr?j=w>dahAYW zRZR3ON+=donhe*oTDxnO7QbMF9W(ZKyFNx zXstcJeeOAq_8{VbE@072)rE&||GC*9W@A$xB%i}D>rs|CMs7JwN}2Z4;Ci) zU%bxhJPYXYD7!YxBgGD86Rlt};KBVWe`H$O6Z*ny3~UL0%7b_s=gX>$04qM?9kkXC zFRpl;Tvb`6Jvg=n<|oOHEdaTQRcvDwDZ6x4$<=R6m4X>7ZO0k-K~+oH0bEE0{wxK^ zPURnE=C;9_5p_9;m7hb2@*$#Jp0(Gq^ zwo(SBMz*Kcg}U?;Ck^Z=jeLJD4-e>;S2c<-H3{ZFeWt4=>enP)Z85pjC^OWgIHWDP z-lQ!5@~lMRS-+PTQeIxHewp#6Nn`!xr4%JCre-~}=5n!SgOp}XKE(gsVut{z09ugq zj}IdVN=Rti|M_Fdu4F|hJ#j=)JbRW@%ige0sjshBQk196(eI8Mm^gVZzNWhs zhNp8X4iCF~;a(+(-_)~WX>_pH*9IaM)(WMk!+FtPe)H$v3Ps+xq;YKT*$QQ4V*?)u zDVqMn%>WVPW2`?5chQ3mHLAUnVy4k6uZyL0^i4h!&)v0$h`B@-CJ8cM@@9Vg`+D>K zPB-ilKTJRUBTeIev`i^WM#%C(3fh;iKluO-+|YZrd(F-1`yYzMgARn>D{{BV;y5n7 zq!}K+9jC1s?nW2#ZgZwp=o|T4XICc;MDMQTtzMvrJo}A(`p#FMnc@D7^BK;<-UF7j z{T5UG#Sz!eeTo7Ma{v9Ii=|*n<7B|A?eP+*Wb*jo-p2StX0M`UaQ>g&AzG8WvGeE8 z;h*2;x=6-y%J}5u-Eqn}X-L$oeVd};-QE4$9uo9vCm@6xTv*}cd{qo}Pe2|2`at zoE-kX+pg_Vkik#(nRZ`D9iLg~L`GcgijNNM^zY|8SOdyr-KmMc@B&UxbWY7m@Xy(RdlutsrY}_hZ%geK9NjK zMC_RUrw>E3!Y+bL%f4}%5kjVL2(jFRFw{*MoX7uN_t^DSIWy+ciV{BJ&t zUW)K$%U)-)EUHB6-+h>(!m<7L%FQ9`^R?rEt1QA%zl1H@k4NasCE>IF?QcTnyVke* zWjv5+D>E{a}9NX@z_gWU8QvXqm)C{xzBp6Ok=Y)v~r${f`er88%@Ki z>;J!f7*yTQ=CeDUFzStdtbVj{*5YhCA*y0IG4Nx6lH%9B2MN+zVAvgQ}DoH4I6m*T;Ua390 z#EGEd<4AY56_3d{p1|XUMCrQY#ncNl9|muv^m{qmG4S{I+?#d3e-!+G`Y?@fvp<_T zv)ZIC?tnp!Eh5z3%kajfgZn%EX1Sv~GMybHhO^47lj?oax3q3%3F7+A7}4A8zpinY z$G`TwwoPDcJ*b6*Tp!7<3KUKbu_4ABigGl$>7$;=HM+Zfm0sd zWw@K1TZQC)U6IX71~UXy(xymQNu~T<8HRIAUq|~tjFyVu_g+Bjs;Fg)X4j{M3#Nmb zk6EGc7sB_LB`oZaA6}|uAQ7CUVlVgNzYp}#%j1#(lEn3xq4i7VCV0Z#SEj@YQ@)URZ1VZ@ zve3UyrYv0!@N8Cg0p?*34jWbIWEL{=Z*_s;4CiReGDMvW(4>k3+aI!v%FY0ElnE^{ zxmAVHnO^ee-_|x!4M2D}RxU{b8*413550izx+toXU@96{;a{2SFRIURLsEoSxfilk52Q z-8kxCao}LYtM*m69+*kE-Z$CSOVpZS}Sd%8gl%C-Fp3=s7 zM!-;FpSza%;!XttA*kk^xy_^r_%3%64{B{#pXBqty%}2Mw@b84}Vv>|NDi~*RNZGt_awQ&!8^f z%2pTU`;{~y}@^8yZC`|^XDEf?LPc;b8LCzaE#eTvtJyJV-9h549wE@rJar9 ze}8=K0*z%5>*i746A5dXW>FEnW}Gnino8O|L||j_?WR#dbD2 zpG_4%di4#yWV*NJ(&oJJphrzyQ_IT}^OWOKbkD&2>0?Gq#Bwj?WR52j5<4Zt7arCo z(Pl9K%@w-EN#`K{b)&_@V`n|XIPM$eFty9)w(}!q+lU&)<5Z&JW4I@?B!NrOVQp>4 z_db2K8g;C?H-RfCt=zOXB`MHoEf$bxM$ZljO9Ep?*$dj*?Yplih08Rvyu~KpCaGbevEj&+F9?W8gaIa8z>i>Guw2qciNW$v$Z2ocDAOUyIJDa`a?JQ?Zb_n{G;>+$-M^>Msx+3D_&QefgW{1+(cwkvekZ z5J+c;n{@~~#$G5kP7o$#La<^v=H*1in~&XB4z{E348EdsO9XI>G1%oyqEz<>K4Ys} z7MUThIU}h-{+U5|;oxnEFe%10D!b5U>Vt9_g2aK#NT97zLQ@u<9N@w@ z^&!CaMPgY<&}^nN%*Sj|2$X#ZKy3UgtyO>(e zc}+`4ZmZXAC|BJ6NgC-`^qmT36XD$dDea1?UpI{Xk5Rhwv?{bwGZcZA8lziV^%)P* zw>D;9RLfXQU~R9+IHfH*`;Y+eiF|P$KLj;CKmwKV_vzow`ar68|PW>dANpP&mXJHeR_P2w3 zeAbZ(Pj2QujJVPHIHU=FY-QkBDbjEN6whT(cmU8OCHaa1_3-I|P4G;-DWeYXC^v_1 z(HAUw76Q0@6~*1eosw!DAMLDu(<<0NhR>)qw*q`YC=|4}%6C;Jk6^2+l*6!hJ;69O zL0(ix@e|@cOkf*)A&-202M64#$ZJ$lIk8n{mgT&$q$vnUlHXNM!U61!xwWkFFOJbw z$^!kvL7GHh-Mzeqi{jZcT(5As+U`m6!Oni?5D%;#I>E8xAS?ZX}!1fFPdxLFLsgmVayET+yO1kun-XuwhuP&Me;4?ekFaUk@2 zoW63hEYQ`)O8LB_YA8OzMHvW6;$SDiOIsYNR!(_{VxfFGP8Y&qQ>a34dQYrhPmdey zqCgGDiR-~^JsgZ()o}VqZ?wXanOH3QM8N^nHjrwLmis~rds2Z)&l&p^yGqy zGX`%o8^iaVE30#Ssd#+0FPC6tW$p7&M(3wCna)|$PfFI*-;}bp->9+@1r8_q__S6v z+h%s-G99d8JG@mbZR$lU)kf}5-utSG{4A4ER&c1|Om?j4d?~fhrGKUI4n+CtD8H)J zn)gSiaM-=tyhoAC7fkcQILEuaZ3e|xBDk)u)owgOXuV-KlB@ObN>!WHIFaDL3|V937aI=5o;I!SDtX!&1LcIVHP^szOYgPNc0W1l=> zSL!iKtP+`noIOjn%_uJ9@MHJ;oFlCq*G^}+uoNp_9LJ(uO{F%*X6Rf#^lVBKt&#QP zbR_#aBF^TIB_%K@!5=t~PG0hX{5fbVn@P0C?sLE0wxQcqHXCZ@)rIyN=55Bk+H2#D zta@e9=ur4Ok6l32-aydlg}n{gEq(W?ClgoGZ`S6YqJ?OG$b!T56vS;V-aEZ!;g20< z@ePV&iNehPHZD5i zIQmSN>M56cNnTzij!P)WPsX;GU;=}>So;k>`UOI_y(^WN9aHRT7z>~nza3Ss6WMz{ zbS;0->;olH|68~67&2!Es$&brX3{C+9@hyn$J)AuKD-&4N4KmGF_AV{RWw;--W`bZ+IfXLWRWTwS9 z6e2>flU=iu)3uX3vXi%V1tG9P+&UI^3y3v9?x|%)uu04j4J;nt+rtLlEb3K-n9xK6K8_ixj z*ItLnUZ;Xym-b%Qxn4I)FGlc#hvo-Q*AHHiAG`}b__lxWpZgF<`4A-7cU!YB)V1$! zWM6neUqpLfR}!>?U*zV7&lUsh8Ip+XiZs;aK59AUltNIE1b$~nljdzvJDX3C&Q`8ss5Tt4+@A% zf(4)idngb$5;TAa-$23dM18tj_$j>OQ^eO#k$*o$3(a7)X5zHqQ2{dm3@{8m4a*w4 zAvEp%w-*Nh{McdL#~Ej$726GTgL)# z3YcBnVF4k4d}&iu<>?HT>9)e&qa9W<0ZwoS@+nWNSOLI9*dmg3ku>*_9tu;{(d`AWc`JL8a1${kIbjn zPUaT^C6V9`mJd(_q?3hzZ)ApBhcyNdTO-2Ql;D2>OPtzE%5F<4@C8KR(s}Kri|{4w z`EP3PzFnfx?Aps{w`FzhC6)Pa=d@Y>l9!FpFii_2pT#t>W`d6d@z`Nu#(#OQ)%)Qu zXNeFe^7K1cc^U@*CjsCmg-g0h3xT7{8qv!^@4np%TnUX{xpVr>EN~@we&t^Dvf2C` zr#7n*fdNOw{5VmbHrs@wtUw-C^!5z^6%2IeYOnhiXOqPbY7iW*!)oIO_nV)KonO&; zw{lB+_0H)^weUi~*2=lM70vXOOP1?&@C9ZohNN_4S~Qf|iarGeSQP?3vFy#8=j>tO zya8A&+Ctz63@8%4f8e^l@XF}dwTi&aa<}zJ%N1A-2CPucD*fqabsk`^DhXB zVgOswMPZ<;MZJBah$F-tnZS#D$I7xWgbRWKk(>2O3y^E8Cqj@LR`g-o3%GYnBLSQ2 zMQb5e^iV5$9r6z~;iX}%g-}a!l+t=D9BQ+LBr1UI@vOhCXnG3tsy`4wMl@ZekELSZ zk9O#E5WFg=y;1n4-|3>d+j=Sj5=(%Ck$`Jh`05UfV{1;}*2;;++AqKY=ltBT(82d~ zI2`~Wj{@i*mOd%Lbz-*16<5MXmv!Llmz7xGL_=-gA#pp9oFKqj5WsT>qDb9i31+>4 zVxTqTe0ZQY_7@Jd&A0$3DeZ(89UG_}~5OBj>>JDrXGtW6XmtVjCXT=F~GTeP6KDal)NP$zxCc*4g!nX zJ+`UQYSh*thoO@H;cHgGNv{3589ad?# zx#QsFfyZZV&d>e+RcKQ=Umf=tfmKOKoPE`f}R@M4W9lxnZK|h0L}a8!z>Q zqByafm`Zm|g%a;mJQ82o8ZQgdSp5y9|E7W+5DJ62lZAmB{RAwX=W#;OlSvsp9s08X zBkb`iTP?$#Xu*{E@^HmH5R;sYglSh z5sr|+vn$ABGFi5*N?4ih){22O_}xK(2ws?2yvAgZCy=KIDGp?S?!*c6u+y$xcSI72 zAW324fqx2qyhU!PJBvI%EJzS(nFEi#2gk{zb@^l~5Rz5e8@Rt*y+A2vF(TeT z7w~KuduD;N8;EpNl*HtAdaH_)O(NZv0Pl|BoadEh z8&JbINUu!azx9rGptJ3u!EGY6ws9Q;l*$FPKi{zuW2IL}5h6T*3Zq366Ns{lQhZz5 zNVanor`>T$~~Q(NQSE{yR$|e z>mgOlgG6MiZg(?!)>zr#Cb_V%n$tF*~eWE z<{Hb{0jmsdPQ+Hh+;b6vK%p}Y@$k3Z07274T@@KbJTEE%j4?A=#D0Wd7lQ=J^kAfJ z7bTa36#!)XleC+$JQUrBTM+9LXa`iC#qJChqOajyIM@VaK-n$(6!}ggtpO`Uo zNje&$D?~;0U9ggUor&*LSoLN>>JcCjyhH~29V~6TBS={RBt(VuX$lv=ME1)eIPUf6 zf_BG@G)tJ(nR>K@8=sZufraE*d?-DQ)^{Xq1U=M|8Bl(CTrY)~T|Ub8%CVxG2*y$;OgXlK@I4;pk}_$HD&Y zA`D0%V-Er{vmeiPzc4{8D*VDXFL$-E@0} z{EPZ8hsCQj>eo2S-z}#G{qgs)xbHHVFIO#k5vF#!;L@mW$zkP*({w?C5HJt~MT%qC zYM@hWz0Tx{)PvDC^cvOFYSk{-H1amN-s|@*zyDX>)9*^ny2oA7`o?~*!myfcb@t*) zu0g(AOLlu@jveba>VqAIW_JUc?ZNg8ju$yKzaEdj8}sC8?ldx4_5S>e7JmG4BnFH zqQ?CFFvw)cCArD-Vzni{1Jk4K5S%v>>2wI$Q7SW!~C&d;d&x4eUI}A zE|WAL=KgPB0wC0r@Y@Pn{XRIuv2S*&A@G&@JLUCTkv=0DVsHHznsCWk0cLXB!vxEcA zHy5AL$&ggL*zl_?tYb6kRs{HP{$%=f$Dg$Ae#X1PRKw##(H&P`oV4o#(|hUEa5kWd zxdDq)Zg}qn>)>QtO*U@F_<0#PfQLwC#UVqC!y^;)ymeSTt-t`&hIk0VLnKBfbmRa7 zLSl_u z)S;vmL7~}lWRT{D`(4l6zwA3se?EVNv$j-gZ9O4(NzO(ey}Ty2y;Gs_<%`?V+m~9~ z@jQ_Wf8O2gSl8N0xT!(@9?06$_jfbvmd5P&z%ZrN*exK*eZZjP=Db@Mq#P9sR3!kL z{5v61{q6Mn$T&rO^uf#WsLgN7a>^} zMc};XOM>IC#SUuEL|rw%bn=DTdsr(HwMG>Ke3O2EG;)bHnEggsFrprGzK=e>c8v$M zdMcXLX7@4P^Q#Oi;PV^&ZwM{ZPJ~8d*?0+1mK^}O395u4QvY0nrV{B3(Db21XfvAj z938Bk2rZ!9MWYd=8i>ibnhA)7+Vf>I9WGZLZdZ83OhPyk7oOY6o0{N;*WoYF(OrGO zx7^8Jsv`)|6=v=dWY*=A=n^#7m89qhxps+p>LUHSc$al7jJpIp{KR4hi2~4 znvAz3={HUnHe3BGf3PwJ%P>I2_j(YiAtWZgj7- zFU->@a-%O%)0i3-X&gP=hfOuUuh|ktggkaWtIClmhe|LxerTN(hp50J5<$waSVX_f z{q|RJ?XO(l4urQ4xTY9ow4X0p?u*>%FY;8q*M6R0-jD0)qs<8jlLM|`6BBEr$^z4> z8q=}}2Byk*EJ!8@hBH9Kg8}>mXNai`*!iLvA?tDNpll0Hxy8<`88_4%Y1UF|)|NW- zw%M#%@L7xuSXn04t=Y6w(7a1wcw-E5J{N~pGYf5nh9aQxsKhGl@L~nyP`mkXsd82> zw0pz+BgLHL&n7UGw0N(U?@Lw8jLcMlay=-ksvr7Cu8&k;F!$xjV{+%uD4rmm?!<{8R1)k)n(P& z1}oMjCs2kge`#LckA#~#)o+@Qs4pdMMJ9v28SVE3&X`}O3}621saEGZf>gop&0Pix zS%DNuWiTtSg%#aZEBft8Dbi#3~&HM^oU zhn6)bU5Sj$^K|lK&M0f%v@s42z+Z3c1-!N3h_z5{70+>;?Fm!`UnL}DBc^C$Q3c|; z!z+H(Mk>H&^Nm#o0w7&zBUfva@^dgF7iU6Zae8TU=C2KEGwBF-S*DkTz-W8U!j^je zfOi#gxgKjiwLE;j&{qBL_{Egbdi03;S6l5(TchQK7kjokLUy`S3}G_~x)yc@S10jE zZNn%#&Vnn!4w^XBIl$%hQ(niv}%kW&yJ6kZUuXAId}z3e>``lyo(M;rof=wJKJg7S`4sfcGBC=F0_3^C{fzXbEhV8dXbkOqbuz0)CujuBT| zzyC?7@DL|l1W3E%BmO#K|0Z9_{3K%YiOwoPj`m{F8Ek-4!U)4IW=0rfxS+uMSpB%< zPoz`Y*O>yRp2#l58D4A_BrWy3(<80VS*Tb=Ox4-8RJm{{kQ67R>zrTfycfYx&fYxJ+gTvu8oCn3iPdWcujL9yUmp(N)oEhAU7(=zhxU-It8 ziSfoVbzSLDbnQ+PNcsy;NWzXjpY4vCE0dfPW>ciEbnScKI(*UmJa@r*BPTNcM-QMZF8g5e~-X zK^IaQo0_)A9Nk_~S}Y+p51U02z8GR~bWm>Jh}4TI<0+FA;p^q$4coyc%sG#1pQ%MA%94{t!}#DL5qfogDLzRtO~j55)ClpdI8*J{){+?c;9>VVNSW z<8J73tNDPk)On_~^f`aj=hE>LW!H4}#BD<<2=Uu*{?KN}$kM!qVUdj8S7U!{@q=;E zp~*$fCWPI-Quea~kn!;m`=<+H1-~zq{O;PJaN%ZmyBW5&HlnXU_?YPB+#-7lA^Dc( zQ!Qr<4fR9Xw^vUnxEG@e31e4vARiYG<-^`YzB_t6MR70eq0ka5Rqy$)vyJn=AHJIW zJ3;5+;mP*sU}a^oYL8M^RnXEkv$waA9}1a$r$0VD8CfzMF;0QsZLex-N8F$7?CP4H zT~^Q8_iH+!O!A!0Gt+0EfK0QY4~~4^QVuD9Ao1(I&1-ukLAvC1#?;??e<}RY8@@Hm z^yw#{-X-jqm#p3uc|rUqRFFC9{S`HP~72%4?UlzCr1Z+1_#>b z7rzY-_DoL?dzCHI3NV#LY;Lv_ai5^TjWLxV9_}4C1fj{xlet?2+6Z?q6`i_8j^szT zRABaMFa@ctv;b~qnAG3ju=s;4?6NxF)w8yTX7@)YZlU`VF~dDGRtR+H7BNc~$*V#p zR&7+d5qa|ohsUITVh@F~y4QsvACpw7&=M*H`s`IpH$n2o95I>5Odzf85VXUyTbhu! ziR78p$%la`VRb=Ta>v_3B>W&Pl1Tmgq_xrP`N?MDJUY|`vp+gHJK4_*CwkSb634TP zMhnQ=*tG)UZDM~Gl2|lO%1&KQ?9p6a?a%VUn1*jO@00c@tGHA`E}ejR*O{iz<)oh)Sb-;%hXrNKh8*L7dt{+A?< zN!Yx#VWB(mKa)7KBJ(#*--mL~`py4G5@*rY{Bxqhw%YAKk~oXEEt_9jX-VA3+t=IQ zi1AD!mhG*(OZ|`JuZ_09`L#lNZuZQwqwQdwmc)Ghb*?JNyFyZrv$-#^E{{@;?g;{pIkO=bbd`B170&E`ypnjKmax3SZWFjCm<;k=n=(93&kwfBSOz0BRdsXUT$ zzr=-b^ni@C%JG%pQO(duun_kYWK$* zuWHWpN{ckZChVZ!cdtQs8yndw^HJy*5dEtMGwOL5+>Cp1KqeX*o~q9PltI1*Sqzg* zxNlp9z5?9GQ#W5c`scQUwV2m4Ni3z(*X~U=`(1DYoZt6=iPC1QZl5IUA}vx zkI7)>&~QVs;RVVi$z0@L^nC;p&B1mxgL1@uV`1Oz)lK>0ji8&P!6>G4#hfPbI8q zN9B`|Op3_e?n^JI;FGmoCISFzOa$@oU}5G2nsrB{SKo<6q!J*~#+{6N`jOnj7!0bS z6TbH#UYL2|Dq5zCJ)f4unHMuU_IGi&?L0uG7Bk;8?&hD}d8jsA3=iw?7CzZYKr@#h zs0qeBV*I;_#^xpLPx^bL)OVAtQcF0?jeF%>c9WfkOSoV6_bS1S@3~ESaKm@nQC?$A zAx?38uVoS**IFm@MJ(}sPc+y~%Sg9vUJ}}c^;U0YW?-31kx-LG|_)ifftEK*d?cA%^Kd)i~=eIUR+ zPxqp}VtTXr0`Ldv0<}ZsiR`}anOKuy5B^`d{pMvVPX>m))PLoXQp?Vjn~eCn{K}sh zE>nFyFcKK?>nWMJT&>S!^mhKQf>rZ!?0&`Q-L_waJCWiHOFv&%*Jc&jJ(bq(yGvDe z-8%d1J*6BCH6_LI?_Vcq&~_4_Emh7@$!aGu7cwulXJ!1bklBLqv z$aFj_f4@}5qSDlHa6G4N|3#9gwE0cbiTv4fUW9g^ZvHCU#F3_Qh9Oz21k=e9{(}l* ziz=HZgOg?I2bJ&Gc~!s~kqE99|Dj)kPdsV_2%4`b?*r@(*gfEvj8U4NkYT z9n=P;RlBa3erlUNs0$ydb~_sU^zP)K9?MdLftt;9@gFuMTGV*(49$E{KWxOO)p$yq zeI9fF z=46n-F%f3j5XUo2rq>8pI1cKImsZdTGtTYe9c_4cVR!+4|F|0oZ%i~YUu1uJ+#_Sz znCv*b$o=-X7nR~h$^Tz zUy=WGp6*E}n6qXN$Eewfe2o4hdRie-XDi zBxfNDP$B(Tn7)4ampeJXv2omOe(8gii-qbt>XTz-$na z>`fk~rR&JcgnI_eIth1qyM#Le`&z#!Z^jsTF7YU<>kJ0%;_82l%i?2&_Cagp<=A?egG3UD{mN5Ovv-KF=GT7fWpSYbIbK!MJXM{?4PVKD&vpalV!C<7yrJ z$*=3<)NoZ@P$%m+t3G|zJZzjAdla9bIWhbJO_ki(i9?dehiVw0Scz3UQSJ1IEjD%& zIu1}GAnD-bc!(4+YEXj!eL#T5IKbEe0LLBH=>)`cBLo~t7uLXbCn0R>M`+Cg{1^|E z-hpZ%oG5sx8XCgW5AC>cmp(Y6@JS$8IfjY^>)}Dqr63AqcsLd+gMiZEfmQ%Ic_^Fu z1q3SS4u56@bRjsrAuQ@skOKx91AwlqIDYJd-nD}9)1EKK-i%p*|G~rENr>A`~=`t6asAw)(A()Gyv#WS|Nj6m12R#sfK> z5d7$HNG50t4@R^m)Eq@UR`#RexP zc#NaX3x8#0C0U`ZMG-<#f*>LyMnyzL35bA-?AQ>n1q)5Y08#}F9jQTSQZy*i)qo0! zr~#2CVn9T|78MZ@F(932-sQ7r&zYGsXP;+JdEdF-Pvpu6EVMu!b- zX2J?=ToQe;k;{L)&^K%Y!8uYxh_|yv*M4NTdT_~p^q2mZt0s$q^SOi6SNHh%$qY|QM zID6sQ4Lm?v2vklY5j4o2i-wAjU}gr~5n3~&TGWf5M8oXR|?t!Dj zEEN_DNK6#=2Rs7u66BV6nOR??lZZN8{EUdG&m~~3J(vx+H<7T*phoN9r&FF6UEwgM z2ZSR=2ox$E(KmaM=%C|qx*l>Okbpujwjc^ZoE(s_oSu36oL`5EZ~Ih;p~^Ym4o=(P z$&Zr>rvRdf5Vry)iU4peABS-8s$7DT5NARIYYIF{x_t#Mg_Y5T%SMxoTe3Oc`3x%J zkG=WLlS>r9Uzwy(iGVbJ=3F7U=+tI+N0rd7n7j*|s@7a>pYwxt;bj^-=06$8eniF!pMmk#kQ)2s`eLSX03;FMH`7YZT#@4f+!~?W86IIuL`;&1 zU@tcDC{S+9z<<+Mx|i-D$0Y1#!DpCcwbBfE-JJ7%hu#H4E!astW?`}aMHGOBna*?} zn8X3RgkUvfTH*x)U=;P!YnvXyg>ez5Mm$TiN&S#^1aB75Rmd@0H%Gm9BmG^h41>-duHJ(GYo`NDkE?CbMv69BdRFF$AD}07w?eVUak)TEYU; zM=SR~G75QQob$*?rrzZBqjmcqnR-6b2!Uc)aA;5EyxRL)WSFvF%4q<64uBalk9Xt{ zxAH(Tok#?5`b_)^4sk~gJPyF)bYzFY<9~|8l{LD)Ze%4ix)?m(;n_Hkj<+hk>o}k+ zUw~5;;&x@+oaMzBcCe>DS7=#vTp9SKCzJ${f-OI!;LhE*B6Nv%rOeQOnGq zJgvGG&T4CGx`r>m3ecgOV&zySArXb!_QpC+`7Bp~mrsR=`S9K$g_oXB-)pqDCR~fA z@}3!}2x6Z0lwIqwMJaK4%lEdg$N5g7o?i@9o=$~4-HWDn`#3f|{b6uj#k{ya=ULVY z_x33Sm>+tv=Gmy}Gu6>&q(s3*oG-K^_Gh=xPyaT}9UaO)RbOfNhEj98G!!~iJ3pE~ z(|^-xxXe;c)VXrQb0f)t-;p?z+~@1=KR5j&64xAlpT5jzQ@{T`yzO)>tyB&r$p6Ia#de+-Jv(7&QDoqcs>UYbfgQ zThe?rB)U-rB=-M~cvr}O3)6=EjREx+!_}!P~ zx%b=7y|85CuUTbQ%~w5q0#)`W?3_aEftwFQDbBek6}nk!0(^B0K61^AmJQd}6<;8{ z4`}Kp?V9!Isz31NWeaP8bXJCOgyw0|6*tmO4n9)QBRrwV;juQQoM3Q>0j6&4p#*IX zDM3J5%p`mmdi#C5;z_2`2lb*GlQ5McA`pV90 ztm)Ocm!UYKs50bt)mBT6145oB!7uGz8!P z0}QmV4>*AR`vCxepe^p7Ko~RM^MD3m56OTrQRfl^3VTvdLYh&p@4ua^8W%4+lt6%0 z#ybogk0g9*FfdK~7UNFv*aC&!o6Zj>KfS(i=q}`JPO4d{MA(_TEbvZM)!j!8k1KaV zA3ybX-?iM9{ZXCCbvnpAX%FRp6#LbRii)mrJ7&#KmydQjBnZTuhocAW)bHoW%F&M| zUAldwXuxs}x@)tb;9baJK*V!KY<932qNlqIS5 z)fn_YAXzPhLXxU)jEU>pyCxn(1HZ&Ud!P-mPmII6EtnLtvsc%lgFdMs^R`mROTkaEa`@}^E70R9@$TYbpXdgAL&zbs zZL-hvx?mFPI=^}ID!if#Gvb{)ZBNurt~Au4oEbiUskTxehNGq|3d9T5ASm)n*NYb$ zy;2n}OtwF5dGMegb4;w!`?E{sd_~vf&pAT;Ffn0PG(L#|v93?ouTBDn#h4C*(bFS8 z#h4Uh7Cif$FgrWcEelx z88!N_h^uSJ&2MdRII5wR#r5){wv7vhv-pt~%)k-8Q2{-_J=N#~J7?s#Da$O-%gNUW zOf?mnvK@?=XX5(%d&X;um$DVnOi7Eh1LHcWwkwaZ{X7FZ2hLe{Y1 zaqA*rMg9HFygy~W+maLxw&rZPRq!<1#CPa*%dNs^m+28w^ZP2`j;l5o^bfS&E`DCf zxVklW>x=hSOB`ZTx%B^* z`3?#rP^;hOYwz|xisJIyeEkRC$54NpuTHw#hjV)W3G>CqT?LSX|CeKj4l+fb{${>2 z0vzeKFeZ!Dxa4!r|IK`d{-{BJ$xpTaU4wQh`BIRB^`#5B(fUJ0`Iz})HRzI|lCpnM zgFb(1&-LnolCL*vCx?z(>WMM)-C;o=E>~L+K3p;HLF4c(q!Ie|hxy*=aVh;)`P%>M zw<_Tu<~z1$GY`}P8tDipjII2sF*_HK(POvJm(i#w-h{^HUmqjx&sLoO2Dqs#6A0kQ zG8Y65W{4Y($5*;J34rtGkHJ!l>8v!8j42mT-BZ19w59C@*SlFqta#ypp2I>wigMNS zmOJ{oG^KS{+x|$>8hFPhydHDqkEb>l3Xb8`Hgku~^u*$1R4oUMR|a*iul7!cMF3f5 zaE^~#%jMH$)jY3Po=i4n+yrN%#mVX(raOQ1EgOoMdRzBJvOnTh2^UWHSjlD4=`+Qk9)f5C0VY1^YZZWpd+5<7S)3|B&R$OrUMY4QyZ>iC%qkhtA5Kh z)_M>haC-cJKjY1Zo6g}(DGzK$&SSPwY`-0sBQkS(Nm9a zt3JOZLI@5ErCUr@mG4lthn*|WQu5WNwG^?958v7cGx!=`-K>}CY)XD-Te$AaqiTyA zyAGbu>0f`J&|=&EC$3Ly% zKej&EoTKMG>t@p6erj*B?`vzn)puJD+}KFDpe%QG%fj{`xl`H)+GyK$uM0bBR1mYa z;G8{4J;%`HcX%xJL9E^71uj{8bZk@~_E29h>nKXTTVS3(OBI^?t?b)>WX+pF?#GlL zC5hzECd+4FQ{_G8&+uPe4Mv-&CG&PioLX$I^rgA#ivA@+dH#Vt^IEJ&{(oY=({*SP zFLJT%d#QcXf5v=A&6kHEs!b%#)s=tBd_U>$oB0uTFotC+|>1U&Lk;^lO8)Ln&-3 zq?K$-*}q_fIkmCxzM{*$d+7YU)urw~5qIr;O-l#14x1ZEgVlOe!&a+9hOmu6xWa^_ zIZ}EsY%JKQ_RaSZn^Lk6AZ0R%V|F$R)0q)l#gB;5lM|c6sT@RxE-$SY25+T};XH+M zjCWhg-`xKec&Hwm+sDbkbdQK}ZFz^7IuI6pkEHDDmF}%4{?ZE9p=wFpwu97CX`mt_ zPkzrc^1U~*-xCG1Lyp$PIN zb)Xe91c9?c`8x|0{a@ipQw{I0G}$E0d7ndI3xzZuxQ!W_mmc~e9a1NO3tqZfWT4+U zULSRlR0htHPFTpppQiy-9uWcv2|S`Sjku{iz>h08YIS@SpXf>_h(>-q^M{kFbvv z0h)VL>G%UE8&5eyPVqtq!9xt9B@+j5V57+pLoOVi5o}=|jyB0(O+UWjC1D>A&=h*# zAs$Z@Ayfe3@CbC2^uqe|`oV}fA!sFG0;@PUvVgddcM3-Xk_zB00JumL88RhrGKo7N zjN(wqR5~3f<781dkE0Lob$6V!bIHjkd;cpahRAOXUl;`tmuJ{LAb$%Z1i??NA6 z*w>HZ{gX~uL<7z;ecTy1W6V)_pgj+d@yh{W=ql_ER2AC4#>tE?MZWpd_GCh;x> z7(ziU7I^~;Hw^&GQ22-t9AhU#d7jm-iaMDA^47;|{7Lgz#IrmY?;J}+|yAdjreB!+W6-BgsqMd!3f{ZtvCjVOvh#&4zj zfB6LD)}4JajeHjcBC6!Gd|WmS(P9C}Lzj-j3qi9LUPHR*CiZ!4dE#*fumeLu zHgPv6!rSeu;OiYkd8Pi zR7GDnSqUMy;|Uy`DwQDNAjj?^jSimQ`8ZRij6%Rg6(&vv1tZu9j*g=-6D)D?NF%J1 z;+|>G{<0d%t#fZ%i!y^q-I=*m6d((5sx*%%5%^Ftlg(z40U9U=fM$8Qn7w1Jp1{a0 zn#s9Pfad7t`f_ucSvUy`*DOMssl>xf+YPhppS~& z!xx)ho>+T=REI2RMI-|9f+1-!3L2o`ZGW7s6r6*C>i{4^AeYOK*VMnVz~icMD`FCS zb#=*A)7h(Q*IivTq;RJykDP-0K7(X)aK3{4DHieo1p`s=63t_X2Th~ke71})KYxlY z@5{?~Zp}aJRB$x7;7C@1OG&|zS>%uty3Rd+r_xe$&SY35x>l*kwQ3@H>;CgQcosZPbIRPqFisKf#1vmjFxPvYZ`@Cd1*qR98h z_t8JRxz<-I5s~U=Ne0&BI68S8DAU`4 zw8Z%sG?iVCD-+a|ZhK!Qm@N}zAsErc^R63als(;gJ*uPZ{_J&wjI!%P*W3Dh+VyWl zI$t-KLb~J1+V!u0skt%YL21@Q?{7sU=yge)55B`^ri214y%{x4YSl+;oOp6`JXF10 zVSTyMzH;T$<&^AlwR`0nugVw9l~dI#7Ot<**;k<(uTv6K5tve;e_X}jRYibSJZ+zf zlgTY3iFCwfk6Rw{9*Tvxyz6dtf4;RV?AFR`^x0bSnHikalG~f&Z&_sAx|I%h6QO-; zj@vGsw*o#984xOaH|i%7Ou~LA34t5_cXo_=3JUJ@?!66-;%IzQ8jCdMUdhmkc@a&Z zvI*Nb@Rja6FW2C)HftIaZ?m<^^`7empwbA1EcsQNw;tau1n3O1Iy)}hZf7Pn10F-PL78Y!Qaq z@VoomOo-w8=yqbgqMj@5BXCIMCjq>3wvT41pgnJR!8*|lco-j{g38>$G)Byi1j z-IyBb>JWC+LQzfMHl+$(??pU9=ia+73bRt~CDKKq_V*rC?>qUE7J*&*wVT34eYqo{ z69_C4o>Q_0uAPlnDrpRcScEiy96|%+M2WY$;ce`+v)KI|=KTcpwrs6ZSq7{UNIU@G z={&qKJGUp3corqc3ll$ntIUZSWyX9|@fUnUmAF&^Gpc<$y=FDR3f>NaZHx zOI_fINO;2ZK~d-2=O+D*{<(LJHV?DO zr32yzE0s37BzSqcUAU0GIBO={op6~gedsUq((A{;m4_?tl%KRG$k~OgB17A91|048 z{(MD_&8^;RPF@%Hy#F@TH6tDu7_M7JY;JsXr1U}XF*4%$T<8!UW zqeQfGhb`t@yh*WE(&$!0XlQJz<~*bk`$i|KkH)UG&;MEy4yhbS26b&)D{Ql}Qnf?c zrM$}I6Q&d*hx9k@-id`YE%vvF#2eBl$Lb-MjgZCRQ=M0!@$oT-%x1%d5M-bK_JKjd z1F`&tDHY$Q&tFF2$f=V0*WZ4L$42^toux2eBkEfoJl}BT(eQbm0E+ms0E8kM#lbE* zmoB9~|0@33MNv32j0xI<0@JZyVq%(DDq$Lq8^Xwsm^3pxISt0mNu^;)z*+D-7O0#e z#!dg~Cj6S6!KU__>qX<@!3V8I1CxTtdI5%37@QgD@Qd;rng_Uzt!@~Z73B{$w#w9w z3o@hoz1*l6s0qdeBO~1K25x^Ni>AgDrF*h!+JZ;;b~W7a=%Pj}Oig9NF7Y; z-pW~a*Eejv(vZ}KeHlEq1(V$+#Lx{3KmOhi?39`9gnrXlG&U+I^V`v|DCHl5_Ip|| zdK_CCoNbrE1PvoI%-8KWs9=tU;kOnO0DA!#=i29 z8XQ#q;{+3~Xp`#Mgh)(i9Kuukxp%TjV(l{eMu)H8&gAfSF`V9|@4LKy1XfC}8K{ic zH2qq$^n1u?!%{}gkAZs!?|?dzte#?tG2pDA>9JVL+|qgEY}aqLHt zvI*s3^iGRqg9M4~hWF(XYRaANz*)e;T-S&VcPb}sH_kQ85k2dLyen3{B701Xz6y4c zJiTK+Yak-MB_DKO`Y!n3c54g&LvMsnY^awC$+}|CN9H0v-cle_Gm7+_|JYK#arFG9 zyBi0uEcF^J+o$}!M&+IK@|x=}H>#o|qOZ%%#f@Hb-;<7+GHOflC&i=9i*Jg@+SYu> z)()+g|NMJuX11tlsOoZR%Sh8-lm^FMK2&U<{AV@mSfLJ(9L{5bHmd(eRh){O{KNST zUJ*yQkoFam#$`-=QZ|=3&tmNpXFJVo?LMM4j5X*C7Zm!&w7OZ>D~}}|sNXhU>VVCo zXLZ{G2wx7!2I!%k^DU!H|8!C^cr>1A&^}VHXZ9{-G-T!4BVuDNw7O&n#PGp7nJgosE~*3sdCuUy@a0 zf>i9nq_kkaZdHs$=ut!8tF;RrFc+g~xV*sP)Jv^2WAw$v73m%7AI&-m+xE|nW$52b87`or99d&(^f zs~XS37oAHOeiOI2%MQDZduOY+kQZKC@lDfCUEftezEZN*u6XBtnf03>D1fX8Y}eHBZ0Tot}NpmGjGfXzQ_~DZ1;Z9h|v+d!|)cmUhvZiBi(a zzcMscb3h<|cGn6dN@d{3;*?ue+}E#KK``Bwg>(eBF-YkvZybPAy?;^b1m~X-w#} z$s_q#+Bu(B>%03J1FQ!}k!TE|oWD#egtH=TG|UMt-NyBbH$;i_`UT@aQ1fF856U1Q zds-p_@UzTs2c*?C69+eGO1<p??^-$R+8Vxweh^lFAgHu2Hof90A_hX3=)DZ~?^9O~Rp==z%jTQas2o+w`b6?^h8fDw` zZ&F+`D87S?O=#?wz&~6bSkS$agA>@e3k*Iyv_hoNPlcQSJOc$>S%hj8Xd9KV3H5fK z`h8yV01zybN0jhL>p1u^S9H9IMa>}ZXTb;`l;?mH2Dk`-4~l>$V*-Hz(s+1SkMNSD ze6s-9#3VJ17RyK%M02#-@UQ_@EY}^t7;i3Rc z<>DPsKhOyBXB;3NYA1u#g%5dq*F2Uw31{OI^)02UzfaY^ym%K;CvAicdw>1^Wu-xD&Y zLYb#DUV5t+B~G$QMzq8*8tx1ef*E9x1EgV^MkBZg&dItWUgaJE0Kt`t48{`lxj>^E zN|9_iJ4wfHXXD5W!UirWm+Ljxh@26?Rt!kf8a0?vz907(xOw3G=h7$ZP=tnBQc0)PD%XS|xdFkk4kwFh z0^_IwMFACFOO>1*0lmEy9&7yXRNgwqBU_6Is#R5+>X1d)zphOc1s>=&0B=h}<)8SR zD6Q6CQG|)BgoD@SN1YZBEV=N+Btj5?hFi&-nkp+w?q-*I-svM52SRTGAZa)j^oArT z8B76NCX0F5iV?HNGWj>PQ6L2+XEV{mC1ePVo?2JCYtAo`5w(dyG~$u7`L*Xc@urRp zU>ka;>#O2pU35zfZUF-s6L|%4L7ROKwrJIY9VEsKKm+iLn5?m-^HTaA+G*YHF}@G9 zDKT~V1hHbyw&PsKDsmh4;Ert0U1V56`t@*@ZG!B9zKzl2GE-Z%cgg8d+8)yWoV=p+IwdlTy+=< z8Mcq+B?`nYJE3hEZ&juzDeXn$s3g!mK=Cq^U z7$1yOjQr|%XHp~bbysJ5*UL_J`L`eA<0*H#UQdf}3&h;|VVT3#4!dnUZjMeq*P$Hb zbbJvn!ty=}Haj;$Nr6!MTXAKt*vV-(_sXSbRkoP>=!A5%J$vfYE(U$uK0i`&E9*aA zHGw8hYlOT+Q)lda60lsD(wSjQntVzGV~r3#@(X53N+GYdCUq&seI=&ORaE3tLRt@I zwW;}cVSy~HoQuf_mcyFFlq7EESGNi&4m;8?jRBKX(hM|}qS2tgSi6y66#{`0W69*<`vXhx#G`P`04jOFT>_Gw5DSAv^9`!qfc8|KyMJz?VR`+V8xBl&uj42 zE^%$Exmd0$#D<@cPCc)IWx*P-aF$4b`fJelC%wk735#@H;ZhTvsQrTRni~eQ-Edq3 zeOQorrjyG`;+r_Q^*6V*aZfcQHAi~TlJbSA9!w#f?SGJo(G|~!9@i0&xH=_wbxW3j!)sGXF%{r`i~?tdFa z*}H#=q-wCRI~J1@y=G4S|F*QN%fgGPk?6_)OKJBXps3$>ES8?z`_!W}e(ZJ0*Esv( zp|9ugzXM!{&ukekSC_*ATxzX#!?#rQfp4cz{nGwsmS|ggJ=_^qilB=I)!lieeo<0WLyZ zYZiXU_WOst!W*+gWmO}yUwKW2bHle^dd+>S{(NI@q;_g#?mM5fTr6r(`DcoXPdoWT z@bPHSc-KuGpNXD(kv{(%;CgV(LdDYP#mB<$=ySVG%Q#(DlJb?kLoW{rx+SN6K6~l> zFx-Mwq27chKtj=X$d z@VRb0k>Qj5idnh!zoxYNo1$c{QkrZUS7wbSxY=G+d)eG*{5OiSX4W|BlkGJ+wf?D+{ER{&$pi_h`G`lFs_(GN~yVYznwL zM`@efL=_E2Q0#?aIyzyv{-}h&$JxE}jNaoFICL#N^zCS4z%o%$lm7~Zw`ayTK|nKK zjl+Uh+hDIUDWbFT5xsOJ9A1GPp(YoGn3x923n#uu%Hk1uCRZ+w5uvb=O_WLiq~y~@ zvE=8;bO4ZJ@vP_5c;V=g$);6SGI(1Ctn->HwQw*Z`D~k`E~$6n89|KZ2l-EWX9)`q z1AH|!57K!;xo<1?{lbzDB-6oVoATs zFdQF3As zq++QrWqa|2Us|B1kva7*A}Lda9e}NC9iGEoUa@Llq<;Ti*{ji$7CQ97ji&GWmNxVE z&U(9R?4ru&7-IFnFoHBcPfmSs#qClS9^}=*n$vW}SsJKH4U?6imGoK>?!?q1ya#)e zR*5ijW@!DbpM#r}R#IbEE74{0B=&VV=R`P=f&&(cK$$pRxGZl@Gd^(2jKc7~akR35 zQXNK3U__i126t0c!U#juSQ$$knr9D6SyH1-+?>IM4(6(cLY#ac6UL9Oc4(7^7jnd! zjx^&yq#{;bauucM)dzjN=MrHvBd?@aFXs;sS2EZ@BqvP$!BP;8Jz${R$T#a^kQDRx zQ9sP9gwOMcwu~h8H}M_5Ecg&T?E)1-bQ$QQEhXjybb4?Al4Z5*Y12N^9gF1kPdt9DCM;ng#~C3p>8?BcT_7g1j)x5^6LDM| zCAZmBuNiBt{c9Fj<=*EwtR3K z?}UG}BTUD;7{?w@ISH)@_)7tst$VDX2(h8#tywW@0CbLzKT3_q4ki5L;f$nIAp~JpX9XMy7v~>Tv)Z_yk{7qB8f$&spz^OB%BMoU|9yC+OreE$=zEF@6T#VIqNjsOoMeb;-e^zl&cJ;;V zn!DMxz1a_DviYhx^=oq)9CI3ja+-_f&jI9?8D(O3j#qh(pjUa?IJY|}_Y!!trTfsu znB1M-t`GFQ-b#w++1ejr(7*)%u$>QtGS7beqBQUraA(0YtBH$0U;19Glo=IEZafvk zg(tVTzPWhW2InJU`1-PtKzdjdpR@%aKu+^Qxu=F3kEt>Ut3`*CD0w?Nki!fhE#UNz z#h&=qJnK^aGFL0{4 zwxm44Y%&i^z9|ET2BXlUd!efI0*@>O+kpaB$?2wo{GR|!;CrrS76xT0noZ?tGGKp< zVi}~PTeqIr!y_tCUAOudtqHq=!R<7SxSH+5DLE+-y4X;06fRC7rg-(}kx)LMPrrsp z0A9)o9cj%49g?5Q^x)HuC+CC_;h{xfoC#GiaU11YxeQC{n9y`tM8bqmpH7u z%6xJMzvAkleU&5Yn2uSMEoy&tm_JjbLxCL-1&r}O#ljkFmpW!Ig`@FL#qk~_Y${FD zzqYkvx6#=Kc#S(YeTMmoPUiTv!orQQkBE*Xq6bj6KeX%8rv-o&S5zl z1$NK1PvZ6Quf2+Ty>9y~EOFWof!+b-XW(<5v4pPN!6vGc}tE@~zDII+cI=4iq z#`@>uQnhL_Mkp7Mh{oYT*o|nNck78o;XB{Ti-IN<>jy0J*TPm(S z$)Fwi--~oxjn-D=(@7TpHWF0oAbkmLBH+!Hz`q>*SL12>iYbP*qIGB#cI^D^(3>Y! zH{U&E6h8&7j}Gsni$5*F&C>wb@??e!de z-13x$Z`24F#(G0B24l@S8J=S;dWB_U*m&CT*b~~{#?!ESqGkX7c$)2+Z{yfK(Pa}| z7B9__7Y>(KH@|QU$bCTpPcQS|GtSyD+3Qw#9ZNn|eVcs6YFak+`qax4Q*Q#Xd!lbc zrX=5{-myuB|NA}BU66nO8H64rbUt)r4JpEHWacwB#&CAcu&Dya8W{1Qhfp^QmJ8<`+8F-Sor#{iC0dSQZj}}39m6i4xRGb~YsqYe@i-oxuy*+UE$)5W z4aRfH3neh5IXy`7`oRZr(_xk6Pi5xa;IPl`&Lcd&mB>bhBXKrBN*kfObn`|a&4tOU6It%65Uks#61jtf0AGx)m*)wAJL#tgKr0)i3 zrYC%?qg83{4g400D7>JOs$@?0)CKkOiRKy$X%h?xH)~E>2ea#U8OFLjZ|foP%_Zce zJ@xZ5>Fg!_)0%PB77I$41QQ2Ut&}?_!_`YcdFCd-0;VhM9#&}?n$ffsmW3AA4w$c* ztP2bTbcME*U-o%8W7OyxKD4(rIB-EYHC)4=57ESn1km&&%|Q_&bL(!arbE3_ksxLR z%^w6WZc+yM(aU&r_=E_roXLoy3xiZQbHioh?kVrQ$t9nij*(U_caG?Kgs5@M7wC#U zKJNRdd60v@qNoLddUZr~y+>xYC}_?!m){m^3`Yu-`*xaRvr;kY5F6g++g<~MULZ_w9?7ebyAe*d2Ye#*v}DM8BT$I-zEStEw51!4 z+{(ohJ@asdZgk2od7`4Hv$XCsiQntWK>~u?P)aDvPZjdTjgltl#jEer-n=-!$vU+1s4Y9J@7R2T<8{p%oFp8 zzi9R78G4weo)9o_qf_lR%<4XTTtATss?Uxdi_};s?aQ@DL0-K_NnA4OV6j1i9)SQ% zSrfP(rm|v!Aa8u`Lf5ADN`WOcc{iB9n`C_K7pBq~rjvSrZB=2%ZrgTj37}U_e4k3BX*0#X(dPNq0FB zDM@NG$O_%_9n*;H#gv)Bl-Lf==h$StH%ET$dHstN>dg7%jHHEwo-ApP&HErkGwB3$r_CaY57t@^XrrFPn+pp?#Xba__ zYWh#BbeEv?J7CPk)iG|4^E~dRAL&is;q3f?c&ISVsWc6WrDhyWaXc*~7;=JYULZAo z@G6yzkQSvZg^Zz~A`hP)G%r*HDRRN& zVh|C6Ae-!f9>VfzryaBQXpv|_qC{}<(&Cuy6U2A{tCBo#=ZoFzU0~FTaGL7&*!|EZ z(RY!7*^!?DvepOp+k<06!=Ol&U7N~FTMp9x=I7A?hP zY$||-1pzTsn5YGBI)_+NPhOTPF-&oueL>nP1Xt3E3v2e{XApbN8K1!`ygr4=&1_vN zcK!}ND*z0c_%Y?OF~@-XG$@lFx?TiLd@3{7a;(&K>Zwr_x#!*NyS@^4Idk)k4^E1& zXG=dzDP429@ik8In^f5&)jts``J>;I_P0=pTg7*(&yDg$i8@<3_n`y;PDoAdI|iE$@4$HE#G`#sN<EmmH?t_TwqM#OVeF!mo z&fqYo^HqNme|n)u*XHCGif4Ow=f2hm>-E1>n}1he@1Hu@Y!n?H;<%Cgq2BV$nUK!T z_Ubp{C1IUONkyg`O?SoAW_dxX!7q|-^$>}kiV!HM`ZE6UHW{{K|i@YDU@o*^R;ZM(N}J!KVUi zCXG`*%y#K~9-rH~(a7zJprUge)ZNW}JXuom`u}0?-Q%Hp{C)p5Yu2na!!&ETOD;pX zB-L~wxeh6c7;;O}C`qCwMUph*PGXdhZbK!hG?gT&hJ>UVQmIs9K0$!Kc4S2rxf$wXQQ zJB$y$CMOKb8HbVLdn#(%Zhn!)mv%(nAH(CQ+J`&fgS|b!Ws2z?c&F)!Sd6Lz_-dT{^8>Fw{g&Yl$A_t~$sayPt2&-8fzwC9!{cK^19F*on`sn`!}BKiTQ6=} zBztOhnA9;oa9#W)VVN02@94O5fX6*>vb$AOFZGmoVr=B>6EPktVH7hXeu(gh2X0#2 z?GWRM5`%@@V*fl+{2g(mEe9x?!TwsWd7GfB@2;%5h@8R{O6$(jlYWu zL|wR2@n53?jnU~m`u|_3Kz?3y7K~GY&IPD&M*ootw3bDj7AxibXHkJ(gwBcojfYCo z*m$S}H#6p3+LLgkvQy>`wFjk~CD4>*GaFxP z=4nL|m1ilCZR5p{%ip-_1QKU{H<|pt}Pr@hVac+!h`0wZ&Vx_X|NoM$s##%(KScs_zy4io-HGijEwA+CtApk=1~d@ znRZl2npi>0opYEEc`gOB2xJGEd#ZiF_nqjz>SYQC@l}x@*(o;zyyr{#wQwRGn~ulg z<+o1b0p%D`S8NAEtoUsk4yr|Sn6w*jnd@*xw>ObT+(suT({%Zrih1)`n3Dq3580UH z-HIjSdJjM!1-ztZsVCa@*97n`z0{HZcC@K35{IjV&M# zJ;}TC(^Tp+6o@FwHfe7V|MYo0zJb>jNZ|P1*MJwK9-w|u81>z;Ppz4kMy{xxBonQ2 z1n~5bN`*;Q-OSc?=yJS-6QJO z5VA*7W+h9K44Hw?1F}IvIwwmzC;IxeTo9}0LZWvT7dWB>EPry_~32`ZrcMl5Ut-AVf{4!g9U#dOjbtweq z)2F31Zuf<;1RjTX4RMcG3!)>_^F>s6@?NR!L?LR92}o)JJN(2uK-6Q;~)Pj={#hD}bmq&}Rt`?9y(5YbTTXzV-A@wEf`YqW6Ev%4l z>Og>JFzqita_+Fj2M#a*v=Xp+3cfXRv!j`st5~1|cSK{e?e3%1*8ch!_*K}kV>D#n}c}gvbCJ+GcV>#Hdm>|WoqA72GwKkm* zuk6bu5!s@y=|WW1g-tf#5_%l1a=Z0(<&E2y1*o`#CQ`|BVxY|H)eP=zs(?7H2hcAA z(&qRRwBPB7CY9-e_|dXY6kVqSO7;S1yy;AlF>h9h#_uPtbii1O zW(if-KHpI>w4wJC=)i%;IV7SGC30a)Ixhs^nPR{qGwznat=skY`y3_F%^{_!90TjH z6w%_s2nWytP!kETNkXDGs_szn(r)(*=O-+U-b>?jyVj3W+8{BEkl=gy>-)(V-+hL;_HyiIb9~tt}hO8olcDL69J?M+dc}L@g;wize-$ z%gt{mSxQl%ST*D2?z$U<8C=o~20TX$EM}tP07VN2Ot1h`0GPqqy>-%CZJ2=rN79A` z{ic=C`2=v*pd~Pq%m{AH)|+5Ya~BwtTId1o;5L&h0kh( zOZm`RKD?JtKE{{3#osvKg_NXtCWTX9DSIv7$~N_0f6gn%EL)ipwD}V$qS*UgeYQuR zR|+R~lIsKZ(S|si6@mRNj)z@ZSg{g#B}~l3YY~}Z-$N?6(q8*fA6@uGdD`-j-2!s9 zfc%T$7en%Mrz6%PVzM-R*%zf042GDk}AUanNSI^^jiBpks`PDcOj2*5&tuK^3mVV#z$Xzb~?LRn+`+14&ub%n5?P3D&W`qSs` z->q`$Y(8j}ii1lmjtxX?4=a+$NV{6*MBdwQ?)$X;?KmOD`OHA=-Ey4OY7vl_9G{3w zZjDu84ew-4^)*NC4Evqx;NsbVXOFjC>tD#1Mif+oAXNWTcB@Nv_Q}ZgU$Ua|MkDTX zQl9KXox{S+F3aRc!6jW#P&xg;D}IX%=a^{4K1{qX(~D{@dm@_~TleON3}=qi7C`Cc z9k-v$oU&hB`Y9{^D$9K^(1k|}R^=#gdk$3(DCQ2llXR>&A-&TlL(>LY@J@%{2^+uf%E7o%TIRT4Q5&9Kxb|B1Vq7MdHMTgpqo`gcm)fhym#N0}$|VoOnRtt2 z6wfpCkICTpp@_->yiS6HesNL>oILV%Or}>ZD%Pe46bNk6D|?>MIR$*158T8jQg!cH z8s3#XOs-hS#{&j5J^t&lo{A3fNE3S%m#Mu_9S<W5M6}_TeAQgxf zb9&h^J*Qsa(TJc_V`fEe#;M#cv9R|Vl^M#_6!!{>L%E?9f>XIh{$)&YF55=0&0o)x zX63oiyPWRb|$5A^f_QO}6@ zni>1>2Z?qr6CZ$s`8`(Nv&0ol{G00s#Ny_hq7UMc9?6RV@riUng!in_41ckNc|wqw z`$YVrx!fbBL@LgIQ7eAEJ#WS+u3`q`QMv-_}6FSrjifpTQ2qe2PGdoeZmKy z`)>K?W zokZj@tJz*7!mOhaXU{2K7ESNQbp?5r_Lw?Z>$Mn(ZI_$^R6+xK`x50ig(!HT)>e^` zm@=`9Y~F}ybhAh%Ig2m)-8pC-!6sSB?t>~$JSLz4&oC#@h)fXjlsv8caZWB;ojI)< zOWLD6bk$wmp2}wtG0sXZ}*Ik9Rz%0)C#I~1rHq?|lhqIHG zns@3z)@9L~9;QTR@}}vFoSm;4qm)a7RDJR?F1k<>SG5KQ0@TV)bY`i~Dx_mV(K>_J ztTI2Yj;WBRAX?Wsp81Oet+msbP~aLgFDH_2rD#M+;$y{|?l#;=(N^W809SlY&Kf~L z3oJlwA4xEo)1YoFO)?V^K*d!19XH0&Xsbf`;P&vy_qS4bCnP%E=W3YMlH3C}xsw9g zguQ0J!gFGYU9RG^cxACX&p>_j?2r+tY(e!0gA%UXHRgwzSJnW?!+0i@A5x{>NmZP1VXroF*DRKQJ0WlD zGxk(&iP~vB7UST9i_d2nLXi4%}qH7 zrqo{vDB~nfGde~zqNmzUD0m(F_5i$(FVw(b(t(V49h;wzpxo{JlZMvwdq)t>l0f97 z#;mVy4F_#2PGM)ayqz~8NqKhsN#@l9`{()FI<;Soiz+{;r5n8CcE@Me;i@;ke?&jM z{ciZl@ZIs>Kk;oK$?~<5nw!htC2w)=RJx*S&6w!p@A0e|-s*A0@vaeR!(i>({d-S& z`e?he?d;Voz!^dbCDXJ&-ZE=+U(*>xKV+Hp2in7g z*6YC-dlq_axv!iq8Y%?MFw!H_gvE`Ds)KHGeMuuMV($b06)O^#_b6Wc>=7!3y#(mS zbFlnX_Oa(4?&eBs#co4V+Gt8V!u7wj*}XT?eM668AU!##2i&rJ?~EmZ6Lrbqjfxiy zv61r!JOtpKbC_zRduV=2Oi!@I5F8{$=dqy7$>-QuP(pHaYQ=zu4xQ+%?x$pmW#@-S zm2i(VdVqyUAcGj?MWk?$fxJz7j8Mnal)_ZSz{-$e(FSiRK6JLOITEp!^32HTS5p-N zd?SWLaKMc<_H+WJg|tuzmW^zwX;+*_LUrigpgZxX8K$U@ZQ#I&@48&ILwXBXO8V#= zChX5Sv_)mtLN0Mq3~RQ7ew8U7oD>g7qi0l{_h8U=4*XjT6Wvjd=P34qSmu;9Xs+1R z7(mPh{X|53@UNvlaFk835&#r#_?3MA`~`lK9N^;$gr0=XXA$fqh~@>Qt8MGt@K`}T z$QEp#{YvR~UD93CBdzqCX*nrJmTtwi*B?2B9AvIkV&%F8r1F=|-k)fm;jaF-X6dIC zrSFuYw8{U0lM1d}xdfR7gZ8oRg0EunBRn*I_N?H*>1rFlSnH$){O)TMB?1vOS7XS+ z-o?Tg!tcR6VfV$h@scWWYLkq#?yOBr$%ZpMr3;~>_lC72%JC38J}-{zQ&9o*sdoV1 zV39pVaIx9;Vaz4>b$Hyds9G70JD4ALAC7(ftQgWdI%b^ObLy?^`WM-P#AisXR3k;= z5p&}HHyM5rziU9S0_+CK|;( zQ{9;1m)q=LIua4V*?((jS9xF2wPuCHUcIQgad zE9;ZtT+xo7vWTjYi|=Llm0BydIU?fhiDuct+yRA*(TG!Z@7{HM`!%K>*I}040VjOL z@5dker<9`(uLBn{aree3>0h>A8c>ga-_bKLFf;%sj?m-UaJT`^L%@Ua+e@cH@-IfG zBo8h&X&F6#?2k`@3*zs|aLI`umF426&dJ&_Z83KTaCQMMKd<$R3vx_wIoT!aaXDN! z@{XRHbBW2OYlJaFIZm1Ng2lO0iqeE?-de=4(i8s>h(?+j1vyhecVW9&@vxvZohcQI zJPr>in|c1|XEyUiPkII9C_#5C-8+@}q&cUxlpX(C;wKd;3a1nwHD4T3-YBdU;3{=M z$S$*B`{_mFim#xJ`Jsp|d?9G-7cUkHa6MbvFX&}*txB0CVcgVyQP|;*fU_r3O_+XS z!2q8bpMFW(Thc7-?PzY+R!q%*JtY-s^E3N}a!Y zejZa)`OEXO%7@f{c76_ziTw944c@sd;4)QD{J}IR-+G)7bK?K}5cz*5)8Oc=Vh%Ca zKWbDhWHLnZkLTw<50N*|?dRfwwg2@H`Tssk{}-b)YjT(W6JAq+d>5Y6dz4Mvb}2ba z^I}+Xq{+8SNvPF-;Q6_F>vfu=EdR2i&k6Mhs#{$C{`2$H5cxl4>HnXi{5Oo!{8v_# z{r_T=X6voJ%?Ww!efs|fyypKrME<|Z()+E+uN~O3DQ*;(hWGQxDo)HvI~ET#5d0E0 zX!nYFYUP0x=a2*v9G{hJQ9hqwZG`4X!0FU3tqG|kVWI|3j$1tES9^o~(htu2WXsU- zRGv~Coo_|1L-*$Mlw9bUmetB<6{gw26E!Ie8Bu$(1hJDzv-UI-L1CsR=Jk{~(prsu`i>*eX7ZUTP#gYPMC_ohUM2d?QCy*o+N z^%IhgH@!U9w>f0<_id_)FWSIZ2~pRCn^oOydbdU2D25_aAv*5X{y@I3`ISdpNFJ#{ zU3(G-9}*L1iS7@p1p8!5v#gXmDSH4ThxuV_-V=ZXr`6heigFhyLkhzJF7t`>UAx{u zwQ2GkxI>(xdWob!8r@8m<0Lci|8SEM(8hS%Gwa?OK}%#0mE4+kz@JSwU*XK1VUeX4 z(mr_spOZi#ch?B406xn> z6|$mFvACdJsWfZmtc}Q|y2v(z$(65@=$xQACteR_nNT~a2O1IUB8}&JJPYMl2@{g$ zANmr1Nur}W;;2Z)=eihnZ8n&5e#-I9qKPx|TY6I5?ypLLXVK+v|2SVvS_rr+y`dY9 zG=LvAuF)nFfc;WOYguQ!K8sG%x?utW%iK|5NX}h&-@4+2-%`eL`cCrj`q0qM2Xc!M z`D2cn#UeswM*h>uPv_OB3xCD~cGPH|v|#3TH)5=%E+}z6tP&$898kUkP6|P6VB^-L zfar_5^HT|j=@De~Y}Z6xjR(bp$4j)LnF$C@&Q>AyPocYSX#?j4^?4R-{Z1P-*lF##mMY>cQ?pe z_X~&0KmSQlB5otKGbW^|Zq*;uo{rR8PV`kfKv#6%t1x%x^>3lf>wbDT_2G_*UxJ35 zjHTK!MH&7db>~^H84{6D-`$i|BPk>{_w875z@Ve95n9ejJurgfHS(7!IY^)knHk2LRxc1_AS~HR zWJhw2u2FenjH!qU*S7DPGrCQGPQzA|e{l zy(R(T=_G7Kh=hxf)l#Cpbn_x7CDTeo86!%Wh}=1Ru$-8!Pn^yt&5ll7j8`dG&?F~x zn9f#Gb@vxS(NfSaD#^D*F+$)qgA+Q*!ch;q;F|R_Q-c=fCmR$d`H!Iba57T3QQt8p zI#uzPAcb{RBT!P#!=xbBQs` zO^U@kXWmTH8*v^Iub<9BZH4d#u3yDx_Fk_IpU)`|IdE`FLCHZa z-Ucl;xS5U_2uYJ1v?2u^W+OtC)LW?;x_uE#Qcz3A_5|TtB^J@h9Nou<@ewpD7Uy-P zqV96m1{O3&v~@E^G!R05Tw=C2q%7PP-=3*)HI2V*g5wUoA(j_&0nn-3ZAX z4Bnx=03-PecPv_~lv*Erq5a5`n$!%VoJ9)k3n@7(z8smiC&PKEqP7?3)kx0#z^$$; z_x>9e9A*J-5Co>IIsJZB?4>og$L8)o&#M{5yV|_xvMsR%o$p>bXFVovyLtM(EV6FE ze0TYmZ{OP5o_bvAukIQ*KR@ib7$Q4G7}v@w%CEe*2$c@X?vBWs8fuLLVpWrRW*>N> z9e$i>vQhS!v^{)l(B)6zm%ounka_y^3mxOx)zXtEjx~+Qf{s5hJ=R-WTdk)@Z|@#9 zJlvsr_y=AGFKHTh{B9_}ar{X<)x*{0ZZ34}LOCvNA9jz2-;~Ct=WG;o72j;hd@Wm= zR*kPh_yxyWSS*%H8PUw@P>gERTj3d>nCf)A^T5%Yc-{Qwi!qG@Vzm-k&Kp@(!%Ks6 zgE;+e=aF*txc7M2c%x`6`K!z_=c#=D7?nSo@n|fwtW7hj@y38`hG5Vt{_ckl?YN>P zabIf(WN2$Zr2RjR-fSHj`qeWqzUgMaq)(Q3qhBy6!v!=Rbv8_WAsrapQ$5Hm=ue-J ztte>5Pot&9Cw7;QN+x6m$NS)78GL$NFTP9Z#K_?;+2Ps_x$}6Wc|79w0GKisRa{L> z__FJEC!99&LneDYAv2Dvlq(tsPmSY5J?x?k=8wyr8dEy?1XMWf)UUMRn(e*|A+Xv1;@XH&WTJe)?M$N2Hs}HU0(jl=( zz|C2~G!N=+8WMl#XP)4T7naoZdNPBJM7i(88-;bRho)2@IbR%O&aCqkeGumacQcD6 zOdKDp*UhCyFi%x*gUhYrUW++lU3irGZdngzka{;$%o3fbQ|4B^69@CHFb5~OQgP`! z@hJf#qB6gDND$R6@az_GBYcA~rk;>VEA6RX!4|(Le<$mCeaWe7TH9f7G@Azk|)o_a`{_^nA=}d(Hy*4*zhpoE1BZFSeiV zykhpJ98d49`gTjY#9c@I@l~xn_J8z(gJPO@$=Ud|tNvm4G=j3`;uJRT+f-e9+Xf{U z&L6v{e|ai{=IeWb!y}@U%$-{lTFMKZX=*!oKTX^B`IFl?v>uh9RFO`{(ncy z|2w;<|8*tiYWE`T%Nd)mekC}s{iog2|DdB~*s8gR{iA=t=2?H7J*mDQ-#s1gGGqg* zSO*TDJ2hF-V9|X+ytnoG$?{%DZ5MjVZeLGYiZEowv#Twcp#x_$Z-h8G8n+%USgh5@ z*t*KO$|Jj?t!V!8FDo}UwP;~6kR{Rm`j{BRMWPf zx$(kyqvM)m7HP$+OiO)FmU>@l^18Uut8{{2>U(e1i>n1UF8L0o_#9i6I;%&Z^DXtF zyWz&C4xYLsH#(r*MNgTV&s3P~NwFt+WZWvauKj>vM`3f(edZO4nUP_ezVpxnl?m6f z8%=CSYEoARdFx~jItDp9ziwUOU0%HUa;T59Un~azXN$M8=Et+NCM5(~Feh<)gL7uUGwN=qI2IZ z;+b69VjeM-2`RK%QXDt}dBB&+N!sQL_uj93b*Id_qb9|PldEuIGhz!hXZF+*wKF8k z;)Wlwf18ceygbB6G&Jdyv(4B3F|up{*Em285K$dQ5Cw7{swkg``I+~j@!wpR_I|7! zk`OH+O>(4kCYB-GxqFEvJC5#Kllgew)}-dQdNW>W4~QC+jCjcz89tC+H-K0O6AbeK zV*hH9EwzxOw;RU`^~|=^q9bj7=C{m)6S>c;HxYi_pR9)hw#Q$z^h4I=*C;=^o;2Ld zj%oi$**Svf2Rmm+4kQ4R%sSf=V6&t(LMyF3UX?*eIB1E{u+?OH#W zmygY${`}p)^mbhFpzT7t4M}a+W|a@&@* zN-|StRO&dhS9hnb(yM0QTluDkYp5E8f=(Vc^ zk&)Dy5_Gzg9sC;LsX27Yf9E>V8F#~HY>HK4&bw?YYiYmpnF!j6xDb88z}=rOd%gJp zb=ITdw2!YkG9TYup(+emgt5hP3(DnJG0Dambn^PV=%7ODkAz(ytkTG|ZpHJzmu3>f zv*N8ZkNZ2D2P!pwx^Ls~#`EsSGm6Zg`)wRpr1?%v`F(~CUc&+LWTOwzYEjCM;j6N< zmT?37C$6s`Ga+LRn~>uaGHL(eYoH^G0H8YzueXF}b=4lb6)TF5T_XVLvqaErMvYwa zcCM{D6PS;SaXQIT1i&J|7a+K?0gMH$r2|wtNR=WHQt${fw!VR&&nC%BiFz#Pr~ux^ zB3ZCW$3+By4akdtl_KBepF^|t_qq(D5F5q;X!#YGoC-3NOY!6;6#Dob0@$P#;jsX) zO+bdEpesNGrHBESq$nXJzd-Hi2%AaV%U>hx0(S~nTj`)5m%vx`8I}?g0m4=ZDF%QI zBx}Bj06rVsIf$xDP=F7|KS$^Bq2bN@m({b2ZtPa)h2(aVmT&gWdVxl;;T4k@@TI{u zU^seVh5z<$S}2AH8xl82N%Qf|ATD8&4eCjWcFY41AFnZ!soXU#bWlM^!?X@L82B+{$w(umss9f(7T}iiWpZ)}!A=(R-R0Kq|ms52>B zIG`Oy(C3rX`D9Br1hG&zE~-u^Q`xYV)Mv2(isuqyga9Q4F_eIN@!0^3Fv%oN<0AK0 z5TgNnEtD`vKq`zpgjO6%@}{oCHabiSNxvD9&{elVJ~ACYDvPqdzTEo4YaeOFrbB{c zJ0WpCfW`>HIb6~XK6$zz`h*zHkq}c=3BGica*LSjgW5{aa6To1A8E*NUxgv+7)f1> z&KASrbj%xoXYB>2F@bb?UO1O9okMbGA7VK9B{V8Huwgw6u}I<|KAzai%psw_RsGsS zToQdNIG>H5afzgdqz7bzrjVk}rx6?@|#43O!WGxYt&dJ`&CB#YB z!$LGxh^VkprhvFtkQXgQxACC~5t1c=MmW1wbAuMoR=AM^0wO}9AaXB<11hj&i_>0x zid#9E#?D|tRC*5X5zY`1r?UYjJzarA#yj&RCFB4KUoMSOHj0dhVQ(X3T^@+sYKn(bZf|xj8ilzyH*{K8{*4m<^Lud38RNS4@=tM30#yr)4E+@~9 z3$91hgMNs}Z&t8nY)S@3fyMaN0Rcw{5XF?kjHF3+$ZR^eHXpe_;UD87_^2jrYi>Lr z9u~4fj6m;O;D%gsmUr%Ie)=GnFobVJ$|dWG!(wuGKTA`1Pyxy_!mPiXwA4>qF+C`Q zO(}u5+dW|L5<{7 z9d7QjI`3y6Rh(oNA}=7BIbDyK6z!OJy@T*AdRgV#*~7t7@rg|m!aOdZD+N?JTzRw)L zoc1L`)!|@bF-u-UKv#*O0TDCiut z?i;)P`L4B6Xhxvh15t{hkZ30iyfs#_sU9$S!)_W3-fpmmC?cX<){KAKVoAq-$SYoKfc*R=2Df=wsfeay{0#U^G5u`U0Or7uEpZTn#g7!9s!t8w-l9Cn|ut zTuhZMLYeiHo%Nfm6;bhhtw1+BQ(w^TUU=#C&P15k4Una1q<!yDy#>yA0BhT3Njv^H&Nk-VG{*KKg(fA z7n})fMizjR%tx?79Ejs&bU_id86-{LPRE=$n1NYyRtrSzBLuOrhnJeO3IRC=oJ@aw z%no|#f;FW)KDK~zgpPIgKF(P{X>obdbK=R@>LxQVbmYX- zvFfLrJ~qf=)h1+5BNfD;wHmZuOg<^T*Z)A6!J=LkuiNRi=5sYbYT0--^}fM|28tj+ zm`PjxP&Hg-P?TcHCExl)P797(DFiYot-5ntnGb>Pcfv&-``Cb^wqJP=1i$nSxuB^bNjZf`{2=dBA7h_qNsU zq)*Gq4mkBj0#Z~mDMxWIFqp~T2uMK7z2c45%J5crc6}auz4JFwmI5E}6p&Vn;JvKc zJ=0XaadXYuvEKqB=P@C#xFKz>oAB&jzo>*+$M%M-4f7O|9M-pm zxRj8SaMaw_=Gm$GYd21c4qJpAoWozY%Q{ndS$R+tiP<^ZF+kRmmzJ;I^beqhSVs=P z(PBds2C@23$I7c6i7e0sdrj$kvzQOe!6BJ6#@n{XN>8^HF64)}d~f&SBeOZ}SFGR7 z?Q8kXAnJ3;r*3Ax9c8T;d?&S5dUBga6BC0)g#Aq7+lONG?R(n=wS!Dz{SZns^tF1` zAiFG?ryE=zbTZ*k{9TpeUq@3_ws#sYco;8&*x1XphRBYi4ew@uSk}o>I7(hDCU~;K zw8VhmRkg79gMAH4p9a%mqLv80m*j?Mf3SL@XubKUrI@fDfL*xfmhS6vI@LA1=GGvi z!(RwrJ1X&}DXY`AmbSmVHTKE9FJz{S6&%+caN@n!-R{LTl1aJGZhdQVR)2QsYspI9 zwj=Yi+PjLlGVE_LivMW0aPTZr^i&q5)sSLm3yvT+W^jI$%FlS=k94#l6Y+_*nSbMG^4@7>#ly;<*MVPT;PNk5XF z%Qkvw9=XwiQ#Brs%GRI#w&ci5?YL^I8{-bY5m*VX_fV&{%jX$F<7|Wy_1cg{EIJEE#jZ@-5+3@19%3t_33-x9_&UH4dhY zISPmN-1|5rlWAs*tg4d9pO;08hF4U{yvsTQuM9J)Wc{)!s3-C0*u3j9@7v=sWz9|% zGS>=OZEYQVY79>y)z?>#jg3EPs`IWGiKrO?3wkHUdYhVRUGK`^f)S6qvX~xbV`F(^ z6W^>+g5xIYGuWcCo+o7`xlD(~rjns%22R5;=;3~q3UGEr!HKSg*Lut<#4dPixI)10 z5lLFFaXdw96`jNBil}YWjG!0X&ClmZD#|h%YjJd_ zNMylg7&j-XI&k<_5!LxlAzhN5=C9)Xh=Po-{mjJLMs9_bSw?7iWFQ7N_Lp^b?5_0WH6w^*vqd38PH*}r+}cVPn&G1>OljpA+RgKeu%t-f9H{Y~Yr zZ|@%8zWMXLC_!GwwYswJW8;xI8=h3(`t@0S#`(1CovOia?bo-xe{$#c@K4G8gOfUL zcdJK#^*p<{;pyEwP14_04oHhU9%?a7K6XRfq*-`2bFB6wYq%j>9b-)~Bi=lrPb`a4hMq1KXLmQiupfMmIJ37@W7Dy9~T>iUo zJ-b`6Y;GQ4CBgVIr%<@l!v&)g|_7P2yyWe?no< z79A(m6t7s))RGyq`;1jh$@0AZmcs?gXJ=YxtoWFX=2j>lH!*dv3DQ81z204He&>So z$3FE#w7T=7A&zFtOP^|V6p{z>5sxo5o=Z)T(!^RiwkB+XST>n@(PlQ55YvwD*Z`NZ4Ebow0FEu(f=(#r-;;fxPY(v-wZwbw4jvNj*LUfptgEb5zbj4rt^m)@sJOjr zqz20ELsd9Dx<5BTZWWg+ui1H8Pr58o{}L@)vw}v*O|gP&HfepU)Ul!UXMQ4dSuoVK zl}_~~9H|b{|C#&HE$Uj1j{k;zqGfWa?J2BJ7P#D(=on5Qn()SVO7{sgm-dM8FBcLm zB{L_R6yMcQp_(i^z`XJIjq9iIdV~&o>)s;aGTmNp8{Oa+Ds2$i11V<-u&) zGwB}Bm?42&Dn+2)A+BNmE5OwJyA44|9yN$TwwBzdf0b=FQKv77|O@*2wb2Zq28_E(A< z5n2Q+y!8FjCZC_jL|w(Er?BjVb!I_p~<@M7AO%bxECtum-Kz z=aVr{1lS0cQC`r$#)4e!LGrR4&vidrbRB!qUvhs&n;_X-LTI>XBRuu31Kkg_KcP;} zt1H`kJAv8(JZw34tw{c4&|b%O?XTF7ZR&TWLlfL-r{ZcUas2Rj@*rrCyo|~fxoua| z(Ag@uo;BK$WiBINdV*S=+Q%OWXVyLK>0YEAc9Ld4K9f3f`HDsFRl-;>{l0@P?<4L?kU1ojjfxUAPC|oqXb_Gsaq` zz#dOfGZBzA0SDW~W&U2jmSK??r2USIJpW06B8F3}rP-Ogt4FodM`}P5A?ZN%bRE%f z!?d!NMDwuDntKhA)fanFk^Cp{nZZx{OlyShU`IEMuCX~e(e*xJeFH%onnVhu@v%^# zT<`uGE&EBh0nXFO!V)<**o3)_@4+OIqb{uVDrQ7SND(8rxw4LhqYaTb`UZU4K~73k z77zouQAd{VyXv!R_0S&c&h>AOqPy6{#PgsFclEkpEGiOWFayG|fU#M7(F&rf6lSWj z&kVy97ST}(uH{10gwUxxK$A(r`2%WnkirKJiXbKaRu>MaL?;>Xf$2h`6*F-T7u4er zyCEem z^o``Rivz91JXi98Bq8vf?l;OM8}XCCd|2=T(a;Ci(E$y8V1$p@2{+?uwTSZ}tYn^5 zHW*#vez_9vNg`4u>&I0+V>!tFRHAXd8)mrkF0#GTaa*($F%u(S)nd{GuqFpK6als( zU>k=pUrJodBshu?mJpmTLQa2%b_u~GI`CZzhOwa~?a(wnB+nu0i4kWp@Q@G97m&#e z(tZJfEF{QFQ4M^I2_GO4l5W;-TNSm#x-)%7JI`N|BG2+`F-Pp!sk7$gXAtI>2tvO#cmxw8?ugVv3!B{PwoNNNKrWvK~(_HtAL0S{&K89 zo`Ia*3l*m!RB2AI5d6*sM-eMqe5_yjo@Q6U)X@NFc;$>wj8K71UbMa zd|~WRDbBOr;_<^YUoRhW7C~zTz_b)Mlgf2j$2KicPt)Xrn|+B94B9dY0MkfP?9sr^7`OJn#S=XPlsIjz;ZgU0V7xla&c#Li4fS&A^3_Q zDvPug*&!M_A-=`aI)|wzMGx2Q-9aHtVDhYtGk37FZAp%uju z4+?G0@q#su43V~fN!|jO5ogdL9)_-^6zD|~A_hq;V1a<_ zU`95$8A=Q$gdo=jfju`IH?1}|XYe>Jq} zVOSy`UBd)nfq(6}TDovuOX-A8FDM zdBW2t?18Tp!Bn7p<5MB*MNnZ=)1+vM6wSn$-YHUAnw0jFBmYy_NaW)Y0xV0`m`#0n zLPmpX9v@wl>3es>vXu4t|Nf%1bli7$$pe*1!%EF zkd$;%s6r1JH#%|yG#d+eJV1z1&BbLkvxmC56GnvW~2 z6hFj1ZlD4U$Dx&yyBe2DAAYNw*bPo{Knn9I+3xAkB}|ur4f;Qw$9wwg#M5nb?3+pI z?B&WfjNs4b6h4~41#Il3N)=2G+aYze~ZSQ7R|RU+P_=qTCIB4t+Up*8tiX1 zI@xM`r`6%8Bs46SDit)DHPT>s2$|1)!IEgh5irqt5wC!TFlxVHlFIp@WRCbex> z@O&Q$QMus72e28FARI(@0f!t9wQVbGdlZYmsK9!jr_5jy_C!ASJ*m3v(^)0vR)66O z;?Bc!k^xf;+Tqo}rbodMx|x1^g;8TqLrusdl9=~0GcO`uQI^Y^e| zx9Z(Ddk4W7DRe%(Q~gvY{lVc=!{EWHjuO*o8-RE+=7X04-b-IYWg_dvq%f)XVpo;c zFYeIi8kf}sLrh}(?v0k*6$kzNu9ID^cB{L>KOXzG-r;u_%hhAAua7?dfW83*+>W~KWj;+I;)uI-8cz!M(p2qjy7u2y(Hnfm zd#3^h^rR}C(%gNt$6vwc;6!&unM&5g$A2)9|M%li4BSMnoJt#CelcLA3hfV}X;4YK zL_ad$$dWcfZ?D6PDrAoy)@AcEUk;AEy{+7Q)zZ26gKgxQ!ULo^dgP1v98+VjfbY7+ z9jPi}yuQQu_~HFJ2hx@m(DDVOHKq{p(D>0^P|G#_8P{dP^M|Hi8dqZNxIQ2w5use+ z{rW;mQ@QIBZRq7a7o!U!Uj_$%h+TJyg)%n5=IiWW3FYvlbp`M1(oiC%2tT(%=|hC@BoKu8=L3gYp~u zBAo6S7MDAKblHR1<&r z^*fVEBLoskAQT}W(xe2b3c`dAQbH9KG$7JMq^YPNlY|lwHCQ8}f*>HG#Eyy@Ix1pB zMC<_-!5?B&#DE|t|FuqguitZZ?z6Iztjv6$+0WklBfKfFSaaj=@26V7XJvmMp&wr` z*f}=eF2F3j#_+PuSJ|2!=UDaMOP2G>6V{oG4iqeW!2BE3%wSnX1umPP`}6bB@_%or zbI-L7C!iHi&$c&){QUW|pml6+2wicr@4z1X?NW5)@#|h!=V#tv1f>=~Uq|h^I@nR? zimH%pjI=ZEo`2U(|JzSdRYm(fn5)}~mRq0QZ_c0Hf#!sx&u}d6Uv}Afb5bs_%4J#a zJF_$aEU`mEhhYMqt~x2gSBR^A@~AXXk|&)H)8aB|;@1{rK^2cr^SmRrx+5NF81&49 zJ^LkT>hRT{ovNKxRpWHATniRBRix9a>_kznB4H<;f0O?6rpPst##>K!pA>nkv#4Yi zKZupRf+pgy=I6#;bm>v*BGqBIp^=u}UFqIgMP(U{aS+d&oA$Obe*7(M z{R+DHZK^N`t{N=(H$e2h`9BzLxp4eHrO5+m@0;DCZ3TP3Ibo@VXsHJPp z{Qtmh-0<CO#cu{-18+&&U23IFzx+DST~*AgRvpjY2}> z#Qz5sNuE!h2d~Bceok6#{lu1Zk$7_Pb+Fgffjf;Cl`asrGH$qk{(89n@{Ll9@5n zyWa~^Z}#k(<1Y7jt8KSEY-)Xh6|?T#T=O0DAG@h0{9i|5@C(BA^fvOMXVWGU6qyku zKBN7kTi@oQxCUDN;?!_ys zOw{E&_6&QQ;Ro;U{J87_H_hZ^qtJTAq*Y342UiIt!)DN!AFke0G z`yi$NaevsnOQ=*l-w~GhF5;(_V&I?A7p2X6KdY&na(N$`-F$KSS_kgRq&+$A_jjW5 z{O$p2qt{7 z+IqSj&=d3!?b12Ry)EPG%+KDOH$YRvtMM=Hth=GtsK36It#E{?q4iH#vI|kFp zQjx-#foM*Njz}ubxS@R)Nx1ksu&!*jCK{{o@oJCcTq7( zTlChcb@OhDFIuUO&N5JURQ|dE7@c_tP#UW4U+wgP-UG^}1z^iBmI$YtiZ$R}Cr!Wm zUf>}|4OL1|Og;xQmR|UEl#2~p;;DNM;L=;bmLK9`t%2oiYyn%(m5kuV4I&!PQOT-+ zr*0K_zz}@`>^L90WFn-{QSO88REjNB==%`X_Yu%!GIBqPaRIrsMMyQOqj(vkL*?ma zeJ}EadG$P~FE|M%yRtEd$yi%o7KD<)D%cDTK|NH}y%$oc5OXwot1ue9u%=O4?}P(@ zDfwM&lq*Wq_dUn<6602vN zfE;+-gC8WIt({15nJELS3=~4Ck`K$I?wV0rfOTz^Vs?Y*@NbhsH5c|?o!(svEICIg zoUM?BhZVGAp#ys<1QR?=Fl2JTPJpnmC>&Q>Mn`hjN)%k_@MGJmNu@!FP)l@6(f$pegpN*DPRh#vSADCkDxEkV|zO&Ld;+ zf>@QmmBp^gd`>QjrX)!3pnQE7zeFt-*eFG**e ztCV~&(ieR=4;QTLGx#3T0zX?$<}!wl>T!7>u8xj34PZdF{5_BFr5Ci?PZyK&;hbwX(k3;`$#k3pKhhQ<*#OKPH$Xf7z5*%A z8b1y;LIEs! zgELA?0=m+n0J%n(1OZ(kbO|KaCW}~{iqB9Qj1G@ls|7@hCkOo?c0Z?w_ofQMGx1>yqLw?@e z+*O29l7jg(w2p`q2tZqgQETChP%kL92mD!x0wrKR8cd@@W>sJY6FqJOW!cF=R^aI` zIqP6_U=BuG3NBQEA6}rFlH?z2?H0}87#il}mYr!Vj2;a`W`cz>=+zfcN5oSSf^>4p zb{gmkV2+K4>=yx%Oel|q{!f6@m7?`wG{QuikujO3z+5qjjvVk4fKLCk}BHS_EaY+fmRWACH33A?YYVItY}IB7icJ zbY9mHtgaZy+l4wz$J;TBRw!@-ABOGUVV(e!KFD&pV$$F+I!5TXH6180Qb@!Xnjm}1 z(xY@(UOK}lZWLq~57B-3zznj*6r(F$$0ZjLUSLAV%*?ghHG#cxg5qG>t{q9)3srvl zQnV5){GS9|D}uNZC=!6CB}cpkM$)Ut~eS zlA|`FQ&^_|2Rw8(86XPrwG&|Ag=7bN5;7fP3#Z{&7`dz5MChj}@5lBF8hnNMR|S6R zKAG)=kAcxUr8sZeJ`}luLgumQqd`&k5nCaedeFDI}E+wf(~+Q(pp{+4w! zh6|=nV-1gmtFq{lqO^3_42bYX;uW0(}Bbi1=S=pU39!{ zwvI)v&-x0PR4HNi7TYsRMsc8bIxtst%v>2(8t-Rb?n4dn@DE z!Jy42M>Cyi_?2WM1Unrudg;8DoLh(C(>y#DN3qDYd|o<^{v}lohSAO@m@*NREkmWgA{hL>;fUqf z^HE_mbQ&x_3m|j(AGk_>3B*JK1@2V9MuN4vQ@wHP#$WtXAx?#DIfWWsyGSKRl6GKq zF$K}FXjhDugN&;e#oG8wpVAPM@iI004w+Z@(p z^zFeE6e&26D^^ABT!RjTbur;m)VUl~t?#a@T07H=$}Uk!L5_ff1nVMh(if7v(=mYn zMsMe7TRtXIT!5mNEwa$>WT=Dq_PpN;&2v4WLef7b1d5QN%A#~J(7CHf&!yQzBj?`E zqKTFGJpL)Z2-4plxw>qdU1@Tifq@BU{a*uw2XTLmShXS%J+u@zmGC1jrSIIz5U`!XTO5hZI#Fgoc#xHN{#M|)Rgt?oW_V4}r= zi8dGI&5lKU&fe}RWV+e!*vQ|_6+g3Ef8avEUh?XplN8^%BOR$Hw$BwS^zS|?ytp}i z8{jyIvk}RII2f7evUxhNJN;Zf9GuJtmo|Y~;>`6#j8{5Fi;e>mF`E2xBa@7cFL1Id zlyS2EG#Qs316l;2l~z{}dRWc{FT=!w%a{{q3ta_dcO!MzM{D;j)Oi}smeL7@-lpC46=s2Jy-&NBAln`$Z6C7`0+x7r~QY>AFkE7yH zk)Q)|?b8q`r0N~S1hr0IOGpY*Db3VZ8aVE5;a62+%9jvXmhK43on@IO-KLpNsOP(e zl1aa4=%+I&no^L+4}G)@jDaDQbr!3sn`T3LH<1(0=REKbV=w1OUy37O}E=^Y07;_o={PsWd8Z5p)AtgZs ztxJe@VPW%Faiu%gym*zp-OlX?f1?JB`Gy(O`j@(h#Q9DoP6IJS8ag!G!yRUXrW4j* z-_{floTJAeefXP;GD3vpyLX+7wiBkBlgH#$ zLv^+Pos!`g{eVEY?efs)rJnx5;?G2(XP!8vT#Uh)vRwAbPi)+qrfLE6!u&(LyPu@` zus&*-9+l#0QB>>fa4q=2dGpL=k$0fT`S&?&uLtvX0{X6PtJg+vUP)OrUp(V7+yDK;HH%oF+2*{nG{{20{Hgq#v>&r>5qftg^GE%u zA9vycY!=h&%gJx+&)thyd;jV=N5$`?d?~a47qjK?PF1^~G8T4K8gxX8woa>#p#dS% zg006al)saX-*9j;va|h657-hq7d8zXb*Y6M#DSq2`ZMBt!D0^STO~@1jFTUgsOh>1 zV^)Wcdq&OFY1H!Os}`l5KDFqaHjmmQs}}*=oc#*7I~>ink{GVo7Zy5oj{C~p z^4JHQtr)Xf^7YzMObiVldi0OOwUt>l4&}An+GZ}w=I{2`n7sw5^;NZ&WGwZ5MA;_U znZ=`1xU(zrj@tXH1@5;#%H6cG`n=tPaO?fSvkW!Y4h1|#HoGSaWg`g~496_-t=nU5 z9s-f4=bkJbeku{=|N5s?>9hSkgQJYmvy(|bbQP-GYfrxn9_?l?tSUnL*;M!JquQoK zw_G(`!!z+auEpWnRvzDdN!kc^{; zrLmnQ6zhby!#_6nmM;sgOKmaeU?(0LE!%zjmj}ns@;>pMs;S4RsJlD&t$Vg5s>*xI zzvqj(nTB1j^@8uKo2K8|T82?tRmPi(4?SFUOxsd9^mh9xN6WG9HPI>Jn~B?AN9>+X zo46iVc<$c6>ox6NRgZ%#hv^21KaYKWTEFSTzr6X`-`~G{_^_A{Ecu&U`+UW7yxpgw zy}i{3_sLL)()xp*8(+1GyTmkUjONDacwa3 z@xSy&La&%Q*L#mm4d**yGfO83mi77Jr27ET5SUB}8haj+54 ziSwKHLt!YcLI9(WKl}-$V9`P=dwX!%%r~nB5}Se0+C8#nziz7S`r1@Ojl%ghn)aBCIY@3Z)`EMX8Frymw4GT52Rs z7VTdI9H>=jh4J$EBEa8ttCyeEF`h zr*;)w8fovcT~Eh_9LHB&G44)SzW%l=k<^qk%5_YN@;q$TG~UKhs>|UNo7)N4Dk^)6 z-+jBYdF{fk<5^D^|82RXoYr>t>^Y;IHxE3t3VpPh1uc=mcyB%%#V4qt_*nhydXE=( z-!Ed!C9X?r8F>GT92I3Ln5^Gr zU+++x;s!($DA!=;h@cG7M(V^f%)@(CnPe$WXRXXz&nOl;x0Qo-krwFA(M#Az&o9cN zdiDQ>F3sl&!~WcMn7aVXuBrPiZ{(8eeR9)KTwpybHZVtQ?UQ*$Ud8ZU39R;j^0ct?r1+ z<*6qbD}Pa5IyIW?v{yJSs2TbjxW;4a9e&WyJwe&38Ot86vshc+b!>50rf*ZqY)Z-7 zq5io3h-*i7x4V@J*NKaEmM%?s9MQV;sF4B2VhsI+AG$$sB+u_GXXPbqVZE7%u5mSD zp*|^ZFLk^2h<=)ETgHJkt)m6Sm%^{8Y|8%6uxs#Uqt5HNm_HoyMV5b9{jtm2I!2Ft z86CRQv&=f`91|*|A~+?}?R(!jUu&A4X*&Ocw(Fqhrk7S`^h>`9`I|n+v`0~He0Vao zt>?|V#`|mASnE9X*XJM@pQv^Tij*otRhk)4+nTk%$EB~47(Cf&@}q5Qu}O5aAgZk%27M%A>-+&UJv8U@&nOS{QP2vqEABRk<;^^ z41Clv%(~2DmvXmQB(8hBVJ!2+z4-4v1>K@=*|K72zvkQI4y(TB0a*eaAKeY19sq3HZPspxWvLLVKSU+&2F8jP?UUER< z`sb&{vg=nbBr}WG57rp(xDc3^5?;Ul#l?gj7h@JuqI%X3U8~!1X~kYw6K=zB2bOY_mzNs<{55J%(VDBL7bYV&w-XbR^sZmZ+ZM7GSgJ3xxOs138xyyy zMPj_`wtn9G>B}$Q{+F<;T4!FevuDHm9YH_5BHxbg{<7gi(oLKCi?k1UxVM9gZptg_ z!$cd|Cb}>DHvX)uNiSD5jUGLJ{A!1F9J?ej`lHU5oSxPHGWf;OpO%{Jei*nf^Jsna zXF0&(am>F=K~MCUZT;>i+xBHueu@6#{AKskynk6$xR`MdlReK4?8~k-iJ4fFxaaxl zf7uN_F<-;#_q@2YZ%0#N%zqoKo6B4N{cf`UYv_a7`>NS$n=SBWa_jaxH?7;Z-R!yd zHP&>b<@3HjH8p*4GTAiyIC0;v(~G&|KAYwa4wmxj^B0^oYaKVX@B1?w zt%>a2H2={g|Hp*Y+pZIv7UC}hd;VOW`rUK3kFDQ2|84Pehl%ULpD+1~3-URD2!pyX z$^wR5U~~YCiH5PMFfJFym%$2^Frf)nY=wz^u+m#tc@ieg!(<{uMVFy!!BBHys0T18 z(F~1LhGs58eQU16-75On{AL@|Np~Avj};akwk{ra0Uq|z9gAVJ#}YPs zIF)&PM%G4)5%c62n(O`Scj~ZNw~~ zOyx?I0!PLzi1N%w5h|G~!2#yaWyQ{+YExOHm;MSRBC@^0{xKDA?r7I;UhzQ7QpRLg z>#Gt2JJYai#g!$cr({q}W%CbTe8wlwR_z`iv`XwG-%s~$8H?}TR6@AG`_1yDo4la@YyfRgliX<ieW?f)6g_fjeO zSjIM$1VKU+qv8I!RY!O^z0R=@7v;28#c^)(FPt77u@V()k&&tC{y^~)zf`Y1BHWVI zfGu9%@i%eM^U0a}4@tp&U#P4}CRs@Sr^ z45;{ACt&3^e119?>l6Yd6>2zR&fKZFZp)3NBfGTR$&BYmWl*tP@%-%*(ARt0Gvbnf zO=O`Mv zG>*bc5pxMRSkmX)g-hvBDtFm$y@IoxTHq@Hm3sjNUL_y|0`Pw0Xt(mW$99X*B#FGD z1f8;Fw7(sp`c9N$X7>^kZY*YH# z+ewYL_`F-J0xdegh=TGlQTU`nssxM~VMM0BHtX+H;y@|NBWW#O z0791g`IM5AG3HPE2(}1fDrNt)sCKHtQK^7@-$9ikYUF^JY6`TPO^^YdHh?1!zkY(3 zVjphM87!~uXkv>uJRH!vbicaQI2MV1`1#oF!DG$?$6QZ$o)i=_ScCusStR;$7|hpJ zbdC|V(G6j%(h({T)bRxyb`OmpQFt1ME}>lWim0i4#=riSZ5q{N-*}CG(@ugYN{i_T zpv3pfE<1J~^Fc4?%yEjJnSgB~Eoa{Cx?re$^b_vP#$T}ih?K&h$*$eP;#?) zkKATnK&K1TWY6Be&`Rzoa3Ujl6x6I8WYD0g-2!+^*=F*cmJBeHN2Fv(kqw47!K5Ss z+7k8`vnT^WL*+5~8?vy+IlGeqMF73a47Etjk)umd2CU~;pa5ba4)$E-&!8EC!qYh> zQ4oWM(w2?V5%~)ctty8AU^L`68_P$q)C;b@C}&?3-yiks8;97!A&Jm{F-HR*?<@h7 zrNv8&;1(E(MPK91Yln(8FUKj!kg#4{q6U(5Ch^24HZmcGdTrB!P~PI=+JFRSr@~9O zQT9Rr%Z$`9t=Sr+tDYp+C?^z!C=#EueFo&;LH2pSrAx*XbBbM^fCBl`;4zeU?-q4= ztcA=`Y#3GJqx2h2q#ZAC6@Z4cLTnC4k%m@wVjGd4>=S4j264WA2A%QHiCSnyKMS*^ zV3!mON%~ySR$!9!+Lc-HwcHQoy7t|9wyA*QC8pR$q1RkyGenzbliB{}Y*5Ii)49ue zfISbe=6x{{1CRTGRZbw}1P0@;n+n-p4eS}`8r2jVysx~|xI&SN#*4LhO9~dx-$n(e zf76aaD+;)PFI!!}#)^T)5{^j{XebY^yavLYBub`ifL357+p7sLZ3K3lC}3K-{T2-yG?Q75AzG2#@3*5{#=$*GX2*dG7p$~Qk-JVccsSAL^) zh7rYa-18f$)GC~#{3_~2)M?s9jkS1brP(m>>tSh*6QU)9Or=1*8GB_C!jK`aZ&s|V zLX@N&5CJD2B8?f^hI|g7`NrM}AxJCOzl+Uzh^jC98=Fl?hXSbD&3^11uE4KIE+DL= z^HC%k$}!1!-K!{_-c0!t(uNvjzk9ZMa5>+U+PZsGM*ZSK&qa@S#Oo)=oG>ba@1Jpd});u z?}uvd55Et9Aqimc(RLb$1?j!7{FJd@3Ixgj3t7!(zifkl+3(_-i|PO#=$JGf(1X+N zMM%75QhPKeZ)K+(i0`?vhjyfgS-L>)T7CNWk_By42c0HUx*5wQ{xwIyb0kQ(^R?l4zXq9k*m0IB&$cy# z-Om6#AB1@*4=HFXMq}&OUUDj2{tdNhA86hHD2ocPIb0$Sq6npnibTNWmhYMflxX@(gO6nIgq9ydF?rx7<-ew4fc;W_<}3;9g|JaS0jHhR;WzKQzB2@z z>@#cv9qk0O|4jZSN|PupD5WIOK*;t?;;oL-8ftyA=?94{`(fUX-dp*DsVKxKWfkjm{) z*9nN5Pd;yJP-+||7*1*v;fYSxM9*ZE#SH9GE$^Ucp{kdc8Z{s%cbLg8J!D93yf0*Q z9w3uY;q;U^UyoIe`SZVjIX>+`^oe1WRmE4kKxOan?3vyUU!t#xODp2R?jU;qYYg{w z4;~;YJ^Zq8F>PVh%;f7^S>LA?oMqC{o+H-V|GCUfe|>pv`}cpV=Vd>?Ja68mA7 zU(y)Ckpaxoy5o}G(-*c%q+rr_VSZ717AzKG2HoQPaFQt zk1(*VIRidKZCz>Gv5eLN1$BmAIz!!o#W}QwLLDQJkZ?(xR&YRdo5G6h*iNwA7vut# z%-bJmVXe<#61M480>+M*>7{_elM4Y`i%fTniF`ziCDVE!$RSnSNn{z_3dd?rLXe6p zaRBF=@@y#sSVnb$p^e()^Q7>946bK$jEWX6_!AT#?tfp~3lkG9VQ9Zdkg`o8KHcrb zp@tS^IJD<=GNk=P`6nA|FR6J5jCwN)ZrNpT#a_3B(>sYS)3oo3&z_JKRx@MZVC^Tf z9gP>ud_hp|cLCZAiBz(OTMR4)RHA=OqX(xo zNatxKutE!-=`nkcga2kgwn}2l&{Ma%`<=#@BZd=zv|fMCLxqq94X(OO0B*my=E3u> zUKwn%WNE(Sk35k3*wy*ljW_$8r*8ju-}(FJXSTejs!bzYomfG}anQCiy$cr_FK^bivbMYrL46seqWBPS_%F3&c~qjrYI9aR7c{*9x=Nf4V0`~X>mvo_r2GDZm%7nKWG2w2esfVd*ISt9xPlDUxbUQY%gbNVD^F$Z9q^DMD+$q3PC1hn=|39ugy zQ*We`UJ5T_IIJO8I(X5%?-{OtlB*RYINGcb$n*GwPz;j`q6casjupW7rO%23lMr0w zsq=)J4)}w04EAsJmmrTQ5q0+MD>K(@gT$Jn>F$4xP)9p&pLy9Kx#wU z1El&LaRSs?A~w|ek+jztBRlMI$SPctY#kC!6i^g`in8=Ldr{D^~$)%tlII@t{-nBx>`hHgys$EX_jeA8#xSP>428a?zz7ug|0qT1!Xs;i>g zLh6~Xjqi$R`JHwv%a3el+FqIn%)0aZ%s;yZk8MQ^{A03Pbvve3#7nDVLALk~*Hk|E z%1#8?h`#=&XH*jv7*JpaBr}qt%&S;?5`0er6;c#TiN!kb7>ddxc+i5=rOE&3GPMWe z^sH(T@00AVX3jU)OG4Ig(@zNV<&B(`%e{~q>)=rFM$)VF^KnVx5`>Z?ya>FOtTdscFjIM;0qZIO?DbIpD`6|y0m?TtJUjRT(lP>4;_XyP zZsKza#Wt9xy#3xx+SKMAg+dv^iAofsm3sdg>-utudajT@nGNx;Ah^Mw8j9B?>#Qz< zIF=ZllOjPjWuAN5is5?dj$%xi4An7%5_ek=_1CuyTl)`%Z!jbt&R))Lwrs`Hc4kc9? zoAZI_jWcJ@MjHSwBJ-Dy?uAZ*Sp5fD0Q#TwUYQ*O6Q{-*FnVT(9f44Iwf1#UUr5<8 zBAi}tdzdZ1P>pVQ1?*izksZE$xs^rG%R#wb?LkBID!#WE*#0TA$nlhczKI0DNTgK+ zC-Qn%k&!(9O?XiWqm)z4eRRSK8Jnj7gY!OLjLImTur3t=TH!=Gd%Z9~y_49w8FCvQGBA}0L=G)r~9CYhssC%}Rgd?RQ zL=z1IM+=k{V1;;*8q5YoETRL*XH}0+LrYyiTpvSC+~GP;Q<$MaQ6SMNM2XKSjRwl6 zy=r3J-KL?{0*1CHa=CyN_b$??PlN>w)OT}C`d~sILy+ zfl4@z3TqZDg2p0*I54=6s!vpgA54mMuAfkX6pWk!O)~L_Jq6!L@THJ>})KBC7_@+aFwF5)bl{MD5y0~o~*a} zy^bn_Jl3-t%TJwsF^Ds+i?cG`>`=Ga)p%#$334lU=Rq;AybslDmry85=^01nx=4O0a}y$Nd6Lt1beg>VK4xt znirCDVHFmK)PP{3U{yNDRm>$t*Qrl~M#z{u^=W!PcOTs5uRG={G$tHPgs27TQh+qw zCdm~|{ATC^?Vt?VQ_)77>d?-KT3gZPA|zac8FG(!>X~|mfRSc{5DM5CK?X_Z~sU`G` zgM8l-RX+`$8{MGN#Hc=v1i3C6p*`1TiwKh?7|RgzP`FM6lYL!_3J(Pe$)BuT9zTRfWZ?fum=-hFqwYp-P4? z+=I48tDABRyVER&j;FqtK(FsurYePHq(o{D0PWtXFG71>tv6o{D~|-3#to^9_S6p? zw|E<;e(+fUW!$pQeVKOlqP}UurG%AHqsJ|uMD`4xyRa*0{G_}Zw)a`}FunEcs`vV+#M$D3!TE_Nn__YZ`R9!wo^u$m9`F;M+}(A}!7 z?%SMd^P7WB-7C^Eu38VBu?nPIelgJGHt#`6eOA8ytJe>cCuc5yKV$Xr@V9-sBBLCb ze_8C(+2PzLGQO_0s5(W9Q*RqmKeMswjh?hudHV~irt@=CkmGg*w{)OG1F8j;a;FNs zgTO>}r7-D>Gfe~jlfP~*c28BL&Am=l*&N=xzWB{R_zt>Na{z-ue; zH@`19SWA`DzYkfF!rO>ZHd|fRQ>5@O!|g+=ac|w5M^p{ZpuUrL{ZM$iT{7*V(g_ni zKe<$*)Sbe93|fsJq^tFO`&h7fbj7!yGgA}BQ|&i1`d^2WE;cJXT`N`nUJ%y~x|~v< zgj73@TP%S?XERtk>EpW6*_&6FKUiVWvm%HQ6u)X}Dq(PBfc~jFeY9Qr=FB(!)@{FL zRv6h%{kpk*eCqp;!EOOit-b6P@;3{95tt)y%f}jkcCP8NVyqe)#`< zchL3~Hf6xd_VtkO`0MS?Pd%LeSoW>Y{I2(%9(L)>vg}vKE!ryD8qg`B6FpPMrBdxF zqg&1Y&RqJwK5NAW^ZcLEhNhzbXtobuPkx!PUERrbO|>xU*w%a4*2MV-=rfJ+Pi?z- z1$t?5M%(f%<6G{tUeSANH*UhILH#F;=*RxDI17zr5}D!Og^(-T-Q5E;@ah>?ys*Q$FI-n%bG&=a&H1{|-&y4&Bw^|TMx-NP81Wurs}Ra3HVtOG4I_^~ zck4!r44DkVPeh5j*j3T?jqb<5phYC+`*w*3)Y*F@5eeRPy=yn)LAsN=?7c2+kakD; zY%+{45Op(v)dQkCPo3W#=m&`-DlkBZ7pb_gbG+JgeSx9tp3V9qwcbvwP#v8rqBvD< z$=OTj1Zr+|i~bb!J;N@Y_8{_>754Q#)ISj7ThdkdSd!f~RLcfx;p-ORm~eM>G)#os zX!PPGtcvSv@4eWxdMNSU(4YSA*Zql}93s^n6U~py6Uk)j1xavZK?Iiif|3qEp6-gC za^0TC^l>MKBj{el>Ofy~jN)(@lHJ)G}IX;V>Wgs%g~lFM-|7nPzAVy}F{T*^5|2cR1c^zORdk-*;zZlL2np%w{OlmLSM3ooDmtwCY zMEE^cDx!H3njg#z)jybPcKdtl!C%t3;$mfW;R_rP^cyp-@*O3=7&Ni)d2*1`>YHXfsdU zc7HCuSNi4MNwgXGUVMk_xr$sfC7K+wldKqw`u z4B=6+HZ=yhxh?I4Ug=5$f_4sF1ewk&)DV>1R~4!h_lf(I7UfAf)&Xb*%kYrJK_RVd z-^|43vlC+%%(+C@UK73if8>2w%$b0XgrsDr!Grdp~y427S0qGzhgeo9l z=p8~86cG`TZs=8dRZ37)1VoyMiWrJY69OVl#83qUM5GhQ=KH&McK7bwnVq})-)=IK zNhXtja!zv2`MjUk^Q!y>5Y6z@g$YTM8QITWlov_Woli|h8%@{Fiern8I~aJuG?7zspkj2erV<&T=mzUTP5Y^wCUg2}3l z*d!IOm0bSkQME_*D`JXB))}5#xq?RY0dzdq)?8(}bjU>j8(&>^m)t28d;=_^IEhaS zKT-$Axp+x+Rp|ua{n5OSjKL|qDMXL%7~dUXiC$`>Y7)CJ!mHf+Ex;?u+AKIoP)R;k zIPvUOjyH^1i?GOg4(5kHM+-ZXrVC(ERM$;=QI*n}!kn?v>8ep#ECOW~+q#S55&k zq?VJjk{CuEdOpEs{D5)s-PI^2d98!~PXFf;p7AKRYyt-|O6rk$&72 z5j9wRiOtxeK`)*rCuVGL^_)jF26=BUrze0V3Zb8N4tf8pu9Q=$Zf&dR8|}mxPU#JJdfXjVcbq%YkogK`zR#WU-=Sz5W=-ai-v#1P@*|dF`jzSx1x0ZftoaV~Y~WMx?F)0w|c+1s&p!ryKA%n0pDpE^;0- zf&x8H)MJ~eisg_B%)dvzL~`pw2>RhKOOpZcga*VpNDWfD!IH`CBWkn(rAJSTf^h_p zG>*WLgwhkL8)J>~#{&8W2{58O0uh8~m2DtIZV4w!x6C6~76_tlM35%VAI9IH%l-hH zz%htND>QThxjYCQWK4;rv98u*qr?co0p_*`x;%B+a88mg=u88UqwX==nrxRM5D_bt zhw4*90~P;Z1Tg$NS$BCjpym$GIGxTyKG7#+rDLlW;nUU?rySL~wh!+3(HdgU6ym{> zbfiPsG7cCv$85Fb!*q28YR)vz?xwy53&Z4+eS8JEQn2)h4A6egOVbSj7^=Znf6efg z-NBc?FilJ~bf_2Q=j|&PB`}oUpdgu#z5=XB^u_04iFm0jJ0Eob-vL3ef`9BLuS_R>g8FR;0Ky%Vx5k zb^dRrf3W>KZX%qu)%go7iWr#{j<`q+0`e-;gEnosVo}5&G*~r8{;$%PkVhZm8H4`S z8a8y_ec@e|{~Y_yBn58L`xU?&MUUePFgwU?0rz7t$eEp320tv=s$3-Go-wzWHu1-l z`7Z%&Y$q!&JK=8WJQJK~C6r4B@WPi(S>9x$V7lg;kBH|*FBr0g$qRH;ZMYKe$A?;C z-Qa(r!T%aI3*XH6oWFNw(8HI*ggVCt%6w`fF8oDjki7iDPXfRCCjBz66`P7qv)JSC z6n|qB5;l1`peQemEgqERK|Fb?H*pEjd^dcV6kac^Br&8 zP~rrU#^lG-T7U^ib{rDYel0u8xu$|5|7xoXT@) zKy$1kFsMD|{WT`5g&dREjd3JQ`*DTgH|Qt9XWUZ{e`%T zS#R5&y>22}C3?jaTE=x}Z-rkeU1fc~U%+p^``(V1OoLy2{hnL)rhA^ow~f~Q8nmEy zk=N1i6j#J3(mkwONbql}J$3%f&#=!rg4;Po)Wx&z;REi1|4JsP%NKrz58o5qspLLc zF>#OhS|Pam-2P(+>LFWByeLovhl^j;4Ob z?0*nC{aZw%uDahl{wYK|oS>Z^{=7${2?4-306ZJONCvQ?fb2LRcQ%lZ3=~3vL~$U= zY|uF}=sXIngafN(gEh%ux_DI|2f36DxlD%8uArdSIH-L#)R_!*N5Q;su&ddy>txtX z6#Omr^LH}yPZY}nj^$T2%WpEvA9_d*$GV@*dQ4`e zp-^B;6g&sTID%qDquDLd+&O5z5wsARP1KT2GKcNl2-|ryyOJflS`NGB2)hoNL*J6) zQVz%E5soWpPHRg}`y5W^5l(kBmzO2i)f}$tBV0Gp+_x>c@8)nvj&R>Y^Tb>7BL_=f1Rv36LhH(_b$|lTi zCCr^G%r`15#3mwYB_f$Ca&A=QJe#PJm8e>-sOG4s4x5<1mDr_RvCE@kSJ=d@t;Fqf z#hpjR-Pt6(tR$}HN-VsDa8S^Kl`89K!Rw=v4W&8~JUZ+nkTISU0qVAYX$P+FdPI{O7lin=78F+=G>&g~0j))$`qQ?LDZA@QG3 zlC|dRJk58_nvxVDDp3wRq~@rvB>PV-JP6o=M{JTV8e$<>toAP@?Nw{-g=XzPx3xF& zbaub$=n}R6bQ;q)B(NEIa2mx51?CF{*j&1uf9dX+(Jc;R zdk;+||CLW@9WkL5G2OLQ-x>U)GB5+b-St+rm&+}QE#!PF+Oy9MbHrrf&sciPT zjR9l^mNZ_p$+- zSYtHFlD)vnb=R_%!&>N@)tLe-ZcaPbSGKYRc0vW5c0^`vTZdaVg4jEp3>eAVFKqtq z*hI?P($4Ba>_|ADJ63n^*m3UK^1ZTR{f4{s3dd(_e@Ni$A)4Q8aX6fFN&e;%+v2b^ z=a6dU_^(CM{FUQv6u2}*zma5lhO+}D5rB|f%{n%^FusTW7mZ*)OF;Q zwf-wWwxZjxwaMjIZa2xSo4YL2SSMhp`v*<~%}$`koW65`Gy2u#t1380UHj;7J_1B< z?p^z{m97grzCOaP7i|RtLOgHXcRZ)0r!)>zQ?)h3GWiMnxEESZDRUw)oLGXb?Vcs; zw`;Ddmo?`My}sGc0S#_rFMv65ji2Zna#QvUNzmV?(P{zRoPTAF8sQfAea#l=U5Ggo>p# z7ft{JkD~}V;DHVRK_unYl(IIO$nK|Wy~=Jdg@tHv2-;z=fAatiq}v}U;ZwvbXFU*s z_=}n(*V{WRMjjmA!qJD7H-xz?#9IU3ts5)Y-BkG(dKD*mhuZ}liqjnf0w_XU7>+^` z)R=ht4VGz*2^pddKGywvm1cmVv zktGSwsa^yPB(h8rnN8aOtt6mgzQaPOYqV<28#7==ky3K2*7b>)KWebs`z&@?|MQ&o zjaZ0hEcDa^B)A_$SJSp(!agbyB=JZ9CDr^ZYudgbeeAFXfOKHB_L~4$he+n4^tr$2 z(j7+MIe`y&&Nc#c@gQA*WHdK!J;xndr2Mun*irMJr+-n3D>+3c)N(|bzJ(*X0pVY5 zd_NKxnTjEvl>jb0&;<{2AV2|l5N|#NL4f#H0{X+a;s}5i0-ac3)YFaB)Mf0Lgd`~< zg7HW$iVy&gw8Loi;gNwPRt6%o`fk#KO|r*C;EMrW+SQ_%8%j4>&*U`!V|iNW^rnE- zpa?*v6bcpL1l|aV)IIx2NiQz3;up;W0 zJls%5e8NNb90U&zq7Ucp2zivG$~{nufZi{*jl7%V%4zThTLdJy2w?K!2}~)kS?owp z1}@}t6BsE|toR7VnQ-Vqc=<;POnVAKYb#+rILtT6XHFszg-Aq45|BDpcby}7VLYpn zclGIm8f*C+?h8K10?r03Q!6nHNMsQNz~hJj={L8}3)i_~8M!8a^KV~xMR55(sNlvk z`c4&`kA3)&P(Z6>F%D-k^+2?#Biir?V@jR?9%PI`U2C~>CFn@Ns<< zvv`I%n-Z6#{J_aQ1RR+V9@5pNmRVzBICbiS^y{3f^oeOJ@N;^n@!& zf6oqnr>PMSSML-I#6$Y&CKNm*lmxUAzV5D!vmXn7a)${wZ74tpo``BPoQV9U`e?-V z>dlZlKW#`;-+BuohY#B!C#}poySR_7ov&U6S?h9#5)%t3uwIG~8wp~BhlKFgzT@() zwZ8^_<^A}b8SNPdFeCi=)V@dMiS_;O&o>l@cd65k0uWb$5Mb!IJ(r+EEMpL0@)AYp zk)lcv2~tRU=+0$zysyv4FUU{&{_YNRu{8STxOF<8#hq3!cl+=0InXVYFU=}5UIm>4q6<^ZaqldbV$nB?wF+GMQmA92d}d zH`Z*owP)G}cguez-{DxJ(5)FOv43H4c>p=#_3jvu+#FkfjK=v+<}_Ui^FI@mchTvjteBU-#ee z$LEscJ>l-$C&aC(S>-?saNbHqt75|(faG=acObFN2>!c1!rC*LN3RfhthfjMsSFa@ zxuL&hExP9@y7#(#FS?tJiruyUz?Hf$M`+_~UmK0_RD@zxZ;sgI2U@9$ zPiXxGGR|+KkV;PnOO&rqx2GyS8!FR^Jfb3%tI3rH>AV-yl%J12F?*;H&7e{<_S~k{ z>3y0??f46qcM&HHs&$i%-UAOV9xHTyi1hpZHkwhbe&$Wc@99_J3-z<_qmGYG7}Xmn z4~OZ)xN?)vw4_gHm0sE0e9N*}V`b)241kI!+%;DSK)1r_&Tf+_eo zFC?uOAI~g}@JL{@Xv>f1(l+);;tlMjoA+H2BJl#5#-6DXZXBLzfbw3?bh*H4&$RPH z#$NYNV~vR!s++xDS#z9HqA^@Y#@;zb8p(V<>e3-|ITqSTpTOp*Nils}qg0$D5YX}~5&N=fjL$uHM{9~Y_~0yP}2R>Yi!7iNoS?1&SS z1k?O%<1(jkm8sec{#ANE#>LCywR@gbJqWCEgLrEx3V8XiUC4P{TAp_8uIb{pVj+Lu z5TBZ+AqD{$tRQ=uaCfx-`peH>y7WNTQa|w*h~%zaZ|avzKb!3)G7!)*D(5UyO19ug zztP$*-B;Z@8}t456H4agKo=koAbbdcf&oB)41j(E((i=-JOKbeAhZAWCImnO$cO>> z0o@P)D0%3ZdbNgfvuC@WuEVl|XcSF1mMR2X^B3V|z+Ex>)M(yatLbM2BUE*~-=W^0 zre2VQs8!B)7DEGFU_v)bm)^5@>(>!x(}0Aw*@rPmUqgu51xQ#L5oD2& z{dqqv2+{tC_48vS_lsj;1Vo+%(m1^r5f(DI^dA*oiqQMwyFDlaM6r$x6emtB!phEXq;3%N0OD7liMRR|D#eJb)njt za^U0xY{Nc8-S2Jx%xJq`tUDxjk~;BD0bP3->&pPkJ>s~(`8e~usSM;=N~v%i_2e5* z$NM*%n;S*(3Q{kqW}m1hvryI7RHlp>x;)ycdWMt<;GAeNa8McbT}|LV6lPcLd@~S+JYi zSpGmUjV^3m2!3yyycLHf^&5z_Z!s~**ZE=+>apv~#HaOssxtVfe)94RhLC`n%*IG~ zPR`h2ugPH!CMh$@B=0b>{!J_kk?7spYZNGErX?@cvNAemkkn6P=_Psh_QGmb)Z2(d z)pav*Bu_ngRWmH6Wu;Vx#L_@6#$%||73wUHd_P5FjYKy@KkblOpB$^%CLheod$M5% zLorp`#LP)@264S`87tO8R&OB>#^Jr+md=psY-C6rdi?X-k+v-6&y;rkA1%^W z`yT&C72)O9I>+Liq5tJ7!ltExVx|ARituuWSVO|f*J|rpw=ZvRCW^oC8uQWIt>Fjc`ccK4sEZ93}`9T1ieLNQ2a`sp0|D}qs(gXlx)dE~wsZ5cmS$UM9y0-E- z+emt~D&Owf>XTx+efnu>=-TQtVv_V)byeZDwdd7OYu0M&rYEk{HhiL8BWpXo*C=~I zBTN6T|NbPg*v@dbnYF&1D_y)%Z-k+)anSBf0IrMSIG}k<11i&W-6L|cMFV)9Rd-Zw z;Kr*(wt_6|LeuVzdYT`f)!QpCep_E$iF5{rjc~*xs(Qx&NAN zC)cqmlZ_Z)VJnLfX0W(vzNM%90!eEafdJu#qgQn9HVA{Rcl*v5be;e_Uv|sux&KtD zVT8dP6gudg1-Sy{4w4}Y=nmeBhk$%;Wc!1}#S^dWWpw5YfLv)?!_Wvu2))Nh$~8}d zGd$>$z8$r@*?^H_vGa$diek2%zbs~7pEH5{5-x1R|4Cpcz!lZ&^K58@*$s==vw|#j z%ads2TV!V4lC3UQC=~cvC$U^6XO*^cWBBzB{anu4{NM|2ToyCd^9L!6&4vfqRH<&V z%D&77MhPv(@kLX+NjiiU3KZnlj?)vHW9(^I+qu5e1>#P?;dJ)K^8Osc<^*xoq1mD` z6eycQDOTh);46>Cy^-r_KsR!H(u!;(JiJR!9sB;C0ZKdqj{x%0O`v_6-Sjylo-HuepdRjD`Hd^vussV91d|x)|3d@p#j%P&l3|?&?Cq3`qX@_?Z6FcO z9fwWNry#YigY^3MSzke+>@EgBb(9eZsnK7z6vtRlvh#5d-T+-rs^J%z6k98biSeKo z1kjiG;a)D0tq@GlhVTy_bG1YuarqV0Si(?vC0#ni^|4gk|IM{ z36zKIXMOcWQsV+!d9^|;roaUuIiDKv-g7@ zS`#(TVO}K-jwy?U7=NT(K&h>S2y=#s>Jfs*QlyA7frx8*vy;|EPP<~=R=tB#ipr5G zvVOm7q%B*Y_NJ_)N$jD{=}J?20}}%54lP|`18*>|zz5GR#bHvw0ziJ5LHq)~E^!A#w&hVOQMP_&HdA%f> zZ`?CZ|900k;g$L=nE>1GR(&+N>)zK4Wg{V%zt8e6g*mO(*f068o*wSC=_(R9O6`Hr zAVAWFUVTXXVxmMCrXq24BjmN_W9SSK>a$cI<}VfpBwH{XCM<_dFh2hM^gfUipr^{* zKYQd^4MT0|Es6yLu`YlVXZ6(|pGXQu)B7Z}6Byi%eUrjN03Vw(0$0yvqxgZHIU@xx z!;WkHUZ@cv3itJg)8<}OC3Zv4cAAOjezVU}?{-}X)HtK~oef@_hz9n!``9@Q$k(+= zg+9M3-Y>^@(-4m?=}D7(Q%)tQ;fz|sb8ca2?>bac-3T#gZ)rXMoyf;{ ziv$=eG7g3ug`ZuVphe`47>oyQfz-1Oha4Pxpfuo*BpJ{b7XMiKRc<`DJO*O!!$iWu zAX=JlrP%=?vA1W;6B{ZAY1IS{ksrx!s-K`L6fAqf{)!cN2`Q42aE^0c3#?YfT42$; zVT zBNVYsQnU8?l(FU&~frd*E%IAa92CInWv5`P(A zn9+DZFbFDQ%15n1AEq-^wl@si5DJ-Mq9wzle#GmZfA$GbF*5F__Bl47as)o|J?4s@ zI!o`ULMzP)YtGn|SYn4?WCKjiYc(t^;I$T1rjvcLCcH~a?ff!w3MWQQl@rVd!ql&5 zT(aP+zgOYy?bR0U+UBF&DPpl^Ivmktv>fswAzkDr==Jz#LC*T?ua&&T-%TT7ORwIY zT-4dx{r)RPNNGK9GwdZRu&{K$~Q!>#vF*gj`r))m7~#zr#sbG-meLa?TWlS-Hq&9KI6(jFhEI8@cenUNrk9-Q)Brzt^JUZ+!;G`A zQ%48w;D?p(m|@Q$qvdT~w}a)s?{ws%C!1e$Z~sb0yu}ctb}HFVPEV7?M?nhyC?H}r z6jfx0dhp4=eEA;J0Y~-IYs@3p(DcKh!gXQ0>#xTNylot&O5jgP0sVz2UV|H=bMCU3 z8_SJmhb^%W6$6)+LBH$>w1&Wqy}-Xog0>J%nU%93ZZza-kQO0my%T_GjepQ|3p8?T zTQmYH9DLR?STb3V5fx)peOBZ3?TfG3|8*zWP9|!`I``{EzW8S7=8%+dOV+nIiQsYW zTy;|5K~fM;aN{<{^@MC*)o{^Wye!D4k5bIT;0M)aR)5=FUlcTAVWV zI+`ighf6o{rE$vAU0?su_%D0l!`&;d!%`x~6{2A1U2ebl!h1Mo)LaP_<0q@hCp*jp~MNMMVIKBOzTSm=1IK)$@OfhVhxs`AMB+k$jbnkGc%)q)p{ohn6oxA9 zwS8NZ>$sZKqm~w-Qus$w@!SP;ogcbBrEp>&Y$p#xSp#pMMYlMhH4sG;Md@t19;=_z z*MC7ty+!?M8B=*V47W1=%MU08@97P zDD;KWg4Zfl;W9$AVMg*XC34~dYRB96u)8wFS~s!XBN#|`GI$SV;O9`mj(ro*^6uM+vy=BlBS zM9Lv+S_vwn54B%pn$>qNtY?OPMsN-09vXWeWHcHW5@8Z($yf{z!RzX zb8~@PMrZ!n-6So8Ze!HJjW)ztBuTktOH7QQB z?PvSicScqXh2*|XlfSKUsaCS?d(f5ch``#-6Ov{JG$vLKu5-f4atH z=VvwS&v{!~d}_H;YgHR-jea|SIw~}eeDRDk$ZQH2>hJmUvx*inylC4y zTK~LU&~IP07{Zs;%3~qdWW8C_k5CXYghv^rnDWSP;0i-SYjigPMb_o<0Ev*5KY-y{ zX<+_tHEgz8_~m9$<7Kb@*JtLm&Pm=fWl*_a>%?IF8mxQyN(=Uf209uG0$nvia2TCD zc=P-#M2_?ZME{#)hl=}{g*oeiJAqYBD5t8oL?2x4br1@xfB^#;iPzaW(}A`L?Tk() zd48vDW>2o81nglUL4ixk-~h6huq_xg0g52_56~WpF+E0RGjejvBX2!Ki38N0|3>*x zU=MIE2xGu`5->tlu{int^fPayKkE)wGY1>h%-dl!3OZ3WyYd$VLqXUqVdkXALc$KQO(!dXL9R=b<-8npl#`=(8C*PDH8Dd)ai->iOD?#A?cc?rv2$fzI zEdBvvDV5L#4#5H4I8B)-w&GX-6Gd%QPt%hG_6b6I$s_F-pPi+O9_d$E10hy)LOzE} z7*HhwQ~>LO7>NMSI)Hcsv_%o7ssRhO1$m$nO_hSfy`bV4TgxcCXI@?F$2%^Pj#Exr zi^?))6CHO3ue8~sG(PJfyYCQaTCZpr6~0d)7gc)~3?HQjd>ZM}i7kDpaK8Kf5v_LdIzw+{}^3=UBT$^2hNwZ4qGd>N0TkBh!cw||+L`7%rWLg62p*BV-M z8Cs4SS}7e`Yad#l8QP={ZSfCpYYp$X4DUq^ACwLswGUHghEJ)(00A=SA{pXJhDDPR zWn_l;WTqcvmJ>2cV1(`B2#4zkSM&%^+5c)4VcA!W_g_0#Sd&O!edbwD0b>TPV@AHRmCAK%%tkNcI4 zUwc0u@MApi2Or(=fW*LV-Vmh=C47SbcU(oaqoI5a6UxC*dR{Stc`_+_GNo)X?fqoN zkIBrF$!vkC+>2BBu2Y3SIQ3;wB_}AoFH?FaQ$&I3vL93Y!0DnJA`hddKhJ%o;Su>* zc{YpnL*bd(?5{kU;G%NefjZo^Sr6RP^l3{n?-Qp?zgD4)P#T3>big z>A23kpJU|>0-;e1R1)g}=_i%+6Cg-|xKU1IDe&2!NEQm%g2Gf!VJW9DWYXt83|ujD zJf{@Y5UYSZ;%X4gx&iEs|M^}Q>5c;8vXR>j^G_P)Wv%p&@I=KS?V5h}0`7H2AYBn-4h!s~3vD9AL$1K@eEZLPWIdm-9&n`J_ z(n|=JJS~KEJ#7+5{~!Yu$AEMD6&mv^to&C*$FHc_Uoo4%9^&Et z^~>%UR6g$KO`0IzDFs5yhNqwyLgbeIVpdI1thRxx1u?6ZnX9Gst0kwaWh`suf@@XU zYfsBp|KeBo39BaLxp)+ul{}q9Sxyz?OCc{t*00sFER}Wq4z2&)9`lQ|`TLIc`X{;d z-oRgWnM=XMcdS(mZA`{&*t2ZrpKkn++ng2LT*_Rt z*JkM0TpMQDcqP06lKv^Caj_=}4( ze8arknZIo|{}j6+5^(@gx(f&Zpzj2tD4?JG>bXET#C^$xh)Byu=Hixe@$eGtRwNN| z-i<+k-fywRDg=OKD$&C2zGPHl&-rW6a@yCR; zW682@>jn^_08X(mO$y``01(9i{P1uBhyx_b)196SM($hkSN@)|EakH9TG4JIQeqCPZ|#N* zZB4Q)MdHEeY%nhXzzjfgq4u^B+fV-1Yen}(#|t_{BrlggX%D%mbC(^U{sKfIbUs#AL5 z&gSCO*I!qNx``~}PGc*URVD>;KGS2X*437Di?q|XHQPGJSAk2@-+tRSczoniG4Ne? zd~8vVnYT|{GA)$)BYsxw{1}3n=FNd+_ejX%x7Jq2c=cw(E?Il~$uABIodH--&jgDQ zDp)_4B!-|UJ-U@=9ecec#1Q|yWh1v#C7Qhqs?BaWcf6krUQ3wu3oZdKK#`GC8GCj10H@P!;{egYdZK0m$ESJda^!0E&5cK zzA!1VrpIy1fbFvKUjq(nn_Grl&(Bd3xSm_p=C#fTr?y6R9DfG>ecLR{k<#@WtD~4k z0ucm6Ik}U^V#(Myi9wVTop=yww156@0-#7uJ z<+nxtHY)ah)F<&wLVw56?{Pt>)3w@Hd(&kt2hXqpiB{>d;fvGt@1{7yAE%u=?W+XD zI6*Ot4&8b2y&~S&CI%7c3ITO53j3`>nz0wu0qYGSURIn|f5M@BFzKBpFj(4^bKgik zu~1Gsd&6OBZScnH*|(hG-no}m554oPTWbJto7uj%ymJrEm2X&0d$CH%0I~7sjj)ec z;DQYRdszoO2ml8;$n-_&hi@}lX+TMAGzB1l+$_d*8w)s&qQv`T8WrzWlnVg}NUJ@+ zolhGMrmfvRC%3`_-~Mhr4s8FIG=%)QT;BNUH3QoINs)zrw>)RHJSY(%!ZX<5bg5X+ z?5Xv)*EaVw3kDnEgvIUtky8bgR1lX^PplY-OkgtYC6k(h{P~KW=n)&(7qv=qkA-G; z_D=3n;<;lEt}z}+65e`bn%7%4<=uWKwwQ_qRHhTf2pmU8q+Iwk>SY?b4fZ5o4st-s z+|V%=`Nm$&4dB>;t~`1vU48R0QS4}~D_2f66+=+fBA~=_lEvCYoA1B>qCY6&_TMbh zxHxw2q1T?Rjp}`$TyR7z4NMgVGZ2V$&Y%W?Q=40T@Ik4uL5OF_Y6-oo?M2t7gcC8<>wmt2&gPqbh9!$oh&i-#sSk^Z>GZepX%n^e7n zIaZFgE?7tdP>UZ6m2uEzYQrI1Mn7ghEWUjH2ENN}G*Rv^544QIvTu{jB%VmlEaesF zhHx?F-DPl;dO-^}5Ad~q_#KkIU8-gfJmn`YgzaP)d=ndT;sv%LCNQj#K=RlwR)NQ5 zXLF>GQwDhUk5!85-+6kAf{D@;Pm-4HE8sR0w!L$DmU13f`)phz0b zwpw5On&rRc1g&Z~LmK{?b%}K9Gig1xTq1xeXp~USV+1xJ5`?N4Y@cax)>#%vJ9bZx zH5S^|`4z13GfN@)dJ-6ACV?ig*KFFCZRv%K=PJgmkXjCAsGAKy4`ycvK1?B_KkE6F zElL*c916&mYPjwp>+Cov$kkY~B;%{;JjufEi4w(ia)#ZW=y+=Ps@CVm_2Ia&bJfIX z2jYzzH=La>H4qS3g*ctitt{A#U0b(!;H~?SE;0>->j}M`u;4hS2_yTrU!Mftxd(Fo zwG07&|4|=$hiw4NWC)!RKOdeG2Yec|FEnEtYoV=c`1_N6$G<1%Elna4LtgC*NmE{4 z*{Mx{0L0tX=U&F#YmNo+IY^RU+>95X;t}pSiq|Zk-Bt_oD07+Y;yq116ZHrzz@z?7 zcVsK&uGKu7sQ5>TPkoyr|IH#DJ}{tTL}Fju5Cdoq{k?+K;1`64e^&aBMLKFRzl^5a zcl97S*Sy7B;+I&z@qbyQm$U`uQCHP_bXwQ*yK=+Yf%!`8@V> z9J(F&uk>rwRjpr+!~bQGre4Luoyh;ONHa(K8A$$ji}Z%cg~-DJx0wG}q*wJ{zWMSd zH9pUFz*n)>n5md8XsWK-T(UmS{K(xMyWVz&d+T8fJDMFk*Pq5R2S zkon!cg#pu_uaI(2{(dAP#=Z_we$FI**o^;1<*Yyc`;VUfhnOfspb+S963j{$;@d&h zj;SIq9NX5f4OAmSagbnp*!%~X_OX@m8c3iKgez@*XY~BlOOV0uYdf8geY$fj<#3~y zd3}9t`Yk^j6U4^?vNOz*J9A)Exw;frt-RfT_UJ3*X$n)-(AMcJJSh%MY(T zI-Q1u+Cdb{XXtpu{3orw?R8kz(emfBN7IngX%0FM0m`MG9_@ghQZ?#VAlWN)YJpBC z-j_ zUb&6vpoKTco^;8a*%ZSLwye{cj~NGSM;wV@hNsgQHFYFUBYD*|QgvokVK4bX+#-y) zWg#aYu}xBayG3U{diw)Zn-2P!un{5hHDuzaW#WH`3VKa<=6|(w57E(z9Z)8f4p`7J z3p!EppYHARqu&u>b)zi6(lxx%1tRDnRXTNOc zy1w$lY{V4R^hx#j*Gr8r3u}6hj{2Y15BYwVY*rs3$?846RLo6A~2j6(*WQIuih=pDDiABTAb-S^v z8e(_s^aH$ibZ>J%@3wLuum>4B(`a8+99(&T5O-A2PV<#e@*s{iTy1Dn8RrK;0dk*vh0Z*{J zqtauBu`0bpjo44kJv%ssos%rko%0ZqZS+h@u!^(pgYJUtk z1Mh{sa}E*O6G!SKLezRYSt7RLF*Y2nJUm@&d#N@wRKclPZcx%sP(Gg5KM6DRQyKy|4PXb%2N7w=PS z=Hngl37mFNnL4#DvPPixFFV+2>q`CsGxmX~+^$cU(Wq5_Yx6T@Azzqgt zr2!-iPH_v)Xt21Y z;U9V@s2i1(O@j%W1!zdNdFr-j6E5(0-yDm5eDUR&raa&g17Auk6NnJEsPYV%W!B5W zhJ!lw*Oq@mPv|vP$va8dU<6hGTr!8OdZ&-!_I08RV`PXbp7dzIa>e*XRhLGJ>9ZlE z1CQaFwC{^^k2THL%#|HVLpGX9kp8wG^G&~jfhsjj{sot7`)v^_*7jx_H4dLm$D1DP z*7=#&I!*MCx4zwd5p=)S<(KKi+v(l2s!Pi`&9e2#k|^Tu_+bBkCrPM1N3T0i@TB}QyjUP@lQ z+Gc5>Dq7QCYsG4bjO1uvEP?GciJ4jKRM<4NecQ9CN>?#{U}gYo{eS~4q44nXk3mvh z8++wbmD+(H&DqWGDA8ZmkBGy<5Kk5w)5{3mujFK-kVl-ZFQYWAM-Qj(DofjN`urJi z*WcU!0AOh#z|ANiz5^1%q9KlZkOI>@=tN~UBuJXgF*qM|@eDO2sSVDtL>_cwSQ=9< znR)U&Z|#vPO!1lu`^NFkLA1CG0iA=6a(|x`t|~~exDvG>$m*TLSt6?&@Owezyg?r4 z>I*D3)m2pUjBs6uxJ=&hqO{~<5qC~~!RsiL)(Wu?J+i6trk(Pq+yER+2J(=mAlQR= z+MsB;0H!~3b|(Vz0MaQ~su`e^tY`Cx!ML6!@FGElvZV8(+tj)G6$p)=rMti8xIeLMlYzMK~p{)JW@|8U>@ z$KTO2?}a=6VRy`e#`lI8?;I#aL0_Qt_}Xv&3aF(dS|D@4%8#kPu&i&%$rd}0_)b=gue=>C8rpfP zd9pgI&{gfbS#(`r0Cz61rB^6Vn!~Nka&XU{!P0oQW9-_J`ycB}(fM6{r)4|4E1Kmk zvI~J;61jPGRWtBJZ;MRL{32lpYpE)Te^UTwS)TItc}9udtYT3zD@S4c**~73E>v%Z z7LnqLR=8>epV{%%BRvln*yYpwWhVI@Wz`tUuvqq2=Hh*(j$w_+WFqWG)v9-e=tEtX z`Pj`NBTZ=(qx{H5dxhnrS9zlazWtbY>?vmc(*|jh6^0m^|5S3`cI?3zrgnRewrksR zGOMLhi!E3?VE!JR*iu9NJ(1g>6n{REjnn088m+J?bKPcD=cNZ6tpszVUA4b1NqBBc z2r<0NChVPAMF{?Ow|)2S3M|&YAncQh&$@4HkV-gbr4K*CzEsWpTh&eBVuNRQa$d7>#o>eZ?-iwwztQi%y9}l z*aQ)CX;;be5w0AeG3I_DDUg$|3D(SXy;)T1{J8-DFz*L0SV(dXsv3i$i*A zSbAIW|Hj#S2Q}F~Y@7Fer-zc89*Pi(lu!&!K@k%`x)=};tPxO9QKO>ka$GoL9SX7xH`^@n5)#AXRgvIaY|hDNi7=d(n_>?aP{&qA`F$7YX~WWVgpem$D~ zc0OB7%z5XKGZB(A8JjazlJluEXJ$0#>wJ!cm^iq&BzLhhcWE?tc|I4= z9t>$LSf1`eUch(MZXn<2 z^aBI2B;#gD77pX~xP-~aIb>!X_n73P_NPfFDCY}=7qR5p-L#lUGnJa@8}`OODf%H=V|2nbKVW@d+J^GTv!xW zEKN7GD3yO@!cn}2$grlmy)}gWV*AP?k#6+Oi(Uy2euE2+(xlF_5Eq z33s$?O$&S!Ko|q%6#d4b{bgo6#2Zb_dGF?uJcKL>qC|%G9DwXKDwO~mt*_3PU0o#t%o&iE;L4XqS%)=7PN_t>vNF?Kg^epw5J6Z0 z^k`cN*reG$2rE*QG<;MPTUvD>E<)D_bpmL*iyQ>eZ+|opo(<3pF9-=Cr?RpDLq?CHy zKmK}1`SoqLuJ7>C*|MFmrCc`reSK%V?oT>_OS#SkI+Dcg%FujRn6ir5Sz_cCwa)zsBz(@I3m(*t-(c7N?zEy-4{aJc=ZQYwT^u2riWrM%<6_8IayQO8W>6|4BfolD^Br|84GSEwtNKYrVC>pAY=lT1E-_0ugqgKtn5e%${7D72-^?riq&mBh%+&f>E4?=SmpV{Ys3(zREw( z%v#+IOUC{b-ukYR{qw@7rRYG^*$C8+$EG8_2cjCkg1A)p|unchEwGef{^UAY(axl zWt!a5ON+@TSw9!%pHBUmzDG!TvGh|!)VsWN$O{>0fnIv1F*`d;=UiWT;p^n1qim)X z?+~((WBF~+@<$JH#mURL`;e&B5dmJhqMp=s1mvGVWJE#xjj~mHL&$yyDr6#1S5;s~ zncLrgQ8Ez-le<_Zs|f5^MJ|6e)k7?3=sjE3ubTey&*CCI>vg)b)1|VsV-5F~UlM=4 zLC(J1@#`t-*D%V^X3gv)l+66eJ-KqQYx6p5E6zTn#pNYP+1EL>*|=#DQe3k*tZvn~ z)RlpJGCYJTU938Z3|nnyUb_J0FOsh;l51z6{F%kYnT%un`PbrYSE$vEcEmD1N64Re zO)3%c%j^UhevEy-3`vK;o5L`Wr*v}!&Hbj6bD}88>!Fu{5ir&1os$ekZF^TT+$+&7 zp;p&U4NdXi+KJw((>XaLJ9$Rb6JfoCKR+kh#vyUFs50awh#?KvKYQ!V&FG+(O;ICk z7`pGeZJbFm{3U}(i!z|}AJ&BYFV-Y;qL#>w|DjBavIqa;_8^y^|A$18Wn#~BbZ-4X=Wu%!w`IeO!CRUA_*j;gv`9d@lIj{69<{+fA(q4GW2H zSNrsTn>>r}Rp^la-DQl{ySL9fkAL>tUODvjUqRBr6^6_->eakMxoX4RH;?o74lbVU z+$f&=INEkFx8c&C4Lk4Uu96;^x<2yj$JA3f`G9>7=2J$bE9sm6x$~F%R%#~q&Hhf` z@^6$WDUP5@5wo$4#s8j?b1N1n!N*n$fc8yMVmH+%>f@<8tLyrxd<%g(c{^4#o^JZi zUVvy{&lAMs{RK2|peE{lcKsPsIQnoQ_kAwaJBW3JMyFF#6;ZYT$_F_;ajs~DR25AR z-e0pB(QOnCT4=4L7jOM<;xx7mBKQhnywr(~&a_*$6{M)#IT}&4Z?fUzg@j+}TiH6S zQW(!(9O%(rXCz=Js17;u_-Fsy&&V_d$C_Bt3;A77O|1_S^nr@^pOq z<+`lro6ofL8`!O=HSN3^(mJ&I^GsX(g%RDvK$nAG zu8;1Ms|-c_JXzi$PBs79**o&f^5#@+)7P$wmG{2hk_`OGWh5&YU#-rvKKae{=kxgR zov)p-lAGEJ-P5VjH&3)|M1PCl-KS`aJerXiwBt}eF|zslfX=Cz@ApU>>Zy4B;^^7? zO#>tz)&ZxF9HiW{uq~a%24ekwzqb7`?DRY9iu2;U#hl1ZS6Z$0#L1nbQH`FzKz6|b>|v6jC^Bfiz17>laAd~)xb<}bfqF~ft}9zsWHqA@t- z5Nvq#xAe>Je~qne)_BAb`qzlLCRZH%d@a7tzvp>aEld<_J-qOtB=X9_WQEi&_9H(n zXMUXMufUnAue-ANsrkm&#m_DGtp3cjzc~EoOXtTcf4+AA{`%*e0JCaI(ywu3>ATS6 z>eB4cnr}-#L>{aD&OO_D(E}EL;&Fc$g)QK~8gqWu4uxlo+^c zjePVPhXT2MJUe4REaxleQSS0%OQXd50;77v4vAANhlb?Bh_^a4k*RjoS&(K)--~f3 zX~Rrqxb&pZMgQ@SU5S$Ms0%6ZQkD9RPM#8_Qem^uK;xe0 zfDJkl3NxtGd@*lz{!J30u6*3Xs-$=AauQ1CbdUN;djB1}{iImgJR-)+%DH+1bwgstw?g%_Ld+x*5n z3^zueeQbnxn%E;a_}o|Tjhm;ftE` z?I~KkIUKw8XCeKJv3vghXE)gaiPVFW0Z+^F9-#{LG1+<{zs;V6Pi|@28)LQ}%-Bkw z?JG(C(q#UA{84bgNQGRexs7euNQd%C4njd|W76V_?EdTg(ZI=_mgKx(zn^Wh>uP;8 zxAXYY=@Ulitb6MOV}nl&+H1a3KQ9xzM2C7Gbvhb)I@M={Sf)O?VUn`@*uBs;D~iF* z=ATjKx9Hd>N^V_;yF-=MHt~9BrwlMP`;jE_gziSMiv~I}bn8jBoT|Fz zhFerd;J!}m!xMVDQ5;sPCm_!VaaCSszkAs+*NaxDiTc7wH7KyvwPy6d$aj!=vU&^F zKGLDsO!!Yxo7^q|g0{2=<|$K22j|mB?$i%SL}rZ&CCRvYkpQ#wqitA6iwKoBB0lv= zRbzo9s-GBP91~hGyAdlFK^;GgE@)hqxTv>S@LF!FUn+UC+b5HeT6CdmA4zyEY#oW4 zsPj$_Zs|qdz!AuQ#Cpr4bJ-_qN0STU+E`2X-~$vWA(p06N2)jZYt4B)ak{egmq*Q) z=#lQC1=v%Ss~y1*s%8=j2z%H@YBqfiM21Mko)Y_a&tt>`jVLK22|7l_ZHZx{R}uSh zSP7)Ax~F389ZKQCcK=9Yjb>;MsI}Pr z{IX3Zc2z@f`lwhRcIG$s#G#)D#q=^NU?LUw9XIKG^dy6U zF{23Dq>oXvnp+?9chw*A(X}hOTd6#IqLW11k49ky@6Zn62f=ZFhE6n&5g>ghz!e67hP1>Er@ zE$>OW^8>uQi-Nr)Rbmr~*RXq3*mBG4wC+r@1Puc^%RLxErvOPB#qea|K!ns#Qk=!Y zVDplOpZ4+$JFDf6kpzhmV_&3QegpF-zjWGi?bxQh9_o-^g+kyo!&8+ zTX36~)Gb$yogeP`gtO-PEMG!c6T7$0h^G|;!=OM0TdG#UI&!xAy&k#GuKqrqrzqaF zC@o>BIOm4BXORXk>ah#<@&Q!rE|Lp?Y4SLofB<1J^mS{3nHV}oIV)x2hh7A<*Bx<` z5Y&X2I)H^>A0d&*CUj(>Y_dXpHh}_O8kf!6A#_C`9-y^;ge-pS&sqbkMWGgrcc0`T zdbYx`%p~ME_Pa*}q=c|$u8sHD2Z5k9ot+Q~KTkUw%)pnd1|_T`N&v=MqBt)msIP%- zD2a8~^}lXC)#Cz~@6|CAMJZI;X7Mpd3b;%G@sud0!~>}h7~8no2+qp219HC!q0GZC zg0Q|KRDuWvQCw{UQ>4se>!cD$x#fhE3Hb?-#&mF?6=@X(s4xkcCLTK};MQM|nFwV- z0vzbLeN>zL7{XDK*K#D==(zV$KJYaXh2~?VV(?%Ka#ag5=_DbPzQXt&!disFOEQDR zD5?o)2*lVH;i<*8?ev4T&x{)RN0W*W&MX83qJ7{Tq(0&pl@UZaf~202k`NZWy#>Ds zvGZJL9BKcHFz$(xr{bifq|?DT*|3&_nDCdn>g)nF*KuclFfWAkBBn=t|y`+pZ z6&BaY4i_jP*t#)B2W-~K@#!JDnsPN2+a?iAYKbueSQemtSRPOwssYHo zxDT)ppf|z@qf7Wdrm!3a!-7G%`_RBRcnwp2ARY7h9O_3$o>W$P&2m#A0mn{y;3X(@ zDJmfL%wjztOITZ;#I-ZAXe!zSD3XfN(Y$=M``IL^m=McyyOCCMQJoOTFoc}x8&~}p0Bt!=qNBXv4 z>Yk!xEzUdX2>2OjCP6Kl!lsQ(jlI6hJcQgrwUn_&%Eyodm}MR+R19XTL_3N&@1rv9 zOkhVkZu?f;ZXQ&&A5|#jAC(HQHauhxnp?8ZAc&3%WB^EafL(%UtH&6d!L6NnL-T|i z_cqvw3C~V?U>6CM_yXHsb#Jldc*ar9`TdLh%wRDg2~%6r!3^Xf4C#631w!3I!rt1< z1S(#}-C$&ehFJ|lAN+G4DmI2mye9Ri3_D7c4mq#qW`<3R^K1)R))pGXLzn<)UlPWb zw^ywM;VVWLc;FJra2yGAq%x|Yas~@`A*Nv`5QB6_qv@y}3{OYbunUcq@+~>bFu{FzQv zvz6(!$Xpv9%gZ=@W+OinnTOnSZZB|yS%9v>`#g7`-=JrpW`e6c5L9KoqYLf;}`4dt}I>Z#<#{q{v&%b09^N0=S!{3ELE zq6vKN7J%mQ5!U!U;lNG}J55s#ZYpl-#zo_GpfRpoDnTWX5OUHMY&I4hOvPJMQIgYy zVgS91x*M8Jw(P;&{dEoO#Xm^h^}udTu_X1vM=y?BI*AWtyM`kwJC}L&yLpG4nb6{V z7{Z+JU4Xhtf$HjOmidIkEp>=-q@lQ-e6P`$jxaNUj~)Qf_d5@vj;xNa{W)6CAYplH zJ6^`(Hx_67vl2$Pplw)~1VgL}iJ_-?{qt5-b?FVhF`*)ZFUDM&J%L{qf%l4!<5?bl zi>O(CQ}!a^z87$;HuZBXVTC7b8H=d16)0>kLmb^}I*|K1a}P&+b4@uL2_vA@Fh`Oa zsNVQa>lp3$l`D&=jdaA;=ZU+SxPZ^-vx|wj(oZ|%w!!yL6O7#3dds1dTLmS2;cg*Q z>p&w)DK?PTsO7l#%Gz}6Q2&FHRNN;7nz!Rr#c`9~+m`-VJ+FUO8$gJ-_@oyRD1BMq z7|WZ;G}h#%c{W6n5UMYF%wDv;`9p9JU!4DiGNuA9{PK$fs0d2<`7thuelBzXvtmi6 z|ASj6ukE5B^)s$Jo{BFNwVZAQm;l)Gxsl+5u86}I+hOnMAWTolDp+zprWCiBj#K-kF4XJRbikSnS)vx7$g(-Eb<`2 z8uDW%MKa?lX0Q@~HE4PI%~T6T1GxKdJ6gcYbd)m-xVsHL{~RSpMWHnlG|DrATbMGv z;i7NHk0Rvi?d(7Xg2h8b{vEpL#D~E6M^$a@Sq99OVLN&u46h!*mXB6Puab;@Fy1{Y z$*__fU8JYwW}nuv5G3&NE2xOCChf+I?p4&A^Q^4gGaf-g=&%U&;{`|00-HdF@6?ag zcwv9T`88+iX2p;X2~f2Fl<2sRpED7acnco#hXu%?BVh@bw`uS<3G!j&R~ly+OESGk zc|k2FBBZQ44Xh(Z{lN0*?SDONG(F+xT+e8L@b4y|j@0z;R@9wNWUK{zaT?jkh-qJ^ zb&}Uf)oOrav?~;V4BA>@IGz-axmz+8&bT zEq42XZFM#{<^RE+X&=62na5aPXuFoM!JxQU|2kdgd4TK~SYyBDx%!qTnT(>1d+S7- zcD4{I?bgr`gqE>Qr`)fsJLNx`N!_tZPPs?|6M`; z<*9i|-f+p8+clma-ui9iz^QQIv;6@CLPFoMx?~1D5#K1lSefs( z+x+W?5B$(_ZgbcP@;5SO<+ek2>1+P=&Mn&gx82`TZTo1j-{M3-Snl!ApF8DF^nLuD zNK@Oe@-FBZ;|l%%J3iH+S}$J-;IEk5P)NSZDL$ZC9n{w&AJO zd)!3FX^}Zj{i7T2pG?{ooY7s z?!Pb-aBKY$yE&26ln@l-@2-7f&foJ?)j`*``uHfSEE{}uNXcJ0(C03?tG!m>-EFq{ zmb0Pd#$N-^+8kHb7%*LN9!(Zown`@?m&bPG=hV7BtN59n&d^36%GG8oPi+J;btE6`n$zkMxZ7 z(-+H%OOPQ@7SXem1*j~ChGpZH*x~6Y7%;^b44Oq78H$k89AZ$!7PhkK9+t!*4u;xG@$GFbK(Uo>9^ z4VjL=PyRhI8eV+n-HhK5GUKV{f$}*PLNx|%Mzr@RrqcBd z>wD!wnE2C_Dmh8;vX0BkbClp z^HkX=P=(wufEive#H3HLHdOG|uUhJhhDqDhV6T*3+daPfu{#|aIDQ-S1wWH7BN7f!YQ^WLuT4cbP@UGXjZGhC0@$Ja_wUFi+^W&E`Sb z{1(x|(!CAO?|UnC^4D?uCyi#VDHzJuj@?x&VSLM-`DBzGKi@RQ87^}rE0x$s$bFtcKVPnvo2GG%hm=x)D+tP~$G)4DDtr5D5oig=Y|eTW z9M}uQ1MCg^Y**Brkg+`2(*|{{;mBoNK=IDuHRC;LDiI(O)A#JD!%G+sekQHJJu^(3 zv&$I2gxzK8;xwT|a3?Ypwpv1ZVWcE`9T%8HLh7v^gcDeNv?24bH{CPuL4Jl4MTQG& z{}7Z^_0?8PZ&q@6X^F51i^uQ(P%7)>(F`%yKT2xO5`%p?pVHTVJ79V2#uNDBr`ZiZ zo^0mGCG3&!OAb?6jHYcK&;6^!SH8sHK+59~0?WXh$$H3(KIi+IRG{BTVnIXn^uVQX zC=hU6nZe|^czXECI)91s;^g{lX+-Dw1FcS`Gp5fcQ#kLsFq+6c9MyV@x*2bc11HMp zAMf^G&#jy_8XLJBZ$u}UNURQn_tNal>3|IYPO4KlM8nkE8z)?wDBCPbrtEeg9ND^5 zmh2!wLODu~(ssYHv@@)2`t{}5YsG7~mDYy}Q0vQais#2C9BfRplmde|6UEZ0!p#R7 zg)3=)4}?7Jzan)=(Xc8?QtX~lUExXFd0&8}2r5+(-`PmtJ!v|lpl+=wIp{l;s}eCI z|0tYII7ZC~tPg{NNGvmBRyt15hbM-+$S=x6dN2vIQGn2NE;?vl->bNf#lqfc`PZW+ z41z_;-J0T*bAdEK>de>?L}I2Yy0Lf|YuD|D0H(y!9+NEakT(!R*l3H^5{fHEOy$P+ zlN9kxn*3Z3Mib@{zB4#F>zRm>c(F1>WRutavc`6@9z8!)`lHAka$#CrwLjhI;-2%} zs*@EZFKjidQWp}rB*;1zqibjVtbYJdAz)62sl7YwF+oDN23MzCM;ey^D)!OrsS2UY z~P964cvng-omK_a956UXaM`ICf7jH z951+lqO+pAY)#;+Rxm`NfT&Tn28nfwgh&}(9Y-ThJF@M0Y;NW)F<*^81^?J%dcE=7 zRTr9O!gX(+j7)+AE^F5%BsMmgTmqOlfO?*62L_1Zu}1qqoPg~uKv2uBYr`Ptrj8bg zWnjm$pabfjcH}7_fX_jeAP5vdWe6k_k%Z9=V2h#Dq2wR$7IQroV8d+m`0gZ1M+7mF z5*a`OoNPpNU0-h%E4oc{Kp-XTr~X)537}3XFO#tBC2U(DnMwy%k&=vvoQ*n2lmlCv z3F@&BHlnn-aJF4Iw8jCn_2ei!o!9m>C<*~qXk)Sb{=^o0@;qijpS7k8*AF6}j_K-6 z-Nbq(Cz6tRYvs*_C>2K1{Yr?|2^u_U_1)p7!N1uZ*K^RHuQ`G9gfbWn#pYddyE*FA z&+aig&E7(Y>~JAbyc#|yd!Hy-LnxI8fLMd!?JnLW)Gtb$#@5E;m6sAd!P*Ad_W@8R zr6}@PMzib{T$T$}!`akE3fQEOJs}%D5_pzmHJ@fAaXLz?@W=yKkpMlCA)=n6O=K%~ zvsIV~n3xhs0<^en?|Ck}1|S{b3xBo=B)%a+M8umv1jlE@P8sXa*s0V_URqY_ygJ(Q9kh9T4e5J6#S^Vk?w zBucDfLqVyJ*1ifDR1$(|bC@7gs3WG7-2$0&%|~cui9#=s2(2GQpz7Jj9&jui9BU#5 z6`4t^rrK6{Ldo8IpDAdy$lHkmY?ZJSg{aO7*4-u%w086QSQB%S0ov2i#neWfl(Z06 zQbgpeC)vqTXV{&%=gM5U6G;Z6X$B$puNv`*B-U_Gnn5_HyR7)in7W4!mqxtxC?UW! z`-$fsWGwH3)=Mpjg+cS~jmUTVQ&5hiDit9}k+rn*5Qxr)Qh(EW13|^ZOvJ&aWWv+# zGc$%c^R12F0c9tf*m{Ued|)9FuHrr-yf^pof*cQQNpb=S_0W^XHX}NVD8ZCx-Bua| z^|(pi^~kAy?41Oy9C`|EFZgxhcEgS;Tn5{|Guh6NR;&8dpPo`*;qA=exJn>IK3k<_ z9TE;W?YYG!#7TV=!7sR^N`@jnBw2ML`yH=Yg(TURtUF_x>_W%E6FyphIknMFPV^L` zu!=mQsmW61nfVd>`9XosonP`!1h|k5gQuAfv_S+-NG@U2#UEQ=Qwg`73rPICm315E zVo+UHAMm9A$cQ9U8R41|0GBUNZ&s2d1A4QibcQT3rDool6wu zux{^s{qW5NploF}PFgXyg-`)dfF!BU4v+<`;|+l--VUt(yoEmvnS>x-#NU2TyRoc_#r3AEQl3^?=d2K{7oB6h zwq@Irl)eT5iP#pmD3kfBc2<1SPce{~xr-t4&(&`-H=s-(pkCh6nAch7i5l7o=y`Ha9J_tBCS7F| zYx0nz?OE3M?176I;m+_Nz^hhq!MH=4$pBdT`7WEcapU7;@wIfT=Q}Bi;nu%!CEp=m z9#QHvzh;XdN$&x;$rM8Kb}GRjp@nnKoTI}+C{f=gGNIgbmQG1Wyaci}g&GA2UkN9W zx_X^R3(G<{a6xx2=7=jx#S}7OUB$v+{oU-)c&_hB)zc!R607vgXN&ExN=5}q#Hmfs z{ITW^p((E-O!lTXy-QO4i*XXAZHY}IvXZb=z?_G1iXwj_g6kOX>Jb-l)g~tM8z7Zr z71^~MgJVD(+Y;NML+`{fuKaV&;c$_7i^B)vC6tSU=A^d%wpfL~Gn{^|xulijVw&Em z#qOi)qg!OVdS!NBp&*Bp#$E&gn@o-pv_2iyp1wjfDzrWvm3B5NK(Ve+#u(iK?@His8B|zur0}??CI`q_k5GS$o4R zElyYalDTvA`XsSkAy?bCD(d(+fxb!ZX<3KWDG~ETv3e zFWKK>W$M+H7Tim?syNMIST-=LasKu6F4ca|G7sze$5VuRnrcN3#Y)^H&T)C5wRVhN z^Kz7{eS*Sp$%=IV&n-nJiV-FxgbN9o=GE{gRQYxQIecyYUuvdQ<#he);T+5ue#dyG zRmfOt)8!)GRu3h)f?DjEu7guKUt^wC=ZTE0dJ2r+VLu57yH3);^o;gh`5e-xqOPyi zRXOAtQs#wV4(Ovc1AC)60w~xc$Bc=k5>ZeGskuU33^GeAj&aX_=`w*I^p^?pl>% zt&QVB4a79v0GnzMeMWfTGyghIJ^GWbIdS|*x`Wj!$K0O|GI(U47GnSLr1d%Vf^RMj zPyNX16(qg%hN-E~s3YrcbfzD%QwZtJikv+Vxxo8aYcNDNlQt8ND{Ve*uV?Xyd>;6o z%MP=zmzc#;ga4HA4r}Uuafcr`m=;Cpyy9&cA3xsf{`}`Cwy^3t2j9r{zHFZufh`}e=fN``Q8?m z1rN**#9Hw%T77d$EGo7hXRHndH%fgBX)b^; z6k#I5XpXXtYLH4yw^?7#mJ&fC{cF^b*tEo0DYqD>DFN^4VCx1Un@-S#RT^uWu0>2q z6d@AzQm~%eyr;bH-C|QEY^A7*NBJPm0pum()J@aLonGEVuGR=*Yd09Niqo8hfaZHD z^su}aKC6E~0>>Wik+{0VxT#44UUK>kGRIpY*gi+4NjNG*5Z{$%P`}S9YP>1`cJ=wq zuC+)TK7{JDXfRD~>WahFgGEzNVtsNX3SlDj%9;|Ru1)4y;(qnUWz}1+l2~m>j=Q@% zVE_|;wL5u7LV6mv^{OFDUv>BJ{ca*c;XifzwSF93znz*P@`4yBlIvNvV#sh^37d(qVgVrU?vr$< zBBoXf46Jv;-8Vif#c&fLjIu?Pgw&gi*RYA6lIZtyl}!SgqrMvqWNEEAHZ%3zP{=dz z2reMeAGw^7V$J3?`Z5|4BaNrtyMERy#C@CbZK)z$R6{^i$-=2m=T*!joZu)k$pt6( z_6iHNiFQV^YIFumpNhVq#*rE8uQ1kr52~Qeyy(xrEMIpX`}pMY!QWPIyW@V(e);@+ zl~}+5|D6&^=@)WQk%4cXzDRk9OU#$9{4Ux^!xI{tg%Yqg-7Kh%8Y2il@C>)6gDMS2 zLP%Zj`ZuJx=tjJnO`$P7r%zYAy9KgVusXctFgr0=YJd<)lbzt(5aucBCP(=`eovPNN(jFk^twI#TO{=l}ElalgvE5 zyTSNQ3ld!B<@GDCi}shDhXVP4nTn({2}jj60#p(Nwrr%21y%FNZ%Tf@oZ91%jUl>m z(uI{Jdomo2OZS$YHZD`N9}po8xBwfAtzg_+_uUt!=^*TD2^TlUvH||#xJrDGEUu8D zW)PF+QNBU|(u&d6oZM5%3Hp6p>FeVJeP$>1u?EyoXxva!7DsMuXzU_4)g4|e*dSR# z=Vwr7rv^>9lKI9b&EKZF8l1ZZ5szwTqvLYTNQ1}W%Zu}I1Se|+BffM{Zbx~d>s$8*qmu`M1_HlRcgP*m_cJ7zkuMG?y9wL9~ihTZKHg0BkXO;*R7(cuA z^ewuk`Ru24ws$I?%NaI(YZ*K|$Su6@clMFl&X}GnpK+HPrdz>B=J0fx@khe*rlwb; z<5zt)tp7Q35m(qfyLvkkv9m-uS0mI2L=&YkjFfHx`N8Tya?evXxNH8?W+f?0N>7)M zX9*INHh*s0tklI%KZT7v4y+p+=7+6+Pi;Pyuy*5gh=MB0LCEZl)>4(Ta> zO^qt3u;+@+6Simy=HaBo2>sJ?3HtKkrhSwB^5p#T-SYJ$u6Gs(hxbgDiy*O9#E^pX zwbg&kP397N4CU;Ew3PwhjmRwa+33(^Tg^~ur(l$7QD$cYHJ%)>yNp!m_{Z|rp%h%!}!49 zOL~HDHS}uvKCZ>FP*7(UsE6%IRs9c1@~p+~5V0=^`eY>OsfN2a#b+{Q+e|M)CeLuN zf*$-*EJn{5NW+o<#@mdZwHp~J@mYNQ(N2$Qw2Q8}=QWZ6?_aZK-hEucJ-h|O54t99 z-nmnxz+r-F?mWxG0qs@lx1(HyviijtDkv8MDGXCDX)jQ*z99$|cNz}u$pUNzpxQDG zKWsFPjGzc0B!iP!QmOnu>}R(!OW8p}!%M&WrfNyi(d69^G(fFuq1yBuvU3$=otA|FL%z0?wrEl4Qee;65K z!)%%jY^sJH2QT6UsK|K_AFNMOB9$e-lVp@O46u!Sr%5&vmK;5xF_r@9zT3&t9ELGq zi~vVsu-5^5lGv=u^}4cLs5_iw&p4p}Q^k`k)vro)c&GQJfTA~gts-dXld9KINN-+= za8@cAZ!;kV?cdV;PR;zXa;Olua@jvc=Pn5s%Kd;-rL(D?Q~)nz2drcvydB2%4ibAb zktASShnlX7FHKFr(gs^dLa(2+&@WUn6mQErgglyeZ5)8EpFdu>jHFwZ}fEX5j1qp?~wg4(dJyQAB>z8z9=qcn_ z!2hpi4^ALrJ8zDC*huWr!X9(KzpYLV=`cl0GReb85nDx$ciYI{Q3uO=z0ssKh44@^GR0byi2V%F*wlV;O-{L^?99yGkM&HEeHw|sh5seB{~jm z4*C~!KMrc|uvZJ=XZW*#8U)DJcIP1|@};$PMLU#|L!LRz0~xgv5BYt*hj2Pu)g-39 zxPlo_UZ%iE1PYp_dr~Y497i`=bQ%v%5FBL_KnDfCo1L`t7DpZ#EuZy!5D^rq`8r8? zCybO!rn0nDAp*%0LagOsR|i6^h?_V5PEdHbsrZS1r3?2C;PS5(+&Ao#Mm_PU4}ujU ztKmms$d3zdpJc<4^45v#XTqgAvSZzQyNmYV$@d7o3Ywy?Cr3`KGP1rJQVFc*#Ho>h z=135!+X>m4_r#!yN1-CcS&bPUN<9{Uz38mZKg9^bjH{^)jRg(9VB4zv($!8B9xl{6 zAK$*D_kt~;u`|t%N3|mu`y@7R3qk?0`*s16X z{3fx=b@-dHVTyvDa*Duq6IIcTs#pOo#`dg&2)g|&jcShh7%h)VMRKX~6c?uom-3br z6}Z~4KQl&s)tOtA-R7ozqkD&2my$rYRPFr= zFP_O+e@cq7^8J(L`@u<0;>(gVV!IadYPoN>#0(wZhP)gDyU+U=Y!>7zLFk!11(w)$b`By-n;4akq$d6OSaYfof&ePZ&)geH$go6dHb^zv%M zY|?HG<()xfinYcZ;ZF(*Syt<8dFu={x-YyncViSm9j#nnB~XK3F-G@bNCZ&vbmGM!tz>cen&boxl&JIlBpjgS-nv zkGQ5~wGEpZInK`r;mMH`K-Mck)vQkP@zf8^$jxD4d7tQh8r4Iz?#xMHhWh@DlX1c^ zs#{f~*`?Kum#k{lN_vtkSn@)QZbFY1t4B+eTKTrG?=|8dO=Mk0;f0AUS1N|F{iRq( z@Tfd3Uej%B1xqbCMRx`yROj;32$Y4X)l z)_sNk)vd7RYiizyPaB>AjfMB9b7?dY$;A}Vh|W+6`Ap4%oOBAX&%$Z)kQ%8B3;~a} zif-+)7}(c55QaqOlU?Thlma=Qrz=12WouMWJHyP~V!$7rq^ArB!X_ICK(3eGuheY|WR`wUTupUdRt3NCBz!trJN>I6}TfK5}x`?u!^;i)9ZD<~gyr<*=w{sQyK&aH zWbJbe&$pLzpzN6fm)JaN2}eWc*_#Z}n6uS{``56t{@1n0x^_3bpTJivP1+<*euj5* zRzT_5xyuJKXhOUm^AiW_)*07KC@GvhwAE#lW{nO!&1EHcUHSUe>f6AsJrrc1(Lh+T zVua^_=IQ3-qp5!d$jg+TZe2HxPMTVl#dgo<)Yn|c zqYizmy}EeiYSc*iYc03pD9kA*typeas9Lg)w;;YhZ9@yNZ$$U6qLD5nq{1%7J87gP z1oow+91=?lWJB=NH)gW1=vD<5TV)jdbC`lTMUmIsTT4P}J5{B(r)9KwYIgrGrryPy z3IBor-~G-m=9=tcnEPB3CAPU=8zz@hbE#A+q*_w8xs9X|C6(rqdxdV2YD0xoNF{I8 zNTrhZ=%(_v-#*{p`JVIr6Lz+9_If>EkLTkFSRiEQC$Z+f_PHmWWlGqPSthl2%$*;O z@nJ^Y{m3i?7_|$K7&}&}D*7dGaNQ95#ql@-pa$-4NAzhM!JJ@U>p$Cz+&J2QzJm#w zNMg}z>>mKC4bNg)fwe@WC8GEJ@jln{AY=aHc5Pv@Lda|b%9a^MN>-QaG3PR43c0Y+ zzm1Hwr|cT!|ph&509-93nPQB25x_o@UgpG)MqHU(`CwgbH6H@YkRifQBgYsdv%j% z&f5o5AA1wm$88slW8A0B`Wvzno1Si)5Biok6t>)Mc6-7sjE=%PIR9-*K^48q)==W= z#-;}+6Y2)~{0j$FCOy|Ms2xQm3xTdDKf0;{zej#}i`ll?A^RW1;4w^EYU0%ty)-uY zyNBe{_27qR<}}#Jk6kzJJ75Y4b9+>&$a=aM(4};knDB6qI&PEa;8$b*5@0qx6Viof zs%vfBW`ddabu61hwk;OSl)w3dxEQl$y^C&x+m>CSP9G~Fb>6;@jAFh>EslSnJNocX z-nCxkaTw7m+q%~0yS@6xJmjm}3qCDsY|qAQKQ4RG5d0{+`ALT4Lg}^WwH9q-gBx$` z_*LHRmi=_Gf%J!2r)q$-anMVB>*dJa|MUdQvdMYZ0Kks!b5%o6lin8$Ji3zxMALwb z|FX!1f_KoXNx>@5u2qh$G;~OB{5b05PhK@%;PrBC;FTI_tMyl3TWQG;!eV zrR%$Ec4&O+(U5~jKjE;yaX2I%@2B~FI(P@Fm(W(M#ll}6)zjm$@rA*klIs4ZoPU`! zZ1nh8OlQ%Tgz}PG%=r7lrCEIZ=)f<7-Ypi8ZGvCzKQ(?LG#02|H#+}db_h1tr>1Wd zgI+&w!6;ehh9BMsYP3iesJ-pvM|H`-lk?`T3h;~l^0kpgMz^-Se{&;e??=}?B{;)p zr}r~ag`wu>LoI#_AlF7L&xp*Yjg4^K*82s%73`~a0^2AO5OETbct%@KON)H+zeT3Q zx|3@wo(43iM5|&?I;}ft;W~!o%7ueX+K9NXUd)D!yoy)ykKPcyX_*F&{m71~+Nz#m zs!(e`9W;6khJ4Q&pi+cI|S*{)NE_IT3n>%V8>bz4*fnTM$09^G+W~IekzVLEy4A3nLEg zJ{i#q(M~#VL>FKTiAh7gn<)?@`dZH!`ID@<660Be7P&_4hb?_fu{&JDf9>icC^Egz zBSB8^?bi2X9+~NpQ^X(+&}`Lx_aQ|0X0||M%w5TH1?=v=cf_VsudrY5_$$4lPkJYi zOjL&aJ~pa&-HxhT-H(72sr1wMcMOn;j8s}g<7@j^5gpGQq}7-A)t20 zvqsBV*X;$MS%GEgdYwQ3EXR{fV-fmf=WbnMGKBC3H{OJ+)~4I3edF#EcAHytOwKU_ z_wUb*wAH$n_wM}VE2HZ>9&iJ3fW3yUtOVeH9N<~ih&ulc$-1h3m{uM;fzy(K+eN%yt*?4VT6@Apcf#ik$UWHp~3 zx#MFvB`))O`#_J47kk$pD|xzcxW@0a(-DLHJD)d4-8}H0!GWY#S9iR;aik32Wu-FZ zRxkyECOvLsgTZ~sV17vB^jPXXDqPR7v_+5aHt_ZiI|+i55+B0B;q`Mtt-i>-Y|SQx z+%lCd09@XMaTZ48p!7dmeNWRLmy?PeS^0w3MH}DMX1*9VtIN0eM9%-T>^F5x-*oX| z{e_0m_t_R0P7d}gXD7C@jrjSIz(3A6&MA~1{qBa|)^o)VRIdrJ zEm15)uV&&z0$Qi^eYQcc)XPY|^IXY*#icI7BdhBZC68?Gc$#1C=pMOL@aCwoY&9vv zISVtrsRIN;5XasTVGRva7#Aqt7H#O-LCvwS0NUnBmh!6#GEpT8^x8`XKd z?`lPOW+e$6f=iVne%h}5onoB-{`~1T>0j^YzRh@)KFMv3<3Qb2_IxlH6W-*&0wB6@ik#fj>Z~iH>F;)= z!2z5Mjcte&Rb`vwJ%J7&E8Be9Hkll5=o=e*Y-KKvJn?t&tEh0*sl@W!H_Y-T!jb9x zdNkC+cYiq4;KMIc&Pl=Q`cm`a0SL&IENEKk{rzEqm27BxsjZ${w4mPm)+`AdsD2&X z5qr$Z@5t+;XKz^aITK%oVSGiF&~iXKn0tp&g24syt3bJxR#Suy?Jei#AFRwYOntEB zvq(r?l4k*JgXQn;7@E>WK!|!;0fKEA$~!@2j)16p|&rqBJ2vv{HwX(Aj12?)$6(MW9NM?v7A5v*5ZY8i3VLnB&UF>+M zd0r`=gxDg~&g-V&SLZZV$E9OUoIRBj#D$Z=&okTYphjJaoW7MfVfd$Rgi>JyOPe%` z5eu~n7$Ry{*6NEro&=@>GN`{Efi2BCL5O5)RpN5Yxs%BEDJOL9DoNH!>(Md3)rS`Y zjTU^L&&>g`w`Os9w2?gYjxnR~#aSZ*)RgAovF=%!@zFawtK0^q0AQLB?=lK^<;sbr zEnWo&LJBnZm3uVJ?jglE_nLSQd2GAB{n*CrYMqB8Mq7@{_Z{l(*OC85kk?7CT z3^PmMqKxK*>yFI6gTQ7)?ipi2Vb?|qU0O_u-#UCk(xImw8{(~=HkSVS(Nz558o~PD z!$-~!t{yJa0|JvmviZ*K#a};(O2?x(Sw_Sv_=tJ^#Gn)_C|oNyDX&3Tv#h zK3zRralLHY`^xpYX9jQFy>>c!y3&4MpLoL?Nwr7q#iyq}J>&jqI}?A#GO{<{Pb%6k z_Bvi?zdf-cb>LY_RD$_Z;+gQfaXSn%R@C&$D0$LB=9jnU64Z&*Jz{G@RU zp}l|!A-#(A#1}Q(uN#pZwke!Mvv!3${4B;7ihWk^9f#hzfvfw4i^pp=_R*?!I)}^V z(i%6$eA%|&__o(&+aHtA1NkSge*{MUJ8^K^)(z#-93xB*5Bl%hsQ$JeKZQ-4XjHK{zbk;|l!ix{i5sTB;J zoISAAJb^D^;5wU&XHM>Nv&jQSb;V9C&g!xnPxmrCCPy(AhZzHDd^oUUarDIk72oLajy< zF~46v^m^A8mBE-}w})$=gf^bq2S0K~MkX>Y*($Ph_=+rT^>|0LvWN5s=NY;LvW0PT za9k~8KhM&fTX#IM=c=HjY2h7uO)q*J{j=*+%-+LqSG*NbvdI%X7tIh>$OpUt5_})V zR|t_Xi4db+_c~lI0!%D}w5I?>pD<|Q>i)DN--V~sHjdTo zu@cztwx)G_bNaIjMn4+w1z{S-Ej3<^gSQX$-=9p*b-)3_KVH4)ydKZDA2rViP(38u zK%RyFX6}qj&j%(dK-dfmFX1gu-N3B}5#_NWcJ;V^Q>#Er0)mUg`Jel@9Q}5I^k2j$ z(e~3FOO0&bT!w%qG2lc+>Uk;wT%Ax>>j@>FFu_ROeKl>Zy*YtO6Vur z8CIqK*uO(qRk9OvP%{jAR5Vp|cj(Lj;zI5~X^G#tWOHeG{?)!l&+Nu_#ZXnGA8CB( z#^@&}J{or~4(Cx!3>YTfV^_yDS@HeM26z5SZ!KicHI45*794xV`SZ;W4=V~$6>}ES zC4an6h?DFS@sbF8r>V3cME^8i7@e;vZ#|>Z^EaE=eM!w6MB0VtBCDf6tu!hq?ize# z+EkW?Kj(R@yag$xe{Sl{_fBfG${w~VD(<|Ds`K?QGX7{3)_lLSSpV-ZNgICSXhB)K z@$~2Zyz~ac9Xkq?O@(e2`8N{F6tO}wU2jK26LX;YT4MFsaB1qXytpqE>k#cL_eq5o zW4Mr83Ot$AZeg%M+CnhBV^N$-KhgKeh*^&gj3sqhA{*vR<8bGu{0`#U4=*%;F*39# z#)K&)B=E3I8EMv{EiLhdqx`krux=*%W~U~-M2g~N8^5Tog5g^_duhVQw?tG@NTT=& z!}Kk|=EP_G;jITXb5M{fLXihh6)J-|ZG{7-Dfi8feO|~9H9;pzIialC^byjV8r=89 zg6UWywc3q8W7JD1_}Z(*ISBiAQ=v}V z_emO#XH3u#c{ zTH6mWY5{=O2#|4P#{;>5R6$1EL+Ba>Vp6U-2mpC1&~w{6mWB5v-OxP>lcX>+s`@2t zYIas}zN?mth;{pTiJvM%#qkb^TC?{wpfO^L0=Ooz)XA)r9fX)VK*sAx(}y zOhh?P<1UY=q6>krsf0Qav4sgMQ9$|x(-0|TP)fj%UFmXS^?S8;%8bhNUJV9?@{k7r zm`)kEiHBUCghFJPoov7<83a`2#bRoHo>R*gHOFeWbTBO;wwt6zq=2>NToC+^j9)ir;#HLQ)oIdFp+FjMy#>95XEm z=0^JfA=y`nshTFCv2-pBI|jhSO_|%jBhAXVmOZFGCK*{F81ZLx<-d5??KV@*TPno{GnpqjOJd*CY6#fZV4ZO^mTO@Q5|-$7c%VwH=Ue{|s za755PvUY+DUXeCcpgyQ;;axh(T+O%jlltdC;QT-_Q(GsncA@SycA&dIv3yfbxm#2JP4uzF!tR5 zoOkTq2ObpfIK{;{n+LwD>*C2$0<(^z>Wc^Yn|g)kZrudi)_W1PcoESD@Jp#%JqA#u zf7mYCmbk3u)1Bz2yf<*Rt&w`;>P(TFzF7`Lm@TpjH^c+UWHZy_yQP@a7XoQRE%zxK z^7992T40+p;9Qmyzo(nZ0Qkt56&dxA(01P<7SrTU7r?gwts_J@LlzPwp6`K zbYKa1Fm1ay{o_H=cK*2`zGOS<%)>(nN;>mWdY#>2vU;hHH7eVh)-aVZvfcc}NBb73 zVBD7OwB2+rFR3L#fSM6}|K*>|aXTin>5>W^g|1ti;D#>?_v)XndDO(*b(7iBl+?H4 zpDb6$X|tKuoCi}K>3w2JA6WIHfbfOwuw#U{Q(Tb9>jN}iuf<$Z;!X!Q8omEm(aFTw z2+^N+6}qNqo$fy8({quVDj(cgRzbhHIAFc+Rpr08n*AF~3lCl1V18*^a&8>*D7T<; z)BGu?FLg=7H}*8QBqDcreB5(aKyvl4Ec0(^9ncKXD)>1`y4FbB7}}`kFMXwdG|f`u zOwyH~O{Z1*7dDPx#QGZyqia9-7n?R!*M{OhF^+Z()$BRu=;MET&3vt)`tR`2sSISv z#TJLFRBP=7@hN^``oQS}!;S@n>WM>ggAz>4!o}O;&FhdYbFnmeq^S};C48}CK8=^oBu z2jCwf3j>EPd^vT4IDez^i$+i5%>f+!!43L~XB|#!k1+#Y5FVAjIMWuk@p{DH&Fz*t zAIEPmej&{TbTKb=J+YLM+jCwt-$CK;Hu09kJ5S8*TDy;lU2F!&aq>?QtSiAsQF>N) zk@-<)JDdOM+}a~Q3hHj}iLq`$F#>xaf*w~)@1TXscd(aZHK(|!mP1|dG!t;T0WDHO zsuXk?@i49MVMbEi#B4#J7XU`F+ME}C`)!%*du64-_HO=RS(|%oG%10x2Qot)I9%7M_eo)XjO{(E8#nL&h<+ zMkLUrkHi~Avnr#>S?Mz;8GY0*X1snS&X3~c<2g4|q*Ooj{Ji{cSFsKFDcJFq@)Te` z-D_SXx-TQUE6WzFu-}Mx)Os-}M*1yq>y~hNu>JlLriRlj8(=ESQ|67M-zct1eq3Al zkw*Qw%{DU$`>XHfmH4(_!7V2|w|^oC7pp%lirAwNGN^JruzEeL?gTcQrruZhdye^c zpzd$5)U?;u>72}TO6ErWq}aFlqfhdG6X~9B{v}QAHJ^F9JSJ$W^}CYZrveNeyk{Y$y?eu(=%A8UaqiDVh}kJ(+1g&0tEh@e~_Yom`#P z{MDB9ttkeCf9o#YmX|t#v#`Q3M`0O-&kE+qNEa%)aJ}5pXL0q5@>+JhmbHKJO!nnGi#K!s_ zx*6SEU;Fn~?W}%%t53sNH(%8tIXq-=sXOsk zLRKMQ>dn2(Kd4FzXGT?brt-UW2EwkoH=k%3-6gh*XXhELwNNXjY9AKU0xDed?JueZ z%B(haW*{Bv2G2O|8t=+?sDEedo;l$@4rv>bzf<3-gvKQ-R+-WCvG2BEyrx( z^5Luh-p;F78qZu7g}y;MHGO(mFPzFTOZL?5I$mGxgFUrlfe+OYF0ZQ}G7ovJ%G$z< za`_eFt08n+A)+^$Y=~5y6J1E23ORi$!t{tqX$Cr&zL_(FypP!ImE5+4HS@d2NbrlF z^Txc8IP8UAZJPErf@Rkpo{i6U66qpe<&<$k&ur*LSVx=IxGtvIfi^4dd^eVa+@h_| zdY6CjgnK}~Pr{i(Mr!4D;>dpNiN^A{G548E+w0G-?LJws6{KA~8eczDjx#=hq7Chf z(JRo2+~|hdQCkx1zvJSm%@rqO%R`zb+3XK5*mo@=Yd!a1RB5~YN0&#d zTrlVGODpv+JHyF>z^ku<#Du7L;G9I zzIA*-vW4CrL^~;6`NyFNgc@v;3}A~VMIa9j9;n|WP(C%-B>?6EW0thCfN0NzZg;b; zum$&I&iqp&h6)VQtFK%$giJ3t{5r7bp2oq6)TcoQUtj&bns{irmzhH@E9}k&nRoC6 zfVFAKZ?+x$ow(&JW-H4>v#fUEDTFHs@xz-D3EEfC3wG?$V2NtAvB!huJl!fOlIe`T z+LTK5N*VtY?`4ij>-RUpCjMEMfQVzG67F~rzQ}-5WU0_TUp5fu#Rj@C&2bUC52KXk%NYQVlAvDq0cB{^fF$o z#hrvE`x2pW%KrjT903PFY*KsFK7?Th&)}p4Nw$rWVx%T64PBG7`045faIgT#P7R_l1&48LoPDy$@SGx>pZzcCh61eh;*_MhY?hnP z!`|;yWM%RNSR+KQd#3;%vu2WXg28l+HoucOCaoM!+VQMUi3KexFyNG4W}@&JM57jF zv%7iYThz;rfikl?vP_fMDli#RV8RZ|2^nOFY0D(KMhXG*)_@IZWyB54kH|im2#O%@ z+9oR_na861F{v7*oFsL%S=eu*IIK3`5)J@zZTM1@Z-x*s$jsM7{10!1tf92SaD6Q8 zwDg_qK*@C>LXZun$o3C1Q6MV{sO`u9(|7hfH(Q|sXj#Pq-L3qz`(EV`yA;s1$wCXO zn~)xBA;3#wz58AA=KouGMgU&a>jNNmeXkE4znzV$B_lt4V~48RvJhMlHHMs(;)l4A z-=!!6M|JDKfFLMtbunt^EJ)3eW@bD^BEE=lG9CyzOV0Zj@P!F`_2O`#EZ;0L3)7<1 zPCK8CgW!7Cbuj_BLWNo#_Hf-)2!irVgwNrPG55IOHXr%|L6u)HFW?D|*x4Kgf9kf< zj=L40Ho>8A-AtwwX<9hD$-1KX>|4x7=SPR0pjmBbSDf&l5H*7MLOm42?RxosdS4y6R? zmoOj>d>#(vEZ5ki06R-qB#Q+3x{S_Tt@0{v!tz6n)ZdckARZYvcEfW~vK4=h0wVOU zBrjJ9fPVxEm6#cV95$Per0AORvfy`3#VZ7gXf43aju_6I!TghQ04p}x8eiX=11bBHlNujp&-v+Pl_3aw;hu@%F2=0fF( z9s<;W!1H6vt|MPI{rl&XMKRREFdYPm^e~B&WLq^%Z6s@YYV_-Gv``2Lsfpu=C%7K` zqOZ0xISPePr_GB@fEC#bP80Z$XdSp#^}Om7;DH5Ah$(9Yp}zwfXc;;OZe{gpPEQ(_cJ!w+|v? zWU!ZcaF_z67P;O^&MdrM_`V)s+UnFP_F3@|pyCx)oh)bsVA({xM=N~CJ4hg}5SxNh z{lY$;fqAuJBX1n}TrPm{05GjJf#lTe(4_FvY@{8+j-%rfLDrzi;9aa6rFSCnu(zQj#A`z=kJ+Tv`Lnr27tr?me@J4F;qh zBH+*8%yDTvxwil0z86#x$EA#U00O{foP=iX^ETrgPUWHZB!gT4uzhNAE0b5l6u$OQ z0ZMUjH?qqCd*7&hu=u5sQtDzi4P3PikeZANXF^N2L!$(OJ!0pqP|p7NEH5(Hoa4C~ z01JPx&QA)klcFB%Po&*&lIXxohxX~>H>#`nfj_Z@IPk7y^E9&y`` z@SiH@-T)v3Cl(}V#luLeX%9SRP3yKm;Fib?I5-A8{$IZssyKLm- zIt7$G1pNrijFKHWMrH)c9G4l{Hd#i&<=`)q*uo*TSa?4-OSh1zI#p}}YLcQvqwz^o z`@qAJXE)&}Fdp{mq?Uh`_Rgv|vAb@Z!Yh?ITAV`=wZgCw9>3L_rvOE?dZAk3^)djL z1Kkb)qR4;)02{Ib7$E_LOUvANFh{Cy$2LAe2~`_StrY5Jb-7yeYWx|fZ5*;)0LaO; zsJO}dS1p58Vj~#1%@=X0tHCGBS9(amzsO+UUieDICg=B%dk@7ARv~Z#0Ez`h^I!?j z@duPKIKg%i12htKrmsFDwKda*0c>KNIbe@6HU=BXV19{5Ov#9a#8v8XqhvuuPV3%j z$7F2CdKC@}!21hVSKK9@ACnrzx7Lu8yj zTD1XU-Hq5pmgd%O0)BA#>3%a_3T;*!FS*=tSHN|Xgg`_Y{>g5QSBI23}*o&c~)_msG z;F@?al)zI3sJ(p+5N2%DL{UQ>mv5c8zZR{-mUo^7+_46FZTE~H!;h#NZo`Yd=QIeCN3VScBT@&1s#3GiBFK(bmU zEkn#Ft58}3fXydJ_E5;{_ueb2uwkq4(;IV2s*%909QWSp@ibjN4(#7v5MAN3fr)B{ z03l|nIzo7CY)~=|h-eMqOK2K+lLNRM!~LLNymDg&q$#;glng4DK>|6DWrhx)iEvQ{ z) zGvN<$!zDM&p>?P18Mu8blVt$77y9Ki2)N(40;H250BCN7=^i@oKCM5d8)UD9Y6;*G zrU72$mB#0AvY#?MJ^&*(#^QsXH}{_%>_4Amzm#GVNiqFpw{m@P2%yBQDMh85wm|s= z#5QrLhAB3!_LTQ=I^Avhf5_JeZSEF$Y)mrZv;y*{wcK28^Rrkl2&iKc26+&U%J`Le zet&yeYxxOzuOSFu#4d7I*bEVa=D!s#mW396x1{7GUll_MNMvgnukNtIU59D<%j>UC-gpWUn) zxY?#%VL!49Z+a+1H(L0NO(k5%5HJ>j$Ki_2sN@+bWi(P{c(axWI>@Fui2&K&@gY0pEsBU zqVKtzDD4`}W35EFj&L69*~J+8uuQyyaLYqbuZqwhJAY)#3p2ba1K-)zh1Z#Mi*J8E zhoPNaIU4j;Cv;eUY9A>-)DZC6VuY=Gw^-NO+PdgJ1E)ios~-Pz=j%UvUl;^buPE4U zaFasLuhRSSjM$4OH@-F?$D;It^lL*VDkkYy?>whdq#IU`SPS()_C&UvveV8$CF`9# z84sSc!^i3@q&%{$)}@K`ZUyQWBi{hmk>7sRzI8{Kdq?%k6plaodcXztB>55+8Z%rd zCwjcrKRJ(cSxxN<8>rBrB;pN%s|~PK@yBDwmX7Z~E&QjsdpLSzwD~bE?}*-h;6Ha# z#-Rfn}`{OvRlR5{g2E65l`{j6}XU`{=UNvUuEMTbIDKa^3 z8v4p0wdGB6@iVKi=j1< z5cB3K^C86iJJ0{{$XWOaa4gx|{#`p}%7;QRf3140m7+7f+kOu8Vx}r=Sg7xFNvEjV ze8CE*_=-he)%7+qUHg130QAIg&!?G^6+x-5E(BSbI6hx5eD_rI>+sx4{O;Fmk-^#G zkYK9Olb)yFhmCHBk+<1=JdU5~8zdj^AO##TP}#j6IUk=eMXU3$#-zS(G}^j^`R51q z?H~3j^rXe!OFGlVgSYWBuU>DJ#-WBLwo!+Ro=~WLqSZn-TrJ!%=r#11=xzPu(Xd$h z@vKK-lUYxO-Kv2@waZ#y`&FJIQXXM|gg0APjn&-((E=~r5luk4Nu|Q^|5#&sk0(Fd z3!fFgF`Rn=A)IM=Y#DaRW?h`o)~WBa!p8|z6;_w@QS;k*FV;6g#Uw{VC+rz?Uh*D0 zMVpCL$5z_tk}o%>UtXtRLqJ<^TYpWl{k2cEVUvX3Z8Kz?XAnDrn@hT1=fwf~;8Ldb?Wx3# zFJ3Q-;4y%fM^waSo|VoKGm|WvzW7N(8z2f0^xcNAg-ux>N4iAC4gFQ90JaNLST6+( z%}eNi_S)=(c0B-O^T%=Ep$#O|@Zy~(laJTh3E&!X2lIVc>&VKNBil$UV`RTuDJ=GdXZN@j3Dj# z%b!k~JsrK130t0zObOtdj}&aox~hyQ$+_spD> zO1)w{x6zQ_JblX7zTc0h_0W3HhhN%!zasq0hRZQ`jzU*#n2l`T`nb~T?1rz=H+H|i zo3kQfZd2!epV`|HCwZHXEOX^2AJUB#hnE#A3t3*Aiy?tTS}Mgurs)^F=i3jr{|}GVeD>W(i|+IINbEq^A+`{p3yaiKRu|lC zI?uh!wGS_eFRok&{%`Qn$6f=RDqD5hanFy@t^AQkXRR7aif5aXlaP@B`KqMM^Inym zk?vReCTwDNEz_I7?bH*V$n@3|;%B)bbF@#1qDBO0S-)3c<@)F0h5z(KKDNyb@A^nf zC1m5WZw=*Ag3bX%ZLJlvkACIPwD2LxG@~!p#9-I=ykf~h0p3KhEZly9+QgUVoN|8m zg<v{2wd_PN~RkUuDsFO@H(GE9l5COtWag!S?3%62XZU~?p z4oan~yS}Nj0FWiOtp|fpEKWV6E(**x+TYkW39~f%V0cYOK;}QPR8%b_0Pvn8&Yot^--^OM1!a-xPtWc~!GsUy*;!Usjy>7YV zxXqNXUfgY$&zu=kd>GHsQYzk+wm#+acLzM~sz+S=(Z+`8D%9Da`yHJ6yqYS5pTHxe z6p*cQMkEM$@gOUQf>ZLw&tEG779F*%>qiBykwxz+3yl-tz>{JC$o_lm=`WfEWH6{Q zp!;36g%Q5$m|k>?KPm40zcPrDBWc8QAVqz{fICv8nKBDEqa}wd%{wt<10vmC9&A+y zOY^``770=neOCf;;+k+RUF6qJDMgtHLX1)!xe?m_PvjQk3q&9JU*sl4)~M8(TM1L3 zuOM@4TSb@>X7Mqk45Gpv2WH3s{^iw#87jb}a17|5Cd)@h$`E9U$YhoYis=wSPPKLq zrG)_0jeBxwM+s4^AWgI#H&<4zE>oZVtUBcGZyHLFWe~_NC95E?22gfs(&D3eKi#(& z3S=^k!XxwDXRc`#$8I(LSB)JOD6*|u+GsfO$?#KBZI`7Ujfj*XTmmOMU{Qc+T!N#& zoa!lY4KXRtF3N($=J-zwP*Dw@$nf@?CD+)eEu!ALPq&t4I#;=xGfw(1*#SZ2JmlRa z_*AN_*yVQ*RNdP^clQM`xFXChJ+`j6PLR#HuMw!|QLWQsLRpvbm>P%>kk|@#7Riua zJRs0X-^>;>zr{r<^w}gO0QoE@&|;p0N)EB_F+EpAm_`<+@!X{pUAzdIfIWyy4=`2F>6X27sAH&ttJ_bV! zB%!M5fg+29N$yhRFSQ_Vw z^bBdWdNpK?6s13;zK~v*fFe~Kq@nXe;;Hjla10r2IZZ}pDFp@MeK2QrzIlHs4?B8V zQl{JoNmnE5k;zCL18bT7pO1D%Kip|ifi7JHY1@B*G9Wi-ZW0^C?CG|(msvMWfY}>B z`DKrWs7CX=EP%}e6p5~|sJmZ)sr=#J%#V#m;pD8VWML@ed+C#bf5IXN^($+y(ae+& zPlxvAuDLvFv3>C$e_C>`$E#W6Ux~XRIJH*cMlyox+_RKan`d~g7aR~P*T-?7z(9e9 zAMOk`mx*s$su6kNdaEp0tIImboe2Or2*GJV?f@BCH2{A3$D#BW$*_KIekM>T$fSQK zp&CG9Ge@9`-Acx{$g;H8gp*5fGVpKfDkPJW{d(C0=fS&wK8W|B3@5!()L0kMHv|QD zC@^f_cK_bGvQR4d0eVK@sxB9R!>S^qlvgO>A^>wt!CX|pH;3QZx#8yc^DDXgTb^}K zlq}w$`6*L%Qzaq`E)`9$_Vh!@uF=S0Yf%kMGK~y?PD^XKGN4KHtz0~UQYYzrxTUsx z7lW%NE=|;VBF}*|O9pw(NRnhYxMg`YidLPiZqDa*nFx=q7;a}r|HkV0NyoGRP2r1C z2H!SNVLTqtr1NYRFN+0hVhkmNSWx8P2=U%sJH2uRFw^0iMfspVk5_|b(Nu(d^3aYA zW6|12D+RI*$Z3L)kb~rt(dm-B0bJK=OUT-DDd|E;6ZyMVZ$4@z?)3V1f{-h%+Smbz z+Gsh@ZI;S1DPwXq^iqri&rM?{!o2)c6p@x77V@B0gdy`bL(ApFf!bbVLvq`bP1PUB z92r7D|E0N@1>J~Sq1~j+={a=J48&uvZ;Z9 z6c%GJWRXR$+}4X>>l@JieJOkhygLr$z3MyBo2Y&5yE$98gNz_f<^k5UiC4JYJZaSu z3t|O|FphU%?2G~=UzwMGFtxyj@e6VZ+}v{g-jTV3Z~v;^!reEG2W<%X6#_(!d87@~ zURj=s(zcT@b+~pY^;Q_@BDv=p<4?}hlBrKTXP^tCjuI)z^cAOskSxhr4iW$eakIu4 z`agRlpXxx)dexw@wgD9E0JY?SS1%G7GXj5S#HVkXWy#qq$XR(VxaM+Ui+$Tv4RXQ` zFcJr3M4q)x?kE$0Wk{WH01$~2{z11lwN{qU5fV$Ji?4|TM}LVdmia?Nd7>@tD6OQT zlE_<4Qmyk-S=>HQ@a^)7R{gc1;!K%I=pww0lI7H!#kCjU#i+Bl3+@h}ZvKJyodiOe zg1Fy#=n3QrdbV;vNcr7)x1AaVJn>p(55Vz&PRTUcfCY#nFl)*#TY~{B8wdY^hxZ8! z!jRZ8nyW8#532WktH-|zaORASg8*)x${rrc%H}~Ze(nA^5VE{MEjaw(3_ao8?eG_V zG~H`w)$L5FFvTC6Iku|XSWMptQ8kfMTuLRys1wGtxHy4@M0j}Y+KOjc&qJV5{TCvl z%g=YX@nyH~q3#_>dw4MWA;0wD&CmHIJj1e9aDg$zn~wAr4_Qsle+b*&9<-b0+%5;v~cm^CiQvyg)9#W&A>0WE*I zeS9d}3J3XEtXD?I{#1=2ZJJO%op5hy&esn0vXn5~YAslq7b0<6pkt8?Y@i&F?vhKAO5a*fe`-OS593F z8L`Tz8+_sK#h^}ckouD=)nJBjoy^di4ykPEzQpVMVu_p`N5)y?8%W@nPr@GzTdNE- z41KdpX4=_Q0D}y0@BV2be+)CviKH;O$C_=?t7>L%W4qGIcvKgNVh{2$GR6LgUG>clbqvL zGT{I8nhit85&-yEgFw`3c5A=y+ zTg?u+)m~VCsG2XeBK3)UERlOZ72K`Xey|Ctx33-Z31HZmZ~VQd3}F142+@*Bo{t8k zH|c2g2_2Gw-?Ht^YfkN10FCe=W;ue@$MbSU&krVxEUrBZzVE5IkA0CKbY3eoP;)(J z49bSu4@DvM`Bbc8xT&LhPZP+tA^S+E4W&ab=9#72BB)Nw`@Ev^RB==0s|S0Q9<0B0 zH^p#m1W1?^9TpxK4ACAFs-4QKA|vA|KxZIb2q>)RFB1d98T}h8)GAMKIFqQ=K(kdg zrHRb%vr01?s#Z48u~LzVROY|1>XG3IB;ql3LGAI(xu^O^NZ~}fNg{Ph>Q_Zln%3M+ zXL%G3860xJ z-uo=N3#vcwTaRLz82SobS2^+%FLH^sr=!`WYk_9sC%&P`6TWxKW$tSegrMJvJp86vo?MgGzR66Fe1 z6<*6Kd;9z1+dtRea_1R%C5YaF8vhCkOtyq6L1B7Q^*4{Cg94cVJdcNM1<9-Q)p&%h z-o?%OMq{_~j#X?+$dL7L`{)G{YOB2~dn#11Y<7)CVXXGU~(ivZ|h! zrw~DrSzgK_L+P7*JA+O+*!ek8qz4QV=Uq@_>ES9{d4QA3_04>uD`MrqE%<*fbl+FT z2ilCX{^ae^5hCY6F8s@XFMdqF@$vA3kFATylY-h3X|Xl1Xmw-B1)lh`Z~kFMj!1Ln z(NIYxPkcdKyz=+4w+&hbl#*|Km|~eY8-}?cT>+dCaS!7@iA!Adk&$aqqOqQnTqt!; zHAV6rLNC&B*cc~)M3`Keu5m6+BP(`UCqCyCWh=@p6kS8>07C=N4#n2Iv z-b5rP|My+%d_P}iX3hO=)?8~{_jT|6+b`H|-R3Cm%wC?VuHDEi&B%P+6jVnvCcoie znaLX(LKkXtdJMF?2Q3f)^K`R9YKkrfAkz2UL2&4&0DsELCM*s_VrHfw; zDX>J=A}*Fi<<|qKq_sdZq0C;T)z379x}G+Vo1C))M|@ky^@-JYi>vRYCrc2hR`|-j zgSneQNV+U%-T-$wKAZ-ymBg-=#b>s>4^gy2I%|haM1)cZp_Tku^Q-bV>X*9~!;3P) z%Hp!vgpy6rWIk*=;_B z2N5Etk%@vi5(J*71~7NG6ULN+&m+OWU5-C*P#NBZkbP7c|8HHD)d%KTW9u<5 z-N~hX>F_)>o5T|Op>$>kI@I#9-<0&q$t0|E*?No8PLgYAPfNDTFZ7K?q~m{^?yb8X z{kx7=f9v{0303XdaIRw?|1LfDqu`^*I8fh|!uro-mYSnlm3Dm7+360^pITPBD0??4 zd!N16X>}Y>nao_}jGFfmEv~yai!x;+w~7w})0Dz70^C{_nGakyLDPd%68TN-^PrfXzCewg>MNxYdz;1BP6{5ib z_kRI*23`kWi5#6i;cjusax2ezWVr^Ow_3GNlYOgD&ebzn(Ak!54BWe-on=0lkuS|z zy>!?;FgN6waQEEb=D@!#SN^u1;=35~OYbW3)ByNFn;h`&VSjc?6LM2=Pz3BYeP@L1 zYcTB1vU^8aEPh#0pN7;9(i+jk2JfJb20%s*fPMzVt}T6b)Cgn=Mk~*JU*_)^c5=*O zY35311>O5*wFrv>$!D<3AAq|~1sX-AWB`yg43tsZD;!_u=(hHvB(_cKc+TQ@{@n5W zbD)Ht(ZYc|O95YMOkIs3T^mR)X83{yCPA=xcbf85^W0<+H!yM%+t7>d%iB-aAU@(s zM$xKceswwH(VrLWhWoN4+!|_hK>TQc$P7i{M1Ty?SRpWJLO*f;fuNfMEICJ9=HLO? zappo6@~`QL8%=5$%zvCUAlN`A8Wh6W2C5r~v|A(>bP3SaU&e-0Ir>+yA1OOZHP4Z- ztBIBSSaqh%_!jOm?o*BHbKiG0m*qd#dH+XZmyc8U(h%^0YWFlwajGTav$Rmcb6GtD zk!&2s+N4*OGiB$&hI|a6+D}3wSBVAo&^cEtP)%0Gn=C>~ea~iBq zJ|cqHf0`^5aj!ITmR!J=kinuEGRa607gZ1|-`>5tSHBvj>e|=4Pdx9~E|L0BOBht< zy%WKkuv}YtAWeia5Hz@6yfUbO4Z|z`!4Dd>BFh(zHj8j*K31!7WD!oqDQ17;@pY<` zfN|=PQ}qhL!4s$tP*toro?CLGC&Q$PSdT|3^)}O9Y&_WdP;gvH22IU0 zFcMh!X{f}l>cWxp;Ay0z|4~7osH9tR|K%84d>=R!q%X(gB8xFOnG;)Ye{cAV@+(}4 zEQZLEuVrJ&Px$sRmnW!{&?om;JGwhkwQVEgvn$aHF||}t)_M4=@ki(1(7z_;eB|Q_ z6v&|1v4YK@ex~>0CxKMn74a;+Gc$57x2W9OZ35vD4#>0d;z(${9eI9K3VDwNFt|5} zBFCE~&Kpt4v&8R)YesOR0}AV3WmsR#2B)$^GMk2bis<|dQ}0RfIbJ3<;kZ-{+J>(C zQo*dUMnv(GPi12v5Cj6mL~&BN1D$9BvNN0>m&*}{6fRa?LK zp(KgtoA+rD#FnEz>3+#Siq4T+q(yab7Vl2I?w&=518G_!Afl-3(3@~v|*VRTL&H&$XjBpmU$=m znc*Q(rT}>vjA;05hlt03Q3E6fv89%Y^-OdM)Onykt#Itc;`^^PUm-!@}xapCTnoK{(nZvs~E7xr2Sgx>=p;KyravC=gg! z(KLr*^Hiy$lu%WoEz(0yJf0{Hv;LcIXlsBL-2~xbw$3J2-Q4^HlHf`Y zuk@v#+)S$;_S=X#l-9nPp~*sycH`ayPWU9 z^@;%3d;7?>sy;=?)1{n&UlV&Kg%Xt}q@A26fR8U(K3k;`#~L)5(u)*1X&`w*rz?Q# z(4Gt7lQ!)xZhDjfg8Bps(ipHdh5+VTsnC0s3o-uI!&-ai5#kKRJdrNW z43V-FH%CK$pY~TeRt#s8;FYxVmNx#tWM_KBqhG2QyrvD}X+KY6btfiPIBz>i!TMIAT3hvGFD*m+} zt`QKwF#vhXpFJ|je;;)gbN;nB>%HtyKB|Ji;v2G&st=pVEZ^Me4++z1Wq*(O5@nm^ z&?OCy)3JfZpWT#F^S1Ilp7@DK=Azx40rYbE-x zIkA4s?wqXpt*4{2e_&Xgrt$`E_mqMa@Vhas@%-BFUl$%1k66!aJ*?mk$=B2|Wd~`* zroRj3PEWX2p~iO4$5UL9Q~DG6&j(nJNZ?7%MG<%J=i%oD7o7ct8k@WpGJdSi3#KoR zM`X8#3$ce2=5&7?PHX+g5LBOHP>1_}HCs1|D>k@&5E?%-qx9;P`m534KQCQ0QP1X{ z`T2ZYm|d7ie>e1QPRZ)8Vc40tcF^r#SKAML*~{Z#_7m%Od-N7n%TB)wjo7|Fr?;f@ zl^)6LEswY}CJ{k51f-S595_S@(5*Asr|{`kAL{~yF)gCwRm z!y0+eBWbXibwO|L#QH(MiNRKWncjkY`=w@f7(PIeylLq zt+}B8%VYiUbC1DZLz({X(8#}2a|Vq4S3mUEudV<60Wm!27Bkqq8F@4(Y4~U8g2DFv z^`j*d!^5#MgWac*|9<%y{{8yHV84C+-+GGS(X5!^pW(>k?Fz$xD;Es^POTsB_ZS{; zl^Oo~70LKJ$5>4qFl78)XD}cH07VD52_RuQNP+;y(ZQ+&hz=cMOn_R`p-u#tJ00dr zfQQiGF$9(bItz(_$f6_i3CI#Ul1f0;&`}Kp)>m}aZUWm7oo$T3{*}%?OW;_cb8Hbf z59yp>A2ezP&F#Y_Ji{g7!;PEaR`uc0nc*?^;kBOOb@JhJpW*ZM;SZVNkMR*mm=PfP z2xiR)=KBbh%m`6^7{WC(C?^^#jn|(Yrav%aIAU`0z0b)yAJMpJ6xvKEe*8pyxBU1F zhMOugFe9?!BjGN}5wBhF8E z?V*J}9v%-yvh}gb&KU~MI_1*5UIXmazA~@;@YCP5xXr-vh1laBdBF-NVBWB>3ka*g zTVomD!=XsGd5E^J5M5HcA9GOaz^s2q=C7=6EDr-t+VB;`6;BNqo<@} zy`Pi%yh+u(&5Hk*-!#Y(1a*Xkq5Jd(edMK6VbEljN3&;CAAOMmWX4idVu}-HCa;o|CT8T_@H(A%-CCklfRt1Ay!DL*kA#Ofb198ulM@N!0C~Y( z*h~oTd#-!oLe@jc;~wWyP7Cm&kFb-Nzl1iG>A_y~1CMDc`JFKixacc#an{FidEtw8 z)x`v9(}nrdHx`2;zN_Xh2FHm6P!~g-ysVYxEgAyCh8Dxd0>Zy8hR+5>tSm-s1u!BH z7bC%eQK+RT?!ai_rD%!37~E2fYTzZErAx+vvDQnmPJx%*moEDT#)T{~0UKBTe~)g~ zQha{k)sjHoPCQ7ED$~)$TDgGvS{_oGiV^j_J`o6~xws%CM8HyF!hI*FXT*nOoDj=m z?8{fFbVw9lY}^O!Mib!xke-jO#Zu)1h*G#p7mg~I5s1i$pAg{ZSPLNag2YDr4DxBx z#(jVrG3ZqetQJp}2x3K5;P~+{+ga2%KJ^wB{T(CF^$KhQRjQ75!rV;rxJUH}k}sTU zF$zH{bU}8KW&G!`#(f(3#NZar3vcGL8)i}_#92m?Wq>E-d?x?Bfki(GpAa|8idYa& z=te!5ztd?XwgZ9{f>?r{z_fn?@#8X8ONPLcV$Hsink6xP8mbm3NcahRwcre`Ar6(7 zIpMS70zBFlGNkcB9gn3VBub1|46Cb8Rr$lQ0Ll%>J*-HoS$2Q>sAy%dg5L~1aIwOg zo-A!fISzy$JYfM{yhfpEC>aU405G>;k*z28-g2-3KgFtxj^i_swppOV2-J4*X-%p) z&i_>ySf7n%&g=i|YY5bxTB~W6U|oYrFqWwUaw7sfI*f3_e$uM4X}A3^|n2*DjLO_b1xl7-2>_CDw(41r_x%;hnerb=JZL z-jpkSeWY&?)GiqId@Ky5R6*nL6Wf?U&CewS{mK}V4Cr1ibeeSxn?(^M3^@8;znP&Y z%o=(=I=Lo>JXq3f@Rh#(M5(3v({TztL}G@2En#9NgIYN}k*O!KHdTrd7lnCs_G^M= zo8Uo--2uO>7nK{7nr7`1mD(NVhVmm2Isu7e*yVhf zgg5Sb)`GaOq&U3#RcYN8xO$62a(++gH$3QiL}Z}SYH85=W(j6{jph1S#9G5C7eZC2 zdFo1O-Jh|@8&IJ>jKg&XI0|6hV8-`(6h?w>Qhy$P0r9N=lZXQAY)qML zKz;1G%w$kbmOJz!MqKSTVz^h1jAzpfi#^)E! zAG*nZDO%v#ra(%x;LT0GR)FEiE6HO>X8{0iH42qWdZs#-=E1gV>1}aY)Ti+6E+o+IHMYhV0-)CwnyfE@=if;zBQJUE9_SRntmR)6P*l zeYa6_xLa(phj)4Q28SB>u)y}W%L-v!f!={l+59>*9pHW;OB z8_BC1i>YgB?JzV>?HKE-n@H}MTBsWjcPkxrDIKX>)awojWh+2(AUd{DQ$xqW)6>CBXg&J=_V3Sdx22=d2d8PTRU$gO*X4jj|+8&opBQLuKHtCoci9vTA zPS8)L?Kq7?3=J=P8D4gJn<6cl>h-zVF}6X~rb~|})j4!aZ=+j{2gYfc?8TX?Z@6bT zzI);Rj-hgk^SXw?Ukzui)PT?m7uwF*3ynehO}GoqxF4Hh)p4RzvB4%y3idm8%&UK_ z$hxs&WdkGV!mjAemh;yxhuJsTw_Y}>TH9-hJjp3B8$u19cpP+F%JYY)p@*>-3&4Gp z>?>wQ(AxIa-Szh{_6yyT*;nIcrX%vg)MPGsok&Kp!GQWJ1|QW7=hQCrTp=)eKu0~W z4d9gQw$~Lc!>4^NWtYtan)JuP=p7oTCynz#jQnGxh{l*x{yX7walwJH=AXM$J{ud3 zXrh~lC{MiNfNDf*g97G2Zplb7N7KxC*S4|w;ZVN_N{ShxNqT?r7YA|T&D!@pr7+_w zzoiwB$G#yAj|~L4wBw|&G{nzc zW_Zb8brb}tne0hlQ}wUtgSl)6r*CUAj96{E3~je~n*gBFNU=CxY~5INU4_EBRrW&# zBiV-Sp>b9>DjdBK1iF;oMls!+ihvF!N8{X;#;Eqo*`aHOY($T$r*1Js`>~W};nqsg z{hSZeB{oJ#w{XGQ4M%mFwBcpIMT=WK?($Ru;7ODjKkdVvM}dJ5>{jl4ee@K|g* zH%8aZ>2T{YgFj%L%I(i2L8ms13!eA6cr=-OY~gCcBizD8{Au!J8f^JbX4#flaXddH z`PI2?C7Le(1w5QatYm_EAb3GC9tq$L=abt#w$EJHxjC$OJ#3CF3`0f%46&h^YEH8b z?o^l?Hf79cvF7mi>C1p6h;1a9ThJK7JR;l17jnXG*cb`}()Gj}Z&G**r zO(tC;Cy89eryav$3Qa)51P~|Pn6*;bQSSwcrs7z3plO~dzC_Qh4rM#Zf#S8D?U-#gJ0RW(M z@iJ@J?FGai44H!$4Uw>@{zCDglzSd~Y*s1F8*L=maM?Z5Ct}VfZcC1jnTb3ck zp>Kx0^{;fuP(V$RW{7Gce4ygwSQiY6M@IR=@mN z{}7{b(uh)H$t!=2kYqr2A99>mU+Q`D3xk~>+n1Z)(YX_H_UXA70iRyo2|f4xLRT7}Zc*6z#=z04 zv+b@SudiC>Ru7=TZwd=p;ysCu#wmCWtbQtErz0WM{2yZ_F?A~Opu&Ot!V==@F<#Vdd1F*uUQ z73DDTRNj)bE3q{PnC6O^?uSz>^8vES(&R-}AMfu*2e_-5FF8yv67%5i!ldpnnzezQ zo@909)N)QaL@XA+*~{vjY<6SLGbA{NY;@Jr5f`sCYvhH!RJP`9( znPin;THC|f=fFxy<~+_c9)3sNs3e=J3BGG$qsB`@xO!xLbP7Zl?O~$XxdoN7!ppa) zx53!=rFscLK1vH)mJonZaCU>&fxPUXK~@H;cN{&};#0@SYYJhn?8g5ZvEQxA<$$xi z|2EFKrogI0mb-CaQgp+g?~G)2n7(o!>3CDQNhI>HpXWY#i=0yCNqPbV+K}pdSRTMa zrdnrid#t_uSvR%TzRCae4KPNelHp()<`F#J!GxYrKiQz10?wWF(y7V?E7=s2^DC8K z&?q3T#vLfU9}0K2eRujZ@e7;5h$4i1KSM$@^J<0~3d7 zDNDLvWLK|brNS%aloYV{Ru)^(Jtmc9N4$4LD4ri}5g}++_AxIz+s!@by1& zTd4s%>w1Dzf?Mv{U%0N@MW)1? zwe|&(0IBm_vGbDRLRMC1^7HRp&+^D+st4Ijjbt5@_w>33-$9>P7DDi6mWgTH-UKZc z=73%9vMHxdHO;fsiOs559evL)PiqbDr092a8Zq>zBenhTfypta-+)!UV>jpgv8 zB^Kq4UU~CnmTf&wL(e9mVP7lG%>y~8p*Ag8dOlNb01W&tXJOkSrlxn0ID`hiuN9v@ z=`m_=rkR&(H_m6xm1!w11fcX4lr0U4$T_hYXuP73W9FGcDqr)mnUxEt&2?5lfCv_L z0TbaT0e0NLyYl1cWc7m#7P+%s);82)mAuLdsecwW(Xq1I%|sOqDI}*t^xHz=nLAQ5 z$!L!eBEKizx+tjY)fk?eJ*YOr=_5~cZZR^)2`)%gHvM>mn5O#;!?I`pWWB+%HlcRtPs-p5?xt-MzBVYxNSf%72Y7v|xzbVeZ~Ttd zfNx>Lo#xexD)+zCVUlAkt1YBWs=0?0kxDlQ=jRnRzkHM^H{W&$*RRCCl>Q^zlD)|l zXkp|2zJ^~Z-y>Vf=~so+CzEFL1Siu~vdr`+$B<^_+q}vY^0`6)l7#o=tY;;=qfzZw zm%m4@WqF;a(fK-mM#S^9d(HW`N`8iM4Af6~U5BUN``bI=uW|pvzqPyn{o7q{Hn8!W zsNt6~Ky8FCZE_Bsm*|p-w$VT4A|SNly=68>eI-2IKfKx#+nx-vT48jtf_U!sg5$n9 ze@x~7A$!SQ^u!s_-dq+Fbzcn&JQU8h$;qZ3*nSmH6^u(ZT|X2=G+?@UCB!YnLj4C* zjHxGsKN*Oted#~jX=%8cyr9?jTnv7=ez)snfJ)B2w*~&sLNo7kb6s<#6<)jP5yI;; zn|1IGE53H$%+puhWU?zE&E}TQFsu4G?Vf1q%&<=}_J^vPuH8RV1$BHf$OZ%$HlC)K z8$EaCfGY5Ma!twiEUN?OkoKjME{X~g@(0MrVh&RSN~Ve-4yRi0ne*OG9DWe$wO;c1 z^20F!D!m|TvZd!!lCYg%!F5e!`knA_#$#-;RVN9>rP~rT zGlFAh$MA-#i^LodS5j^h4;mTC{H{DRSzzX8o)MG zUVu1=teJoKnh5?Xa)~oyJGFgMBI%%uCE{#!Ip@P=Gp$2OuI(H-E*%m$4OO?qEp9mdHHhd-|w5H zR|MsH%hSZe15Rbb0!DpS_9Y8G&E1dh>u=@B7)evGbCTvBVN`Hjyl}LjQg-!Sr1v%l zn#*ukG+{KSbmvhkO3cxjBSXGmoGg_4@ANNy*=SOoPtjOzg&+w_v}Q zLDaU_Ytd!b=T9Z=4@DYmKNL$`miz%aQvJ94qAcE0^`hj8{B8vW)R>pTQWmT{V>u#y@W$cTr4dL+h*LjDs(8 z<4oOrDa>P_jsOev;4%L^|M3jJE1n7X`0HT&ok(SdSVQeLppFjIEs!!^Dc?Oxj&~%K zxFENT$2ve{MWdv+QL=CfUxI|Xc{h(M5nR|E{*4h}8kZ||NDtMKgFW0pmMf#y7r}0k z`88-pzHGTOs?rX$YEKGRxkf%gZ&A~v$CG!_Xfx2 z2!lK%SJZ2HCKE%UV$f+U#StwCyEbJCQkw{!ro%{hNC^#XUES0++g;nud5MbLj^a7} zf=7Sza}zr*o?y#gBZs0wvw`YjC7J`N?Ia6VfDeD{su%$TapAgatRk=X3#XoiHKvyU zn>?w}f|)M_2Uoi|exIU($zMs$_@`Fcy_T8^0?plu4aQRlW1d^lCtkid@!D}NcNC{B zj~iQU$)yXZ*LKmmg_}t#yb^-{F;qksqD6nIm>pz`*pSz##v%oZbKI+9ta&FTYiS3Y zIN>n(FBNgV7;&L3T=9G(YRq(J6!SM5x5m{S!!;F~hebUX*WZ#fQpKM0mnf^lf*XWc z#;_Zs;yi4kW?ND|s?v%-v3B|IM7bsPhoz;$1n&QCRL;guQ?VpfiFFm3d-LLVNv(pA z?vpZc@3U3LN1KDjm}!A>O}D0snTe_j@1@y#$5jBq+Me7zF%8uS>0v2RlH@3r_xWt7 zcD^x+qE{-bGpyI(X(QdZH{OSq5#IaWR`##ch;pXv(|5AZ@`UfQx1C|_wp;=0 zh)+(}He;M3vffSdL*By~wU1rs4&aYpTvU0rwmWTofguc0yHc`?gb6d&c-SpPOx5@m zqZ#}WIWwztniW||tJPy}5A(am-eUE`PTIxDJA-93hGf(($!QE(2s$_G)WAqMskj$C zZZ{($)J|)K(R7{)l+9nNZPXQ-dqU*CySfNNQDnX8?3NA+gpV3`!40kugV08U-ye5` z8&BCky*p6}iep7igf)wDH{G_1IaDT}QEjq)N;`HIwi@=dBvk`6P(9xJupTSOqbt^= zVlnK+-(xin0W=G_?ZKlfRkB|r6-8?FFBI5X63;6Ta@H=H2aoS;bR&vTtV#ssgGbk~ zffe4FyKocl+l--#HGnniCpdP8Lka&xrvm1Vd&IW*#4YEEugocH0Hs7^5tgwqLRsCS zoKZmNa!^2Tpt?=!d?)6>E7*u-6u?2y-ROQ|JCs!jG4%m}c+9CIxK$nH?3U zm{Sq?m)AzPS;52(L{2G%=BY|h)4R<4M~b+OjTZZEBw#%-!zPQ)ie-H!3UrueIi~}o zg3Uqwp>VMC&t~tWTXt-cP%0fbqN`(4s%0%ucoTM6NysV~<&ds=4ALT0U|pB6wlao= zw8QI;>Ml#{RX9k^#*A=%)|{;q5{ZArQIA16RKV2n%pO4L zSln-}hjXYBgiF)0+7{y`F3iW6Plf}cM2~YAkn}nqX2|>DUhr_3raH|hzMzEF(-ugOJ-DN;;m8w5ZNR>80#+}PB23Xw#NzN;` z!UID&=|G1YueGmrVJqq}8LPv$*UKOA`Jz^B>$RVFchwV0$G>>VtWp-R z7B`;OMt~FcBZq{6`Sy-XnO8D}2)0S-=SGK7=Yj2h6XJTJDiXOy5Ifrg|f^4sUv7p(g z_F?+1%wzUv>u*o~=ziB0Gv_q+lbfM1r<(l^^H!G6wk3Y}ON5%*!dowQn$mpL*ZAR{ zN+Wi6d}~Zh(?br4k1x8KR3~{aeI`n^ehjW>Z*NWfdminqx^Fu(=Q_#AUTrykz0 zyxlsZ+sReg&RNhcdaXB#tNkZi%YJRg{i*l44SGCm?`v;~w8y;2iD}~uivY$aV^o{l zuYGk>!JPw(ee~#5(d*H;zT+L$qkq(6wV`R$k!>mJ9YG3 zy#6M*<4yR{o9H7m*M3S&M}Oi`e=0LLyloOl-e?tV+5BK_Sx3C*RB zvX^&W&)j>vd;Nn<9q*TG_21jy{ZTUas0X|WTVO7)^Tw@0uQjv;6yooHkV+gASXS`r zmOiO3DE6>AnEp?CIDGnkIqz$!)j)V)ZtzEmF}cJ~=l_|W`Xn{0XJ!JSOzElPFbjBQ zIJ2GP74QF>-b{2qB!X|x=E|aj z=DweIN6V0;V%Iri3l5}qH0AN1vGm<)pIN@?90=i4b)NnY6@xjUj9^9Llq4BSzie@P z;mcq84=XD8t@I_2IS_%AIQLq;KT-bV9c)p#42r1FN6i(DSk&lTN<5C>^@ZUmY(c~+ zzu63%dl1Xh2yn)fu71h&)P?h>LDa+sIN_T~;^l%CwMJvZU$hn$vs$BZ{$*^4WXC}LDi~RXItw?XL;g)AptxeH`L$dW(K=||NcdLM6DwHPAoKY^l0$#NSPf9*A0WF z@2~Ccy=%}8Fk=@PQ?-$Y zrdH4vTcG{rh?KT9(as}sdg0vS?z~V=a65XIjUu7OwSDV*t&2_-F#KfA; zKwGR$@v1NvYq{8_4GD9Xoe|+P!n_l{o-OZJd#ZW43)X+W;X3*#aJFh(F6ZN)qraDZ zRa|dSSaSX}mMB#fxh#!DB9gywr~f7y=&cW)lEKOMR-P*RboB2BtSk|#t0V(|czDDN zbmGu{lh1p({{T$=%R)W;_Z0@d^Y_w!JN)_Iw!V6*-rfP%9Oc(^9DO~px3{}D1?}$a zP*qixR@FP4fTAAmN4(yG6|HJ&s>i+B-`iR}K0G?!n@5$bDyb^Rb+4+*%I;I`!Q2XU%_wu@!!-(Vmj#*LBb@7wz5p=UBgG+z{K|! zQ+GyIN%*nuTnc4AfPmR*p?&M_IOxR03gS!F9$3~rh^OTC4)Kmv*TO58ElK!SL#7$; z-}aIS%60f})*01Nn2dS7-dN1+H_V#0cHE6+Rb@;@7ACe%FREi;XJu(FQxb6SF`2JMj z`GsfUu!es&ZS^xf_)qUsKMDM=xYbr3c4#$REDt&rI{o%#10wtg06rl*`*W#`2*)jl zVQiz5AEZdvEK{>J-A}?X)w9c$g{~n#A8Gx*1a&HoTlx8zl7?HUt}F^!c~V_fvr<#r zva<5D{tW~7tF~z(`-V-vGvMH~TT^3R?r%yR}L} zU=92Tt90w?)-XA5)6|HQ7PkFP+h*atag=3cgHisx!p?~4HSFMfk$-v)BW7B^cRuo{ z+~VSOI2XSA31KCnG2waT_pS*{^55>H|K0GM$%~Jl?S0yNposn&+ON1j5_Jx$B6Vr$ z+5YtPea7$oA4C?V13FnC;$S92rtV-iTWjrLF4sco&wSyzh(8O(fpvctA6!}cvqVW( zI$W;28*%uv`f=UiN^R@f;jj9BrFOG@g>e>L`%iTaU5)!|x^Zii?|bXL0+C0X18Ty0 zMweyQkG7q6jYfWN;v@gAtvH6MDqJ~9L; z6|ca!2&ztEObecHVH}qr@f_b+Xq|V67op`BK#B$b*(pXvSYHFcVuG}j+PS1?XJNS3 zfKdkC2o#k|V6m_?CaDucq-@Jk=i=`Rj#worWQ#wo5y&wJi!>4&{9*WBtMnAR5m=RN zwuZ5j#|=Isb;HnB*ULvtGn*HkN;cWv;rA{r6iM}H+~i3FQqvbD5Ch{0woW#*=p$b*@~83$(LkcJ zHXY;6m=H7qR@?9)#eskjZANhZ;2yn|uLPjKmv}Ai=9G-}a)G~0Th(ZddLB!{@fw!K zEcs5!%gK*D<)7FMs|`P}yd%$rL5?Zl@-28DJwj}Pjn&=wV3qg^aAxqG1{}{%yJkHu z%SF2#A{Wp6FX`{%&={|3khdQ>ur?u6 zB;Vewy)k1S$ftUqq+Y}fP!F|ICuRzMBN~cibm@f^lPn6wMU>mPB6_+(pWzn~m5Ebz z#QRe~@@|_6$OLj*{%ht=`9r?oQ_L|k`VT+!^~v)JdN7H%f;&EeP^tB>Z(V0e8z6}u zK1&^xf~>%vGgg-tdDUn4?FIAgyXY7FdS|{2WgfUlnk&BjV$3$nnFNi%nxEaZ)$>V+ z-nut|%}9fF&&>Etia*F!v5Uw#d7+ z+OBDRHBht8S+CL)ZG(ah`3`OgK2a!};TkKbMVYpr&KbeY5dULt0>RN!5WWc(eB$Aq#V7?X0K(95f+O$z=v%A$bD z8>N`@!3ZZ-oc{Y2IPKA>3m!S=Z1Lt@o#;EguWbu%Ch!UUx{L?!QbO;new~nC)o>vv zp77P3zwjpQ9(2Q&tLr$Wp4OT5;_gY_kaZ>XiN%5EMozZh&SIz3jHdphdDTD$h+u)+ zdp@&{`d2FF3a=VW*7~UBJnJfUop)_@vsFGHtqS&M^1y{#o`ojYYsy>dwmsFnK39NI zoIX?<>>$Q>#s=C#6KLccb`>*8gBTXn!0OY<;?*>?-mE<1=aR4ldivJIE|j=W)Hmzf zTU3X4T&~3m(0Q#KL3$HNB$pWCp%Gg0xkIk+6Y+?g@RV+Jw0!pT1+Aq!Zd-ZfPmDwk z*}kytwqBpBQ?pXyRdzr95sqK<67Upj`pLF?RIwsrbe^wx>f_np6waW@)qsc*P#q68 z$+57Diy!M#@%Wz?DPquSTjNwidS#oyy>`jMQdxx^W~$^;HkgRq=0}tu(+u@q&%erV zFSX}jMCsX^Qa~111BWYREN^uoaIJLj9W(h9);pc=uTJiJ6Mz(b(>fuu9iM5Q)2G)K z_MR_lbr`9eLfYoU|2_5y5G8ossAutA$W!>(UsZn0pb2$HsC=!T*7o+od}va{ z+f{?sq?dZzDOKUa{+3fmq9qa@4{)JznjsUGNBcL_EVv(3Ue7BhGU}7qs%5E_A>Bzyn38L$--^PCnu9d50Wv0B%!=>Mi`Q`n~at+AnibsnIu_}klc81%VkJfJxM7( zg^+(vF+D}ESkjvot1n1aY=DFUa3=|}<$(C8Iw!J-d}bN5w@-G`PIZyBXx*1P=a%Z; zmKq7u8oHaT;+V|qlSl=nVL*}Uy=eb|)Bt9VOIO5y<4)FZY&$NQhi}`8qzABYsV7*< zM>VGLGKCrgX+M?lMj#>0SgOossLBvDx8od*A~@exfecbOPTllV77!HRC$a#a8{Sb z5>y{;;$WXmzll|5uOhKVqO%FGM9O8;bNW46?2Hlcy>r}L1lV4E^s68ptw5Mu z^CcD)DDQ}u9ERmQUy3Wy@iyIf)J>Sw54!1w4pGKWT^6dUhisD)&b)x=YTwRQJ6~`Y zEx*ete}{t`fLxUV)d-$|;2~$}UT`e{?~r>tk3(iR0sa#2w9n~s7p*)3{k6-vE)9yo zfI(3ZEj(E8v@n&a3#O6a3?p&`=1j?E&b9>Vi$MP0f*c0sHbe!wSqRpfN67Pm{-{GC zz%Aiuh+nz@(+prwD*z`uPE{0u>T?B>z0J?_uAw>e%)r6~ly5wbxB%A+va2yto01!$ zj0W&hDZ-yGX*sY7ieC|?*by!He%8aiUc&uHK)gU4&uH8&jq`q|c_qzVxCyAJR=%HT zn-;#iLXdo%qrLH`cm^KKmCJGSk*6T&CZG7#?~}X_G|{1S_=P{5-h7-C4A-qs#U>lY z#-kZ4d0<6KF+Q4%HiC$lq2E{C6EaD_l^0iA#I38_E0If7l8dwj_+Gl$|9(Wmorm*m za@_jFN*nZ_W|)A%LcF&gJz$R}C#OHSQE_cW9oi`XA}HTri~#@1oQP1i_ou^erNY?> zFcSjokCkcG7*iGiI@?#8sFwb&)rZ&3mSJ(iDJ}4zKVq1i&ZUFCdzJIWycK6F+3tl# zf`xO3WMV)y#kJA)N5A>pIU@IFB72aaleGVz&zeC|7gH>g5)U-rRtCtRc!c8~3f1sE zD@>9d(yCI|3-h;*4dBvENme-&2-OTd-IBD!1o*zuyZkxgyfv?J+Qq)YRL#7LrxPlJ zQRxjQj50PSX;1hM4JGe=t#_^Y-Q1=MI=2{~c+3casc zeL}m!kWnKf{KikRs`>;1PLX|5gc7nx+kLzGw=ZwhaK~G=d_-rQ0?T1fuzf{w7YAKM%4zk|8A*yezPYw(7 zDV5Y>CTm4WVI#uQ?b5ZfKDLCkXQ!FS@)uN`^(C31XZ5^~KJ4?Fgv20xvfNxlLtj;d z9E2}mGgt9-pWILMRNPnBv|kHAJ&d>8%OZM7KO-9@-j%!Qp-I#&sAJiTPz|t=F89fm z^|nf=^Xancn{8`hfn)?ba8#j02k9g1I{Vp@EMBe zxbpX)j9`?>!!^M~V@ zF}~k9UZ3~t^`_mud}7y?gv&hE9)zPiedrjUf;lB)D$J+B{_3qM%DRFWeWJbN z$~y;1B^=1{6=WU*+JT1T(t#alQ27S>%aE!E2c<{I9KXIt%_9r?+yq=DCCz|CsTm1J zVGu^Wnks|}+%jN59Y#24TU&^R`6Es!>dsX3)b2gI+c*EV!$O#(8{1)8Nuuxu z+G9f>l2Zs8k$z)Y;3X@ex91E(M^W}*!OrVn7+;O$xykIl^Ah(;Cd=^e&!JB6^qq|! zAsiV8J0HqdoUu{!lTZHY^gLQOuydLJ{;Y+pqq{bmx8A9KGse}kQ)s_4KDA_~kFqE5 znFF$G|NPgs%cT!)e!)3*6+X19%#De+w7s#Xr$f!vK5Ey^JgV|AkF_hC~04(hdug z?H7OTIhx*Ic=>Elg)uG4#J;!ZTrWHU*&P+DXA&_Qzj55TX9LCWjlRjZE*c-bVg`D7z~QB0(+xsSx z6p@_UsGmRlZu$DVwYM@71kpoe0K$6bR=*!ojtDW9HlQ&@BIU(Tj;pFRNC!6*+-=xq z3@GztzguQW5Ker3Gbs*%=JRpr^*l)f+C{0+apj8;oOYw3S);YFq}{9|wxM zrm*tZqUA*5H!J}VE~Yb=@4gEdCjOeAROlocaB_ssOJU`jCy|m%8z?yM|!i~NMS_NqmpRSC- zj<%M}N_E@)RBUMNQ}!$bkTUn@%?0J z#X`ODXT`pS9^bKq_D5RwXXYXku=XP&H^ncxXJ`9AY|5s5KC@~H;+m~QWqhZs&%Ow| zfIZ+y*~qEf);^$k^s7pp~tF-HC z(opwcPr!`rDPpur!3|0CAmdi+wYl|m^Pa}j6~n3Px~km!p}ebpy_r<_efPSK)29Nx zHv9kD9DKJq%>TaWNyPq`-AoPbyLMm3ObxN0U_zoqkMaGY(qS=PGG}qeB?<7JM-g++ z&c*61T1h~pVCbyhZ#Gsh*qX%)$?Wy*XN_7UOYC$iBzBHjr70XdKi=Q@!-l46m7(tO zb=>auZnvkt179Z`a`&I@DBOMNL0vc^==b(GW-03_y6vxxcaLjNc$G&Q}vyL7bb@X7SFN%Lj34%sXR}7A9vKL zsP>?WQw6ND-kKjLf64xx_DK8N*Yly@;%}eO;-wpgy&ta4O!E6Symooo=7-ma*U5$U z&l)2=?J7qD{bGL>KhZZ)+7U#1^rPT$opH^_dw;gsi>Yj@xpv^Z`lqSy-}y1Xz5@j* zF-BYjGJg2RxwlV;E$k~}x!kEeT{BtZuadeoZ9inrnnOgNj)`D*X!wwx6~0vue{xV} zLs!syJ9GPD)1)QW#!9^A;cV4N_5oA@W{F%_6&o)#ueyz2fGL~{Rhza^l#nz-;gg}{ z!>zt8W}w3lmlhnbAEXyGp?%2|XnZKQS^98`KajT9!@gNqV+TjGBYrv!NR26HfYXxY zcbBHoSjh!2z7*fvr!Dpc<9(sLyyFv5P4&v9V|d+zkB`}uW6mti6+OV6sfc} zg~Yg8xpeWzZm3dX6sK{q2VTrbxSzVdynI|C+kw1Koxpe!-_M%kD(ST>4>TM^k z(L=;VE8fk1IM0O0DHR@(KE&CsxTURj%qL*Fb-1Am46!t}a4F1G+bLssspIe}&v+w+ z$1{DFt@vkr|F6w+gDjgc!ARmR3;(^hPdyR|t>miPn>0&aX?a#J6XfVMoNDmECzeIC ze9~3@(CKiwd?P2kI2)q%OhfBy<)>bW2r(_>A&bn2h0o1`&6pyW2!)S}J^5;@b`P~8 zr(-j-qMxXI4bn@<&zIw&3p%j#sdv{z!$xrpcsY$=9ICPgt2+$jYEx5 zo&}30$A;f*lPS^mr(mF}m-h)>!AYLaC0g+$@B9qesb;J$D(3M51M}=Ozw1FT z{_U1Kakmhnj0HVjdVNo7g{+5!<|qXWrh)&o zWOzD%9lOHNy)R<_QL9fY8A_s+r!D`XnQE(J(yz4zef)7DM-+X3mI6OaECBgyeo#a6 z&4to&pM;HGB303@X#Y71achUW=+}m%0Bzx&xXVARC;(Jr*h0mZ5&I+14ed8}Rz(ns zJ7RHwA}A8yN7*%_b2*L)ZD&kl)`t$OVWHO>F<=RQkTeq;kHmC~|Cq57X<^3uED55$ zmyuGQxa80sE=5{rcRLFbj*^Xl)P5pd)HMv7KJKf^t8I}GmIU?aGzPm;PntFEcTFUz zA_*8*f-f0@)w`nj3A zV+R~AjZG;h$L;ZHM57P&Sam=@C8$5qhLqkjr(?_B!FGxm3@V-R!NK`LzTSWy{mu!U z>mF_JkJ4S$AefRWND_a>BantOk~|?Xb_jY-M&cuSOjshkVgfKDe+Y;f6AyZkuG6)S zP`d<`38R@w9?rcN&LRn8t4D=2k^@4(WLoQ4_nI!R-AU(xgzB5)8WwblA{R&9reujS zV9%NQ+@tM5W|xR`&Y4;#O88fmW1d*qzAuxEPfjiaRW08z!3~|t#;Ph`EUU1awNtP? zhE*n_L9+OHl%6JAd^fqF22)$8ig|6-JwZ;|EZtk86GYo~(Ple?X)UEm4?JAmpoRyf zJlXB52qH?hl#@@{S(XVdUdg7aJGu^PGGSu=pifHspNMPnyK3z(LJq5srr8g!noep% zE|{qb1--D8^d%!ME|Wa9^~^vd<|VvIq@SKe2_xKF(Iy{WnOOZpg(PTwm*Lp8N zK_29tt*WJXbb7*`cQdAkXcXow7Nwl(IW#n>kAL_u6Z56Qp3jH_$Fe8~2(%r@iDKFI zqTg2`-hyp2ireV{FoQOW?W>k4J3Ki~8m^Mx_#=Waw^;o?tR?_2X|(hb)OQSXnPkN_ z$4k*UACn2CY1OYLM2;W2{VZ~VD*k+;ImjF=M0(h_#||NV67$_~Xo9U0*{Bdw9qAy)e zZt|!}$%)4uuw9pBboc&A+k{;AD!07*L$fYsxZtxy!oxe#P1nZFb{7sGeRcm&L!ByK zucl8dCcJM%JYJ*I5Gpe+zCyXV!+Y3Pia!;`Zb@9Y)L`tObYb=8u+=TpP5hKZOhmVc zvwjXZYQ~En(a%qKU6C0z7ZS5^M?ZL?dWs+QCn^&cIwxpn?24XGkBJ=Lb$addx#-3F z{K#pW)9YO&(aRMvn?o)xuKiQdt94(Lt`lFp|Gq0`t^I<$UU^CF)VY|Ak?q-0isPG$ zB{7?)V-sZtPxCjXV)&ba?*XDXkP;5uDB>mY7L3QiPU7IfI7B24nT8X}#|f9?L~3!O zZ8))EocJsb#lxXR%_Nk}B(=??jLoF+W-=$uWP{D*BF*H}%oOs?6wA%F)tV`_nJEvO zsmz*f=b2$d%~h4mcW9fd8Jnx)&3B$O*9bP>6=|-SX1+V$T;S1b)tYO!nd=Oj@0~T@ z$1}%@TI^S{IG}BzYiyy1w>Wsxg0CNJVGwCym}YS(-@>Te;&82nahrw7u*H#C3sas2 zPT=h*S(!ohT#T(;@m6jpt=xmHjz?M%)2ux5tvt)EPSjeRY_swjwmLOyb(&{I61DbLvi8xo zK4Wa{i?=>|(%LWB`dp;7f0}hbzI9-^bx^H!aGQ0=u=V*_>kB+02~V@RmTwbLZgaiXCbG>YYS<=v)+UB$LlG6M5Vnogwv98kjmO(2 zoU~00woQt(O-{4Dk#Cz)Zp%-twM}bli5y2nvurc*A{ji}n@V+hXGa&cFHo|7sBQnq*uD^NUv$#GIM}`< z(!Mm!{&Bv2S-Jg_TKn=g`-)-vr?d9Yc=ilYhv!NTFSH$A8auqYZJB|$n`VA`Rc^Jn z1;CLVCR-??q&RfA!-?BeDkj>Nl83wY;cW2=m|q?JhLXz~|syz^SQ^Lp)K8w}W)7 zqDcS>pqLSp@cv2C?NDjAPT8}aGEqkr(vK=$?Nm%Sx~=`F(nzO5Pp8V+&QRP@=@7_v zE@4shC}A9-h6Vsed_?#$&Gcit?;qP!aZIc3n0EUyopdOW3zF7MRm~`zr>!Qka*niN*UB_2BDV9hh!T6K(`CSKD-`DiVgXZ96v6AYYNc7>vkJ3yi4CVfJMNiq~-IO#Y) zImA7lK}r?)EI=_agyr7v zx>wYdU)hxlb9G7>kRnlIfcQuo{g3-{{2Rw>wwF}!aR z@e2l(&IJL;IBW}a4L0O}>vWNaGGtDyS#>+)o|c9UnXy5#Oc1CaBCQ;cu^KYvP-8fN z2=+T4cH-Ldz(P@1Xm$KV)G6V#Z!!QNjZDxKEbBA`DcM2nykt->h!wh)z4sA_5arw}M+3*su<&C$7La<;(Yf46PtaRe!2Y>JOioWYbKAl&;yX1NRv|%xpx2Dr1 zlpZI&0yyG8I3l2;`BjPmC9Z%RS-#S25L909njyN#KJMk?}& z*~|8_I+1M+0^#DZl!^T`zwQ3M#Ns#^ECj~_g~Oq`lq5fmqq~53*Te}J9pb2Q)Qm`h z>jSzZK$b&s!-AtRY!gP0&{nUtm-oXKpg`Hv`{{I_L$3)ADuMw+uoO*Ap?yW*TTds; z9EXw;U3Rs{D{#&k0ThQ^4-kW*DbK$9Gyul|E~`wt^aHZ=I5R^~G>d9WIjbulj~Dk9 zgzd%p!Njd3G48Aw8w3#)v1x&2DkJ1xs*XQG`1eep;9po=xThOAstvr{TYbX|1Y%M7 zQVhyIB6#02b+7I08$WOJZ{1Ip2k>ZM4;P`vpj-t26pjjOnO!l7{|Jx2rx5@m2Fv0S znzw#NP$u*+f#+5zZQlSuzFQCH>P!PWpaJP4Aa!Cw42hypnuMjr>hw=UoA_Q!_hM|_ zcvCn>K!V0>IC#?wz1Y*#c_*Feour zhkMe|5TuJ7(`Qqw#o|k4g29UCkX(z{aVde|Vcx z?Xf@PRt737hWfuPL0x;zD4xdF!)E;u<0Ds}eEb#Y=Jg6j*+~YQo{lxCj`vbI!F5Y= zt!BTyGlH%D?ura_B!Xn;Cb78AoR#l`b>Dl^ zLJWmnb4(s7I3D5Q=mLaalPQgZwNNA&pIIj<&}8t@chJR&h?=Nly~^u#Is>?~A;v}A zrm5~X7gmoWeEIoEo<8lgSl4kZ`T|HhNOV46A$0n%nigbFpKMDRR2!XSw^wTe5b^iAp?tG0}Ec>=gGn z#i~_A-a24!-9YKjHU;;%;@S0sv;8m5bv+H)(EmML6V@mC@!?f?4)RTDEpMM?qF;l= zvr`=#hnA+lmbg4SziG5G`vvqo(2I4bbwZ)PP@5Aq9~cL%e0kx|mI;r$FxBIJ%myq0Kq1+_iBUp(sxfh5MuL`wL{qQFF)gB|YNA45wQ7=b1lK$17XG2M zu@)tKN6PN9>K&;%HR0XDN!o(??!LirwTweE)oPgwoiC+L4z3ug-?UP^rk-UdIBmbd zN7@~`Wp96I=N&iCYdfr?#%U0Iizv-?BME|oP$R^Si(VhYa00%TMtb+ zYw@^h#!IX-V~&xbKTB>W6A7&QmJ4dK_iyZ}(R^gyplf?C^s8$hDSfB~s$E zs9}wJ-fF)*)FHS{>C%1JLU8?!ED-F?HJ#TZ5gT(Zf)GwT;vMKcPQ~EvycT9|3xXuE zTMzH6TNXGM5RogRAc$x<8Rn!3L_XEvGq7LlgtTh0AJPx7Ex^18QiCv*t=DAALwftv zie2aJZ&7s?dXC`ZwWl3q`TRJtU2^PhORXKBjdk1KJj5LkmO>qvb^zpqbLoZ`Yx7L2WGv#l_G=pF8b}>Pc3<}&B1C}af!VWN~;*l7r znr4I0F-ELxEe5Vz+8}m`5vRh#AT2cCOJp(PHH=k-T}t1}WPiHcdPY_BOsU!PSI&w0 zwW^SSguXh41OC4y4?$H0&_)AD zpbyFeB?$>bbqiKTE1^%9c**CW3RS!7_BCGq4_@6e&oY+TRt$glXj@rT-%eGDsd~hooJGm=;~g(`BkNW# z*g>_$pampz@UvDhPeeLdY>HKzRxXz~iLqIrh1zA?(&pPW^@ z(IszLytvV=wXwdwEsbrCfxfG+g++F64Ql+JUzARt3N2^%jjvp8TtAk#w6d|j_6aI- zd)@b#=)(v3(dU&O#EK4V@s90CpUX75_$T zVWYnxi4_zms|wfui{$bDRJi_;Jfalk zbJd^pJtKWcQFf>*A9(5CRrX&EuEm*=&##|-e@B6csNnyWJd&lfPPP5p;CeCfIal{T zNgl6$c9pt3In`cM`ESW%sQU7+Z-N8MKi`=G$-}9(dj5w%@;Kd5`(|;9^~m8br@9(} z^d)j#YHseelzwQGyhT~98wlIk{AIX_}_RNvKaZg3N-K7V=lj?dq{24Pd6 zvi@u;Qlpd|E2=-ujze1uBoAqK|Iq|_zvL{y$bWh?36rQfmaLxbKXya2xMffkB19ic z#WrdFNYm@}zpt!6S^6X6Xl0yQCJw%P+<9Yj@dwRT<8h(GlJuMLTLfz%NfSr=fQdUq zzsD2VCqsWuVMD!Bsye?~$8!PyI{s2%mgB^&oQPKO_%&ylmif zLGr&OkD2L5H0wP-|0Q|k`j!1G&i|L>(Rv#7FgtJ$5m5?Igi8dHhby#{-#YW;Rd1ea z`IA9`5?29)2U$ZY+)>?C~y4_P(4)u2NNpyZ^>hp^8x+0bgO-;#$?*z7-&$EC`pwBUt|h5YhM>ARoJ9!S&q9RBIE-e0mWy%q{*ecO$b{4Sh2 z%V<=gcEol ztS+g~+5l0L6=ExbaTQ3Sh$ipyW!DQ1{Ki+8_tN{m4G&1LcgUan<=k-;rFZ>sLG#m%-?gj1H~s{FT1*g* zP-=uJDENx;7TOHnX-YsE=6FjVu5z7O-RGWdt_+9$`47osJmVv}$)C8Z{Qk`?5juddWr7ts6eJ!~G1!2E8F8rSG&*#bZG*5UCsw|V zE|5GL#3MLy7|{ZxjqQ8MJWjmk-;zhmd)XRJ0yeEc^qlPn#X(M@VOxQCSc?VWZjhge z=$Hkchyy)Y`ykdUwd3^+LK!?u1w%Sde!I=p+0>Z=5W5?tAGdtm8*x;%a+_^Oy{2Uh zOD)jVNKGNmwg`TJaV1Dyp1*R&x~r`d!%O|a9Gq6W#(fkN(O6)-)R{SOu>l-~92cL% z0D{Dy6qFc;l)h^bRhMRe6>jXW{$smVw>}b-ma2rdhxp1N>dn zHvc4tTFGoZ^#*l&99)v6CZ$eL*?Yzoyd6scozIQmW{Iu#ZeocYAyJXGG$CnX=iR;e zBm4Gw#pP04 z$FgHNt=+{&%Z~}^Wv(Tj_wBeA_gz13hdj^gdAfHpEub;bvQGGj>5G?kOB|}j(aX-m zH{D#0U?6gBEso&en-z|VzfLHB1j|hyklJ~fy42r_tNVTDXoR6TI+6t6PD&T-C_~68 zg%KS<7>E%rPMkBD*z@W`;hoBE5ENu(Fw2A)0U`b$r~1s5zQT?GV}T#~`i}EeE+I*T zx!}5H!8tJ|<<|mtXcFmuYbhy>mX=9(u&Kh8@o{!rFd(qj_U)&+YHuD{(Rl?$Uxev^PsgZX{lUirho$ zQ5f3)b*G#TQkH?+-aQ(8BEjLN>+r;ZdjosDGp6od^YZ~Go#nR$HFdi^UdpV< zTEpn*Ud-PuOW2>$smkkGe4rNk<(`m{suh?+cXThT-0SIcNf#*(-|(l&be-fIHh_4Z zKW{!?lnjz$7VjSUnNcAL3zA1lKu^rL$2op_dc@<_8OL9qIge|@stz`>uRD9i;NMY} zt~Pn@p7q(b(cj`!^&+Qz*6;Af04t;FRf*$V;E9dF{*DzQ=kZ)zh+F4~`0MIs$KRLk zZ46I4y{_qN{~h{vV}z6Ox^~L(PsGs1H*Ux4`qlP7(Hk4z0aP^;;lzpE#$zL$tKZ9Y za1symM$wtojk}!YQ%>;4w3s)76LrX#Fl@xcaf3Wus;B{?lU+_pJw>s<3Sr(>!3@a9iKW=(gA({kB~ z%^BjCn%>tP%TKRw{vx5?_BT7NytubH>+k$_u&-k!xlmOsB=ha?+XtDEZJWQtzr6jn z+Ob-{vH6FBs%0abx$n1aagv>D$K<|nn+|Wy(=uzvcR8=Mp4eK*{Zcz=@MW#z`qm;H zRX1(py#Dpx)>5f+-OTYX>%DKcmKm9Kv*(0l-V#VbNh%to18V4*#htCsG!qpVfeu_Ak zf)+$}4XM(G)D;41o&i=NK_FcDGZ^R$gR)4VsuN>1!ee(<3vtO1avwFFDl|i;E@R@< zh;hrLIK%Kbque;->bN8QaX4RHo zC@wuw)-cx1R)F#osG8J85^95jQsW@`oX|>sQuHr|IK)gSn}hm=6GE!qh$%>lwvDHR zBgh0H1OK=v!&ojSagmS`kQ=9qM98rbVU(1jJK3? z(l-6AW-N#Uh%uo&Y#b#SmBvW@#SteUlU>4-)ohc6{o~Xy(VfXi88XNm3m9@x5Eh_C z2ANWzVgTZ6brQciF^r86I2=MZAO>W3Ado5Qk17dIUEzp-E2RjPQZ~pL^Jt;H1LEgnvNnh}%ZaF3dD_@(aTzpHnT9$;0i|ogZcqRe3F36< zri=o0o^sQW22Z7cJjmjPOd1}I;=LCC)*`gb5Z`MjG{X^};bc#>AUAMAHz~;56y!~g zxDXa@hz6*n>}i9zKV*A>|$)Iy2@CgP?4U0Iy0@SeJSJx1> z7^oQfUIrQTi;)B2K;+1vnnPeAI((S{^I#yI*dRe_RFMoZXMqEmNCW@G0KV<*Izx)> z8sx+PNQRz0OgIptf`&vshW`nGsIs7EI4Ch3>=Fa% zgM+zoP**WOuG%f8KLfKO0BSMyMgd+tO6U^#Ri1xdZl21P0W z(ag+%H#t!Qa6A?Wpuo(T2zeG#1`C`)BLwFfzKW>gJy01AXde?{O@Ln|!A!{zm?jiO z6YN5UQfG>gG-Mp*D3akz>i;7)_<6QEWclocD4?@^9qfg;&- zE5SxpG#rE$GU=zJ%v`@sxdGy!l*x}n?e7TF%lC0WOLplQce4-BO5mm9awMpG>odne z_)S7V3at!-fkgAMKq?JbiV#;Lpdd69iu}Zr{zMfEhcKbqrJ!Xp>^K2fA%pI(0iV`U z9xU)OQwYBeg}YnW@#KN%VqLIeHwDTwb<$~K&8_S888(B)SCdvalj=C5K|KD z3>~IJ0z(+kd2-fqk4G27Z#QvK-G|WfDWEG1FrEZsCOt;wKHfkJDPkxCIEW+`c8_wi zI1e>Nf(X&*mVqyy+E-7JAu|NQ2LUdhhf*Ve#F#mz7>FkWc{K;FMnY);)w}tgDDLiu z%qfshOQqFxWvC%qkpYuqfXM`q8yk57`(h;TF@-B0NCTA7U}Kh$Dh;gX0W+tA%-J`q zeu7l!@b^DK(F#DWAfL@HLor~=7@=qKzzGTzk10}Nft1-GIV=iK28m&ywoD|M1-?uN zU1kZUz_N;dQDn5D!+s(l&mYLp#gkcS(VVmxYN7hCcs?<6nE~ESN3IFZZvZi#f7UMm znMTO^10b(G77wF+OeP71VSy(Y{9Al0${jE6-|XoJD4|DWOVAGu5A@OmD;)1U~3YMt3GhXZKhAqGf)o ziCdw=(~KeZY}i2@q!JHVqkx1tC>OyXF7{(GGD9>xW0{siFQ@1Um-!Ln*vX{}-1O1A zk59f8y2GjbqGsQn4krSBw08+VPtYyM&K{VF+xrla4h9B^CWdLR?uYdQ`D~ zRIpn{Wos0pGPdJ<(v-a1}{=-Bw!_^x&@`eBkNEmYKq%<%UQ03Y(Z5}$kT zZnor89%GT0{eI26a^b?QTCdBua|U^KIXwnDq1(iut!uoo7trYz6@|EO%_D2aif052 z_e{z6&M$4_&6bI;IN&4kcVF~g>*M8o=N(FFfyHnmPC*9;`!JTI@)!LF!)i{aGb`^P z<#Lu678VuHKi(18T|Uk0f35VQtPtj2C{(gGJhR4OLLCxof30t5r}RZOtYWigBf_r` z>D`HW)dOSmPBpxp54ajWw~-MYmPJc_Wl(|GCVeVxa~P_g)EipZHdwDc_Py6>4|Mj= z{N?8h&A)i>pBhVLOm9p1u9(_A`VQ0DJ$}jw`u?fq%+Kkn2iosbpbH&(Pg|F27kF1b zaI@-%AO7Zvq|dE<5$%1UE#RuIPr1vR8;LW2qt*UR9&c^^`xY;@iRbsAv3`cP@Ku}J z0_Am~FTI`JlQr&B##>%l5x>12SiJ<#+YlBY#V)91))F{nEwpYWv}#Q_n+r~x70z0N zXRHe7H7yH*pINxpVgh-b-d0wNeb`v8&m69b6vkknx2Mxq z*rXS^tOJ-mkvLMaF{i4{SA*GB#ra)sE5NB~iN2D?N;Tn_CT?S`D2}^6F2J}XzwzJ0 zw!;fpj5>xijw3Iz1z6Vh5?ugTNl%S)$5|`={g>*w0Qb!$&R(f$F_I;*`)gbZCF#=K?>PH`* zOn#B*>*QdXEP^0Zd|i`9F;;--juv!4F`QNhI($Pev(Eq|}OUF{QtET_W zYJa2~{>^HQSEhgb!)j@kvH{~a1*~>F3$Oq4Z&tf|;iA#QFVpz*FbWTeGj&`?Y8yV6%j*1zhmO0Z8 zf;+Ixg8jKE(~o{K9}#=Wg#W>6Z)wh%Hp~7K|r{Q0H4FB_6^+ z+tA}*RGhdD3!kyg+KX*^eSZgerpgyPj8|tDzu*u$f*_Av$Wo{6u8O6v_`icZgzt}S zx?OK&lY5BgngV-Io~XLoM@rIJ`8&w7GT<)=@(c#Qo?96r3xYhuSNcL$N5cP)1$j1R zU-g~en5&-pAFP&%*vI4iE6B6!S#2km)fKsj-1nEk;q5Ok%a|N@a5gX*mb$drFgP`b z+Quht+gdv+xYsF6|8R^GF>M@*9x;Nl&9*HLDen_oTNNx61VsODtd@ISr81iMdLByMDBYrOTRh+~_ z?X#n!o&5YH>@T7H0o>}8<@!*|hmIA=j^*2yUdVkchHmwY*1o6AbGeMzUgrL~wdZNX@)MHS6JoP{?~AQ1CaJ81>w(ol1iEpcka&%y>AzR9YqK?jsm&{eF=@HRCSxD$se z6Um0FRX2#A!p6(+ND!Oq_lwooI4S(7(BbM2vcH>Uwb3McKM9%0Z8rWbk$HXi%*TD_ zn^V1p$7H@dQpVO_%(yt~qr6IN!alv27KR_+{w%jyH+0^FmOrjORQ++i+U5rJ5;BVS zE!;eYVUaib)!4+M9nCWJb*Zf#8$k3G^cq%ob>3GuuO=M(R z?SfG^U1gy>=0(8qeQ&z?L}=>8{Lw(IH_ZjbRV7pNnL4)KVjI;}*#YH&W(J<0-t2vK zd+7P>eau6Zk1MaTH$X^EFAi#-+; zKUk509-;cO|9CNtZt#x+y9G{|Rtq3hjiaH7B(xXW4D61DijmFGmyfJad+I~;xW?U& zw-7zgIGL&x_I8Z_dto>Rx|4v}o=*9o#2}>#cZ0;!DaopqXlU*BLX|*&OAi0}0@FsA{80s$GsIG5jhK{F}pKxb&_>$8a@Pz(hDx#_)0N2zlV$^<}% zfRx4|c9X%E(cnvfga9pGAw|NEf&>KWDhA!t6T>G7SQre3yX*n?$67}SPfH%@3mVdo zJkA0UIT7D9pyp(-ge?@qKx(n6L;^xm6TR677TFKjkRaSJv@8Hs#fFJk%*fwDe6C`pJX+cM;;=spnAOYmCrh}#F;H!QiKi$u4P2Sj7 z5S1wFr_d{&Mg#cA!IBIJoQX8gfn1@X$ShDa22w8v)~2NLOH##-0+Yx%_)U~F3#G`0 zkO^1h&IO&b_A^4J?{1)!6#MUUC!NIk$e|%u$OvaT)I1C+goW-PL_3l|>Ke)Fa3r50 zE_M`h5(AUv&}3=hg0hYs26>VWvY-J)EwBi`;IyVQo70)QRMQI#f;UO1c|HI(X2Y)# zK*nT|9(mL<0TqWuE@E%Tl2BV!$Quk~8Xbu|3gNM?0Iz+&C6E|Rs1@MUf?ytLz{{gJ z@U?8f;a#`1Kq=)-0VeK9XDnn54F&@s0suoZA;)k~;n&`0&Y?D#If#bycJ6m%t9&*Y zzB-dW_IJILJ|(8E1m5@0)_9&c>6bXGk6Hkbcm~vm14ePc!W>{H4Xj21l|n{{KHeUh@NEW@r);qa=$o zwUVrO`B7}Cog_)JLz0#3BuPl)M@Z6SC0T1HNtz}mD@l`vCP|YfNz!D8q>0H+(~var zeQNjY+5PO<^WOKK^L~HM_k7MjuB$G8bkTLq{ds%b9`{E<+|x<+*B|Y~Pgq9PH%IH~ zAt#mif#!&|t}m9$Y9KNDixmzb)=yd^2ufi=N2If%J@G5|Q= z-XfD^)8^7q3+R|o2Kv0P%sfls z=}*JcF?ewKaqf-_Twc9FpbGc*B2P06fJTwoLJc z?g>q;FH~*^Mdt}-N0%+LhWeU3LwzY70=R)gZk1{J8Y~$3qVRf+g$Y#KECoW2J^|A9 ztyx2Z+A;{>k!_mxu$6BwAC#*lw#EILo_^jz;gWLe)xfDe0$|%0jvQYl@|#?I!v~8r8UF zycrs8B@BbFqiXH1!TZt#NLGWbR^Tx@&|;-sF!d4z?|5&Hlu#~Ha~avgvNb_r2}KGH z0bavWB)3bk`SQ47Atp;)Y2qR(J-v27D~mo#`QwbaZ6_ifzA|f4;R}DmBVAh z>ahx#Dr}P}x*1`fw2~qrcR<#{W%_W` zIW4fGtdl8~Okvnt3PVd2^{vjrevWEX z(!*sqm$#53D@3j2x&TIg06ZpQ6b*C6$K|SFIUe>2TEs|BiZG6XqmwM`xv;1;YCvK! zF*Zh~QdOg41_YW?EnmYePS3CiEpNdV%heq+d5ejNNwqAM)pKdil?vNrSwa!J+KOsL zqtYwow*D1u?as-<;yy9KoyC@RsDmu1<4R?zki!|1iK+{OTxgW!4qJ9d5Q`_O=+e&_ zGY0Bfi-mnZtCdTDgDl27@ofcE6NcQqK?)QvKnsS4`vFA&bYaT%>LjRCQ{Vw;U@Dbn z9P}B38es5kzyTXq10M{)hT&la@WB9w0I*?-KuoCrG;g?_KkIMuhSvLt|C2ZDek%AC zZ+I{s{bzVX@tXrWt-s@jIc?KVnH~6J0q{TIhW)GXhAB5Jx)Y5-;w8`i;)ZQ(*V1$3 z94h+9+^}EphK(D!wcTY-fH!da*H?E2TAT;G;T*kgcyN0zUSn;Wiy>^cJ$%CyxM9yW zH!IS4?k6Qk^hd80@R}eS^YhTRk@Ru~>_ z#Jv9Ch8d`dy!TjJKt_Ld!>rn#@?D_!@77ciesaSWCXDBhkvh=)3qojVRFvwL)ft|u z)pn`?`0wzBJ2P&qnD@kJ$_+CTuJL+b)8RK&035LG{K$s_;Qw2^A@TB{c$&ubhk$pV zJf3!KU4aYP?AoZa+|kGRT-%u)K3X%pXNph{e$Ne4-dr%LQ9t~0^8MKJs>un>@9_q9 z+>J!W9ktsst>&mugW^Y{i~d_~*mcu!WhP80B~NC0i)I_Y%JTLp)qhDzGqinmke(CT zw}_4S=r0ApQ*PL=ctiO*Q)92w&5JVzXWiNL^o)bmZwr8b%NtZj**RqvQ@kNil~*YK zJG{ZaUUiJ0bJ}*>r?&&URRwk8({_7q-3}gC9TyVHX_=pjLycb-w)m7UI(|zW?(`ep zaOu{a=!Dl_%Lr#2Z+_YqQ}p_u${Xyzy)3-x<+ak6+~-j?_kV~t+y>+Mobw*P@Gy@*hrjB@5Ch{Iz*cx%$XdU0i(4sL zhh1hilojP03m-6(vMh(XG9wnhn@+{Mp+Dl>BCu$I?Fn-+WASOIKa@q<4;NC$ za67K83MT2*3fLRHqECH-P&--9)URMA8l6h(Y1^~VtFCH`JLmJJuu(HeUbR_zltiQ; zG3TfA88m*1BOzoKd7^4V6bp$-3`3Jr5Ky^q+W!7DEdx6OR*LK+ld$Lx+J)>5zzw@H zc7v9CA!nP`RU_R;)O*EHBAmFYS@-nl^9vkFE*)JbH=? zhN#Jsb}m$!Yx4cIk1UB$IJZ9%WGZW@dJWXvtpSNnrBVj2pmbJ1xzP|Rp`*c)u&7i6 z<}gHmenSBS(x8(yl-jC!-wmNq(1}E?wmuEG>fm0gF6q{Q44E1YS(}3F*8$>O7x+XT z)%1uw>s6Y*8mPTpOwLiHhC>6bw#}8Eq=Gjft%2k=pwtWwDhvuV*`ZKpwFx#?qv@b@ zcXp_nq4DuCAkyRW$Hv6AhwGvCTF)L4p*oA2 zRUs;^5P|Rp`B&Iy!-E2RP@$AYps9uSHGvFbxh&A#zQ!r6t)2$5UtWcrM`36tl*xUZ z=FxszMn!+OOxQ$OQJ?_XiAcb+@}(dF`VwH@MU2i4rMpl%oDL_eWXAqAS z;4`E$LjtXKv`en&C<>rT1fHGg!U36#?oO!;q*WJDvlB!aVhM8%)v-j8PN!xG#Joim zVVAw9JGDz_#ZD##gqJe&WDzzY)X6nSyhsenkSl*=`Z^btRQmxoBQ4E#S z$INwgW)s2Z8Xz?!bq9_#s37=_t7BnC{<-%pwdg_3*JS8c=GkRLrh%t`%$45_FUAeX6{mxUPCkwsm&V+vKhtU&% zc+e(6gZE^?%RRS>s#*&69E*%YEkyWjoojP`4~hV>;33arjWyDh8_<ed4 zF3U?QJnHo_$fzr1b3|3FE8Zf<->622BESA=O@MaL1MjC4{&WlCucIe{-!h02(gD9G z^j_y1WCjIe?KD)BTat_lo6P<%qTnw^Pxd8yoaZn8g12VJNch#@^B1>n{PN|<|E(za z?uTEEo~G6Wz%2-g*Mj%zjt$@zMAzS46ZoT1@E=?g_?uDic#Fu=X(|eqQqFka`1uyZ zZ=&Fz8a@3>N5O4nxMc_@(-i&xmC=*c-p19M5K^KX&0W8-akVoawXX|(&Tk`D8w%Am zY6(Lk`CcTU(=n3N6M2Evi0`tVZj>)GLvoOtr*BD3QNvY+!2pKL2cxI$R{QbkgyQ!)>pj5esq`Z(!O)vHaT2w>u-5Jq_$48n znhtw1spP8js|ffQ1lo}Lo6*y4>44Ll%aX&Dv1e9284P?=-*w0CZ5(HF74y=SAS0{z zOS6M>An3m#{Cog#FPdkWFphq7M4DS#!;C8qj)-^q2>RyoBbUH*)Z)-DBDO~G`oXfL z=Sh{xmt0hQ$9fn1P1&eVY<^l=I*3hx)&UjA($X14rGHa=BD+ov;N8k{#m0k|s0l5+ zAppk0B%DOmte6`jooiSZp+VSJ7$P-yEXMClr?sc?;4+&HcfD~ z8W1|L{kXSUfnI$iBSSDhy>;5Yd!{97rvyQHMOjg`xRNVPEe8vbkWf$)S0W(#7pp~( zL5B2)SFcM4H5t_%D>7;t8n0oq2KA1(q>Qn8d}!CS>HJ z^nJ+3-vmeJaL=AWxyRNIYueg7u>LhSnnn6pC|sa%Do}ji(|!A<=zQhb4w-sT-ruj$ zboVI?vK83E@i(I*+Q;95blB7+!sd?l^*ur5y+!3Juz6!39CY{eYqQ6|nkC4QJs?fC zL8AaCjjIW9YSBQxxJi_|h|08pg>@#pHXb*-X0%JXf@mS{kqYbl)GBei(8SPzvZx$p z)(DMjg(XBdH?(U}ABzyk&~%V12PE2o{mdv&R(3zpgu<&783s~^$CbtjIlc}|I}35e zxNKzt%nVPm(Du%@5NgEaTm>xa>uBwCY|CL77jm+A%C35$WsW*JJDypWBUOpz1No{P zxTU!ZTPR=SY;R%8?C%oc6F4P{7-gZcaSCCAFJpy1bD-TMmut_jF3fG?NgY|r`nut2 zzoNP%+XRj@M_67WZxM+5+U4{>Szv*Jqu_}6LT0E5zl86Tpa_bs18`7WpG8|!X1b<~ z?Q0@Zi=6}gd}@kmj5?{x(J%o{@GBlyD8=>4Db;6cEfY{VkkQpZ@|kD_w$Ie9E&%4h zJ|~D`Q}R#IKLX&$e=~Kpeuw%EfSYseSE=hk{htzkijSl4zYpN1r%?XQ09;&}mJRI} z08U@mo-a)O=K;7A&QrqAdXTz`EY3{n@|u->!_sibjV8`z+nDh=gmI^;6Uo)U~<&$C!btb-~ZHO z{^D&bKl@hzaQ{hN-~!jbJb?QuecVd4Y)beU898P4p71{|{FFlJt0BE3<+B&t=<+{B z*ULK2_#e=9xW~e&?%~e)Z^bzrgiS`t=&C8_*Cj%flDO&QEgKDdg8JUhAITlhpz_Xdx3u>9bHXr71W{8@w!*nra*2rj=-TfhyS4 zcTqIQj94f%Sp=t9%AaZ{$*xZyKiW?zY(&0we6=T0A&aj;XuX%?`%&uKACcV< zo<5;&^hY;e@nK?#1n(j~Icb(1pQhVid^ov`s!NREQpHK(7X>nmF;$3(Qr>m%;%M#1 zUpFhF<2@)0?fuDa-#%1fog{A4wdumVk&rYefjQyZ0S`k8ALArI>g}hEl-=(`%}h7P z8_6?IK2TymORPsYGgEXXE)1{L}ct&og_N7cpxoUJEAsyJwI5Ps-H_srA39H?5QbuGUIUUnRn8tM_x1X z>1Y!f0*!QRGOA!;V8wNvvEWsV`|nv9t}Gqm^ClO?!dK}wQd5>JwV8y>%6**HN4XTg zY4jB-Z%%RlY=_S-@Ab}&Id&7%JIT6y`*)TzCzfB;e{VDH=+u5}_*g=O1@%MD{$qpg z4`Tf{sd~xb(E5{IPlS%z5ly$=Xl&D3g=`4;^iDxZ86`ESc|nk0skTdm{=QCwI6jFX<@U|S_re`0_bS{wNu$W!DqB?onC%@MO zWD5-Z^MP>he)6qyWTd*f+BESV_x@X#v`d564Q3sDN+}rwJoWKAO?a>$0Iqw!dxK() zLT;%KA3WGrtIDkGxFV>oRB4)<6}EX&!~7qrn>$jIV*ztru)F5$g}W0{DCVTdGMYCt zyMy#;4#@67m1B8ebiXo|l077Qp)9GF7F3F2+BJm*`QUkw(5Px|6Gw*oRrhFWnx&(o zqbeb!bNnqKYmi%6`TjmWGA4HT21X9TB#) zl&B>Hzp^@F6uc-IcF4^i*T|dsLY2g?yr_;~mlZ1*Q`OfsIWSt9MAb#?5(jwL3T{>l z7X?$xS#Uybf4c(}WO2Y^WnCgaCS6)D6y@Zos~zPzR&DiJplAfomXs^<9ZH23Tv$I? z-aL>~ozpMkSjlrLnDs5?#a2$1SLNI~pA#J}FeUnBmr2|DMDbSdzTB-o!m{t0&$E`)~|A`9CYmLwxBqh zI0Vc5vYf$VqdX_9vVoV;DFK}*AEw!A0L7=8QGiSjlJ^Aovypr)A)Y^ z-2{W~A9FVMN3kC9fo}4K2Z#3Zj7RQb){cx1UFh39{f28?9&2bFe>R|-94$&3eAoSx zm$g#v!#YweEfhF{GSVNJbZ@(gy3`kf@eZZ5m|)#TlM{~Kcc^tl`BK6ULkCncL)v|d&BsaAoou*Yo`k;CAdD3LQ3oSRW|IIKU~?cwy=+ zL+XqTWDi`pFpb=QQfpCsBSc_4yxg+I%$j=L)tA9?;=t1|-YF;_I!oV?s=Jhigu;|Z zZaDbch3**AX=P#Y6b|AuMii2(%+Q_`_(Np6?Uv7G9#0-iGo8-%FjbvBqTMowIDahD zMa9lUQQgp&7tjClX$)yUA4W`XvD43H9I-76!TDCOD3B0kkT1mcFdAd;&nBfQPno@` z^Ku=%khx5OCT+xf8dSqamPtH#Z`fY0@|4Vx($iO=FRWerdr9SX#~NQ3;!HK>{?4+K zXHmi2lsmIYuG9dkZnQFWc@8c)%ka9-?m^$hf{@BC530_<5Sk!FCwFxl@^5&#Gv*2P3W&y2H8|7H-Y|24e(vbLV5h-Sn9wTw=sf1#1 zuJlGx$c47Ox8n?2X31$;=3y)X=r_arQ4ybbHer1YMN~P1=v3Is1e#X=4IH4!08mT z(0a5+t=aU0_yB~Ni4rk=4NKd@5JjwDrGWznnfq(5JX(L*{hO;2+~TNSv>9876Oc1p zgHD=;NId36GLTk0a{?$qF>c~B7vs}=L)Z?2Q>B^v1yl^m8#YuSFeIKE>8(kni<*;3 zjbPvxfx}tG3I_TUK_hm-{U$8@kwx0=4N6dg zGf!+eP`wJ&P+LjTjy`uI&g0i!)H#~DjmE-^oUZD6x&8AqH#bq$T{xWxPWs^?kH-dC z@3aOuI0BiW^{xe!pp@+SZryV1$75d_oA6l{LA@_GNyfFhX_z_EZyH9sJo@J?c)M(D zvvm|XtLu#$LL2HO$ME5q-SjkvVvdo0mWQz-gfwUSgeu@w6KrvfM9C4pjtQvL>f(^* z*~*aTjyNkWl^zk#2ve?m*l6BGj@BXc4vkKKr@UUBY0nYjS9rr{0|{$^t?X5jBsI$* z$aP;;jSF!b1EFik#Nu*N5JX86VPY-HG~ditt?OxGLY{PtKpJQsBHt`A;BEW-^+nS8 z<5=LwFIC2&tqkxHdzzf(IzWLU@IzbMM4g=v z$H%8OcvUKea##%>FR0YF;PHYz_IAn($bJKq6KuK~pnq)kSd)ln?Gj;7$WaOe;*J{a z90`*z(6o_71MFNHHMLzL5IDDpx`-}x{Qzo(R8k&I(>68)M7&$&%;V-$IkNO9pVnfk z57Aqt6gSm$v4!$gOY^BTixzE;#1>EMmPm85qEh={LAOY%6g4}*QPE|iol+AQ zY700UQ!kCNfR+79gIb|Rt?V{{!_+c*n2)t_d>fn59LUg*hbP9z-~>3z53oo=x0A3- zAoN)j)eYPaxvZd%GdNIKF5uaf!(jYS8p`ix3lp+vPf43u%y zGSA|CH5)c28!Lvz_f-&WrVRw2ujo z|6pNE?Er%j%hY(_!-HjNHqbd`^@1l1m?He?m&@&ZyTAEzY5n*&FPGh?e!UX>Ao9yU z^KvP^B>epe!8}q5=HF~W;DEyC#{P0bfT0j*x&OQg!H)%v#QBxBF{M3YCi3w12 z2R1iHWswN#?(a}~Zs2gmWqz9RWEk_M>;2^0C-wV?U^vij&epD1s7~nU89|SS1?tZ2 z3*1J93BRsy%qewEl3&L)Omy8p*Z5O?V@|LgDrXMb%_ximkqt6!RV{zyG> z{^dRIT@JDBK3;LL_vv2qNB%_=-T%B?{*_-Y&U&WfdSE5^mwe3UOlZv3zk?Eide2x>asZ6j$K z8nj#EwomslYNfK1*&HY;YdfRO4V7ZWz`iz23m(cl(r6rRnlYEKOm(zFG(4B|={GlL z8LZmatX;-Gbdk5^Ni~$DOf%i$c%7Ql8c;UywB~hy!dd&uqgp?i8L{p=|;W^S&b^qNITn(Xvpv~yhu@??AymJ1)CrJL()q@^a0YzqEPep1&L;bGhk zXJBfOx&*R2%8-xP+wxF17Jq$uCAD`V7el=Eq-kaz{Q!y6NHAkJ&D2L^E+!z5_VFIZ z5*F5`tg&g!&gDjqY!-&bLVeohZh(?voLS~Nfn%@^o5PxIgJ=$Y;iZRXBb+(N=~{A} ziRuw)ldRWt6KJY6VPrbT8r=$c;f0|IQ|r2~s55!x4q{m9Qvu7_}`6{msL} zC_c8>=5h%V>nTBKnIO=s*|1rvZko2wNMFF0FES~F(9DnPign+Gqi6OpGxqzy-&#Fi zX$tw0f^H%oF1vf(bYg9aAybH5io4y0%NyFg-~7cFkCwP}?hCH4c|zS=k%r1<#+>_l z>)_(CoBmgSQQugy){#HUwle>jaV7B|KkyQ5e}TtFm346bgYwIS`=JGg3|BS||hvj2VD*-5?Nvr0!HY=HlWE zBxiv8iNVD!QVp0o0Q(w*?+0h6Y-%8K12-Ee*>SaM%jg=As*UsH*fl(mVq^+%@ZmG0Q(uPV^x3{+&WPth{&A^NPrY7Ow;0tW_IFM*S_y!3cm8}8N4M=r8 z-5ns)k59Y>Ij^rzHql7|%o-$e5Cp-rK-?!8wtzG8t@H~y16e|Vyhl}Ho+97ULa1LV zs~&W$sTAk?QO6}#fWIs2BpFFC#Fn>9WCKc>O9Chv@8Y$Ub@9U@gQ;wZOg4}|JFuU} zS2zYyyPAYu-6ocOtboFbsCc$>U_U-r0;H7=3u;5FPql!e8JD+r2+IUML{n;3oKeF_w~9BQ4y)v; z4nmo%qr5;Mbr4drWC1c^byj~(79-LDc8_2<(-;Ph6k$PGvV_yp#EX>3tP2$Z+kE4Yj8s=1wf3{Kc>m5465(VFP6i-W8 zi+=QU1?9R6Z|B}6-t<%wbmzW^u=o$}&;f-fe*BOc2%&e>_fL#yk8~7#y82&WhweWC z{a-nt|Dv-8db(`*=;Ym3Qnc>>g2Lmy+InRM^DBEvn&}tx$n}Mh)22tHnNF~+*ZVQQ zBCut;n2!?!8z%8WC{2InT?xvu)> z9txW<##-L){-m!To|%}#%{{hCTVIJ4hx;!eST$iCl#ebepHh{8tm0Xz^Mo?((-#j- zr&3e(CN(S+g(`IAGSh7}9)!@W9h-QFjPUqg{G1jqgQg28J#w$Xwz>?Xben=CDpG5b zhH`5Xrn|+T)OjOwpHXqeAX!@^m{aHFGTf-0T)RQrGJ<6=k#b-mdxNbR6(3bKgh`I? z75E8Zbb<0nvUJA$2lT2KBMHV351Aor;gokFGV~D)0aw9993-qR?>uwqN*x%ZjJ$H+nB+}^mNxeJr6`zdXW9QbC&AYmm<=bsD zaMgZ;>g0>cu<_Y{gbPDcXMKLIZb)Gz0Wlnpg@6)XD4428NV)U_;J*MCgD6;a=Xq3l z2li`?0aNg!11^@mQ8XI^K^wI!j?X_2WN=`Dr zsl43qO7+^`-*0EiabSoqiYX2*5(DQN3gQAE{KSb9AR?YF=K%)=75@+}1r?G!ijlbM>MoD2P9T4py!z{CPjZfD5igw^4+Ih5hL>?; z4eaH91&S<%%&w0WnZt~UVPuDPfoQkJj~P|3)OThPtXSDx8ndAb&|c3PVPw4kcqG70 z0qEJ#(H>Ybl|{TLUq)npexbM!Na%n~8<54>3b>(L3G{GJ3o$UkBkR*6B^^NSE(--G zQ(&Sg*)UKJ;IFJ(%FSXIX32a5%YY1SR{{IP)B(X!ANVhj zSAf?7GA97RAa;TW!jwo3eg#vQSo5c2=k0v--;ABD(~$qAIX=GaPjTTTDd^uf$MsXR z{>`{>K`LfG^b0PWhd{C6f1){VH0v)$%Wutb(i9h7^vmjos4N^o)chU#(fxxKZF`pa3L?{3~j zgGnnL((9tbH>iJ*3n#tMQA@tnTCKiUWOP{Fo;MXc|HFm-OTMqt4@?Eb)m`Pv+H|VtML-_ej0-7XOy}+*bRe?NBpKL zvfkcSA=6HRxy~B%Bm2irnNC(@2IJh1BuLUKqc-apl=BZ<3mmB!sj~?^%H1HcG^k2h zz6w8alC?iRgkV+3!Wq&Yo|-*U6?gHRt6cBVMXDRp(y9qnxHi?ElVZw0@G`>V9qG|z zfx~=ndKwCxG_Va4;;<5tLB`l$o96bSf`IHyZy#0H2XT_Aw_e>2jMH z4P))HSXvZvqplSK=h)TTNb0N#P^Dl@rSMgou9RtU9PD(NhwdsyBR-j#f${FL9ZQ;` z*C-^PYG$65X;#i6+1Blb3}tAu0nXEDX&5u0v5>745TYM#mLNyFjIfT(lGT~LAH$iA zH{#3^my?pMJf`#LPaR~Zbayg63|oZgBx)~Y$iW>u8@07cHfIvTvfQvz)@Mn)6if;S zHVj~q@JSpTeFB$%N;+^}-Uz(>Mktz$viQpFE;S2{8HZU~hy=5BJ-CxP-%L*`4AEg( zxnpD4N8;Hjm=F#k^|}&C$q8wl6spUYZa(JmEs|spyJ4;9PiKMl^nC%1x|VG0K845q zsPf%sTn}e1fZYg22&BtXH{>F!8_sa7X;y5|R;x0%M}dz}rV2L_$w!8!$dCw#o}$N? zja7HuoFSZ5keq}hOlyI$`K*+rQ$n2UQ@-xn$LN2XseQ<^rz+38ng#8H;JDg-pU(Q6e}|H6&IMiCAy&?0d+a3%Vr0P6Mi z^<%WPC+_2bX|B|0`V?b?^!~xY!GVGPNM1j&Km!^#KokbOY=HIxVhgA)7K58;!-C## zY^tKYy+Z{AifquDt_GGjHdTYdLQO4Fd3S(wte)M@!+Q!u8Hae6e z4+<63E1c__C@O&@!XZLPgq!Q43PTH{vSqm{nN%b$$nUT1Dr{GaDcKxFr*u>^Hr%gl z6LkR}p|eJqz;|wE3)Nj#Tsvw(dL2_Z)?Px(NT!0&99}73k3TtbmodRWygT-(cp*%forn))oO!&U5=X1D)!2HUpbKHqa?zTX=$-mZJ>;l9s7xt5A>ibpxeB z=t6*9Xp8}=OdC(L3ao$wg=3x4ya;C?Q&7U;piq;7x|Rh0!k`@Iq5@V<0lQBrY7>f> zwJou^&QhsKl7+~$M3#`v=Qq)#DhoSByuK1DkUsjQ9ff|*K#iy9Gvq4g2z}4a4xv>U zY*i~1I8kd=#r=XD5TJpoKXpEHLetmN50dm$$o`P6fqxOsRm3zYrX+FHRND){^r#H* zYn@8iK+gx68({h=yB|dWkD{sMJ#~pw^ryr3s$-^qGkkadHhdpDmG^6%JaWsQ3Ew}L zW!M&E3W+~6Uu(aAN9K#R@g)ClS%wEzDV+8X_q3lj0L<6o+?15@OXj=vB`C|_`%>xX zwO5rx7oJ_Pjxv~}2vL3;%xzxoY0?H|8FfGEwy{XB|H_)+XbifXNLFa)^e#R3`Q^52avpT+h^@pU44?XSQ?~T6a zeF(d~-Di6(kTN!m#{Ngj_~SP<|6dK?f9YwDxo0xKe;%(q`@hrEUh1j6WUtqj7dRaOhYe{E(51^NXz=%Pl&bc+qaZ66H$ZM#G4{Mvh>}lVAKMZkTzDfGoA2?hm zRp9!|P0zGEMX&hx%yvt+@tC=6TZhW->==o zFHF_zEklObF7)60^%nY&KfkmaE#>ozUSBuE;cqyQ-FMN5r;6_UO^|C08=@+v)v z4O<<$!A8!`oG}qXjMboLyf#C*g~SUn8iYsAHruDh4+BJ- z4lbZrBaR?jSlWvWQ>S+}9x)lebYvcNU&0-C{Z~q!o>5G(ag2>{f5NvoiYi z;paZboUU&nY%HvvSHya@!1mGYFI`lwV{Y;aXCv)f6O}z~Imc^O z1WlYKy_(!KEgR0Yb~e91m)eLNc6+hz=_gn2uW0(HgbC3#9Ei#mI*;#UR%zT!7mZ~) z=P)57`xNB-La!W~o?}TpZ?x!ZgsE5p72)`m)aGqI^5R^^fd!hk&zhItoaWBle*CG) zfS2rT-Tq)zN^$D*e9MG@T3XoYOw5ZlxI>at6Vof!ZC+}5E#cn9hTWChHvIRTi!G1> znR%t5u@Z(BZauXsp0|asWHP^OeEhcUjRy1M+A9q+n39^Bj$M1) zx>l2L_uZDVKI|7#jO$5W`&)wp1EghN9zJ_3t8x6>UQKPS!0)0aQ>+0Des0Qxm?M{H z%nI7B#^K?Yj_J4KvdaLK|LUP;MsNvGuXT&Zb+ojKue}bB%Q@Sx2`msBu}1-|?-?8s zwzRqj=jW(3lJ8%m^c{hcom8#-|_9ex0Q|36{T-Vhcuu^**BauGxeUSgU{=c zk$H!{FXD;sBUQzL==ACxV8$jh_ z&#R&I!Q6T&G3O2Tz}x%n;=y4>T*KSQ22F08WJ zZSCT?S_N=D9POe+ez3GlM(tzab0jTo`GW&;dY`a$81Cy3bhL={^;@WAuvF63rjjsK zvavQ=U#q&Ujh|m+%LtQ?wstZ5IBUvV94uPoMZ#EnYOyz?uw4Sq$X6J^+zN%fh%q`Q zk-M-e)skqgj9kP42bL;agni?Zhz{AJK)FgI=T_#2SqO6_9B}lgMa7A4kQJ*rqXXjc z0mVQ^*P=jCUz3>82e-8d99=AcXsz$iA7;-0KZ&;HmhMhTQMOE;MRnBnE|$XWEnSLX z4#mlY!7m(E!E(8@vRy(e5h+>=qx=HeTE%hoitcW4Of^s>)L?CP{DU_E@;7)gO+CrL zqX;DFY;YS%5nU+-0e$MdlmV7x1%reAF|~@eR?tcVz5)D=2%8PY5kR|8M^{e0yFe8p z2<3k|f8Wlh{muN{x(ojs`295PSNZ$FpDU}&+0z95F8rQnoN|2Azg2H>q(h26@|W=2 zm$WS6)q#Jm6y5qEe2x^Ukmv3ETU zX5VzJ+W77+u_xJaMICg*b2yghm^fUY=%N%7$$Xn1fE0a>eP#65H|-bKAF8UsPW#K9 zq}R(>FzFt#25n4}A^v*P{_jiCA4fbGR=f^hHfgI4b0h7j*|Oa1=Q~ONk)r?c-r|4f zvO4ns;w~PzlcXtGDmD7&-$^o8$Ie@JZPESX17+n7PkdHCzxC^z_S4TSJ$-PgT#_=4 z*+|I5d-)KM*lc=~V4s4nN&ok3jNqdbi)wL|EbOciLfYYAK*D=FR^}^H}t+f_4J48#FR~}2_9-8(6_i^{o z=H0A^f~T{-+_NV!SebpPdT9BAgzr}ctJ;?|yj;Ctd*V=!(mHgOtpw*fu=mMV;_pn} z7kW9x+(;w=W7 z+{~a_mACjpR*c_llO@E;17?CvRu4~^CU!NM#=awxo{wI=v72Ay5!E~28-e)&UzyhH z96IgW_{+1yze_w>jHb~y-c4+aaTT+VfPchw=V1?*Hgm|z6Jh#Rp5_{`X(OrXlw?$% zns-7cnEquKb`>*)oV?@v-C(Yf_HyLR0^4n~U)MgE-@NPC+HZ~;9rrNRE`Oc=u}_an zR0z^m2}f;2V6^bPv%b1~5dG;L431;d;7{v9>}|@A=GSo#spmlZDWM8#8t) zwht6N67+1na26+i$u@Cpe9o-?`o3-MGFu^fQqDp`eMn;6Oj7bB+s0XR4-;REHnqEp zbCDg*O_J7{4moC;1rbTE{b}e~N*JQkx^@-MG0Q)kf^_1ev?@;NxVR=1erqFjf4uSW zblky9?~oB*iTkcAvr?vo&V-D+5O^HJjo{pNz=X$nvXGTZ#WONYESj(;EsZ)pJ-8Xn z6tqoCqjM#UTK`AKJDXwUvR`qeR6cAPo};2#D8Sh>Z-4 zE(^6og4{+$TQe{?u;joB_>6|wAVEyZ&|fkTu`-B_`JCwxT|akc!0}|0kc4vv5#PRv zQ z)9JWL7@^O?xwB9U$=F?!FwWfzxrx0`o65o}19Tafa2RRB$1hb9H`YNE2HHj9w}_FV zgMgkf5uuXoP#9rPi-~H%Tzx|dWgPP2BNFLR^}90%rYDT^@sB$*^>*&;PxUVCd!(QGZkXzg7fMv>9c2Gtt5z87*!l`V1$`yBRudK6XC){OXfij z7Ng!uFq?(w&1CGVGYAv|I|)P6X-Axe=r9L%Xl-bsV~z;F?iq{mnw-`AjG@oQ<0Qy6 zFv^BXu7lB*@hA&6xC{u+awo3o!u8c1TwjPDA!E+fL8rlQj0{aOQ)=W$2u7@BLbE5y z=y}u_H+m|?2%1C1*0D$jR(vsQ^w6S~Osy~U%IA@8RwR5g@ADx(W&w<|cSu?w!6bsa z@tl1cWr{sDFGP5F51b3GAFqXRi)l$38aR@LT5bq_Md*ez`fI? z5+bc6d&2pM=gk-$Dz2{rwS#qHAu~Fh6P4qQm_z+~NSI|J#MntNR&?aIM)>JeBuCXPeV`^IR=wuphPD>i-}+ljezBZPE@n7LwCJZF1f^XKeGTTeJd`JV}M z!*4x1FQhDPTT{fTCEeTBJW7^KKbE?Jy%l@Hv~&Ajt0>Kl;6Vhbtzb*j^pI-?>E8~N zS{S6S3=i2F7n-Of;trn1w~|`v=paet^0VQsg&_?8peoBCLid)plbD@(;T4&;!bA@~ z{{kDfNelAl5U{Ohh$&n5Ah7f3NGn=-pJgEu;jT?w7Z=Ka$xTO_=^;Cje_uG%}-qIRLqBxzrm9Vj`n|G&`C$T=?VSHXv zbiT7S;o&&%HupR|93KtiPmG@vYJa0)fV19Ew9HSTtW+ps5%U2VIH^hQ=qdsn^ilkeuft6ns@{kxA7zq7ki?fkfU?xyed zD+xYyw7+DH(e1NP9Ap1Vybl8RREB>_zPMKBqTjn3|4kPIY%T^~xft~LV(`$#jWcTl zH(lJY3jdy7^Ko2_gSOu@Ce9y$T}&lCqHC$>m*Q+lv5A-Ve0?e5_N9b(msm6FQdeC{ zKXfT^)1~Bhmlh+i{;b-sS0?n*NWDz*kt-KIy}j;`&~F}@n8m`sQ(oo_UH;al{vBLj zu2Wy}bv^e=J@0Y->6!KXq54y|F{VtM&c@3dj}z^^E^GC!%U=AM&vSpJl2jM>ZS$sG zEs5XO6$lnz64<{H)X%&sc_+AUbG7rGV8N1r8=nMx*L+pFX;=E>`m2-7fIX}$8@G|Z zT2EGGUU7dGV8tSnk5B7Ac&_Ni_M(eKr5(ZWwniz1=dHV`%IG<5V1HgSYXoaAp>w6JlK)r8XvHr}LX z)4a*?OjCSkqw9KH`y(S=ErAQ%;-B)N0&#>GvJ^KklP z)Mxzk6`Ui+bVM*&YcYe&E#Aq@AYXsnx)fQs%MiKSyJV1sTTMrSxxYUXIfH=-rbDev z^fEdknoho<2$_VNT5Ty7Ozd#K*uvyaJnIIU4XvZ2ePFCVjP;=t5i%@-i99N}=_P1A zw!6*K4Y`UzgoSNwmJo#lz6}>AL2svR@rz^3;9$q8ZO6A09iqgmeIyv?%@i^!SXMhj zhQ<4%7t?Xu67M|n5f^MHf=~5~NkTguf~If+CS_vN6-RcmkO;}P7YX1i>b(#48SBo~ zcUSfWH9I_+rm-PAZ*ICh7iq~x`M^Yv)mXq!3}je;K5{;P$Lo%ci<%A>HwX(0Ju2=ZaYsjNN6^fpqIl*Jp{x|*cdNQqF>xtRbQvYIvIU8lpL0hx#_%LgBNFsZmPzE{pMCSJ~LR8M7 z3z3HmT3M&xmgD`HcpU4|`|}2SSf|BBq#s!LUcrULSKkMW>jp88rc-Yv9+f%NWB2p1 zudf=YBqa1g25zEvUE?~-Tm!2TqyLtq90m;|GtE*u>X#5gLc;QdZ(R1CUIBgr1k=+m zHC+Rv*P28t+BBMW+|5@Sv{Rh!nmwPhPSw8EY&!eGyXGB=Idy5|_?_{9ulpifHNdEt zzP)NkUTtcd=6q%K4F7{p9}$+HdUdR@@M8B{^IZ8SG1bvL1uauj(5Q@XNJfZR@$~ zN%!BHo(g&Y0C&5UH_hY0$-FNwH9q`V(+qm~WPDAUIStnU!WlcoqGhd&A^VIDIF`4Q z^-B)Iw0u~EJr>&yPe0Zl74H8qpJ*RH0Q zVr(+-N%QG-!}{^BDfEnERZH;vyjaBCfuQ=C$!RS;O)zimMp+dc{=?@l)9>^OYnUVr ztW~_3mW^J3mO>X zxKUsGi85JGzR=a%QC1Q7Kp)Gz#DNeO@)~%%vWK5!_d%Q z?g|4~n8XG(z&kU4*({7?VbBVDXkb(eW81%+Hf^oHA7-%sz_wXylVj6x!ye3FgBliK z#@pZD1*2WK&+sp#OJj2n_q||E5pE)Y+k|TIp+shtK>+c?Dd%m*yl@yZq0iBLAx1n)-7N zwn&JW49~ojNU34VU|1rv$n9-MXIuZHCS}S83vZ4|!YjDE;t1?Sv)cF9C-I-0_CGo8 zKkeE7d;4+{Z+-Arl4EWx{-58oAG#6LvrxRh=twa_NAthWp>Zc*;k%}Ij#RaN3na3`R96Xy`cesPP0;140QV}dl31i%PL_1mT zrg%{NWrGnZzAr}Wgo9+=mZecNHmw+iy49c;5B#u-3DlKAi76+aa#|l5+1iZ%NVc zk3Wx}u4}mJedYC0V$g%ExOUK_4(4UW8)9|AE7OCA6^>=ZiJTu!&8?}v_t*1D}dRBrxAlaE`d3Gt44QReuOc@ zq3U>dq@oEe>XM4gi&2?MlQ-Q2N)!ut^t<)^wj!|$qfT;MwM(h#iKD9L_g7hM7fMUF z!UNOch(w*8!6HU@X}4O%0SbGcaE0RqiIFbX?NPY{A!FO~bp@~8XCA>s(_QUn;j*ZVI~@=7~jOW_QbP6~nYU&I%v%_7(}O>KDaPt0Gtj3~Z9Sfs@H`Q^ZO0)#Fy) zUCL;x(s`l#Mz+!S`fB|+<;C*bD+&um>yAz6e!kL^ieI>{e04(aqF#6Q1HW7Qu8&_E zY&97QO1_%WB;ilK&uR7c%};nf?Rhx({o5P9kLsQae`C}Qe?7FM(RTH_=f2f<7rcdi zGnydRfwS8@poo25U*$dzzEXf*@GojM%*GrJ86h0L((d?aF6UwW*v=Gwm+z-wYNf36>jD{_t`MA)nJpXv>n9MMuxRdp!0?%S0-LEFkC7pT&6aB{b0B}KU_g3f}|6%(KGxjJN!EdCm^}koCfs(v==~_WZ`GX zk$VCowag=T*GB3&Me3JC>Q6*caw7M}Mw;>?DQZy%bfOGuqs;kH)YwStlBj)Z(KaP` z9vcHd2um&l+vtWgax`BgSQd*dQLlNFoIdMx`n=~gPyV%YxEL?B7!Mr&LSW3LiEHQD z4u-MBcwGD+Aa)Xp{X>bpHi72@u`y1u@wnJzfq85SKQZh1J2sSAeNgU@zlH1LYG+t7fR$Ga%@Ck!n4?fyx4>|r?{tW z36VO9&thX=)g}~sCbpU<*4HMs@DujP#AXgA-p+}8g-aUrOlmVvYBY~6@kBDDiRu1? zY)Of4GS+oZ#JF61DlYLxPErp)ws|6UW-xiqJa%3tr4N_1l9RB=PaKe8@?_$2+Y(y_ z6WRh(K70BiTd~oc_%W=6#kJ($RM)At`QhwzmVrA2|U&&Y~ z$yl05P+Cqtq?@KDl=gliP4#RBNj=l)Y~p8}2swbRw|wgG;ySXFwdAsxbbBTuE|w2q z>EuW{Lrktc`DJZVom$#(TXKA0W*RQe=6h_IGgDqDZW79#Zo^P%C@l((UlGT`rOziGjPHaM0IN$vDq*l5Y|JPNrmC?arI9tUgt(mO z?{^8B6L=R=KA#*}y_|0-lV9r@mE@W2Et{XcoL}t}`{Hc=bP0BM2|7fGaNikMg+nV= zATE=TbZWkwY;2X_X}&g&5I_b);g6P$4Pawb0o>hRgk3Q<`l=aI=JE3rcq$bs2O$1j z0S=ImL(4dEQsl0{94CH(z9&kNg(T8YbUOTNQoWaBV)-#}$xRR&<0D(Bsg~b%HgYO9 zI!q^Wkd{peWYI~Hg8(*&j=W4kdyqkC0D?|4xrU4kg{Y@i=FCi zkzRbqe?HFUcLhPp;`;6O zKodLiXGo`_i}Sr$H;R7cc>#qR-A@m(F)N%iCPD;@V*CNs>p`6ONd`gw*XG141q6|V+(bbigb)WS5GoMTnhC1&5ch`A z01I`HhLnR40D#q^0tW#Mt)hJBDR=-9qE&#l5Mpcv(RB`c8A8ah%56FK53*1jX{b$9 zP!+(~af*+zke?|?N&16LbfhVVU_nJlQGqWMq%F6c$V94AK|LCZ%0hjiA=QEV8bIM6 zHfCJ~@&N+?DJU&Y-XK6&;oiukxmjD@qzd%z9X*>k$s&jbI&7lj_$>5BGBBqbyhcMo zjKjMrLXPx1LfPOx05ufg0C4eMbb{z0DCCGfNX3bI28>hD>Li>xRPE$~wqSzxbo_1z zL8!PhlnvroR|OE#k%U2U{JoAM0455e1q=;<#uVgkwwpbK9+XBBcqkXS+Dm9OxAw_6 zfY{6}_9BCLI%v-Y#i+MK$>0h@O!FyD^XOx#7PlgcdkbnvITn1xfio2kH?i;iW&_8W zSYZaZ1Fqqs*6gJsb~8Z~gs}bq;<)Hd6x+l*`wewUd;{~LWx5#B_Y)r)hcv!+$zu; z4;XWCyIJ5~3fhthZlxeCIfOmbr$y({8<@ZdfZPV_MH~dkL~P+;mFQwg=zE*{2-iq? zwl10cw)z7Mz#6K?L5S~6q-=cs6c70RHz*1iB?E`r($)bF660_m*;foNeU8L#4bA#+@NC#>)mV`WtLx{2gi1%zgQ15vs+T*jk%uq#(B?TF(kCNn7@1`KnSOsokGz+gGcau?C zD};vi*t1@UKpuuxh9y$b83$1s#kES5Ct7rXOae{m4!#GF<2*J%1~n-_jws5E2?$6+ zW*mYLgcAag1Ay;!SKGqUEcx6Ny?X>j9?EAcZXE@Q4?*q<0fwkZQPS&8B!p;1lde8+ z1t1vdqrA$n24&dLqi7Wx+FD?R-np&CuAs|F6#vEw?MSIIrM&Ln+WbBQupq&53qg{K zbb+uw3|wdefF|QZsAw$XO~`bIiAbA(;V?T49-{O*P!Y?+DA~VrGL0Cz&?hE+uRY!h zK+Zye8t8B-+4Pq0c!}RZsuZLO8z`;su;+E5si@r$W<4F)%|ktze*6bOA7FuG80{v& zXZxoE2a&popf2ac9@hJTRfMA}Mqdo|HstlYL|``?J0OqLWW7EPA(WCZ=NKTCgqT0r z8bN!5g-?DQ(2|M#b1*PLHt(|kFZx55eak`j12R9A~kpa{!L?Cq`EY6T0wO$Q02!?T= zFfIfDH`<&M3AVH$J2G-uzPIf4kV#VWt|Y7+P;JcyY`HZS6{r{-o2+?p_4np#5VJjvePi-Gg^4cqTPrEM5S}18cuvCwUq)`#; zw;(-8NIe?%AmhHY+#@@3g;@OkP3Oy#sh}bSXQ1(56Add@0bU{@xd32Gh5xhr0PFf^ z5`s=b9$+CilaP*o9{PEYYmg8C9b*UIQ$t4=SMG0OV$esyOu;JRGWpR)=9o<=5W%UuAwpmwgo@Zo!JK9z0=p_5c%TsjXm`i&y#WZZ!AK6c9zZ5Ay~M0-A6aGy#bxvh zVK-v%pK}X$shy(IF;q_c)7+A{j_hOHqEUdbWiocRlPAaG`Xrs8tChZX70V};=#~|7 z*@gGp3irxAHW0?Y2*pgYuwOi~xfO*TKx+MR)>1{`i+0QqB~qpg>%c>ZmEXCXjr1== z16XsSvh=~%cnBlLLz1kHAII5V7VB8dNsXSkB^Q^o+vzU-Y5r(?w)RA!xJDFd zGLlZpr^_Z~>*gQvj5G*}^e>yfcrKg%{l^=@*~mWt;ibj&<0}||guwD{UWOiosUc;# zqBq{)gvdfaIJj^&;s^&YWqA1|*&4+?cG69>&P^n)kKKbyTK_P%uJjiIXP}cGVsV|vSgJdlADD96d*9;v z7dL!AC(5TRWjV#}axSQQU*zMQ-yK-E5fZ^L#eM;(L!_@HE}%t2W&%@Ne%&VXu!@rz z2e16K6U)YW5qJW+ssUoKFiH5*$X7v5L@xv^mX#6IZUbSvtv&`*h zhI+prDY3b8=#ER@qN^4`ne&Vk4gGz-y}2WoP5W4P zX@2bfhk=VH8VEl|ejlvm4YNbnwe|(HRvP*Tu$cVt@9S@cy6rJ(h#){CJU!C>`~I_(#q8?Sy?hYzXs`T9I_onnLh6`wDi z*Z1!`bWCr4>TTuju+ZQe&wp}%+`;)Y&l&dL-F?^N^QYgz{Mm1B@1FP^I^esi(XzLv zRuJbqML71Uy3O;bBv+AYn&!wv_7;R zyZJ1LkdZO^X(;2C;bXe~eATR}yl<~fiEkM&dR;krVhraOuOfb3xvub*x!yA)kM_;o zHfa`{3*nUxjnc%lHl;iIkJ^fz_4%2YbjT6M0eJ)z{abN z!{>XCseB0jd0+bDd4*q&pTlOa27CzriXM>nbq%R>xh8j+e==4%OJ?Y*#&(aJ3A9Lqme{`7QqaOl&KxJaoW z&!Pmam5E1-KChXfuD;ga2UgDNQH@G-Ltj5Be(0|EV(rl@y{XV@hxO+w@B9fmSK6pm zH(4?8N$*0rn2#Rk?yW36YFX29z4OJbV|m`s9yY9>j7}}q_zx^y{g-I68^}Y%Gz`qS z-=D0SS=02){q%c{QT!UpTFx3=LvA`z+_M;MGMceT z%Q6u76MkDn#f^sH?54%Jb|DQs7|dS$Iy&0i(p+4@wya*$x>U8^E~n$s*1@4(-Ck-t@zdAo)gQC`#kCbo)~a9ST=%=)#W~(s zf0uB^60Eer>e{7eqi^2yUVh2Pq``U*9By8moEe3MpUeMHfIbZkGxR9#q3j|FN=I}3 zU>Ce%Y1r$el7e%Qe_;o4SF*c1aPTNapC7PTbE>^?W#R(Y#6g|t6j-r~{i_H?x)Wv=ay z?sR5o{hN|o$K(G&a`V5H@ZU&o|I5*cCd~hDG{OV=e=ZtPZG>NE^{;w?Y(>mn8Bzat zq7l&FULfhe(TMf`=!^dwjnEeDZGMdUW%(o8@jb;vMqm|uzh>Zaj#n+}Z!|*sAJK?s zoG2NGe~Ctj^bh@GQFiKImab}IAJ%~z3NALnb(DX5fy!@)KqMoiku_L|5Ec)Z{*Os+ zk=69Kl=F+e9Fv1ue%Be~&bZprnNMFQ?7K)-{Air zm)r_ZzYXj4E6y*yD~n^id()c^SWT#VOy)AexD?V7zk>)~LKb$Y$O#4;DQuo(*&k)_ z(ABto6|}xEzdiSu?MSK1OuNTx>|)xncIj6x{gv_*d2Q<{iw;Iil{`biC-c0;n{ag9 zi2Xw~b(G=svy^(IgG%4T78g7f-=rX=a^65hrhc|R$S_Og3?=f!hT!+fCQ{q>@y~l4 zNOP{si+p^mug&AF?fc$qx7SA=+v<8uM7&XuC-tQ2iMgyq=g|AHYUPk8_b!Ij5kG8S ztZM#de(IgL%do2U#(R4@k6m9Kj*+RU>Ak;w{}}ODjg~{5%<{{1Y@Yo?r#;{-u)}nM zmm(oLs&L_By#3({!mr~|c=;TSD~-Eib`36VbXP+G@p@8t{@2{ggI$IbEVNozp)8>x zVna3Ji@R47UNVauy~*{9$Ps=c;ZsF)zE3nUJLjchH7{y!{Rqx+u!W@RlVD$PN+^2} z?<<3nXkdPFcCS%#;dU9mnvM4JG!i+%iAYT6#tF>Yt_-vc9`<&PR@c5H5N9*ZRBKd<4wzuvb z)<1}({n~huk2Ned_yL668tVIV?Mco33nBE?4$Y}R3yKBtE(hkSv;YMVAZpvNDr zA3<)eq2!1iym4++;S=z*ZU3RU)cpEUf&if_V`BI|xT=1Xyzgn3+oAc~d&A%Myj^Y+ ze3_G=vqgQXW9`&e++r9g`5B#+?(_$KcXn_1ZjEi-pZCY_?*8YKb|;?o*C_axyKR_s zKKyL(;i1b91Skwb$EacRqq+FxulPGxum_T%&#`ZA$zd@`y@JMTVdd*L{`vOwz_`ul zXF={ie~{UT5u=osTBj8TqGPo|MGjn>By!bY#iRZturKA7ocv*PZR8FjAMdC59ye#e zuEcZHj*EHI*Y>k3dNV{$&t)pcNFlk&$!b@Xf)#O7iaje~3x5<_uz&X5{*)Xw{d=PQ zA#N(wka_!|+lC8HF}*P_Lf$BnMEoYM35Gp(q~7WOb2Dnd;D8kcLRBC{f9N#LB~<*5 zvbs@byTf=M{ph#<^b1nCBlvtAZxItRBprh6#(!e?fq@|y1m1(gK*kc^d0aJf1dmoA zkFqhS!5}UN|AUSBtd0NaXZw*6WTZ;eqe41Vq&O8x=#CHoNI^vyF30Z&g8}-0#I}G7 z98B9%@H!vA3tWao8^dw{qr*btSx7P!yuiLH;EHX;g%;V{e$S2|7}3y`sAC+leVkwn z4LE3j9PCC5NPwWiPEW`A6A*=I#GKBt8_l#cqa4TMFf-Jc8Lrs42Q)*+aJiQPVu}7b z&JlqaJQpDkGeQ9k@SrnV9HaecS2phjb$ZavuvoFcH`< zsBJP>0gPoJtU7=cW&xTyL|GmZUY(XN1OyOPoPlCa04O$sN<)wtr~}+kFUD1S^N0g6 zHuG$JUJ22i3Bq4@&htot6QqCU@Dc`pbsRcefjSHvwxB01?|~33kjhMUClf$AayB*z z+Xxcap(0t10Unrx4Co^h6yl;#N}=u*1SA=yL&t2PqBoQA8!G?`D|`zb#4rPefzVB! zwws-j)C<7_nJ3BuF=1^GiHC6KB^XmNANhzx&y@Z)1e%7x&4TluASg(^{1Nv5o(0Hk zK!_=ZW+2ckqy`OvA_I6c4pKR~UX4futAPE;-P^IAo_AiBbYwETDOv=(#1r^b+AX1GSre z8P^D-en_5;0>iUTQvd`RuwtX$_CxON$rcsaxRXGbGY}Dn@?O5J$*2o1NDL5lfrpeLA%r0;3CbqgAPpg)UTvK%nV`f?7a^gj%uphP z-XP%J`9dL>@>q{zqWAabR>u%$YV16q=r-x_U>#@qXW~m-`~f=V2c2NX2xh;x`^W>i zG++ya5+md1IXOuych0iWJL$RWI&1*W7yVqooAirqWdLMe5EK-b>shLv8uF_q1b=W{W5CtN+)fg>v!%6pPvQviLl?7|XKlnfe>P;fEaHU_Xoz)ILhEAA|oUf^18 z$VC^GUP(dVbyzt&*?P2)`Xw0 z2?)kUOw|M(tc^HYn-q+V6sb+x`!xA{ZTyy}335+AGiuiuSRU``%~e7m4^#vIHx~Zf z-qL{X$K`g1MHbN$6#Ucp`zzGCC!Of(;JT;x>Z&`@HWhX3sk*u?^-n%vYenjx2G_SG z)L&&0I^^m*r|P@+K7U(Rf0c3n#rZlL2>q%P?FgV<1k7g*!nXUz2x3|oM>6&ciSUJn zovLdnCJ|;uUd(ki{G4jw$>EDxFV^Z_eBm{$PQ93xV+)SHn4fBx>1>!zVE_2Q7Tx*+ z9l{nXXD`UTm|uMX4!>Bt*NC2GD{Or+ng3!{q_LQez5$@uzpqw3bLA`j2^Bz(LQSJg z!cMCuE!U>q1xCzz*Q79!6*DG!U-lP20$%0oGtX|RUU%3s_E>6EX zBj0+azSVE~m5*ram4eo*<@n2Mt)ca=VhY-V1;ekrtlGG84S(oNjgYui3gIgS`-j<{ zSKnSR+%%+CGQ=UxwY)rNFFTkBk4wN!_^zGoV7?{ZgzXjjsB zMz>d2<8(${c~@q6ON(gN$B-_Uwbu)j&S`3AhyLp<=}vY3fUJOsU-fU39NV)7-u|wC zi~R8xz5rsZIoRtQj2H*~nj>rgUvD|s4V=}Gh@JLF9s~#YI5>^ebO*HFk$-(>gLNRw zEHJ>MN8wnH`qdtv{+>?Np7mlqia&akmG57a}8?ww9@(5x?*l^#r}|M!Jw8WOFVTRMn2{{(H9=` z>asB9?^lc>o3SAJP34~Vb@C|}!8>>?_z&JT z;O9oGsm`6=X;tcl{GJ!y3*9?%g0U0TAZv21K|@p~w4Yrh#;uo7&-lBE*Nk|^E5}s}qA&Y|C?{i%CF0aOwwlW#VonUI9Pz@F zD~!dLy&SW-_N=;)xUjaiG;|mz<@D>VY|NAQ^K8()TK$hoD0?_>j(^a5^}>$f>Rof~ zYRT^K4kKR=1Hwh}Fh+IJ--;9_kAE6?*)Y1&kDlq*hw*+N~%OJ7+NN}%tjwT!KSAk2xqvqI} z!nDaTmV*kL9YK@7!MavO$?_(j(xRnBjKVE3pENn_4wDCSoD%ld86BOHDzB_D%A1nj zS7RBW$)sU+?{L}ah6wg93aNOG^~o|;uYmGtjsy3L$9J&is@Uap(w~0OzXdE=f35z1 z-iZF~ckh8;qJMfs|Kdh?fU+NidF0=U@qa8)!bRgNZ$$rzCLUgs`&TsanN~zT>Ls;$9HnL{qfzmHz|?A8!W3z{(A%eld`^hPLI!h?07QuE?$5m z&RJIf>!L$lV&Hndx{66{;QZvr&YFjxUocSnqj!;`k5xph+j6|Cw(@H$Q+da8itLwT ziIN8_K6O2PJpPuoKOyw!vSMX~%kCC2903K|3g0HelbfKr~^aGYuhH$qfvf*T2$s(p!)aPa&RE#qGD<(mBE zi7zpvYic90Dp{T*acadSBk^0SCq@#;uhhOKYW916P0|@F`I@Z1IPoTMx96lL(b}ZNPlGe|CSrQ*e3m z`zd|W?Dvw}S!2j}}Y2sF&rpJf8W?Le36X2p1?R!40q|bH7PWwf9J$kM}hF-R% z9N;##lRFO@lkBS&Wl*B^W>n#r=IQyTy9Y#FaH4Bo3$?oiO>^B=+P~Kc38J_Qy>>ru zU+Q!6*tYJqOTZ6*OWm;NKfqJj7pl!p1Tq-n9yLD}jfo*U5y->!7nVK-zECy!6mnCr zEk$|9B;Us&1GleC+|Kr1 z`CfAO!OCQL&CJSFMeFv}>8b(m)gQIv4_0UDmuCKs+k}19_ZPlcU$a#1JUiRvw)gNn z$85*%gqj@biqbBqF1Kw^f`?WS-nNjlU>+fZQC%T5$1%vSoAE$PJ!uD0}C#bRl zdYE{xpte$ufWDHu8ajf@*15L31xd9{QH{YP;EJOo zE?&waZm(sBD{)BZjE+w-Beh{sGh4^DwB?k~y^Q40Y*lGUtc7Qmq&Qdc4=ct<;8Ma; z%%bjB;jxTVu$g*1jcri*OSSS{Lea1faXTMp=uo?Pt9<2t5uMKBW^+hW^fukjs!i5m z0$Fl~s(ejJ1pUI?tZ0y>$e&PLA1$tvtAEk@IKNeH=ga7Ak|IdAa<^puQaU9seA67g zNnxEhCc-K~nSZ2X9wXjnq;;C%@?~RkY)PB^2Bk!U!p41LTygQhaDq^~vRn?caZARx zpf4BRH)yKS-w(D zU4%%fxLXddKu{@%A)@;dp`GHafG5+gn;AtSl{wMbzmyXcOJAx`as|-ttmZId*@KQ{ zYLYHSn{%h9j}Za^N(x8mnzjwen3mhd>}n($=M?T&ak;tePb83{iQ2j&Dk5sqA_5bq zXiU*zenW3c3ADIjX@Go}@Ab&^ou+z$`w;V6;W-C*ME+2Eq(K>If7cu>bU$!XxmZ>5 z{9Ky?bwjaoQk z^HRiyG$GuBT2#$F%&W4HN7K&Sa55sQ2Hw7=g?3|;YXspZ7PD|T^8OII-JxT6QH{9) zBDPibsMiJcv|Et`=kleuv5Rdixkq0cy1sUQYMIg>C4QIj(dvHh;%AwC4mKqAz1=mU zQGD}BvGutj65ea!xW;uzIAW;hp~91L59=wH4=eq(Z=O5|Tl#QpHIHJ}HuEs%*p2;m zk4W1qP?gzYq?5Z>-+!CkS#|fv2Gm!^&|ub^{BwCfyyaRuKjCX?Tdij<<*yD;IK-7b zl$N01%|B{(V4KhTd;3@onfDUDowNzNy)$4-X2ewJQhmiy<{2%mVB<}($nkK((Nno3 z|5N@cNQE?(sw;Oc&)%i`-lr?IL(U2UtYN%agmEkz^c66pp@Iuc{To3h?}Ig8xnbCw zHiIuv;cUqhsIjcuyWhIR3q{bPwz5Rkb4*aG zv*vF3N|CCJGp7}A=@x8$6@D`LSwAJU=^CpWAum&>r0mOhNjH6c?%_~OjRoY~xFY#cXWLa&enm zJ%w4({M2}`^=K!!lCT#e`-dQ%_*_}1cvH*kOC2v?H^r?#i~U}BsW&{T5%EZEx1;7% zkiq+U)wn9;aqOjqWb>yxRCK;k(gY@ny>5IP*&PDEiFm2a+Bd0ZYudjE?fN!3&@5cF zR&2j@FH=uHWN!YsrA*IZsf{=Hx$L$J5RhyV_CVHjk69mrH6wuf#TI0tvsqG-lu*Il zt>O!w*_Y*$wIQWe;tuU~%K;Mm?8Q^YE=uNXNni9dmb9N|TUKJk>&7LUkLVj6&=+cS zF2AOce$Cdh(g77Kq3I;v5)jd48=}rXyCa9VJu~WPYB(l5D&PLZxjx%;RZlDax`Mv5 zraL24e4Mf5|eW~`$MOE?J`ulO>_Bd(0RMZH{M|+UMQa#svH~ONv#7VU%MSgVX z+*wl$UFl17qRpvun_@$p42i)HV0hSFQ-bhr(VXTsla2L*dlb{6_n zJ-W6H&AiwasZqK!UnN>wpacD($Gnj|yFVvY6p;bNL`m*eZdaKLETr_t*(Pw0Qg(&Qtc8hpXbSKs!E?ncg#5I}N zBG}O!9U0hbO0#W{eYPbCP)Wo(JdYBfUQ_CW7)Y@fDEUbM}$$&F6fvrV6?W6B0~ zxd+UkRPX3>P)#OUFso`}XK&5)uz^IIb8SVwAc7c&J-LW{bwiKZAWY*ylus7g!{?EO z{?>_eUVE^^`%y&twS!LjaIorbJJ|X3r1vlTZG!}_rx_kj`uaTcW;c)J_u_X3oIoF= zWDd2>S;?>s@?xDp`FILpJuC`uDuic{Mk519&-pz*5ls*Y=sy)78+2@9Z(FQ(2ipllgA~A;gD;_>BCv>g0O7#2GNoega?r!zK|l(08KOea zv2;twh3w(J*#zfPq+daGVPh5SZ3iR_yBxzhG@<(=xVLUF>>#{;4>^!kEeD7lmiMeF zSbRH5x(|G6iFJe!j#O+ulImM=A5=o>GmZ4w2i*$>X*=QsP2(t%K z%2ZW|g8gKPie^IrzX&1>OaDE{5?;B?YzdwS9ySY)av`BF)382C`@>O6yoZ`!khx93 zagvBB7ikcLRAM6xXc(!Z!H#6%Xf|3cfN(pXAW)Mmaw(qR2Zx;4<_>gRvi2iu00*%#VkF@$ zUlFI}aJIK<1x(Zl3YO0XbpXU~8j8Y2)tAc`$oqqRFW^#_&=CF(WERsyaJloEgN}Y{ z#)hi^$((`>dgAGq!i0SQBc5|UiE(%D#$XT04i9nBz7v`>>~RQfK)J8NMcx#7u<0(k z(kcI;s`_D5XwMzzAciHJ|L6#Wh&1H85hRwXGsiRaqCAlHiMJvX&d{6BaARdo9(o{$ zz?~=BB%<^=`0*&zM$U<}2n>Y_2;ZxsP<8mED(W;M^E`4~0%OG>9A~XJYegIHg>svz zDr|%ifY23GJbc70b!S_i2I&lF0OmIW#q7R z;WKp~G&u`qd1xIjU`z+SNlXJ^&&~V;rZi+@UAt)z!H;%NF9gcz3YEhlSlN*L?fcWq z1o5#7v2L~s7ZBmxm8uLU5nHr|vt1!fJV3#7fiql$85gm=;$dWTJZh)EfE%z>(Sl`N zCz9?$Oe^EMD;$wzSTcK%h;acBHWd%&X{c0vYzz&Z<^`QOg)|x`5@jPmn-0{@HdB&_ z0qgD7ljd$-9lTVd-41R$x+ImkmWMC5dy=;p073>8x4bzN13I{!jnkS07y^ow7Y(J? zPe6|XOLWkScF2^ASWrT$WkEy|Kmqn#xm^I(iEk$-8GpkaS|#|?!Q-y$uymXk8^vet z_o4ugxPZlP^j#j|>OI(riq>A)CCGH&{Eo5|0CKv6_{E1I{tsyzhqW-ttR18YyZ zP)Vp1*DG_a-TR6v$d&5WTFqWI9q4An?=3`HxR>eBc(!whem9(R5N1lu)75s5tOT&cl$KzP>@(ogFN+t z6%&r}2n9C*y&)%w)G{e8Mqv{$VdrM_n^3l3Y%O40-ll@!8i7R((q1DBxW7b&3#ac= zw?B_Q(RyqBlQwiC!ys}{vnXYIxTTv^kB*PKDubc6lVHHA%#B1DkU$j(9q89dAse61 z8}dI0bHAdY*A7}#O_L_jl!wkdi1nqR zUM3JWvQh^9E#Ag`wtr;htF`|(iR(d(_)P-S7)VJ<$DoFtNFSKYqPg{)`NhV9besYW zGt*&d%JYM})|Ag+suv1DBa>XgGwrYq2!=Lu#?VgCy_~l|msQ58p)_Km`2qM9TK>LP`&jl!y05 zaUVKRp{=NmZ0sX8)`fOdrqNCr6WE(LYgpF=@=JdGFag8HK_C#qtwWn7f z*L?4gp=y4An>io2o4;qBw*Qg-2IAWLh_cX&rs~%hO2V8 zESMitPx1rA!@l);Lw@a5Zcg(MU zmnw^CF4&VJ`R;5<*i!e|bKC40bW5MxLcgM4Y}^ng;pBXMb8ZGf*tqOH*MN?m>N``W z;Cb@%#N?6IY(Zj0u7tnf%IbmKm8Ko!BT3R6K7qnPd-BlQuFI$26Cesog^dzl7`Ndb zFnH|bM@AlJn_IK`1OR0AM@+?>Nifv2HWxMd`fC642;!zgx1G92T4Lu$KduH`bZbpn zuX{?xxo6ZOL*4$t>GwU~4(9AU^X9hmyD{qmUH^Y&;J2JNvAHchm7z3hY%7CNkpH!+ z{qsg&xY8hxp%#IP!Nsfxmd(aR@*(+-MUqHsq)VI#wr7?R`KnMEzp?q?(7?|V>~J(e z)pd|}vN=w2hx>5tPWx7!@mZtDSGZef?>5_yI&V{x$YRQC_r_IQ!u3RO@=wK;gyVL5 z{>fzsxDh1bI6o;!bABHd@+*B9VaRNVSb6x7sn= zWn;zgL9F-|wY(BDN${9#J&*QO|9n;uPDK+@5f zxEY!UY)sr3ucIuAl!_%`x8TI*MfAo_b|282ppPml1)aXdLR;};;$)L_7%9~6I6nuM z^G|*`xcc_lSAUPOyX4$eYG z#ORTDT;X+Ao-fhTcE4Li*SY&}6>)spuf6u~$!?Az^L+s)LRWv)m|vM-05P}6WDr<9 zsAdX8MKjpfRHGmYhyckg!a8M_;72ArL}P6ki{*r0?E5vsKqXV}y$?I|fRy-N-YAk8 zh9{A#^#1f+@wgGZxa`5Yn&xpM)YK?GQnkV4UO1#0#~_Lqm7x>`MN<`xEoF&xWe8(z zZp6?Xo5+gV9?1F$r^`HPtOFa&>%woHF2%-?jcMz#yCeI9FE*?$uKslWm_L4~h*bMh zQLm~5z$2qdHrJ^J=D1mu1$vGs%6umqgK}OF8|SPw9UjyDU}gMkgpM&fV!szZrcQT+ z7y;-|A!B8>@4(f7Pr*yiRYG{*#~Tb*b2kSzj^}zPr|cTyDOR3wJ$}1a_PXap#s1G~ zUK1@@9<`sFq{BkyItToNelnYXYsg|xeNrB)x%jD0?EVn_Rtm;A>`L2kOv9~vy(z&8 zC)1Zj11X>?H5~Ko1R}0CclG^YmG#}R_T?iA!n+Pf$ab*=sE?adbO9)Izud_csX$|i zVrujjuVkS+^YvoCzG}>TZh%K=rOk1Z!63 zlHYNoYp>GA{ckJ&f2`ekJXG=jFYq(_*vDA1jP zCpmBe0ql2{@PjFBrms-<*^uq-#%RvsNI!c!!eq%cngWMnT< zDMG7fp12M~3%PsnxbEfCdFhKF{Yh^E29Q|KbQ~^1u1D_W2&3vqFij$f{njMX^Sf!5 zqyw`6S4Toh6$<0RA3 zvPcRwjX!TBmEMmoV*=0h=^bB*Mgl!BmXUn^Kx$N>QVQTy6lWNYA~V)xflcx!Cnb6#yY^X2~(^9<$y)$NX5Pzo9>tOKLDy`qiZj zPTz4guC}K#KX`DY&scy1MR;_W3_!z4sp3R=n7QDj1afQ)rBcM&`@slF9GwxTX`)n4 zo(QA&kZ!*v!)Jt%j(M3L=#4py;(e>T6?ZNRE$>MesgMJcZgEp;OleZupDfyK$PgM` zl=ajBf;XoQ;9e?XWkKPUz2;%;Ie1>tC1lp6!1%$fB^2HF3Nip24fy!!M}mC$PyHk* zRb25s@4>od}U1$7IH7j3FDW#-M444=Gj zV-JH$4L@cL*P^|mQs9?1vC5i5WJbvX(Q(6LREiq&6RIL01(X;loH_bY52zQFC^Sm@I4@F&_Cbv?*= zyF^BLox6-rv)r{kn#0 zXDeq zHeO#?{27Bp)b%6wQdU`+C?-8xthmsemlo{^=WURaSj=7uEjE4Uex7@542v@L-{F}i z#mtKU*V$FT)$iO->H|FiwgPTmd9Fv`${c!LQM{o-^@2e4>(p z%+h%@E6ytK4(4im@F+eGgH`tJ5fsIeW%w|05U@Bcj%N{Q+~nv;>mIt4_LPatB~wS4 zgPi`Cw9ZVHb7;C_rd$s$Ep;Htvw*lA($Or@+`gop4scb1imy4ye?LxWkD}8?8R+9Z zg#wxFA<#J*S@Wt&brjJgq(Tr#UAOi39E6UzW~3Qmlu-ddg^=QWOnvAk2Q&zbQjfsN zBSh8J&|q^Mnb}|HdAjOfU&`WYT<-zmWF^7?OHvh&XY9CeV@X)|K6w>LLwYrhY6Rsb z4_xAAzy*%n*p>;%)b(PbHHU^B``SG55r( z6Zt?(tK_BFDBRrWAHGE+%0$-o+k+>n&P$C|5{)oLEt|xKfN6 z(@0Q}%X27@4AZ`HXmX_nog*k=akjMB7L&4PqLyx2vTw?=Ds>~p`Z|dstNgF8d!{gk0f|MAeg0v`i!tm6WhG6IzvuGU zii!T76iq`tL=P2RKEReN6@{!~bDYZFnH650Hg8aPBWNcU&|56UJhVJAn1r*8lqk+j z9!ee=l5t8;ka-OWv&f1c`UfhykEFsIr0Ro;Px{H#5eus(hvfX^^wlf}ldWP7%p&IH zbW21}qpi67Id(y%lA@T`tfxnX-a5C4X|P zFLG@9^z7POeUJuSl&Ki$p!ZOVc|#^X<1sVB45Wz#Zlx#wn*)^nNorcrrrW32hOK{H zLk&&yoUJersfOq5T9aQ_T-A`JNR`Zr*@eUvYfWY`RSfAXR*{|v2Ft?-!iHtof>yCN~@7{_qWS)AnX44CjA5{Bu{&yBGVNx=f?QCC35uw z?Vdk~eGoms4LlSj`7v|HweyhiE%)lkF26DkNac->ru9Z?lo6$bHftA;2ltRrZX2E_ zSxB518SW1&*9N^$vN9RQ_m?_*ksN@dLtoL%= zmP8BkrMZksF*x~*$MtIN(G=3z-J<7^90VDpJy-)l6!BBEAc~U%6x#cby<8vl-JtOF zey2w3t#(IIvMU7KB@dC8NtL)CU+we&=Xmn7MtY2j4H_BkOXgiuL^{&OknU+vSC7ry zuA)i(T`Y2DvCC04mDMHN2nl5`ifU6t25U$0>Sh@fM?F(aUwj$=rkIb{^^yi9sdyum zT!9m0<^J|B4lbht&WR4HMDoi*Ph;aJUS?2TUuxgM{k$Rfs0h-euY@S3Ua1f*tkp94XPEoBJo@WFtb-fEERmDOw z8)0nGU8DfEAQNbzCh7;r#-nhN< z)*yV07|JjY9}4R#q4rCIt`w?O6~?zoQwJ?&^1ORiyfSkzjHF++gOYfv$sP#HqGNHr z3+b6%SU~H@8Wc$gEp^FG`I9RW`q4X9DKV|6cp1Aw4-QEPp@NfF-zg{opxRttJw-@s6#Tus3T-s6swv}7U2uyUasdp|Vz zoxjf^N>VpnrhO${ zlRiqP(ST_ksJivi=YFyrks0(UxAgcqM``*1J*7R4M?7A9#8skdDk%fu==&>U1K_Bz zOZPYS;Bhf+LSm~h)EgzQyVo0_dMz=hGv^?`{pB0h$x?iv_6GURF?j(J;J6`AQv);E zvJ4_GC(+_gt3ytbo`$!f)k%O(MV!u!gue5vgJXT8RS2&?sYVJ(AKNGshX_s5f;@?I zzP3852=OLho~#mc4}ku~WFhB3OH=)CuJq^DL3AAewQi(1iiA;$-!zGNR-W)@|7JqY zIc}u?+PlpN-GzAMvn&9=ogTAlqr5AZ@i+0AJXY!7YVpAaMF`I%?+dV_JWi~DaC?-a zr;zqADt8m8d@~QphgU~!{p|qLt9!^&?woNsryXT8pJ6?k|HVDqi(B6UbW}_VAm_P| zvgi$EBr;0%w(gVI_JI-2)=rUEYlWc*%ouPtyS>$?8COi4lPq^%=J4V#O@OaRPG%uFfB0S4Sz7) zoL@ckWwM(ZMh0SRpiP$H2=@=XErNVNk6SEIB^bK;>9&^q1+%@#7}_ETbnupmv$Ce% zu*~+NdjTiR0!mN|=iI`&=nuY3&<5EPIXA#P@~Y}u9ZeTI&QPLTlXTT{I{X@S&yiUX zZE^q9K`$P=CGw?l3#&h;1q!%P1wSW-tf-#ClKfa8=sk*Es2+L*jEM)Q1q#a-ky&Fg z3-cNjz9YJ-C&jPz{y${#vpfDgvv(HGJZ{ybj$K@P5jtJXW3X`2V2KgcbhUf=Bp6#X zq4%(RHDi12i$OAp1o0n-FF=OF9__tfeJ?5hi`;^5&Pz+l7to`7V6atb*GjMHXQ+$vrW}2>WWlLfx zQ|>~;wI5rO!#Qd`V>MT{rQYT1+}`ScT`WD4cb+>}<>Yv@Ny2t`8*)<_nt~yi5r15G zhG4>)Y>Xm%$OvH!j-X=W5c^(8oY^Q^OB5%OS11a8z5+56D?)luw!XCig>mp}cDS6& zbOQ9D(9vq9$A)oI(!Hba`;YC?qU;1NB&+NXnD|F22Y(OsxH^^8c~74kP5X2vn+$-aS5xRF+4pKwWNQ>AdITVeQftFZ857q2E#5x=PpY_ zmz^?AC#0xzWd5ySD$nDpa{R8pT@%KU%r!6m*>Hz%9>h-18S&&eXR`m@kh@&!Nv7Wo zZl8QPec30uX%;%NWm!()vgNscLupw!Z5qVjksQBw@pg`rShoB5+@(y!4wu(``CP4` z6EQ*uRYi*QL%76ph+LfI$|=8N^28{%qYYe^;ElGqSVWYif%dnoi+8oZ>laY>i4vtYu}pL=DgmiJ91sKX zGRve0viKkCtku6U(EZgsKDZB7ms!FyE(oD7GR0mZ`qxXrdwN^1={F6I_kX@H zq#r%DG=*|6v}?~rMJnOOgf^mL@6Gjbx|#JD_LB-6_nuLBJF)PS75F&`Pt8ZS@P;d@ zj~Rng@jn$&CX;nNJPma*N)ht`-)#`e=GMrXhFL?Kk5K(KcT5BA{GZO3u>GF8coRJ_ zbOtgVYEpEY)JNpxM$7QX_S-iU6`!4^QkaQQgwk9TQ+Y|hYI=RL_gZ0PIF8hl`(0j2 zte`%0E{!Xi#HQzqIQz#x`s7x9>fOV~YdUZ(PLhlsjH|#5X#>Jc80lUhp|Ikzug%W} zx-|H|ozyy^DrNp!g6Hx@Nh8@I+jO)J#~aV@)Y75zxx}kw5t0h@%d&6g>e54^oE&ni zqKCrYHazG)lvGg+O{GN2dWeI(R5B`uz0?|W-$h8NKbC!aNmX}v|+_hDm=1-qTn2HTbIBexn0j}N7B5V;XD zx~T}RFGJv}8i`SBDrS$AA&Se5CY)_5;q8(!IaxJ&Kd|XB=19iONNy}Gy{S}6U)I8| zYAmavsZ1$S*6Om{cswXhkG7hg7#zvkM9EDQqnj&C^ySWGR85qrH8YfG zIs3Vq~L2LKQ)@((p0Xm=x0|w^`W7q`Dvu$wafBfK99Auv~(%nxK;gSW~-&O z`$*A0N`87C-P-m_Unwwy(Y~zK`uts_QqW`hnIC6c+dpgsT{E=|8;+?wR^Wq`R;c0*Q2f07sp4+B#6Qsh^vhTH&CH) zDY#j;8TGK=Rf&GMngTa%>*dL>i#b^{&vq|^OXyf-Uxsyolb+GmFJ+*bXjikq)7bV> z>8@(>Wraol@wQi|x>Zwd)hr5cw+$E^t5TyBmPEOp51JULrDxPENuGTE+WM|q=3|9# zvUbmh&UdS2yClswC1||?&Eg)sZy}>YwP|cLqc2q|57qu@Lg6-ynaCJ$YMfu114+yN zS>uzzhaIN3-75I2u#%SPehVFjV*~527~fiY%L8gE{^99ejhf4fKh1-+88^sI&1YQ?ce{SN z-qU~!+suj>xUaDbb!ZRY2r(;AyzWgmLeK$?`cDr@_hfK%kevCkM+#;Hx z|D)@h-E$&#a|0cPkl&dbkl82)LNmGR#zt?{7v{>pxBm2`rUQpxcM5vB|D-{!RYJcm z1)C~fQb{B0`pin0w-NuS-iSPmT098ZyS#WLe!Ho6X7jt2nT%@&x!U;~zv;di^c`m; zKsvDs*S@TJEN*>>UtkXV+ort`I5(ItaX`{G_FbQkU36|R`fH0o%?8}Xx@hZ&y#64m zb`wyU7M{GJbB;sFKh!7Ezhz_JaPH_&)B8KK0>}d^^&%>MCHm(-cb&<~s!crY%NHW` z&Su3sj&?iG=?LjNQ{ztqs{Rre&(V>y54e^)FWb*W(QRlPyY37yU_KOi0S5wXe%*`5 ze6_Es*vdL5XAm*w6d4`5Qng#{Tn5MR!Hn502VT9V($(jJ%q_b z_uJA~Sh0HUI03V0cAZOJgCCxJz8DhDq$6WY+A{yJ_ym z3WR0F9_|R*Cs`tU;1^6A1W5j(v_=AVGAPPoB1*JfVcsMYXTV2WQuQzt7G_K{z=L=J zsOY{YnVlOaz{)sU3}$Qqo+iUKdXJBy1P+bBW;oc;44)sf@C{-ij8^ue*g!HLtVM=3 z0q}L)z5}V*m;k1^i~0A9rO$FJ8N1w5mUAqdB!GL0xNiQDIo>U zy9r43h)q(6zC~}=7KlyYD06Y;r{i;{d(b4(4t{Yj`64TB5q$_K@ZwleJy-{tNG4d$ zPlRzY@VPIn&h*F5X){>X-etDJ&AG<}(ie-;MMQ{TuYPfBWpB^uWoJc9@0I+C=Ob7? z0-77>70sXe@X%On$+_ptWUUK)^buHZett6w@3cg#1e*was4I(BXU<=BWN+hfHuGOH z$If=7l^Q2bTdK^ymyOma@H8r0GUs#qrS8CLv$S}cc_iQ=*M{ergHi&>%fbeLFD=Z{ zmdyPL1`#-r0@>=Rv$1QbHP#jJJ<4u&B6^>|i|svs@RnE(Ri+s^QF_`mJgu!tT~;5T zw(@K=c6EHk9s3g0Zd|h22GN@&$W$=RpFZUgp_i}t$Y?M?V*wqzvK-}Cjbml!c+7U5)I?=GL| zTz*K9=XTd<|89CTWneWK&~6l{BpoRCM0W!$y+%F=r}zu?__Wq?L9X z;gx##_HW)%k~j|L(p#BdEOIW&l*+`qPCSbw3Hg#FQ3ci&6uHhm-NTC1mL$neyu=Ef zCUt3&#TS@ybiU;vY2o{r=fLOw*@ub4mBnLVa|yqR%135JLe*#eszZpMjjzsX8@pN!O;D;7jYe@w3f>*b2V#oN<#qz51kg(Qrl1T&Bu4gqYJV_;QS> zCr51LeeWe!eY{t0nj`-zMTSwT+v`Y?^d*_iR<}D{Z9Q0N{0?SrS7=?3ZwJd#duvj| ztA}n>zumpo-docSzt-+u{rp&lT18Nr?0a2Bp>;*UJ>3w8q}RLG-i_6aPALqBf5Aep zyfcs=x>98|@vvzZnjwWT$Ii{EPreFN*blvCT2W0H>@i$&7nHzH82sWz65h4fP%*zo z4X#TL0~uhs?%1E*Q;=b?YsF62i(PBKHeBr~sLpGU|HQlcaa}$hjYlBqy;K`-^{wkb8qMfbhy|FJV~txz_s>bF*-_$4v*O9(VCPzZf& zB;(m5)_;Z79}G;3XCx{b<|r6_{DKaeGaT$`68M$EJk3q2c%3KFOZMG%TEZrK_JV#e z-Blhh!2V4aHk7H=AHxYT!^Txk_eh0Jc;dyPy%$f3Scdwrw z5$4>$2u(%9u1UJEe>0qO{oOtC`v$Z{jtH7_1@D27d=%I;PAY<=y8`Ua5O!R?vL2Fz zhH1P(IIVRWqKOvE3(&wn1WDu_{$6H|UJg76c z2#uA5L)|2^T_rK6yCMdA1e5WS{Wytfk|?p4MXLv)&>MS+q-_F52GMwll%4CK6Bll3 z_HOX9DzSLtcs|V`21%TaN z!6xIsH2!m(e-(?s?OlKPuNg=RSCXEfe5w^!QFAbmps`y3Frn>} z_h{*0l5VHS`4%$UMGCkAV6mVvn~_^1=@QLDGuTi4hx0_1Ob>}K6ENMMhSbOG{a+E& zB%w}{&s zGKRf|5?|PDXt5SJ8DPa?d;`-DuwACHj`(BT0k+#TJ_nlGWdP>ii_pSvd4mLhgGhnf z;C0~iPXI1-k!7tXt-a62aGs+A5cBU9_N1|6#gSNXJ-Dmu-C~Lb^>SV5I(D)*y&!rrXGI)8RZsm zzM%S7ka7f#+aZu;iT)MiTx6NraQp)}nQ`f`OB6P&4r}XU`_lxKqp|xF(5$_z8x)v= z9k-9$^g&x##kMOmJ0)O1Mj-%M*Y3K?ZW`e+!NmI&X>?cO?so>x;G{hX#>1V&l z+_uwu`-^9wgMK0`R`Z4mV8E9lED+GXG{Iq#T%aq9**8Hc8b@cJlpTqfvd*ng2lXRy zk!a{SO}GqztP29$oB}E+k{lXrZ>>f>vWr43RL5* zX?306N({X^#RI_j2peTzu1ViSJGYRcaFQ#eJM`d)_pL&QSAOjN5mRa5T4SIQDxQ|R zm}!uJK${}#NfsHcs8&Gmg=k7*$jyv`iIg5bUy|QfcSKv?)!VousjXxECX(_M*>#%t z$wu%<0n7@-PXjCS;gBT9Pquu@5+r7;l2rSJ;HxA)Kle4}=N6pL34q*yqaZ-+WlsG2 zXSXowL5YAnjnxhy8f|k-_6ha}zyDStIZb(}1cn9C1jCz5=;21KAov)j*rN9w8pA?3GLN`5oU>Sl0MyJbQ<5n9RYbWz%l#%cxP3w2kNpy`!tDRcDPc|nq# z{wr>xq3r}VoKsW$G|P+CW6_CVRVa!3(bu4LK>9;RU_J zEL5J?rx0};;Oity9s++~;y|5v&@^L2@RfBC&v4|mf9u#@+%$Bce1vSW^#kxj8g^-e z_ppy`>1g~FX|~E;QeE{g4@s!4e*X4X4qu#P5bbLvcIsxp3BztKD>~>e(>h0!>Sv$3 zEEhMq4DN#RBbm$qhQwa@g2b!`D1^Ew+VqS){!Fyeqz2JgwR+H=*6HidEd zSU=JY+x@f8_vQM~#^+m6DC#)p;W#VTg+YG$JE}pcee*xDEw%Tde+|9FL*|g-q6%=v-*!f`;9uG2aQja zXca#b>*^;ghdTz2D=A=Wr$KS3-m&d`9G?3yj>|P-;YpuT*CBdX<)u)@u-aR_lPwWW z33z$+46&bVJbdA_IE3pJB8W`^M9PlPN_hP?TPsavgutfHJxb(p$s9Eitdi7Vr3Fqr zxqZVH7b9C1if5MP-V=q#HIxQDjzCKCe6T;~lJ()di*Xj0+wp4x8|!NLx$?$8S5~s` z{UQG<1RCNmpKvzT|1jy9<&yo``%z?exs$*Y?!I6PX}6U9m`MYE{c_uUA)8a$`Oo-z z{Sz}mA6y>Hs9s%+o_5D)RK|w?>N@c?;y=&) zY;FBwmKXVs`B#c!FnPYLSHDOWIyvq8N0mRiE3jHoR*<(^RogA_v!;3WVAbQQ$H;ui zOU%QyhPMW~vWnVd(6yBLQ?G_m{Zl`>-Gr1ig z9Q@Ji$x+bs#jlYev)Ab}w?CX&j>aqK8)EjCvfR2ynsYYT^D-{I^(r`6t$l&{H|y8e zxiU4|toU!^rAXo7)>}i7qdyD1}xUr^G z4IBi6A~Siqfp{iy2m=)5Zgo$bm;;{06%}=<`ZQ8)63=lL75(axJJQ^Nz*S&lC5W46 zcAO-f;C*rm6gtm(#i8#XKcI1HVxB#0(kLqv8)v}1fJ$gH5}GQBH@9Cvo40YVt8ymV zW{Pcr!GP#K6b1o6fC6I}$M^sNr2l*Y05I4J^uG^60Xm@Yf0&!`7haU-%PfwMT8o8m zrPqJ#HkC>IT)TE?tpNq|+rV|M2e(eY6iH|L>7E7SA7?7=S&&YkXk zj2heimzDKUC$Q4h99dOPWe7E~*AQm&BhvtjN!oL|4r zR*nBrHFXnXgD(GA9*bqQso5)}tyE>m72SjO_t7>t*SXTRkY^)=F`OYGAq^)va_%w_ z2*fjiX+}vCV3TNjW8}w6&hs>dyRi{&^?zUx=v=R*QvTo7Zlsx+)xQaul6V#$W9Zvb zC?zH5bC+z31rc(8KO-1A@@+rN6}Gdtdo3uFn;B|TGX0`d{d)^k#Et6j2%qm{AE_4& zfAwc;RBqxK!q*PL%Ff*0{`}8-fvI**xHpaA!nBv`fy1XYL`Aj+VGKuRYg}vP70Lp` z6nF;OU=7Xwcz8S`nOW88SF-ebNFm%?NI?{OHn!>Op#9;*3F>v|+ZyBzSBX>H(B;u< z{|*is8k*QK3Rz@jyc)E-y%YK1-|k0ZUNCgw==S1 zRM;JZF~ph8*Mhs#(5(^p?mHNRo;jX^ojRp{JSB861!Hj22Ok+E4a1Q>IC#gcrlykZ zucD+vWW>`l+P#(3RPt9;`up{4(sLL#O>9FALy##@r&X=@%dxs!u;RuRhSgNCv17yU zx~c2mi{{ivHqLWftE*J`V{7_V-Zia#r_dPU%w9J(GZSktffEy;Z8XucDN89+s z!{2izyF1HAn*4Zi>?Lz*GBWV&70d)p%G-I)BEGarXm|^k+@ewtR2rRvUEgx|qZK)? z(cJx(SoQvclgb>gjk^VnJ$+na~b%t@Hq@=)bZ5Z|qL%LyjHw^5Cq1!NA8-|0! zKydz}-Y|YVK4d%=3^e=O(f`HV5W-M+d?sS(f1J6IxA%g6&folhn48>Eelzj^hq?Ks z>aSoHRtEh)%#CG;MX_4%S+J`24fX$GZZM}0YQIJ0K5@4?{B8N;znGgAhKWnhYGW`r zH?vsb6z18qz2A$28DC2MQL~RtNjRB8YhmpGTY92r4ZgMg@9#NXHM-`YPUrr1u`+7u z#`JtD`RVAJ!h3f$kN)lPw7vl5FVhc!|6%3^2d_Lq%*g_$>TMLMkBS?6w}=s~lw_Cw zi@EWx{PrK_=G%iSUcmPp&+IGSriA>;?|Ih>KA(BWU~YV}4*wf-!=J)%ikJ4>URU1gAch!$_3a1C`Nl~oas^ex(^pA>)@+vv&_)Mp<%Ia5ixt}#AlKB5H zH&s8McK$c!Mlh@T6@$5{9lRT~(lBBo|Ep=@{Qn4Z!}8|LBQ{fodNL9H?T$oL)wy_(91V;5S;gFK+p|jpT2?|I{0yHbOk{ z)-J+Cy7rHit}+A7me*k0nXr$O2>$TqDQV}U^W{vU#EpoNok`CV6Qo+Y-o@RiYpwdZ zh#Ld?&HAC#k+Uw+U$K8@_dn9d&!V6(RrRmYCyqIouuzbeRg&QP-XhghX@4p6!j1iJ zIX+MKzvtgx-(N0@`~NdHNzTi!x)2;y)n(nXhntU`{Peblb=wY&4Q!e_^^yEr@3&J4 zhf?}*uhEDXo9=Er8?c?IYlaI~{W|wyZ&ly_Jqo;O!)Mp?c0?M=LppB&4;~Rc0p08| zSoc6twJVqz+&E(J0=38dC6dSH&8u?%=z-zByWtc^@JaQ!#voBeCoGa1Uefx?EKXtD z>?{0&7FSl+dzp~SiM%L4p{ahuBn+9zbzE$itu-gYM~pu~Cj>S&(EQ}_!)c(K@#50S zG-<;cqNPQ1U(AL(@Bo>{iNd3dRpPlc@er=}QH(;IIvEL@KAgh2?iw@c1eW4?!*!c% zuE72jm(gfUsKkJ3I09t1vS=%`QMq-rAzr0jLKt#LH-g8ox%MpD@vRKZMp8&x9*cM# zzTWic`D9+((g-DF3CRAe^_sldOQGJ>yEeZ?1o}7(7d9<2DpaJJn?~i%d@gtKTk?RA z9rQ?HZ+=X?eqhZnrTpLur>AY8#e2{4Q4+tEp9Po7VCQ$=wVqU`z>^QAmMqo#e&o6^ zbiWnoxVA2(JE~Oe(S}|cotPej6p9x4lk~*Ee2Lze+F8dA11%b=x4ox?S42bii_}!N zEFN$Ylj*n$ymX?dt?QY~0&k3XWQRuiVD%!wtB4c27Gu1h>q=$5QCXb!(~#v8vM;$m zYh7QWFi^5A<())*EV(Q9;PsQcVaus{?(c)Y|BSruy5jX-Vu+Rg^lK!bLLD!OPOGi8 z`@U1u?DxD0Hxx^%VFlR_$;aeSRX&+g|!M=ay`2CiN zjTB>vxZF3-21TTZg|X-PwO* zp%jpHJ_3!1a&)2z)#KT(egAf4jovF@;-<;fYpnX-_p&!8;Zm*hSdm_T$=}#wQpD2Rq;tD z%Uy{HQ*L9nt;RRi!Ob>OvA2*OJY(u8WnT|8y>0G38wF=|Jebw|hq281Wwmfd;~A4} zlntilk_qh)cd}8udK4JN8LuZEI#>Ij zX#i_9fc~P9WbA^GcKAZ&av@ZbD9^|*@7|Jk*EEc%Y;{4c3zUOddy^#&rX zAe`f)3Vv$t_u=0MXZe3zWS?Fce7yRQ86#C_doBIlW3L>Rf^`+yA64hQ1!QYWG4o&4 zeBMKn-XBEf=&Mxuc$Up7bovZFyr48k9!U@Fkv>Q`eKYIp7lU)3CysuH&?lzipy+S#YijiXG>O4G3ckCDUz!FUG;mix3_pBoTL; zPm3a6e_5Opeh4syQaKh|i4uDhUXUkT)l*89x z;O3^$Z@E|5-&OF443EbSl%j_0<))+K@)@F_KOu|Ena}>x+gtZOeObdIPgO(t{t}X)-MVFkT!`BB;@tRyS(eTX+yhh8h5K#k< zBJ+29*vyZpY!j4=ape4C?%%##3C5^%sMuf|U|YqC^#QkWCSfHilJE^xeu}H9=}P#f zlwb=ZP!#_cDf;Xqsv#RioYVI*=Dsu+MCbvDPMFh+;GrWRBndboA#R~UOhGsw`X9Up zPT!IW+r{2z@rY4ZO}|RIe?1^H-91x)oX%H#4dR|5EQ@__f(rLSA>+99P*6R8ZW|jX zBnnTpiS~&?`prQVmpLWsLKKRbsC@VHQ3UHECP*b`eTv!8qG%d)>@`|>1PEhvdm<;Md;<1!Z+Z+MQC~K96QKeB{z8oGZR6l=6 zw|3!jZ{|r+*S>Sk*EjR`)z3iW4EZ@@Q?$8ZD3CrkypF(;`SLPKN7;KBJ)P?UqvaWl zx_teBrjp?7by@^%6tId?_Rl6VoP8CTrf z$LbYMXCTXn6C~_@MtBY~u%v%$F2y^ul-PHgGoe(O42;!t=yAs1tZ@4pZ+T89b$}dR z>07QP7M|sQ_g1?ZZr)0;-p4s0{zSIry@8~NQT%iIgD2q!;%k4OP`o2I+t8n*FC|(e zr{wX(YPrb0;uDt)e|S)#Nby;T(w~U46g?NIkG~sbkvLJo^^7}hYdJ2>qzWfiiKT>} zIhX9yd06uR|Ivj8yV@ zD0Y*CFsDBL8Xl7|koHX{mgjTsj|2CI-sE2b&+gQRx63_qj?{+4aph0o!L1 z_yjS$WucSafq)Xi+nzKp1)A)~1k*$ra#b++}5 zTBFqNoVp+w%+Eg&67Yy=jAMJ`oE{5CR2yZz!;K!|R-I=zr!|3rDe2 z8J9(tSY(@)AaX?I@SQ7#s{$7;HczN#!B_H5r)5Q^Wh?b$KktX-0T1#>PuVwNSSq9B z4RPHDbTg@SHt@zoE_Wy~=XwAXIfc$}jHSEhKEQ!5HRQ5;+I zg-=cu@fWL^E`j#$aIuq$5G_S84=8&$XY9s{Z5z!ze)1_>K%^8AiZxDIf^DmJe`Arj zD388aX4qj{Nw+Dk4lCY1i4yQ*AO)P%+d0sl7lxcA;!Y*fd7Q#1xCs?{eZxtU+y^a& z3*YWJKUO0=s3qQu;xC;IqjJX#C}(+WrFCURnJ0R1(P<^wLATG9)aHdSE4 zTi#_35XE(?tAg`Tc;OKigK24Jf%_;f!Zy^_N+&faiPuK1%-%2J{1j)%9R$z>x16*0 zuo=+oDRX5mKOnR8@yKhH>(8Qn`drUdR_O_@xQ$ldLLC>AtK6})3Z}G5 zan5Q3Tg&CkoHI>#5b!)bTg$?T*Debd6Vc%wVU;ccCz&cy75Qjyq~+QL?uZI2j&Y8I zxJFIUrUoI2Qq#J{SkKKk>m)9-yolbW#5b(c9nl87j;fUw zye}0Zf~U~Zf)#;sq}M|4kZGxlol-*)@0CqzZs7F`aqS1my0~QCxX&;Sfssb8H^{CL z)|nCZqY>1MMv2hqU}Nn}BG20~j%=&ZHm;}PxTm%t{CJkJ&|AHYxVD|eD2VE)q|3dT z{z1#Me#Mznzv)#YDf5y0dgElCyE<=Ay9UY(EKcm1zznls^*6yozF1xg&qs z0amP5C;X+gIIre;ko;xMjxIjbn=cZ0FgtDP#JFQ&%wRRQ(-7Ns1ZpQR#h;pE=1$n ztgq^btZ1n5HR*+yoeR-uVUoe-$mc^g!N5+}pli~lYrNZ8=+^c*+}lqJ4Oe<1;%d{! z37Z5_T0L*dTYBInzLcB=y@di>xftJkp2hj`E$?*ZMLG7=M83Bz9v=*g7wd@CJ~KRg zrz(=o^gzrfYA;l4q=c#b6nq$RPWCQZ@7Mw(|1L0e0lm9)98^`ne77PNRjqExeDQ_a zEDEO)re3h5iErAR;lKZCk^2>QWYr~wf|}qhgQ3HB3`{8&HFM{>8>Z7@!y?gFN&1n` zyYsFFar7G~haz}Z-FKGxPbY$1Z#=y+X9gCcA!_c+O+>{P9^Ln5u5WPmGECmvq zs4`-z9E3VhaelhnqlNBnF_*=`Y~kv!&OO_AF`;0`5k17a<(*a3>m*urjV_kqifWJe z8!j5zwa3xAwxTibep$HQ*!6E0xzeARi|^Y`<7lPQ=<8;)zxgRBBz#XcEg_b^^OwkV zzk7E%;Jd}sq@8o~Pip?={zezwJ9ulfS><-Y3Xlq2w!l-?qn1*Di{F+z^ydou=^&5FKs=Ed=X3C`d`ewi9ghV zzW@LEeC9I?CNs(&8YP4@vLwXVg*26YYwVIVN%k~$NlX$_X|gA2NJ!FzO17p_siYxE zrHoxn<~N=5J@=e*@BQ6-?)^P}zsK)inDy~`zn-7hlfvKgTg=@3+VgV7YGl^b?_c|0 zj$d8jaaR-C%4YLmaFmr>Di1VMuT(k<}sp4uCC7Tia9(`b({w}D0vYKKIW=UEIj`sPRr#9L*Q@wG?H%t3s;cGJzgKhn?5h;%BX*;*mPM%tog;r=~Jz3Ller) z-JXPJCIX@Fz=3D?PP3h&PHujEut2{2bx_mq$f2hq_aiIP`hPFx*rF4nM}NE?*)V)% zZQGJ=DRmV;UK*uJGk2t$$4*N4K7>TF`A2_E_6@BHO>Hw|gw^_1Oh6`@Rf_SaJP3r$ zQ~pcnlQ+2q87HL&(@q^EVErS!z>oZrN|TH#k_S?U(yFYI+>2x;K0gn_mV$}2J@lBG z8(w^r?vg1!jhwQ{Gh+kZrhVv_=}A?&Vj(x1R#hT5RlCe*&5^>Ab;IOz_URGPAgKcxdf4;qqp3_wKehavrk${0FL9YaA07t%y?`M=Vn z*+&bh9W;z22kq}nMnM?b25BlN!6PAXbTcTDfCvpaekn|whUwnYBV?})!Wkeo_%RJ# zI17bSlpVwM_fo%-;G=`^_FF)*B?G{#Wti#tG1|{G(k`|eW%3*kJxJat?wQWGiVp9PrKe^9fMo$`CU73G-Kl%*+b>*EexS!e*Kb)G+!WPNUockA91_fVtMVRJ?~Eg1 ziNv%rWlPi^d?JSYwwv9oQx@R#928{&h-foZ4;~QK59;UN_0|;?!kg~@yjxr>nw?y6 zZIh3m(o>6t{Tq}o0G3X`fOIDfRK){Ew@+WKk7=|lrYp%_Z+-&XaPaSn+_0kz0KuBR zQ-9);F-8kSsy@7Gi7{J4WV^RE)0?-IwENC!^~3rbL8w^(*Bzowq#bKfo-q%(N`=(e z3q*#*LwM+tn^@sBp$oU|a8KTspn1t{>F0(Zi2ad|;=s!KKLSQd+E>Qaf*?1pNs7S$ zv|j(AL(eVKv}FJ~;Mgt-s*zQOwAQ7#cIIQJO}4j=;MV_WP&fWz;w;xYQsMeoyHPCj z5VrB*u?OZ*wooZI`a%JUwzo#;vkuO#Og< zkMVow)Fz%r-In)0Vo}f-Hmc$ z2(-^PYwo4G#?qi;#BAy_qe%P84}*;Maq)4T3tlZi3fy#|Eh%G}7go zb!V`Q!4M5#7CG1-O2~Wme#XhgtuP9n`Z2lj+_y)QJQsa9pmDPOVaL)-)!2h*e8J+E zF17m?(P<%YqXWG9emy>}M>B$<6;v1!oFS1uBrv~h6@j-qW(?f3CP=_Tbuc}fS@(Le z@EuP{0RyRehVFrn?}hK&ZRI}GPBPZ9jctf;c>m(Xvki$|+cJ8`zfFW^U$zO%5=|Pr zwan|erB&QM8C%lD?Zrdl`hnT4+b%AJcqA&C2#kpAjcVWye;D$z#Uc>!Ouxm_Q@FUQS>h~rjs-)`4TAEV z(}K;;&ieiUw$+0L?wjFNoGOPxjw=_LF z|L*)usJrt8Rdxku_+8g_-)4b;I-A)r*xKoMxr*RAw%yf#sG7ox{8L>XgNtTnF zOK>Gpdh7FCMM=Z1Bv)5X%{aTamD@Gf>FUaiZDx)34^-S5pN7nx8YI{C?K34$IfUXmX4p zS447bzTBF`(vhUZXA_38q=f-aZ2ur$Uk-J7qPtt1MJGBY5y~bn3+nW|exu?p`slzM zUf-g(VnD8tL7Qxi^(J!bSu@p??4+?j5}Ci+WCV4(;58KJtX~MYgE>LRE}#$oRPKM8 z_CJ=Hzt-$=|74T-*WA?qBb!W-WbGfD%#Am@#dcK>9Pp?>PVV%Jpr;od*kWJDC~ zo0%gW8GpCQ*cIE~t^eFpsD1d~Y%&UaS{lB-tU7SRyRYTW-)u6CKi)SV|Nh4&Gxd>` zEV99&wRu`lv#THMZ@oMFg>CX<%-n56Ca$0lR-It?NJ$0n2LwS>!1 z`Y&xVB-EBMx`pJSv2!-c*T-`Iy-nudYIaK6mcP{O0-H?5pPIe#>-e9V{mbQu*MGOk zeEo8j_QxiZA{jFAH=9iL=$dRRwd+pay>&F~`M~Py2ShZOUn?1s0qvyXw2*Jt4bCp_ zy+Fhss8*J;cTHWUY^(mW$Ap5&yZ?j8#w`eMjs`wnUYCJ`)3xHB4Mu_=O|7nQpKRmv=H49T|6clXi@(ZSoDzHju?#?fu|u+g zAs~AOB-O=28E_NvSqxak=Ap1VH%YqpKe(yil^s{MA2A(IOj51lrlKyU%X(ruWLFW$ zW4A{zZy4t5Lu%8N%hK`u#6mO0?v8kic&YJ?dO7na$B)|Bm)v8yq{a1a3fa%&7%wU2 z#Azr7xy?~z0y#izLoMKj*@RYKz-<}aiuOCO30;6kLKZjI1e31GsR!RS<0a$0un!e< zZE|AbvlLQ-VI1nBsTrLH8!@bn%Ab{D#-6cq_)@T)`YO2)7h1ASDAC5>iXFJg zZ`|Z^*M<;-^NE>D>z8U``q1C%F0CaPYdG;!>riz5NWhcqbF)(|o%%r;6X$EuG@Mo(mRBWGTy3dtJ_f=W# z=zg9ZJ6B3rbKOR_%swo8u1xhpu;P)OeW&8J%e%A#cfV&hy`)^4S)aTzuBX z^<8$yGF8O5Ec&TWMTfF&97(51*floq6k8dImc_~n^P%6aj!UNE1$*&p$U%q3j_tj< z@Kq>C#1s)hqSY78M_XN~gd&)zrnU>wWa2lIwyI@rxzJLYLFtE&(^x(t+!7WV=69_+~u6F5q&klaecRnOiaAJLP|4Q z$d=wQz?ba~oMHL;XRCH9XTEGqmfaYzF|g-Cwq$eHp4#w&o}qDr#k=gYwGoweAHKOS zwhZ>wMmF_)___U7+3=cM(NFBWzc)A1FTFSt^I^Z|p0AYqXJ$3xk=7Z%-YvE*_1#KX z?D^Q=OGEGdKGmy)M~GoNZ$QOwMT7~-$jR*wx7;(A6z6WoyzDJhcIr8{wMM1y!nO{% zHrJ!3a=vMOh~r9N z`|iE6{Dvjk$V?Zwsn@Rzb~!ZG7xYaA8m_!$XE!!f?)eeovGQ)Pzp=5Y??+hN%6rZ~ z*kl}TN&*b0ZeJ1AI z?G196Eqc!z*MD}mKdOJWc!l?cgll1^JIs}=|2<)|x8+4a|6GOP@2}*XmVru#`D%~f z-&~&w+|>Q^wQ;|{Q*ieLLxl_VmwrzM@4ff#P5(mUz285mIroOX3@d1|fB%ej2^N{@ zUu;|XJw?N{a?pF1+SjjgGxo+u+tn_O6WgYHVvNSlZ~FDrV|AwRAVGTjvtRwk2gHh1 z96p;*t*4(i)~_)6eRTh=*jHo8V*IXjlfZ3pNxj2_nxnsiXU^eHPM9w|SiEn{d$@XR{r`Hd9Es}O8OrJ4BS%#~U$?2Y}BvVd$FQig((5lEn!&_N2ki6y$8oU9j(+L-}55MWIVA_9*=5P@V8*h#@z z&=9d)B#sGkzN8c@!a*!xo{&b z$LJ8zKBRDLRWhG~i{*C#Co!^-G%%hG%2ANwWLyFfAQ3T+OpsxNj3?uA22;*;$w*N_ z1P6m-fglSeka5X`GY9~R0U!hexxj!yG9o@Y^P<-2(?Iwy7I*@WO(LARgn@dS5hMy` z4;`gT$z&DESW{s>7nEb7H_;(65+aR^a}7Qd!^v{TgIkEnuc~CSxUrpRjEpM?5P?Jr zhQL6&<546cfWd>CfYaYq#mtHL$2+83t>c&JiOVeT5HTl_gBfiG=P4*LJe+~2m(-y% z@BlyqlbK*B5#`Q06U0u8)ryrCTKiNA7Q%x>3R3Xcqdg6AkN|rzrBstH<|;gl^Ars7 zlhGg-xrGcKVnZeXj5vphK6l>Wt(X@VLEeof@4VneMnrOP@#M6~hk1LRin#;OQ3~E2 zfKTF4=D;bhr!pjF{^6Z?8@K$c6KLCu`GsOAA2vFYobSWMMaiHdxu@ev1x2Pvb5dgJ zZX};nh^PbIgk-?K(ck|C8vd8engYlH{_rH2?pQaQ$KgdJWT{>Hb|lCjS+jCBr>xlw zdwYpz9d~2DyT4!EcODxf?^|%Ij#=?;`T2`JY98}ln@-Mysg^MwGN|0(>X^5g5Xv;D zY?i0m$jiR@^g{P?&*-oC`_mI&zZfMn8l3Iz%D~u{jvc9+Mmfi8y2mH5d6pMmLTa9k z@0T{8ebds~_O=Gz*S>;WYyOGH6A= z2Lc0AMDmti|5%Ya&DoaoGNEfZpr5z%#%#om=VABf(qFCEXEn+>geq09KpTymLo>KM zUc}?6&9%JtTBFjQDYHU=Gl*pj|FtA` zZ!opFa4uhCqbi$FOB!hD%pGFun1wnt6y|obM<3@kx92&APBag)CyhvImwR6?PpH+f zHCT+2cO=3%EwXtsk~KLx$!IrXX)-6e+F2F(RJd${Gehcq(Og)@9m}sN%GYSg=v?Ma z%K0ey(ugYp(V6Qc! z#}2Zi4M<&&nXk)8;{Fr4YNW6XqnXD8%@d5~b}l}jq2oV>y*#neOfGwlvouT)?)$&jRCcb!Xd38>3KMU{=dnrML}+xZvMr9`u|O4{eNgc{ckess8SLM?Jq#XQ%|!u|3Sn5l3A5)wK^He za)=IMTi!$;Cvy}wf$-zke9XnL`m z>9oEp>2C&9Y3H8*Xh6+%%x^~gem}(;P1FiC#ah^L|IL6p-6`%OK*ObjY6J$O@!%(QhHVSI1oMc%S~Z$m9J+i<7g@Na(F|0yO-{+;bZN z8veq5hX4&HTW=Mh;Vwt!1qRfc0yI48$NU>g`qqU(|AHe6Z-Xmu{z1ckEWD>a*}6Cs z@#c>K^~=r0;rK=VkHwEPwB`~gMJjA*Btxb4pEK+K7!Cic0d?Ddm05#s{azS~n)LKwbv#Q>?5q~C`fW3yXwrO8mBsiAaUlVreYL{%` zrV_KRVS{WsWZ!Yq^n0&~Ms;;4EOXOI*b+QH-KKM+>~w}8sID#O>QpwEK26Rl5wEm) zq~<=I>DpT&+0^w&Gj{q61zRfp#OCq#qUo$)`%>9AU61uzrq5EdO69)TJTZ7TogLj< zs<7Dg#CUl+hlVX9pm%qf$d`)tu*Z-rjd)4s6S*-IQ9ccm9%{nKU1mp|KA z8oYVhAK5Z{g_~7r^kw(6*mtwVOTCrGi~q~aYHj->w@8p#_guGi>3)&lGFMJKd)+?B z_GQt#xeEQh>kd)fFN>GwDoJaq$?5OpcHt$6u~ney#$y8&!<8uViEpmq=R`~$Um=`+ zY%!RsPuU#NdBg6)H^-vsbGUd?O)LoEG2#6;L*_0c5+5RrD5)nW5mF1R8{V_sF0Jog zDa72rv1_s=N8j}!)7d7}2iN1;@z`g>>9e6;5_WH&+PeqYo@o&%@CKKcduKV?;PuTBoxTSo#L}Dls2V;XlHK5?x9ajtTnaN#2e`&YZnzB zZPg4fxa2v$vFR@RM6E)}d(W?{dM*9CG*8^>@r<1uxySjFSw)7Sj5n?09}s{6C;fd` z!%coP3y5T6qMH5W7w-thsd^6n9*vR*#*fnYmp+10OAk=WT$-3CXGP8R;hF^I$xV|S z%#@3KunjEB282YTTst;6q@=9_h1Q-g?2uWdrtQc|12rh9PjjjU$ZP4bOHwR-Z)&#G zWOj5-$CGI)Gw01iQ8`2XC%YbRqo3*>Bdj!c*`dO7PhK8VMnpd~X`7;#+WV_V-R&|V zv>SFB2{Nl&Z?MAgqL-e5+YgWM(Lr4#rO@}!kBge(7n#%N9}IooWggRQWksbU*Gz1b zy7)ve!c>Ad`)T8W=ANuZZnB`f+1C0=kg~NeJ(9!hx#}ijv1BTE!%j;dZy4xf&6Y*Q z`^zs%vy;PS&Usu3&^-Q@?YwaOW=`mL!0_&C=d_vHPY<(qF-Bhe7>u}Rcw}79@cqjv zOsAoRJV3~6DSf>P6wez?nk~w_NR*sOJoRJD*`(-ouJc^+hF$(Hn_Qoqt$kAWpgpW+m*n;^K$*Gd{mN&@iJ&R=JrW=QQK%~1h#H2Rp2qTj0k&1HXmqh z7dDP){&@4J=Ha&!`ol9#8`e-F2mBr=G_e2;Qfkhbn2#1rorYaEzix{M`wo(R;nSEi zIqoA07C7$9*~5OjScm}!w)v(64rUiSS$>jYID9nwV8fTDW^NVw$y*Q?#o0AA6-gal zH1;9zgF`qJYMELV&?k9E=%3%UX5Fuqm-y z;}ajPZ;YKHAtjlRA^|R_I8knW#GJ6-nSr*bj0Pid`?vs+jg;rYs{pJ(MksJ_G91`} zhPhvkZu=bnlj!vbiBuqB#PQI18b)s+S}!5#lGczcD?oZXslm2JHn9fpkETDu896R0i~wh)^NGSwvtz9&iBwbv`G? z8;{;kg_IZ&k>Rn4iCB7tF{BA(PZ`MPW>Pr37sghAG7c$Q?(Fh_) z6|H^{*{Ok5#(kza{EQm050rBa!}*bAVU_o%0?zIbKGgbDiKzFi(F4Z#?x~X z@TmQqBwIGI8%g3$$iIL=qUq0*OqF91(KGqljGCi3$0#6L@%l zPXa|~g)(>y$VL|K1QUn|fCKVb=p+iNpbFai6ioxpr``ocf8o|~z<4fv5&)9PC|f+3 z3?M|f2n-vEqr++(G)O@!P_TPRkPr*hlm_Lwh3g2&cqYb)h0vy)J4Qr&C4pYQkm_te zo)5rcH1Grs=}HGaN27l0!H1Fi=eok&oN+lE*qNFBm5toX1QZHIXC$HwnLwuCBq0OJ z5fS&w(dtAno_ryPgPG)FP;ZgEL+BSaus<8AL`EpG!FVFLo+1P?(296CnS#_Ig4$dF z!o%^jl67318XhvF0YoO~M=rd59a^PAF?8?@1*6Nr5USAW95jXkDzd-=p)2uB4^~X6 z8VilXBeMy}8OkXH14NL)b$FqjBw!~45GDbFGt6;9`r$*7x~O20f`ey?0*nGppg{^G z4-h~yE`q)QQiKljNhp67S{@Jj5i$4XF(Tb)al!kaLyym*&;yu&1EG>iyB0u)6%U=3 zV}f6aC8~H>n+fziMf>4FO7q|anBP?NHlpZpdU)vF;QB}$ zz<^u?#}P~D!>^oGVu`$(3)99UEt8?n6g^{5n&XZ;mkF3NuSGI2BD8B>6r`fe6~gj$ zF1|XR2@pt(%A#rli?PkMG=K@hEgpi|XcK&1i$PfeK1m5LgrT6R#F|Gf9;X>K>j6wk zCggIu%#4J9*zh(!8{UA2@c@kHg6BvWeIh8q1rCQq#wdq=wxYyRKy4yIuxqD8M0n9F z71&5^3NnoZ5(%PW1bk|2)xAfeh7{!euV7nqN(TF)I0-7cjtsGbeAq~TBD9WM`;(rt z<`RIFt=nc$=V)81=Z*xpxHBA3ger>RK&)SN3LLaJp5eu$3np)#eZ8i3qbBfhsWuIW zr;B2Uz#1-?KmoL9h%aNfe3s)^HZG9ZVEKI?{3TiIeyc1gg3r+ywbpQ}g z!tcd{I9ioD3->!jNb)X}&Bm;M>itFh?lTXMUDq)Rn50EK6u>PhUk0MMU^1V9N${w9 z`1C4`K$p09-j|CbGH+~Hx+?@+sE?`aG(hZC6FEo&61b@Gkn3z<~f3;sE<>Fb6tHfX#@gQv?7K>|W8q zDK_9igQ=g<#w>_72^7*roj5IbT&Scc{%83M(HV?$vFv!ZRKg+$V?q?lVR*7Wi}t>W z&mcz~xfs1=$>S&G_$1eJ-tBk}7h@QWJIjrj<9gT^qV*QKcQ&VF(=Zu~q&en6WI@ca zf}pd^6bBM6kCYZf24cv7ymFc^*EfND{>KUE0s|>QN19TEzEW5=K$ivpo};4EjB>2i z58En-ePf@LcpV)xj#14xcVTycn$!Qp&!4B73M)4 zCI+t@z`qlQ{1Ci2e-dRCu%PR|a3XkbQ#9@V!So=1)SEY%M#0?4;O@nP?c;-KDkpz^ z9=Py2`+8ICa-)wd!S~=EIFSObA-*op7bS7QuS`%HkMt$fDmc9pSYmI#53{xoz()B~ zFGigH5#n0Wl^OrO(JKP&9MF6v!un?Lc;rF(_2Ji>hI(!W7NA};R-h1KUfB(t;Chb0 zV=UJ158B-RiLa87{`*7r8wwQp?BgEF@6E##dxpQh878?5r}qtiK07Sj=p&C3TDtOa z>4(pX*K^Mzlr#mBCUUmXp)gLnHn&9~6$Yr!jE)RXuNfJ+GQ8GdWS#Qx^p9cD;t?s) zVR_9F=!4)tdQ{1KRM~hmhJ%uzqa-+}FdABdEP4z8`JCcS5-4xL)u8Q@(eNkZ)lVda zF*D;a3-2)#O*h&F*P|4q-SC+GDvCTjwod_lj0HQfUb-e+LZ3LF`cWcwq5(V8YsEn$U4$+%geY$i>YP@DUDQQn+7e3KJ=8k)+ixg(OU@ zo5FaED5#Hzg|nP(5?|zMepNa9LgnOFwAR-m=yJ`o|0hfQe+ z@7iy*wcjugzww#hOlkNvU5@lsacnOO@8itpd>2yuRw(u_;8TBDDLE)OMW2S}!E`4g zJl^XTe-N2mc7OQeFfr>n3IQ``dF&e^nvyUsoY|6(T78eb$*e1g7ddJR%Vv%=UDHiJ zf~wBbeDSjX>20z!2Da2j!S)$PoRGJ&(N90E5F@MKw`w{!&+F~bLmLN~m5e&&JwE%E zcfNc6Socq4>`dEs@oO{zZ1f=J;dc``m>he#?Co+#sg!utuZ+CvbH|Vr8YjWtW;hge|?kw{;^L-jfr3{#m>#&s($`^x7J3-h!?+jg5%joIL{jl+4ZWQ9;%Jq7wK5y z%|F983@=Sj{n%E|n`wuCJi+ANeN8A?I;ana<~0Xplze}x*wWSnt=(t78Ror|TH-Au z(-tRL7%55N3}5*3xIg4`7GpJpG=*zt&a8r@G z;D8!*ciQSPFZt1ebTeYX`C=wO`Y9%cL+?5sg;<0y)#J08}?D<9XrIr2` zA7af?WbN1k7R$j($-A3poK&M)v%LHQx&7SSF`sSSE%t&16}{T!$F<7F^(%VyD<$FZ zj(a=^Lqz4T2LLC;HCAg(fL@U_t!DD&31XS_FpUo3#N`1YNVBW+kn1C192j|$% zsw`JLCE;=JuukWA60N#ZV`7Ms6;ahcs8KjU@{b_Q2%wFjPyx$Diy&6bFh=Lt!!smW zHX)?HOQ(?`*e6MAB!#qgWpp!Y>`BZS_QE^P!W?^h@C419$gZl!}3 zlEjH2!rClGR?>t)H7Uc0Alk_A^dvBWsUC=r~l4eI}#uK(Ak=$?WNsa>?)w=4QC=^y_#^z?S+v#X?JVR_qzs^=+TkepX{ z!}XVy zwRhMxR~Cx!*KdZv8dag??uRW~H6J^hI&?ja!_x z5j9q&!__x$uRZ(T@lL??6@1I97WKo`W4=A?#*uN6-0BYtX<;_M!$sEJlS9UTBk{l8 zAlBbodx?9G;h_7hDNgGi_mNj!fMzX*zm9mTBh6imDRzIEYP#X-;1;P+K5cY!ZK~S$@0b}C*zPu7x8bDryEQxew%-rB5vTd+wJrZ7)yxNd zrRlBrvt2sRlfC!szFy|saA9qTs?VKj@2Hz%Z_#eMYIfPWD#pBWnF`haxNh^|XPv2s z4S!51uS_2MVk=#Do->i8YP{ z4{Y-tk3?G`hy+TGUfVh4tNbCF~0a@ur@^T-m z?pn4VbI#FF`b2hm`ts{IGvjsJV(!{9icK49a$%pr~uhpO=B1t~t^7MymZB8TA>{&=-R?^x?3KHiI zin%f@r0|?%c_l&Rua6K@qti@P!41ajhww&Da(rj0h#@ISbR(M&s=A&RcGd6Do0kFA zNY@ZztU!I-wY|afz~cQ{xvyzOsjYuI}xWWnWJVws5D-h5Hp~Wjqlq`hJj_#Kx7GQ!IsC}hLJH%KRoNDBzPjAV%vIt?dH!idrz z9^Fht#S@O*7IG!YlGll@kumOZ86;vj2)}rVv zRfvEt>Vm5IV2#yVfAHy}HNti_ zEM#+BqUcY*jC-j}v8J11e8rQ4QL@96ev}(>o6qI6k1XYg9JH|&BLyfPD?Yi zQK1ZV;L|ZwuQG)X3DT5|5_w`!^nu`;aVs9^eMAZ>k_o!=dSOrylPQKUZMH zP1=~C23c1KW$gF6!`sd z`tA*^%b5kLT7ZZuXj``RD+sLNcsFgDjYU786M3K&nhY zl?FLcj`Tf=4`m{z1t$R#0$?3Cpax@^5`oGg-fyBT$%keMpeha4;v`bI00l@W3wKkc zCk7FP9SLw(ke?10c%mG#(BV`{MIHNd)dg`xB$=^aCLaJOU@{S>#op&iH#wRPOHojQ zGeH+RPKFQ{?x)|H9(O+~EwC`{%xC!^w#fr)*~(3L$^y=h07w#HSt4%rHF&uLS*MNC z;sW|j2*Fp=yYhrO+w^=X*j^F7#HZoxxZz`8e7>j%Q}kVe3#_Nn5qHKRi}ZL~2AqHi z(Usb>R|Qc-6rLeRcUcQP&-2d0pdb#yngD#PM9FOiHl{;r`M7J+nN|KsRVF0DNd1!L5HMD9x8`|AKKHxE=i zfg>tmG66_t8JTgs^(wQgr4Z$7Gd=N9Ih)h&ZSoIsO%r&+AUC@GxO~D=+QmAUPY_H_ zBAo?Ua0f~=)dR(ZmuMb#c)*632#rHJbkHXtU6mvh#6~U!IfgM|9ge*SH}KiQuAuVl z@h`yF^y5$Y6ZVeMi1Ithnlxl%bFe1kaM@tQc5Z|@6ZT{5fhgy{2UuePqFYl)ny>tg+L-t!V)0#QQG za@dWG*dgph2j6~1U`a)OMB&DXeVX%yT11?i4v3|}wp~cQax^j!H5rI(3-DY^puo01 zq73JeM^WS`YtruG1v=#t(r1S1quE43(fw51yo8l)QpCZ-OgF(X$~E2h<0n)oXII;1 z5R}+uhDXTVIqJpmyz~g=Nx*3boxe2eQv0j)hD_Pbo%YO~DxZ)@C&6`%Tx`hEULiP* zG)Nkg!Dq)&uf#zOB=T1@Y|Tw@B7<)SoNNM4w&5M~@VIGlkn(N+QW-qzhm^g83!#v0 zxwsG-k`GjR5rzHmCLxw&dsQ-ZIl+&J^rPTh$%1kQj^lTSVu-@#66GrZ(uRUu;FgQ; zzJ8_LEtD0P?pi53py98Ba5XtVtj3k& z)XEWp1Av#UkTGGO#;dgVV_67iq%pnBfCh)_;?z@NkcOCWIut~&FbKdYe@nO;X>ff@ zS@q7cQQ6uy$Fk$OYUf|-!(vwZgKpT)THa{T*)U*5@wbrlzp+n8xTsTqiEDAVPDdrk zZkBN?*HL%B5{dlC;!LML!O>87CBc{uzMRWw-MBmVlh##%7HiJ(j<&j=xGi!n13ru^ zh?o#OHC#LGq2JExyK(!D>%sop_P?|j<_-~hNPxvIWQuN_huPhF<8`05x_;7fzn|yMFU)O1|aHZK(jQbT#CCd(ugtNYLl;>a@;O)ojr1AWBC3?p^k02J-dhB zH6lA(J4bDYmk+5#nIb#4OUD__78SMe5jx{*cVpM@&=9$Md#xJzOwmW-`a+AAkFu@b zS8hdp(&66QU3TftM*rrKlp^CBJ3Z?3PwU+GK2T}8uFWqQ&s*D8cA)8{nSn^2*v!Vp z&7aK1>&?6E8hh0Z&^q@Wk88Rot0BajQ*RVpkJuWwa(~)a%dfD}&5!i+Q?2wp9lhha zEu&3whAkhUHhFDU=izOzIJH*Cc<78_dY*Pzhq0-gZs=i)=OS&cex@N>dY)SMy_ED5 z5&Alxc05$qX`f}ay?K;!TkSB$LPkynEKnDo+^TX|S+Nm-tZ=F8^WlP{_5 z4>kAHz+X9RF8=A}TkV!g$gsL(=f$ z^&N*v{&m~LGr-h9?kOUouXM5%A#S#B$V|XJT)xp6TGR9SQ~$}8yDo5_&0%e_ zh#ELXdco`SqMI#~b^Us^8li{fi05C;TAMsoZz?5+D8x7*(0MHSz|J3&V+Bd=}jf=ww0+Nf_G*8u3N3n%K>q&C>> z?9*Rrv8gb`X-N6+v#8TKa=Y5!Mm?%!EZN3tZs6-m-9+rb)%~`GEcanz{#iv?pe6&xk(~LlDNL zJ7DqWuTY)zE%z>z9fM!(btIErg5NrxAPdc3Kd-h=G@#~}(mwHWl+=ZNBXh2s??@QZ z!A(y4ok_@<165m3kPV46ZOgqu%hoex2zLYAwOAL!RHV6+qxA(xd8Xr@I|nd_hs-zc zl_!wTyMwMRPN9mzrM7#mqQl(yQO>gEusjDkVrkyy|W4i zDZvec$Zc6x$d`ti#sB$jhj_sjX(alo1yu^XND zB_?l(Uziz0!UVfqX*w~h$;kFvJmIq=GL+4^S%C_*MxNesIXu1iNrqX>7hvIK6pm_5 zQ;BYXE4!r~hx*UFpMdB)ggt>uu6}k+DlUXwz6AxmlQPU>0n~Tk$0qL4FVP<90+Jz? zDqAQ@nUR~XqKa}8_O8>RUNYSLc!5oQ+W} zT#ib}nRsbHL9(k(Z9H{6gO$*=L)hUId{V^?4m?Gnozf)d{jL=Hu9pN3rueaPx6_13 zRW$4b4L?B>FZA*3idVXWlbcBFszlt`tF|{V$(ELs8J(bsNxd}{>qXQGIg#wlC*Z8! zCaZIkpIE`kG@(XaX2=~xAPMny=jXduJ@)CRI=Q;LW&rLJ%K-DrdWp2v)y02WDG?jr z68!91$Eg*Rk8B4c84xko>0O_9Epyjq+vdS_x;ANmnls!*Wu-oZv_+%`-#6h>(*Q_G z)rYt@nZCs^laNuGvPM{ANz$KDQr4BEE$8RzL$b^e(FG(aLQglB0pb#dU2GQVJa!LO z^?D4$G&Bt>D;cc+)w~=)he%@ZOd2K=jTueFp2mGNRu^^FAcbGkFpjhIg{j1<9vRqj z=JG=o(6V1Tgp?Uk1&fHY4Eu>x#SSDyl+By$;On@Vi@jQEnPlZwP9bFExp$kH7FTg# z@}!nndkUDmIq`!h$y9&LI9?Sduy*Vn`Bzp-__JzDD#?kygs$QkCEpITEpvhZBJwF) z6E}yG+QGN|)WkHb0n3br*|O7ojf_8A5m3r!m?BgqZ74}{YBmJahDgjLwzR$78d1?4 zO#xN)a~Z<7YfCI>STzhQRXUOkX{d5#ZfL-1uD)1}7S;B|OwVRDQ4QC7tkig4A`6VK zupwp0j}9t=Xs8QBiVt*cLdjDzHY%&q2NctVdf7CLkQ^D(=7XLYnP>H-@V?MaKUdP} znDK|c*fqg);Itg)8vx3LVQ85!OcP9_4|XZ0qXz}9W_vtW(P_g*j4mL9EDXZRq)=Ij zFff>i(c7+H2krjyPz5DaV}mCJmtKf;5BalF5_xXA#+J3pn z>D|X;?E>O8@Q(_XQNXIYB}f`>TxS2qWdNaxNy$;taM6-j}SQLZ0HX*(}S*#J&u<2 z>{f5$h4*T|i9gdl7-(YrD8-E)*6H_xm65kw28&=S*)<2mg%1rTniZP%; z)HeLyS8JyfhVH-k5lQ?)Igp}TL;rYFU6 z)TEh-Kfci<7PO?*Js&GL>qGo`$>vsV{gl9}b1d-+a+~%^ zmEDBckdY*8K!Vn~yC4-%r2mV!H;;z;@&CSO-m_X~2qF25C1fd;vNQIbAta%xWG|DD z-OLzkmLUmAQ^`(4DoHg-LYA?WY@bm=QVmIiVXpan@85Obzxz7Bb6>ynyRUOy=QwkY zKg@BCInH@MpRecR;Szhb7ZJt4=o;@+-vasWy2Y_nvv$ooUU62kAxJ+y`-j5x9lJL5 zM|tT9L-J{0B}?_OTd}yam_mll%TZ*Py$Cx-$KjT=7}PqMbSUcHqO;6PPTrwm<*4ab zz`g`3X&*jN9@%?#FYk_~k*B(1RM@>MApWVJbQq@hu<(-F&_S~U1(}x;Dw;oWsDGDS zJ+m#2bQ&*iG?4AX>pWGGK2l)eM#cGxu0;Qc%FvJ@sfA`0Y`3a zI0jk&GIfN0HXY^ZF*L2A)GJ}}nt`A?_MY z#<&XOYU2>D_yD4&1}GZRyJPM)#>rxd$om^^#a-@|NA3qZU9fKmlV4Q$*!NXQtfjwv zy$}-#&BGlk9ZBomMTLq5I)CGgq+u#2?Q(aA9Oge zN?EB}unTjwxia~?H8OwZ%-mva&&2)Q0Xk1EPwmaQ(b2K>mUrhbUcR;EvuNFP^~=iK zv2FYE${#jQSHEichd$})%0lE>JpXZJDpUT3^@-=-&WFcOZ~1Y$PQ3VaKRoe!{Aup| ziI-bn!jreRPJ<9$42TMWB$9xKs(QT=3LvEH<>HYxULCtC38`8MXM_X2UhkPFq#JY3 zpwqoNl~gWeIwhQysPcNF5pe0MFZZnUTRx?v@>0%)gmZEWUT+QOFXbivcS=b_eolhF zvMTRnk3&GjwOd?&HJg*Y$15YQHzb_b3_SVn)O^H^=iKw!=_mWnsa!7UPYBSdI@uo@ zaQWsmH$d<0$$`t2mv4Pf2sBzaIT$~G`Svz95R33;rl>^T5lIZPRP`RZ8W4GJ?{<)_ zjrTDB^y9u(Vz6VN_sGrp$SULQU|hQQ=slIF8mGh%_bTtPx`3!U-|Y~ux8Cm`Rz@{k zNDTE^@c!^@KI%c@b|@ZkYW%fIbW=`Zn7`_&kM9DaAKuyy3$i&iF;W@*s3Gw}Sm3G2 z$@%Cf&$llS(oao&R=M)DKk;H@)v4)k0au<)Z(odgdurxa<(22(6T=f0PW`<#f92)& zb~q8?!{R|yWB4c01d6K9tWaRg>%BXK3>%+MyQ*T|XeC|B4)poFXCdaT@y;b`y3d@F zYHW{FQbb{u&lior*mu4=5yfwP=8sgx_FqW4T(;n|V7L%Fn7DJ9hVWgqP>mbPNs6pc z_5JD)7&mfjC$ieccj`#hrsq+0E8W=x0 zy%XK~*7wKds`%;eNmtqze1FC-#Q(j$bA^HMW2dMl@NL2|ovMB-R|69gN16Oo&TsWv zl~JZIF19bw@7K+Rgau<>EHmA2?H>Q8!YMg!w94;yU0~ujUtZk!Tfg;(Rf*p(B*#xJ z`2Bgdz)Sp@$ctwoPIF$XCavToC(Nmy-gp<7^y?NcVbSLF=15i2?}p^W<-pThlM6|I zp7Rpf>8H7$Rg*XRlatn}PH%q;Ox~L2C2`)K-uYFPy!|~nnY(bBx3!SW+vd~Cgt1^b zETD;n7-6A~SeOqM9)?9EV3FBafikRMJyxh4E8K?_nZk-LV^LfzTG&iX&P-g>Y?qOl zgrk|HkC{}M+3o~0>1;EZGBeqFvpwx*a(!ldr_AJ+&Hmz=VT8>Ur8JLdVhKsE-Bj zSeS)wf`wkTg?^cZLA`}xyM#a_;Tlw@^`A%8+EnA)DTH%GQ&&XMy)wDimWbN;0ecs19Aj~>2!8$10I=IX_ zq~1ET-8!t#`ofg;#bxVot~Ei}=8~LEgr?19Bb!J^n<%8>Z%fhX{)x3+*nAs3_crtn@uC7Klaj~FlCV_@ zP1y*7XfbT7&UIQtdu;t*=X29#gTRtV;JS}pQCLq=7;q!ouB6Pas6GWtx4WrHDx2!T zGJDGB>~0J5W8&W1Yj$@>duZ);_qcYI61|muc9Lv6Gd|VX{jd(&E}x4?n(93)*CUG| z0k#k$2Bb;(U6ZCmi=4wFop+DI-nIBUJW6=?s2;JW+TmHdLwldY^C^cH%MLHO4vZGC zJDVud+PiNO@>+)?+e#K=r>Mj@?hk^zUhcIGBLPIB6$65!rT0%c_Rl#Ea2?~MorX1? zhNm3k*y%&={i8ZgALN{js?&GJ0Qxb&ahlUqegD){|8%|6^qLcIhTA`r08A}Au?it` zElz*?I8XQw%+>c#>cHj-Q*@C4rr5D=3W5nD1KK1Vw(~AqatFos@SKe#BgIO)KTfUx zx4+AXzY|B3jb;y_24 zyliHCD@33HC-i&JiN+MzCTr;tla&V*EgUgyh$s$(w1r4m4Ovk83gli}kCIieF2i9i z+(;MM2E_GppUb)#eq z1M(qk@OS&rSm)qI=aBqfclmwp*f&FaV5xR2ik9SvcA~pYj=SwGcbo6&hTTwyTTI92 zDNf(rmA|_mdNgboM3LgWt<^cKgM~=iLXbqhNi#)Ej|d4OiBy9Pj=px^PXFaND4W>t zw>{r}qKIUUt4-hb2ASU>}Z)4DpPsNhe`|1;~}^XmLf->Gb#G>+VqF?Xk1l zLt_%73jIUxD?a>|8{QoRJ@m%ye3YA3|FEi++y3d%u>SX2)D$huh&+;nUL~^*a#AC9dywRDXXKN>%86&BRL;D;&y-gK8RCdZi!N^(e7=bITClrs^d2AO zdc`qPlx^_`@nBJD5-%A^vF|1)OApE8C;*NmCQXtdc%Z5wCO8t7K+&uw$+A<>3`ZmW zal9?rp!l(w$qWH%I-QXDCwD<6=m_1OqlDrdSO4D3^P%ra~pr zU>F;^)G#FwNfrYVjUl~$ zo-PcV&aIdakw1A_%L$46`o;((sRp{I0@i6I%cv1eiXr>akp0ypO*Hrt91t%Ci)Dmh zh$-*Z5JniJNf0Sn59FdYrhx>+Iq4c~VoM`Qj19c$0}fV?iP zob+STpo8plN-u!I`4mlT3IqwRm~pO!lSQOKg4JLQ8!%h^hEXGFaO@>p2Oz~HUFox; zBUr&ftDi!PT zV#2$f$-DJH7C|7$3`iV95*bgCVpIC(A?`>@(*Q-qc1hlrEY=!Yu!Eo{{FGIrNP&QN zEhH>%SswWv08!jhNiJ%xSP%&qhkltpJ)WczTK>HV<{sw-J@JJIph+sN!lvlBOWUTTS>E(*+dN{VB$sjZesUS<%10SGX_n9 zhm*kQpXa3lGm^-VYVg6u&u_{gANGQI`yP;F7Q^3Mq|BHQX-?m|E5GSdQx5(Cnl6$u zatXQzQ)wPVFg68FB#EF?z}x5 z*}53@qEFkCB4!)HYk53w62p0TEc9{FiVXUvx-MSxLxjf5Z)kReMG$~m3>8O`-)n*Q zg+owYP-6t)P5aVn?yr;uC}%xIp0oPF>H~xi389juIK-n=N3C(l&=?Sbz1Wm{C3eBX z)OeKj*qLgXB2rA!LA%7RlVup=?iUudrAg2kyn-n)YafaA$akf0%oqvXGk(#)Dg_G) z%KiYH9Sr$3u-f(~`rrwVJu#fd6Cpu1Ff%Gaj1l#>XmHqH;0vnplG1%IUW8h-l65&? zU>qXIB1zZ=)~^9V9{}sXO@Bew$MqA**cJ1l&tj~UciF6uB4q5b(~`yDlLv|NEdM?V zOYiYEk88Q2j08;CkPoNlWY{VCqWrf5e&tZCtNF2lw+U`TrW$hnkMAwVRJ#ny{B4RZ z=saHD`_?j8U;A(I7#}?()Qsb6pS$x51&&c8VHZi6sL1MQmK_};Pjv)9A8cqu2^Oyx z!Oy9@xf(%iOb119_u;TbwnAryxT;%y(28PLwybW%^5Tk8H&xN5Kr?t%xwlaLM042J z)i0fx80^r!6Ax4dN_D@I+$xYRvPLm6WFWOlzTC<*_3#Dzk-(8Sw+*dT)wMSj);IN> z;?8`2b5-kR`FKo3Rp_`@1Y-w08T3wy9-)_i{c>PK&I4oC(SrCtZ?47v`BXH$%9~3q z<1?276u0&v(K;6te~S5k7D65hT33ici3K#xmrgK|@{g-ohXNk<&th>1TvI(|R%; zx24rOng)GRsDsF!Plkw4d<^vuRWcY4Q=EM zc(boD1XYS}7)#LVrOI5HL@B@Vl`fSJvWE{?#S^%Px)rV(9q!pTc?<#_o#nM2ey8>B zrd*#MnOvNFbTZ+{fd04kBZGRESG9%RgxRlEHSyAbz#evRvw4vAw$7-lgYnTZr9sx= zT#I1eDS}4$^zRR+LcgQ%E{?0viQu~D$0jd4+dejR>78*VaDKdj2w;flEI|qGNZN=y z!tdy8>YgOMPnmBk&G(w=?Zlwfu?IFj7aCsFpDPJ%)SoZl-2)cyTs1NHdjDpU!BS1# zfwsRO4E83-PZ*RgcoL20u(H0rF#P#^Yv-Byex#|<%9}l=T&uTx{%T+CH{= z*rUg91274_XFBZZc%Ct5_G}z8h9p~NqgpW!B0YYueLcG-(H&X zwzvLX_%7)764VwzgmBZrsA}q_0+k4F`a3w{&&%pd*5tC4ap;liS0WMA5NObAgsGmG z7@3Z_5af+;>MBVNgQvirvILK-y_OlKryXlQlkRO>B`b%ACIta#I~+t#yeY%lNRdA< z&mRDhP{Fn-0_8zudw+#A`*uaCht+Sia`TQDxr5V&X&I{O9Z-cj9Oiq{aYExbk_jCF>4kBqO2EdRVNYPQU<|reJn4qkzw7$^y!{k!1=CfRZvM@ET?Q|h=l;#*-b)iY-Tu3FVhiUNblDg2 zrpdLiZ-Xz4m7y+wW5Cz8HmeI9TM7jMY24@UYx^pGL36gORG_ThF!lVgyGvXz9VjgU zx;-h`RUx2r=S$(WyVobVXL`9qEv5yv?X&H|hr;u(5unO$ksHGpRCH6p%h~3V15y?1 zu13%+uhxZYH^Uh0-4D49S#WFz7x(zrZXsw84*Kd7H@x`i3VT_tVT;uQ)hQa&ZRNHs z@CigMFxr+6eJ&=ejKSd+HV;Jfu61>_^QRv0kowEdzG3ROHb)Q!^sVx?sXyKPiOlnu zzV*mqu1V4IfhMl{LvHCR*F+q;wYlM!RdKj+^KnOCMA!0show;Q)`dPUq;f;Q?i(Mn zvong~uRu)b9H3xJ@iF&s^A@~zOSXO!eq*b*udkz{UF9)X{vmgBK=g3!22i>sRm%}? z*of;`FsS7otKEq1TIR1Mx;iSvsWh*Pa|5-lKB8Fu2qWegCX&rkZfB2ov>p@1Lu(h& z=5ji%wDq;VPiuXcmPJZ{HneCFNo95~QtRo&`iVYw1ANP(PR2!sHf4(w7ImLi4qZtbpTQ5E@Ir+*=KqdS(5HU2Xe0c!btU8qVkSEYH4 zKN;Zzjinm@1>ohcMvAzK&1=UR*Q6TPqC4h*+JB?({uf9_?{0`YFv|Xe`H0RU`L69X z^?yGfQSXWIeE9F_yPmAJ=Ae;U-*^AT`N(CwET9ncZ}i=p!^ool-Spl64f7FiwG_aY zPv7-dLqg|^|3~`na0~>sHxjo{p0NHO(RcrY`N+RWM)ED9CY=orMLq9Ss>_*F03Sl+ zIAy&1OZB8ub&ZDBPf{q8>iMN_WlfJaztKYk9hU#0@78BVGO=%)nWAx_zV|%+Yn#wc zd%i!;{vG0KG$T&&Xg!wyP5iMKDSpZF65-o{Gbrf_s1?*m;(-m#S0e2xbnM*&tdLxk z>vP~$Rz3q|1-59EwnL;G7E+7E0*iRt{CyK5OFau z`0MDY(*f&J5U?u)BGk@yLGyyj4j6j~Nwk;;4PM{CLK5g`aWR{LbSQa`gn_x2UR>Pl zw0gybZkZvajhUD`&zJ}Zb|(*=I4SZ9TC=NS)yy0zR*Efm5H$Su@|8AvR$3u(7m8>5 z;NhCUncG9{z{>LK3bePlQO zPwC^{76*!6kRq{3bA*o&&kqMw$|@X%GA&;0TuK3i&5)?>2~z{sVaw5b#ATs7$LWvi zNOJdmdALc?;uSH8v{`UDy6Ca^Dlsm*!UKg>u%xSMOAFJ&g>W4PyvU4|SIL6NODkx$gF>oG0Tq4|>1x{7taO~nY- zh{^X+)a2mKY>AU*2tUwk^3dn2UK>QnQ`_!}mL<<4mgj7|A88oSdZX_i7P7|v>eds4 zYBZ25%+DU}Os?0+=jolZy?DQeG4CBt1_?1WDm3qz_tq5Wd$elqvn1?C zd%jx1RAhPBSq4)>_Pgc+cWfT8Z2L|Rtd=;e?5kN0vUNM_rj$NH3X znnh2aL-a@q(^1vc%fsCF@s}F|oi@)hWP0Pslyc!$fv+l~cnyBJ$8UkY+o5~sIy0*K zRmPjo*rXMAA1VKGTiWb~?#T_51hnDA52J2rNbe9$y8Z+&t4r&i2zZA277K_BU zlcs1i-Y-v?L*zcaEODQ(*Pe3aFcN^JiDzWI-v1eWz^^C2)ENs#8uq%EVHD50R__)P zP%M2uJAm<0V3;X##~@4Ah`^Pb zpxGc6v`bQ16qRw`T>kxN$EP`P&97oZ2kl2P&BBUGN4lkoN~xs^a}a%Df#uamtc0So zl7h5(Cz^PuOR+;iO&TPXRMdwEa&)=vi##vlFnOKl{v#w$T}QZXw7jqau=rzl-(65`QM*ftFu$T=Rm1nDJJq z1r-rjq z7_UfOrwciHXD*NWyam!eIK=6-Dkw+yNP&FC^RzkzHa3?(eZp#AHtcLg&W1f&FfM2~ z?7w&Jn!J7ZCsU6bomqdhkiBfN2XQb*7N=k4`R*TL2@(>wOa~S%l*@-5I{eFjP^zuV z-_!*k;eM7Vd9S|f?w~_>;Q>|NU$(u5;=$BsQ~ITI9zCa>f333ZKZ`VZ^k12|QIfpR zQ)%HT^X47loT|%4??3e2!S;DwK7BWS=NAq2e9^{bbNJ@YTD8mbr4xgj@1O1b zrsq9h4s_X?nA}-!9pqQ?gIhCOJAW9c7wmKw?x#IGPPfa8)frUMo%LtDZFb&E?t%+%bCS2i8GO0( zXOOqE#b=;P69GLU)Qbp@AtH;3f~`d1aiS=Ph~|gGdL#)il2i;yx|k%}N|GBV$#X~; zX|kdoS=o!M5<^xiCabrSHOI*ZIAm?7}}RrFzDsdKIU7x2F1xr}}YH@zQB$_0s&k(gI@A zf{N2ZTGPVD(=Kw-2-4{hdg+l~>CrLiF~#X|t?3El=}DY)qI3pXFN5NhkrtDYQJj(0 znvp%8k;~&`P^B{q^fC**GK*p|i;FW$TQkeXGs`)dH0i9ndRY}-S(Pza)x}x0ty%Ts zS&f`5y7bj%y{j!=S0Be*Z7sgq)_S#l{OSwNRfcqShhBE4S9VuSc6V`hZ)v4PlcYO!egn(lbB_Os6feILLaGUnS62me2J6! zQnC5cCHb;X^W{F~%WvdkWC|4Z3zSb5sKgeil@zEyEztZ}aA2cATjttf{cAcWuN{lM zrpGI}X7Kcy(Z_2h8`rQhh35K&mM06XV+(Cd3hkd3I({s4-YCS$TzAvI?tb#RXY6&a zlIz}2ulszw?zeFrFH>|@zsUb&Q9x`_P)X6vyWo&m888uy7)A(Z=JDB6N9Yh9@dglq zynHe*k%Cc*-NX<&D4v2ZLbT)X6~SV^J2baF|tJ_96-2fvfED}C4_njnzjNdt$|Zno=}vo0SR2CBR8lhmAJbqrFW?q zST;>md-JY#t>{7Td&lhW>GmQI%ic4xzh~Tb&)DD|cIn;`^$OFt3QL0utF{V9^?S}) z6-VtWmN2L#79^Yi&d`^C_z|H+0QoK5Hza^0m;lB;-H>?qCl&RRj{Hflyii*iE{OQS z5>3WdMSE9WE=5LYS6yzaN?58&h^r!dS5XYA)4Z!Q;;OSstFw7+)wvVZIi*Mg49b*R z!Wt@HCICkWpg;R7MR1juV=7gbDnn}T2G>@mfZ&gj>@wHJFUgY6q?daEdHsCxUl zMD@C<(yGgwh>6YWIl-DQagFn(jdLMYotu0vw0v<*qkPHiSlzKnFpfq-BbqE6c?ltC10t*~XfF@($7&c0k1t!oC zCLxcL83OV~_xBn##bvdnu~Cs(PXzWnU6{P?rO`lWL&koEh_X>fnVssTnE8JePGZ!O%MRaBRyEi zTox*oC=jKNp!)F9LcM`LRasbcZCzDVEhHBI;@YC0u0FpScCms%e(I2HzzAq;lok$BeNe$e2@W$+c^OCDp;QX8&CKz^zR2NLe= zVfL?=0nv1D8VHew2JOcUg0aXfhQJmU{2mSBGwjY$5tSM*973C2czxHu#@8~k?{@Zq z)L9@&JiM5S+=GUwGj1fJL74=Ak6Gi`SGv~$w|j4_+Jhr#qHGrUb{jPj1fVu+w&IXJ zB0#$Kd-wQKR4~ks{zk$ZGLTj5%O0_2-;kIFBp5(20qJq|0}lK~=DHmXaj&Mmd zq_GApgNE?YecG@;d-C@imCue1FwWD^CN{HPuR zk7nI@Tmxvb-YjF`Wf)j04dRIgH6?02&Yh!45G&iFp2>5w6bw zZeU^Q1OU&5H+}`%C;d%o0C+5j2j3#6jZka+{8Kw3 zaMOkp1^^F+fD8uijhh)0;!~Ht?jg*%Qy=gcbFF@VH~WGKpoI|70Q6O#H|t9vezqxC z0E|HgIgfHg=6DR`jPderOmPVsbZ%f=p3Vmq76CY@2n(UiMu|~DAR6Sh=xliHqa)9d zhIFtm9vZ6+Nx{Mr>Ek$1mm3}2H3e)4kKdMuNP^%J=t*D9+iW)CfcVYW!3FjC4Qng^C6GFX7@s}*v}0J<9!W->TJk43_2JK+nks>q&;Uq_-0%FVE@cq?BGiH z-sPj(GdtUGyKtC1aXFQ}s)`rz(tI$J1RfGyI!i<7$b;kw0MmE1#2X9(A;0;dk5ZdK z=pwIoA7AxVsu@6J3E+s6?*nnjK-Qh3ERZJwTrYD|W#?<8*5@08qQ|umaX6$m`i{^^ zNGKj|>U<~W0>ZEUwE-1;n)yeaF^Bp2Eqog(8V*0Z_vT4nJ2;*9MXJ2!CKc@0U(92I zHugf!g5atIBx(@oDudiEg_C*6rq9zNuBi~GFrQ`q@*ZbXuGwy)FRN87U_a(>Eih!U@TG3!qPXj_(%hKX!e!p zRU`R&^st+P@>P-0WeMXD+nM~M@+@@hkt1hQ57{7P$e({@$dw&F8T2$|w6`=rGk1K2 z`X&RU69lCjg5kuga=f)4+q?G<`+?#@+53FP*=IU4B@YHn{m&)0$J$d^-%^?c1buiq z_w4VOvnz-_N>yTV`#o67KI0A4j69-vg< z7pgbs{9i0J&*fY*nj1QTT5c|@u+tvpuI6D&`py;bmR4gf-Zs)dw3MFg%y}iM=$!vq zKu*vh@WH{N7-0AyLE?Xq+#WsrAujtu{)eCxsL>)lGVp}{Tx-OME5~|rPv}qOD~ajT zCy#zma`2XVw;+D#{ay#X{qGBWra#)`>hJpKnSZuw+d}jVssDga@J(p+?d9h0BM#wt z%O0Wv*DrPcwG_8~kA7~wz>)~9(Ej8>{`ZpGmD=Yl zA|IxLzm^+L`h5I7?9+Z_dpP`s@4(5)>yW?`;T@>m-0-&k3o>n%iYGcPPPH7vT8iw{ z5W{*m@#&YD7P}K8haGgcTP!v?s-q$S)zaS+&Q?XOTlF!2txw(_-P^lQH8aAFRnnCh z^XY1GGiNr>W`^_S=9Q!?Gm^il6#dblyD7-E32x*Y(T%cr_Uqlr39Ij1^r9N}j)N{t z?7oy7o%QVD+j7UnCohw@D=$rV?JPX`o4472kjUfnBn4tjc?wJ-&ycnw-O7Ndlj)B!h#tj;Uahe>lk^I%*Cm!4MLQ?=4P(P^nRBD&KJVSKecQnr$|WoN zD~QB)n=c*8kKo$K4RUO4t=$T)RruF17CW9xW3RzkLaMwwJ&qUM3h&JELF!M7-N*&n zmHy{7d^ha9y4;GY*8KNfh;{Ipcf0Ydun#Hu8U*Jm6?X{FYg?Uj#LGVP=$YHMF}~v1 zf!$TwUlDM$ff4J}p^Z5hKU69BsKzmj{G;SEw@jyB#yPU`_^ogLfrh6#MSmLqLZ^3= zAP3A-L7gmUFpgxnz2QQHyVD@kLPk9&Q>5@LkdQG$R8%|VuY^3>uKPh&T5+zDUDr}Y zXjqFY>>&t?&raDFZ08i`R%nu4#x{aN40@TV5ubtm|IA0?j+ea%y1y2Q6;8s`fczQY z?Y>~woH+Li70JUIzBLQO9N1}fkJ{t+Lp+>%-RlRA)OvmiIq`gROacb|mv0pc`k%RL z2q0z9<$v5YeRa~BA=L5qBT5N_ah}le2E^Tun_H;gR(nmC7tG_wI|)=#GWo+gyi=KT8F&*szYp%!!E@$WMbQks7A7qkFIvt_ipKl5 zm8JF4{9C)lAF~ZQum%@(nxOwnAXiY2DEH%O{>aY`5~ zN@rHSP!pxmDpqNDaV+#PyYj9j-~6gaE$r6mEHQdJsXus@#bhsj)LR?>q!H5vW|?fib1j|AjH0@a(>_(d;Yq{{Dl|EbJ(*7!=F^>u#5%YWs6 z`%gE_uY3Q&1`hMT`2O1edgJSm1`}-mj~d^WYBNFLyzIYkeE$Ik9&y7_|6jmB{Ac7` z)_<|_eYh}4v$*ktMOHe+{Ivjrdn32c0#TGZ{MoU1Pvyni4Fd8-RmD<;Qo9( zS>zaj4-EY8?wbF!Z`EsiZe;K-)jGt@WP`56ch^ME1(}pYF9ll_C8;k}3pI_nR995i zhTN~_`)jImU+{gaRb>Mq-!3n=Onfw0uD|^4!Tj%~PQq z&Am2PXHfv1gV?%JHQxB1@9n}4Pjcb%TG^721fLdBh+vE>LukK_BM!VC*XPqpQ3w@# zrqcP230Hg~=OZim@>t_Lon-imwQkCsWq)!a`{3Z65^mmZ{XBmyFaUNv&Ofi~(J@zs zX#FMti=nue%EnjSM^(YE`k6TenoZUU5_2$9$n*Tc@#9aX_uSVy84}!}_T}|kgX^ok zU+D@*dG>!y-?eFRE+#+h46be~pp4RkxtCjQk}glEnJr70aK60QTdsGuNwiR7p7!h5 z6YNb$z*Dmg_TJ5LDX|2Sa$L0GW9CguG8k`k0V<5&tv!C$ZsbLBDp zaFIJ&VfQEv`DB+d3FElWnL{({O?@TSMleuAGe$%Yo8&=B;r3fL>vG~9SL;yme}pZ3ubm( zABJB{7OPNF-H^5}^^Y$6H+Rj&!y<8f1jQM(eH@5ee@GK)2(odQ7%p9JsdoA|cg^}E zdQL-Fpu^+@Z({v%Yk$MVEAJ*}HrM~`}2RfYaC`)OaHVlIz5Q{ z@NQ(K!;x{>+YR*krC;C1~J>$I5&TYyLbo?wk$?4J?;Gbjn zeU{(iyv2$(Q_~&i6!&a&+d4NF+~}KAG2H0Eabnn@ znjyGPg<0AZmX?e&!wiWsTk16P;?U3u$i(C8@!II~>4xuS(io;_A~E1xKtD;k`#|^i zi?63<|K(f#iTRN{%17L}JuKxZut~@S*02@Fw44CdTf_((5L5WR)l2DyWf%kE$SYkF zLaxj1Sr@eq!Btk85tTc)kLR+{V|Nj)i%~%VPr)&I2T(_(i9&}loLBv2gqS@vA$vW_ z-er2mKaH=AX~tgBhil38`1w6I(uL*Gr2V#7IOK-SD^tHbP3_searAWgt^@1M>D$Za zbu*07Dd~?cSFu8+ID0Dy5KT)Apclg!dvpL*?s7stg#+0o>bl-B`I+xqZJ!iqj^QhE z4dqNZyDYJ(NbF6)<8Eq9}GG zZ4O`Its#OFcqOcvO9^aWc^3kBcLi?y>kI^F-);OU#WbO15`vD5v5_g?K^Y(`zV1Gg z-0=q$T7`Q3M=bph>Qxm{Ml2e#67$;=JyVpp8WOnR~g8o~$o zSnz)qgm8HRIY|^dYlGN$0*}U`BI$^8HmGQ}XedbBygE*PD3wPTyJF?O-u84JFg8XbmjCKl-2}ttY6^ZN= z9y-~=Hu;PViVvxE!9Z{fFk}e4XEs@b3g$O08d%i5aj-rUj6jPYV!|PpK(ui&{^nsP zEing^JRKPGlL0-1y$EN*F*pQ-6b}I-9b&{r=A(=V5I08B_djAE(#2LWFwh?oza%cy zOYTrjc=abug9(;mLoKL~lT0KVn`Vu5TOjH0X+#=fg;dk9-sRL0+MiIku1QCP1Qid5Co6~0fp)T>oQ=< zD^Mdgia-^!#HE9K&}(=;~fw~?m=17IO;h{V{=&KDJ&MtAqL8H3Glx6Z2Ucmyol0}A~+9#3i zm1$Y{Yxh*6Lm2{=4A^8eL^ZacCRi+18>Wj7;9y_|)J$CrA*o8NrsVQRFL9lkt62;2 zWNPXK2ECpu#1Ijo zxQM^R5aA`_l7P=Z%}^u0%(Ih=4+p zR8w?3sQf$@MZ}~jtcXU_;pbU*q-Oz}5}1oBQV)*~;&)f-XfP=3TxMM5iRhxBqR<86 z`C_q5bVB}O{6z$^D?M$GYjh%=EKd@Fw;{>YTlxlQQ#MN60KJcP4~>OJ(G#l|;`1{r zs#R$QUMaOzae1oIuvd3Qn-H0pioK=L@+2gW8R;RL2^)e$>YSnF-6nG z#O$GqS9xMNdh-{yT7jS1HHF?aMfNq>hafx_=tP`!Zpb+|9MTvB<|}`~7|_eq+RF@h zoxN~vZ*83cLTI(-nDtE_2oA?W`GT7E-nwTKb&R&U+)F@~S)G0wD3FcXO|S2ps2_*} zi-H?QGIxLPy7)e>VOa(JehHo3wtHGIjDrsUtsRaeftD&Sev59rDhU2t{lb?gQBTg- z^R#QBW)E^^s}^f7Ky4E95f8Qu8i-9%I;s#j27LVE6{P9|kl}7%Pn484pIZY;rN;Bx z=!rx0f&C~OCLpE_g3zuEzm1jpw)@hP%OouH3gUto8)Qt6RWxi)5R28t#LG_t_c3-& z+8WY^HiW}Cs3;Zu;^QTK2kFV8GP>?{1Kk$Xe_Fwi%DA8GgauZq7T+H+|xD! zLV3#~BD=Pk22XnjSy>lC{;a z#x-kNUtC(cJ-8lr?SXICCZOV`$mdCoa_74(m7K!jp0C_)dNVUK#ZP#$v$JSZT=Tns zE8hRbR|@A$axIg~a$mBn3i`*n+{Q`H8dGDCe~7=yWo>hzAr%9Uu_(VX$ClN$QcV8M z`U?-gy!gf~Ynyt|zc@U(eD53IO5jNB;Vf=!@t?K58$PGz)i{M@uWWPgmKPs;!d?CG z{oVZLu@3IaFZPvpzX4o^xnJbppQcp8vYR`ZCT9}{m;>wE+_PC_l*&%sx+TGyEqct`>6RYi^@9*W?LLOS_dS6B71%$5vK0T4Y}`!YwCI+v>{yq%@i# zt1E>g>|zsh&8i8Wj;HqKa`rPe<5_CW#86|20eyyE4fqVe+D?&nXf*~2*USj|^REZcb!_vLAS*2*)b0|Gm^d~q^qX<KPrRqpYfm|EV?L|C&VQ^F___(bF_e%rcp^xPMAi*4w?j zc@}q(qJ8=a+b*-V?-3L@ws%vP`Hq0UlvrG7EhX5#F~9F|KK6(6-bGz#`2XbYh7E4} z-*sxuhyq-Gn zh~;n9ud;G`y|GSds@z`=>bDe;&;XOTpTRLILv+;FsJ&`DA}!oiRXW5DHf+5SAN1tS zTTR_PhK!tSM z_$`lfc%eEzdA8jIg|gj5{qm^HyV~9BGpPWE%XEtQ^4(y`>-Q{L)XwhYzRk8>A2#Z2 zN$RZb-~1)FjZ@-V;uY$C{Bc)%g;|Z6Q@J15@G{IauD-nV;&ks`~88BS1H%kh@gV;>7mc8!cl8U~uet1;Jf?8GZA;1a54Nde4t?`oQns@f#y7!B z&4F&)k_)T)&ft>oS130)``+n%gly;Dz=WeQO4oRtQHSG5s-IWVqLR2>jeW#19%NXM zFH+p{<=cp&{ujhZD3|t9uv+iM&Z4h?R5u?^DhS@$D){N!Jm0U+db6v77c;=j?oJDR z4f^o$3jAW~d-f@!9=fD*lM$t` zJM?YkT|dd=P*J5@H7p?jdAjkE6@{%Cke3xQV31Yv9m5r+W(-0 z6I+e7C*$JW=uxlyyoEUQn*v5;>}D>olMSh|Aq^okOM(@tfIb7(VFLzKKo9Mi@v#6O z)FENjgv8wxmX!#>@qi;FmH`0B(uvE?r7NBT*7HH+9-u>K8L*-CJV1|+B`;?IB@fC3-C1WLaFTb{7yz^=a8Se9L*#5U3{hi1 zZfwZP1&8Wzc9Kq~Qn1(Rpo4tqq%L+H32V%ORXEry`|x>zP&ym%Parz;@e&3o%fv^} zForzr^)^U@8=S3J@ z1D2BEbwbR33M`Y3^YTY4Gj!| zqPN#9ST~HgP#_6R<-le<;5@okL&j+eft4IciUDizaQ3VK14iseSu zCVpP3^u0|6FglE#PKFP0VOJOH4B##E;4nP3SAu&0JwaFJLp zu!MbAlT@HbzO{}FISb*aL@?$Z5MNZd8!bokZlWu+dJH5p5kO@&U)RBKe3~j5dxQg= zV%$ui6{!k|ccpKI8{k9vMOI|eIx^<%{8jx3e!~pyVC2i+o>?Le!uFUMs=tT8}g=iX z_IPx{X_5!Pd@O2hS|UuxO93**fbbsDnFAbTLpoI8gbec(ziw3^e2N1mur2`%xN{I$ z&wvAHcsM6wr7Lkg4SyJ4;wi~Pq!^Gr2Ml07X=#B_ymndfi z{DD<;wQN6U+c4)DWa&^O^(A6a==-*wAmZYK__YV|%nvuSX8@K3LbiuQ&5ozv2w}`@gq!^w79)CeE3Y)w6ZL$u+j+2kyZho4f$#0@H3(Scj1kgvz!$vFe zM=PsFt9nMczeisykJT8B)twq^2pfBsN+>4)X(R~$=Qs#<<=)sw!AV$yLCUqh6sb`F z92Nc;1&DltpqD@#3=@zkq&`o<5JAwdEKv9;_)Ga`U%o&@_&GrMIif6>7yO(G`#EGJ z1b+%9Qc2$kp!6%jqSH7}A#l+5N{%7q$(EU8%XqSgE5gSWu8*&59$#@`TwxbURWiOh zZG4WgSnbt>_P23z_{2)$iPe&E-ER}?(nu?srM6$61Q+A*$|^Q1Oz-Mqk1_ey z!19YE+!o%{{-5yv>vs6m=O(*+E@T(m?y|;LO`lMi(xgrw-F0GM=uFCY`PFTqnJ;%D^^}w6ESIq~=1S-V&lhtukt(y%KWAcyv$5A_<6q52 zJ)BKxo{f{tW~j`?oL;>9mGZ~uvAdX6>&RFUGUKdj?>?K|gIeo&b8;bb>~C^2a>RT; zAEE|EjgnpTYW}#_>Ar^RcIz;@3~Yk^!ZQ{5w0q#SU2fIQ^0N%=Au=}Vd2zkU%<1JP z8s^0=UZRV;ezoqB_k8uMbE(SAmjj+(Uy1lCzuo>4_e+Qv%s)=UM2M!Lq|4rxU@Z1}Z-^@Xi-TG5S84+pZcvd|sm*f-N!s!Er< z;F1|}JBOH%kZ_12G`rUEy?)Qw*oec+=|@k?0^iMF?iHg;%`g^ckkgf3+N^dNeUDat z+Je~BJ6ka)ZmqD&_`FaMi~sOTObX!H-1utRCf*%Up_^P&G$j5@EH3}HV3OE+q)r^u zh8F53r<*q{%Nkbn*PB; z2i}zZWqfjaQO&d^mYkgHL$2ZWhqU9%GVE0PtEeXZ7>mz2-E%?%+37TDb10nBw83Dfn1kfrux= z9>U#3i>y=LugB0jD=vQuyor7kgEyy8c7S39lp~-t0o`cE-9$g4h@lb13PDvaYCF1d22f|1HPZ7_HNv+Pu|2HC@ z|F>(IeQ8wOx_;Ik`E&j0=6|bY?lQ)=R$n?|lh6i(=?>qsPWYh^fsTrJ{`0lWo5{NW zo`@$Ft!3WMvQR<)tS+vG3v)-b9JfD_Xf3v}(_MSt7C*#{lzk{F>L`(0B^R-~Y~F1w zqSDAIQf~3u<4dF^twCc?V2cGJxZTe3$FuGN7n?Gf5h_UVO*qQ~^ zDJ8{v)|2D3CmPmX`5Q#gE*txMh)_J)v}0y$vYCo(nBwhGI6w8#T;su1iZ_qWK8qj!4d8VP>Xns76DRY~Q>}xPtF~N$ry1iQAZG)-7L^><^ z_F9d7Z!L~ZWMuzyEi-815?khurrExChjJ$}3$5;G*}i>e^Pi|?-gy3I)raJQ{QPwv z+>TA=b~G0JS3-o8!aW)m9}|yF-BkQ{Awt}gmFuDCTrdGrwUN%uvZ+}$M}`*5Q}H?A zkdnufVav(!w4GuI(T|6iEoT~5(3yZdx0>WUqEfIVqfn7ty+oNG7u@|u_7ry1_D$E( zN4b}a9e=sme{^emTJTxcbLXhtFJ9Xt2e>5Q&izx9?`(HztIK-%oU=r0nbp6cTstm$ z{kIZ$qln3G)h>2AGeX!cej}sUpuIn?<NC zejPm2{`}+15}!xMzm6T7dC@a1SS4V`BD2h`(Q@(bQTld@c~rDKgY4{AJw4x4RyBPY z3Y}IZ{+_>51>iVFxbAPimvp>BbcNwaB_G~W&Lx^MqBLaAAjh*`FDaqK$~6*xzk36& zHIF*G^U|rveyCuVQZZP0UB&bi$)^AVszLXT=q)D86XIM|L9}I1we=;3&JJ>G756#=)Jzoz3C6Qg*PCs|m4!7jN|BrtF8IJ$gYO zQ&Xqdf!%3goCrw3(Q-k8l-ZKg2 z$aL4#2XD`0_v6x0$XYT6l`1PeTeZh0d}rUOs%kj`IbumB6*R*e%flSJ7AJzJ$A2Rk z+VoJc9r%p{8@LK4{9g6us8zaI-rZ(jCw&>eYu$x`!;c7kzh@kkz1qW!6#R{5!Xn9l znGoy2gj^V*AQ`zxaZDKu+!}kapp6*90G%1$BbN!oTm~Dv++;e!oD90LolUmwA!_)p zzDu-a1Dni1Cjeovana}%HUN9Du%Q}6Z!$7PC%Cf$rqmD<3Vt0QvLz!MMHdIy#9f7_ z2e`O+g_sF0Vo1i%tI@@GPDhoUKHhLTffF>qfkyaI)N;a{|LI+>{%C^sC#__|M>rTW zHatZ^9}GU+KnT{Sn-q8j`Gt4HVqR*H{-kwu`(e6Yn&ix3tt&XR!^NO@?tMa>V1z4~ z5#_1qBj5%;xRnMXLd-@!VVw}o7qPY+j1mb5`Le zA~cLDmw*PUCFYO}J5-JyX9nO_(lK(v#M5NhmX;((h0uBB>IRI95M#l@?qk480B$)6 zwBSHns7YPf7!x7JnuXgh1Y{_@I}kNnlAiWgH(d5#X-Q8L$YfrC8kR{cx~ zC5kBrp^6Y93zve2tjX|R8aT(q>c?QoXyCmMf%yokuE%j<2_;iNXK2TsYtF<8(8!#H zm8g5f1jI{N1Uov6r2)mh-ir2$EJgdTS&=5uo`t68f000h1@32o8%ZfT4D9$2^u7V4 zvVqkcG!B9e08vg1aJ>+=MAtpIfVR!K5H3bSf@B!rellh+17y&z!T_?4hS|fGW!t_l5xCwxqgg_h%JV^#mqh(<-_7Fc|IR{z-Akq>pun9mm@}T3x5RC^C zd9deOn8Jr#Dfs#!c*a`cii6V$igb7xA0tbHa@yh(wkxJ~ zp6?T}4W}4+aUN0e5uQv~F9+wu1$MLX=NS2VO#Dt7hQ^1-w_~Mw@aY7+2`^uJ#{CBg z&)~b=oMn%jhunKSmMwLKZ42qV_d9VxzfLWk58MGWhc2R++!=N4+bKN}G ziVE-H!l)qeJQ;&_WOws%a{zq79Pw7XC1C>>q#&3D*t=zIC_*^^Hjz*GHJlVv;JCQM zX^L`Hk$e$U&Bl*lq~EbsB$^>#bVE`*L!OnT*Jrs5uwfn6J$d@6IWES6f)_uBOlX)T zEU>K|UP}h0Ss+Y?2S~T}bG?(w2oa>LlU%@_2W{X0ApM#Q9ko*+`)RkYsSc zz=zk7bJ244yRQ6AWSsqc0;L011K`j8xZ^a?i35i6aSV2p41g>l1J+$Iqw5mP0r=-0 zywQU7*tozsj2_8%hpE2@kA)3lOBEF!;})_DaA;$D=jX$#74PkW{S_=+_d7dH(J)q2 z$bydSran~TL2nXnt589~QIu#zuja$=mxC8c;O2SE1QQuWYqj=K(L5-O3m91-GH6Ns zC>4Ao4GNgIh@&45R`D>!$R;;Q4viGc4t6lEU?z)VE`E)z{N0V=qu<= zDh*bmA|suCYE;1IAloNQysJmS}-l?F^IAYI_o=@kyje z!Ov74bYp?BEFyzlAxFwIXJ)`G%zi%M9OIP{yGTb1_MqKgg64i|@Oe5R&m7z`cixkf zX+^mNjN!aE7y$rJFp7CvPeu%|)T=K9!=UA&+tHlM8m7o5A?EA+12i&q{{n4agxGPi z&PzS>9w}ME!s(WS%1JP(@!1byNTF%G*C-2@TbS5Yvy5pEzb`w~Z6)I#Af9p1BY_PK z7=!`KlfVEr+)$2jL|+}tFmfzRw>fq>6>Gu41#lBr^6K<}fSd)43l;j<5QaJk&Dizt z8wemDcbZF3W!Hi9y5$lYCan8bVr7^f1^uo2t8xKE2rOq{_wjIBSeTt$T$C7V?}2%0 zjvcne*s|)5Fdz>h_L4TB!Np?fzzWJu?78rGk?*E9qRjHDIEyl63ZM)C$uZb%eB`j& zVWV2BY|Z$?gJ&7t#J!qGBqtz#Fp7USX5w-jlI1u_{_yLwXIdOmG!q5YmC`z5BNR>> zmlGzw2P7ysPLYuiZoqsk;=zxa=i&nRQQcz>f$`0eEWGh-^e)AqDGFVp{lS|Tw2p-{ zXO-_g7hLD;bIK+@Ht5(k5`g8QIUu0SvR})wBUhA#eyRG!#*P8|&HFF98obJqgIH>;l-5(47oK-6;=qDi}-%_r8^OHUM`RlhE3jEzRJ_|ef zFLvtUO}mKo6nxW5)&e#`kv7$H>@z3jr!;hY%k z1pu>xMHr;xqG%jMu-pqtU)`JTZrok4${2oxfO3kD`6Y=RjZfi^inAMH)) zu+u7_ZcP4+QJM{YfLYbVk@ZBew;^cdLlkJx2-!BX^WX?-53C z8;zD)kDAd&ABK%SXc~Q1GV#3RDU%aYNuo)beH{7N=3{G%sV-7a2p`0@EdX^#Bz zYo@tvc4vV_4RoT2Py8nM!B-aa8wmz<{;-3=Q-Yx;fuKqt>=BIU{G9qNm<|*CCjI=Y zw7emWE5J?b^n0Kq3xrV-ZfwmDM>NMJnvXYy{jje#v?qY$h(=D6N<_9z+6G zK15b*99LEum)kY5{MGm}$++6}2{CC{<8pf9r7$k{s)g!Kc-a|Yirn(#T005PE=g_}Rynq)dg{gvPM@=IZU2#+ zX}k0@z0N;-KreQV8so&bW71y^X~>6MtzDLJHenqix_Dqlq4WH;teK!!Gg;XdDYFqO z0fcGG**X4{_s^BV#Dp-(vP*JYAA0q9$?W!z+0j_MG%N4D?Oay)TuKgZtq`sseAPHJ zXQev7nF8DRUZ?R(>7UOH{$qi|A5yRp{*8%Sb#-oe{7_I(U~03tU_xBhHj{IO z^<#9jd0zZ@R%~`-s%SH8?GUotulNQNcP8;U_vYG-E~W9w>H2{a-K*&yzGy5c~3E0YeN&gsFz*eZ1ym5@(l#*Cqr*`4$tYtbu93tvfIR{OTppJ!1<@5EB9(}XR06f ziQjcj>gp)@Wxp=9hT{s}R?mrl{t`c_Y4u2cXykl5_F+d=zqsipY#vzA`+5%{=EngY zn36stsDx*xr`f$?qa9n}jQO?k{h-^FN>qzX{=D7o(GAzcGc8&h0&7qW#qP`=Mc2wR zoT9hsoAdfDuEyq<1en@ESa93egxpq?hW$qB1$u$SJ<|T5f(t!;)UE{1SRs4^Li~N?t;aT+4Ov zu4!{+O0OV$bJ$!Fd)YHC8t=Dt^SJ%oo>?B3Pi1%WJeE*JypAz8SG|||n#FDEXk^<_ zjh?Z?dieBS_MV$H?^-yUpYc6(=^jo)+_p@uA}Wtpi9!UQa$dF*7ljBFA|5*u9qk&@ z^&68;<}LG}_6#+GiDEEP>|HtrCQhMTz^~#D3z(QdAL$<$=m#UGz|^UMfiW-^eQ*kw zI@Q(H+SS#Fas)6|j7$8(4w{-8QE<@IRO45Heu5a~1z_qQWPq{*T%!0NCI#k;bsYZ< zQt%<$sqpX54fY#2{t-C*3n}omk+pnQ{11}?L*2yzYyX)P$d>L?Y$-f^|I~;77Rvs8 z`9u|SRN&z1D{2Pq{xvB`SO)J1;78;#>edbB`LvxIycRHU??0>T|KFs*ZRB2ILD2|x z%ae+c`;Sv3wKn%lUc0S#KYQYK^|?higlWab=jaC&mGqgl4;oevaQAM|e!;uS)$KQ4 zbY{=hv8T=UmP@5A6@yz!k2$ROjC@VFZL0V^a)qFLu^Xe9x}%b_r?9Kk{b#sa_x+#D zNx^?e3jY4w!1tOlyS72owhpr=pPv2@IbWbX=~!j5XOz0Fx%i^Pv|wzD^G=EO-;;s| z$9UFep$e^sY&R%;wsH9?-*(LZ$N!K5O{*Kywhgc4D}*tWIg)q`>xF zOIF3y9ZJeQD;JATxm{BQ`XBCD`@j2?KR4?{uqw)y8 z$Ua^=F7WnlC7|#%zC$%tlaE2q^P`TuKXk;OA0fTmoC>1id>tlLdYO3y2vTfH3*QuD z6oFkj^aw@aEnHYUSCPbqmbY%x9?3?OZ?gbXF&SQ}NCnL~m{lhLjH|x3U8^d72il{J zYoNMd7Bhh{ReYeLne5hu%P*u&q?VU^fRz-Syo5=W@#L>xZZ|6D%f%2PS&>TGBsi@9 z6K=7-v8)dl?D5;HBv7m&Qz;Qr9(>qz7LjE!BEu=|&rhr?TC$8DhiRb0+lN3~E5uIFhY`K;l>RS#=j=C<5zJK$fq%H#V*IRu+l&D-V zREDpjM>jqvQH|Qv&9Anb!yO(xgY)C8SvAax+m*KhtFLLSOs;xow8!I!fBYJiEzU)$ zugY`I`HPP1KFF?`(ou z#E`6GA>K$tiQP$c_?VKq^_IpjSBnG3S}tcjDOe>tZ21$jCRKpk*(;k6HgrRUg`ZZQ z|46LC&u7fl+%0z5?`|(yb3J*se(mq{*sVZayMzXtI);uOTWNS5@-kUT;CgWRIk)Ol zb&cK|quU+5r16GlOF65E8cxT*bQwjLm3{qj;p#&7Um{W2=M;h8i!a?{v3lj-t_eIH zuYUQV?qB(S|M@oI($ra**H|A)EMrJj31>E2y|hUfwNZ>4#GBPj171<+hB8J6As%935r-yJsc&bpe{zjl{dt!)V-^~#Q3R}NKq#46WL@*<_Q z3Rpn}@C@dfRb~eaTCS8#-P!VW*aATeZxW`LtqC2myi)%;O^0~LedmZBV%T2xd+MR% zuTdMb;FdS3(|0XHf6&dwJ3jPGFXoVOhGr=b&OfNL4>rbOm{GgB^3rsFI^K)EFsUbf zy{|glQMe_n^6K8?+2w}H<8+RE^#Q9GqFaH+!(XwhhT_PUP2oHL9Re2)w zz|Mj78|S+2pPHJBkCG)(({{(l{;W0iTQN5ry{X}ra9>Z{;ke3>@1x~&N35%+eDgwv z4ol`gH5-Y_9)=FrKVRq`{4JTecj5bR+_#1R`kSQ$?T}_bW!5!w8Y4_k4WaC6u#)ro z9aAh(P3n-C4jl1%7H<7C958p>BF~gEXBw+BkJK@bio&JhnNR>z1|LDRV`A~lrHY}; z3Ykp`E=TJK9#lv~KOyjU*HSc_7)0t(G33*TC7MyKdd!s_Oq05BLuaQQ@ll3ZQ3mqS z#EvK&K3cvZYKdL6$xxKiP{TwU>p+%|?geWAYl}@?Aswu7v6~gb(P&&H5)a z)e{(0$eItwxGryTj&a^Y?Bm4zC5$W_iZCq*F_(+7{2anij5ISn`$jR!Ocb*BPDlto zaRJSV?VR??M>p9r(`Q3lTmw8vfENj{poLwqOXr?MNwn~2W8x0I zBzHLNcmOor9{cu6^4?m)H}pSMCNj(?VgS5)ThgAkkY3tZ0UZawCA8|J9mgn=eOUjH zOZ(mMS=%Fvw?{8e2w&i&tIUNslL_K-V&7#naRmgNbqA< zW-cTSAt~i&kE^=`sfHvp5W_D6Si1eFo$0ai_>}VKWr|J~WGI+pBZZzi0H6mIqsIaF zUM5;UJ+i85B^DZDYkmRPD}w$`0BwkWiVOepo*~j_FZvd&? zR79E^?BSGD-aycgjZ=6_*vtowNpR?8WPp#Xp`hJK*c_ciW%}^R#05I;SUq8a0+RVi zv>L>u5P2~OYRf-dpEg3mItyjb4H6j)hY7ZCsK_@7LEv>nb;$thW9Lz44pALP=;a+< z+vzgQJ^C9U=yHitv}4i?$aY_bhA96a@A@~o&#Sq7)9ff`O@dkn!N)Wwc;>=!J1GS+ zLZ&#GVKa>bFZucbx)kst6=TZ3_{N2fDlJmtqeES<`TJvbF>p&+Hp{s%mWAM17-=T5 znMs5wfHcZ2*g!BHN@rmdX@CL=a%BS+EEa=`)h0=ySV@ZP-sBm1x5#BrT2f&WSk62mkL@J^u1sK? zgbAGDAPy|_6ak!~V{`!!^$zO@vCr>7=6q0r2C31pvV0tRqCsTddDos8NCR|fpaK=J zr2w{HFlxXpX(1GThq#xAjCMg-8iZaD)Eq_I$IjbmupdO2%qX2=YvfIluueIr0F`Hwhr}u-hnQiku zk)Z1a_?x*3Ci^nw`B6GC&N zpgZI06zln7!#M0a+_oI#(mGPhvzSp@MZxG#sszsu|mT-HO`5p^jEXTAqB3D+g?zzk{d=Lz%1hAJ;;`YT_gh; z@`}kM07fnMG|--cK$7HYh4L%ubI-|2=WpJ}ul1-XT!~mvNM52;p=}a*1)-=j>gufQ z7#qN{Fdh`}FcTvda=cl{0RZ239MYlTn*dmz0z=gIWIln+sf)P-5AHi{%z(apd1=dd z)n!=qArYDqqTs}T)UxhLa^3H}bqX|K`uJ%&rTPdRca(-bD744yz*+OLlbrfPY%b;t zSB--ceL;4zPZ&@zYdDpPd1)IhA8qC0m1QdGp2gfARrkCJD!({Oi+vsP@$J)qB-O4< zN^j$KXAzbGFrI$r%6sBg3K&L$9kg)JM1$A5Ug_%d9n~+3;YC@9i5ZqbyLX%e^)c{b9+Cv$ zwK>p+G5A>yzFC_{{c(DCD8?nP&S~tVJr|d9=cOxhTfLk8Yh!+>s;~*FB0LwXu4G-&G1bElV&XG?Z3WQ7zoSeybk}L=-Nx&EVJIk3k z8)oM+4ziw4Jj8%bGO&hPw%u1jboxSkKFfoC_tOTfE)%D@4mv`@u4h120Dc(<@4W8L z#u6l4oVn4#-{Ja_(TtY0Ot@V84iaKqH@j zjc_kSTz)NSCV)voqyadP`dvaHBnTs=XG>+X`|;B4s@;T@?m!|LRA!)X3Q}ZZmeHK- zo7$f#zFA}!`>w+|YB2nsYfwRZx~x8NlJ9KpnX*~TOj5{-yBnx$6CmIdX|=<@`Gf^d zM&ckbwLOqu@?&vUXTWwRcd6**a{(5VQwP{KXt#w-ev=&#ZanZjTk9<%MB?csI6g*> zf$Sk++_|#9SxzB8cws-{t>e>_?a#h6Kk}vBc~eJJbIywuyV9)!epr9MEa2qsvpF(J zPF*&fp)X&wG{@kA6DQ&`gHsbGAK_g zWzdfh?Rv&ZH*a+R+^(6@YR+DfJ)N$}9DVC(ekwW4JeFlA!fS>e)MV0)n2YDq_Z&?< zoz41Gp8vgs@SA#NprLKv$|;hUc%IX*+UT*11ra&Wo%OIk3!5QuT#{>TDJAv3eypJ* zM1MAW-fZr(f2d{r7}i{5<(fD!lyFrgVM%9%$6VA^*RPw0qiYoBjAIe>7_UcOSYHrd z&wgpoK;*bk1gmzYL++vcK4GB;mV@c$r#D=8R7^`9i}685LZQ`L^QjdkA8oK&Jcd9!!z&eU@0_ z_CusrYpk=Iy&T`fZdo?FyYO1eof}6h_ALL&eP!s#HJ|nB zh1WiJJ$qkCQhz~ozWcfF&w;OBW-jonV~860a(9+$Air`SjqzL&7z&?@)8~E&o$S^XLffOS3C!*9=3&o%P3?A6AJ2$HXgt=7+b? z`T-3$%cQMAgng-LTU+$iUT+OLQ=%`krIoRpU^pe*P1?Q8YtJKE2G%#Y-gtL$kdWn%Syd?GX-j~n!Nt$h})$-`hA%ftqn$>Oj_@l97|LVtJ^04 zOxg~@*Ni{f$I&DvxTBdgQw6!LA59mh9HH%z+j(TMxt!YVkNXvBTMzrJ{?SU?zw^V^ zLx+veF1toOd~*8m5!uVzKKSLu-!;CKrL|Q3a_>Q@?WfPD>^rdJ_-c`z)1{++_Rd!? z7v1ryJ99ftciz>d%dhzC?Jkc;Kcdn-UVP5_a^aP%?QypU`)9hmK2M8IcvbtBoe21R z{%+T~FQl1MK7Dttbo+nC>UaA$U$Z$CuzVj&W%Jd|B9$+84&_$Cc|Z2IvrXJP98wKM zvyQCYO|o49OOorGFP;DJ#woLY``q^|d!5ejnWvrS1~O0jbvj)--(x?Ra~>NsblK&1 z;6Uy{Yntn>w6?(E8-2zGZjzj9e*2u9_Pq)E-^%{teSL$Z*yRJ0tj8a0igZi&qqBf_ zT6JG|lz%I^DtPqSbKTFEpVZI)sOSv4_oHl1ci}?WK`=yUv`E9y^L3}u33pCk&Fo+A zwzP*_Y%;888UKs2->3Dk?MdI}|t zra50~O=QEHQ1N7Yc=+#E1sWJY^9*bgU;S&|p9-tfA{N1mEl6ypz6=L#G1IXd0*qzC zVh$+iW9;zUN9Zs(EqV>A?B5%oLC#}iR9(3Q8CMgA}RqPd+WZ7qC~``C!s+Dg1wYvjhVYK)Vc8 z$!q_)Su#m#+V7C7<@@}>g!oMHSj^Q|#-_I0*DFZb=by5G2_D_gO_1)cj*4lqU%xmt zBXfE3C}@%gBa7CAwJZ&86IQ{Mo%08uiJ=uIwz-!=;nTl(xR3MVr0V%Qz2eh(ZJRTO zt5R@hnb$5n99OM`V3h&)}@M+E{PuTNVI(L!w5A)04Mqa}@6=G>uZeCvA>!wzneDU~{$RwkYm_GCBpMa<|YwlF+lMlQ` zza}v*VeXW7X8-U)Ra3u6EWYtstR6WA#|@X%wW60!f?s04S7W+~H4X)>0p%l;f6VeT zz5RcoV*0lB)+H?T(gr1z;-J?vExblBqaQWP`@I%>SB!~fdADyTH*m&G348Xa*EnQN zHSnn@EX?Ea>ZaHY99DcQ&(m#fRbl0rDOH9{Zk*!fomksD)MyYw6--g-JbqhKL%upy zn#GIlrJ7W*yS%9r;-R*#25+~1)a|ZaL~Tl@XSWRrTIsj*h8kF0K`&V})Ho(&dlviw zkS(0bJOR7Tls?qo?aiHySLgD2Yu3s;wRAKH*xaroT<>G-yeH(|SzcXhX2BGX*ZRcZ zgyKl=P}ef1AD6dwhZD+8^@D_Lx7+d+Tov#viPRGDValq8JiI ziGLVm>J-W*+gch&2KrF|iDJb+^fC31GQO>?2IZID&-zgSIWjQT*4BukO1~=fi%fwT zVlZP0mmzLL@0w7qS@n;S$R%qR$#3|#NaRj?V{+q-zaJ03>=twD?{1bB`J^BGzZwt! zf9__f1+6rqzRKC-c)gLKzuhc7Q;&c*)zJDgtaOL_FRA0axal;Tzp3Q^Yi^d3&ePYS zD*5{NI5jV=%sW?{wcLX9Qa|!!ZWYY0zI$Nn+Uh+^c1Wrt?`mRin95od6^&jrf`Skc0TDGQ0wQ8mx{9Gl2Saax%=Vl+cg;C-)}1+J=H9t8|ME9kdnH-# z^S$r0V+4-=fOM9Mvy)iDiH3Wp4@`c#)1Expm_69=e>zKYbzH2zAPP=qLu<{e{@L&u zTJ}T{HE~_~qvY8CLn1xDrbZ-BWZ2q+>E?t|8ZO_QQW5 zi9~o&$_1f@iinCMH%1)|WcTEbQxgvKOQ!~vpIH^m1EdkaD8)ywTI41itKD+!MRt#J z505FWkDUB&rvngNC%$|-1{s)F4rWqu)mswP5h=B$yb-pN8>PqQ7BKX1`rBDC*h;j7 ziFvfxG71aWaxuzWcgN3Ft=Or1XmcJ_rI(zrVd{=jIBmqfv5P<@cd1&=nW2}vFfffQ zX3sDp8M50;9gyp^Or~5PFTqfh7$X7I0g4$&98r?7Df=2)T9X;Q8krDsfX$@~1*v)f zzs!An5Vqz;6MFfo9%KM_iJq{I+WI_ndQ@5{K>bOP!*nbq1irbsvPAtfWXbXLRHCEB zk?FN1{HD+kN51Kkqd96c>{`ly4T0&&+9l|i)Ojoht zRFv$shobWHiLE|IvyWVRM}IoF$93piR?GJ4jfPt;y_Y67R@lB*BRt;aEPUWUp{r@S z={(D)Lt0goxn`VecKDhyLH${Eotc+J`n?}KlhyG!ty{%z1&g`ClXK2n%bL)x)i36*DEiLO+%+@rV9 z1iROC?L5+1+J674GQltQ-k0m~eh+;B%{(Eg7tY(Vu9UO7p zv)IvUs#E%G$>ZEMrH+Q2(z5HjJzX|@?`Z3+HPm8tMoxvKT@>uq9ikt5&yiOzpW$k# zPo((r?-4$?BycCy1ko~;`~}_eD!E2MtVS50XjA@n6=6I^M%YcL)veiVW`)bJh`xtAT^ za#An!YKV_A^wgTy5mbVzwrq+|tRIHsOjsJ~lwW3F+F#E+AI=uIn1yxih#-V#@=24f z_jOgO(3Di;--%DR>?_Vm^rBWvPGrn?n;i=JD(9$bW+UY5b;7R?pw;)vha{@qFFk(Y9IR5fwsJYQ(DfHk>qzmw3;{q5rhmB7gQv zq8J&ayz@}GsPy>espL~D#v=dVf3~L998VxKFmhy%&wT-AWrV|VgmH3^SE~;;!RL`nM9M5arlq+cM%E& z#8YHD(%~>DiqOLiMV~%4K=+sN2_9zoz70Gxz=tMgy zutt{)$^EA`@KGX`tqKQ(0n{Qu=ydk^X?patW{_FJ@gW@#IG&)xfzSf1IoWf&=(&e- zCT4>m{6l>7ZZp4qtsxPuq@UElpS+74InyyY;&>q3ML`{>xXPp*%MO5tS)q!Y^VV7< znEhQwD^g&uw+}{9ang0dz8Kz<`@l&3ncLQr&jZT zpKLpAo|FUa6imk5c<6VGNwCN`d$Rnz>2u;S20?HgcTk5AjGz!6KxRUs>uw)(P!~9m zE(JAD!y2tQP6-O4=MpdD0%2X!&}zIkAB>^fi+$K<;u?#83R<&I!6=j-%^IQ+uv;!x z?1T>sFsf9P++j&o0Y;OI0cetkX|{MB6hsFP!`5gNRzt)?#q5B8a-dbPyXqaM4|(yV zK`;Nc-rkvvU_6RYMjU5D5nPm$00puj6)sAJg=PZaDL(2H9bM&&rc(hr9ZUxRRXV5% zWcV_WyZ$She2g9&HDR7A1AufGgP@dF01jdtK#`t0qPsvZI&3gailN|d4S-HOTq+rlOf#8ttTWaT zmH?bC|Kv&@Y444A_qzCQeloQ7!Z|8xGZ%Y|&YEWuk$pHzK1PN~Z#s^#pn_;JA)Jg? zCfgvYf@sExXfl=|BD+Ft6q+X$O(y)L5H*=Z9ZISm3rc@vwZy;#^HF(Qsb2lmh0>ex z65_yVE@nL|Lz#=x?qD5c;FW=!s(iL4hk)kX)!;$?=71F?73LE?e?u6itquU}6A;() zk(w;g9*ItQxWi03HQ}OXE)m~O3g?3wY?KTOD@DEM7<=Qv07+Lsyp$mwA<9Cn;@WFb z5Pd6%p&TdWQYTP}u^u>cDvO97Py_>3F-WM06cSz_QmlKcWu zh6OXJpon!>#J4x$!`M)mZVJORQnolK!^C>j-@H4-ydRRjBZ%?H0;=YN>ioyji>SnX zz}tsu7Bu`>GF}P*jA=L(9!?i8F%+5uoupxuske~9WHYi@t2vy?M~w%;>RghEPP(&_FI$fA z;ReH(jnZe}mIQz_4Lks&YOGIH z2XG<)H8+nLqhib$&^ab}fe&_yJ6m(We*Q}{R<`F_c0p?lZawK%-Sf=%C^rfe%mi0b z@XzG#$XLJ?q6`NW6iCcJinxU@aA7wl20ZL4R&~pgkJ4h7Y4b2TToic$bsENkTkOzj zcr+6#*a5q;Y?EG+UR``DWfZEEPdvs#%g{hi9uBE??n97-IHb-)uVP)b;jHd9U*0Bf|MLaB(A-0`n z-%SVS*{GKJi>I<`o_q(wna{d;U@(jgf1Fciaebo%s71YzlTd)zoRLAqZVE64n@owCIrk8t@g#> z$4@BE5CQpQY?{XyErq0c!fM^|>jA-U&0wn?gzL3Qzivj#S*A<;kZLTi$5RSFkfH5x ztRD`IC!ZLn;V#o~zHqZ*5Ft9xW0)G#Lum~L@W*J?k&mOUUW=NeVyu6j-M)h`Ol~?Z ze|f~#?RsFYhPhv*F!SWDbGLQzmgMKVPnwpjy(3W-y24pzj2*QmAn$mtQ(zCAyl{*O;kl5r0N+Q)b|cMT1}>0_mSoo98K*xyBsw%W%>x92 z2W$J~)NU&^`Sd-YCctNBP@w@n&|w2xc}BbVVEP04rF?ej`augp zUzAAW;qdwJ_rJ(@c4+bs9F*31e&(bUNqy#*h(%mZaNqvGZ~hhk*($#L;a(B{L|6gr zsoRCK!QyG+Q9NQd3%`zvR?$YMaBv~i?!4Lywl|5xLAk%IkMa^cbyB>J%P}fELR#Yq zVg1#~vi>7LCZM)mh**#PNy_*v%1f&&6pI7;Nwe6=i9tV7kvqhD>ze1!n}`tRSFT zt#LI9fFzvl%tik}YQ>Cfn0(>aO3%QQ(SeoGKfFA90!NE-M#Bup+DZu)47`(I;7Tj; zD(mjk8P|uU=QFT>6d#^G(C2zEN^9PXrJ_p!kd27Z=270bu$i<~k&G-Vz+HNu#RCLH`s zFg`SW=+w07?P<%RX@@t{W}Bx>eoZ^QnWFERau!Xy?3p=3oIWI)I{bO&L?k|zhgwf3 z7|{E~27`y1Cil@Wu?*rh!K^C{zzTq^ED-UcAZH%xRD3LTYL-8pK$D~&norv^f9>|X zvG@Eb@A=F(^EX6u>A&WEQ|D7v=N%b%@D85Amr60Y&7cz`xxh3_a*#$WyS-TcW^s_c z_~O@MB~kclk8m0mBG!@0+rrmH!iH1Ax1WU{ixz7mgEzehL|DVn=2T6iN8{t}fD;gq2VO17y{ z>MB<&md>>Cx{MP^Ypm|ue(BzqtgyqYx9v-h8B1+n%IXted-tcWJ6?FU{p)Yb%q^QP z$+Y596fWrbk2PKVmi;-$AhNI8%{1-so&6UzF^|(-jy^mTygn=I>f>+s&8}PAIed1ihjUC>7KiVfU1*&ZKLx7}ytPvTltLt)@}PuKfE zxs)t};r*Roa|2iDO@+>l|NfkN>eq6(aDGqHiq=me(K0Yqv?r@#9g7Rdtmbh61xTVQ zLQ)4i0d8T?IkLNdEEp1PYk35tBn6q<*27~ZU=ME z=e`M$9C>=%EJSkaTb1`8p59b`KfmR}nkuI&bzb!3t+f$#7hyBi#r%nSFZHlqqoud9 z7Y=OwxP9`#_HV1VZPfYhH+k^CB#~#29yDB>nmj~BukfSomGCq_Br=gX?uVex9aD$R zHLm#`vDol@>d1j@&3;F%c1=$mr5UgIXY%mrC zlm50&Njne{xww&Hn{~y1=7j6LYXNrGI`7Zec|2A9=Dk^uxbThGw z9wpzbZa(xoDLCO--jlKD0xEz3UX_zAi{0L%or~UF^z9ww|2Azy|D|n3fHI&55x|5C zL7|;LJCEM$=Wq%Ori93u%^};;XF;8zvcr%}WS=y;&GPPA08x^tRY9C%g&MEzkG`Xvfs1u$6`yQlBdye(<|eK*QWFar5CHQ7fkL>CY81!hUiJ& zMugF6OG0~Nxyg^}RW5zYem~0_6P6xbk6w^Z3pqb zeQo|d>uiPV6)fcU2z8Pg>Khxx9|}E7{-8r=j%OI!oBz`D?ionwc0e zy;4bWO2j5F+?^B7EG@RQG$Gy}zo+BajK$KLCf~x_sv+>wJfpZ*FfoF#H3aqe zm(N0%MmoEHOpJ~6_RWnA^!mLO`n{g&8|w3_5q9?UP0UOq{k5^FxsHw>0WU_n`$oRj zS0ijq`!SVWVvxtn=8yFXdZ!ScCZ5i-kT&n6GLyRv*vTA|3N`}4821et_|yg#movrl zx{};jQ;s07u?cEh4VOKZ?YeRGz|aq*Rp%;gu1H?JJT=$QlqndQGtjJKjAi!@H8eF< z=4B4F@!H0Cl@_{T`VoS?4)P0#$EdpQ{MR21H3IEk=9qxJH;kI+8tba-;T524l9S19 z(+`1Te^&uZM}~%a5xq5n z-2z^ZEH6xTv@{^-6~Sl-jvE>p>1b&}cp8`?T$m9eO-Y2mAv6-{2_oceY-r>k2_8b~ zy1PffjH$-@hJS1C@7zbqzu5a*b@9wU>;2ubqyLlM-{pT(?@z&)3BM@*{V{W!duPLo ze?r^#w~|~no)5Qj&V0-{__B2Ld-;Xo&QCAP{`}&`NT^y>mXG(;UEOf1vGT=aKkuI9 zZL3!m)5C4g+B^77Yv%EzC3XH?;^zNM+y2Qy;8mLGx(AM%@af!iTjzOeiG!~Hc_DCj z2pyn>s5EPZgjhsQqJ zG3w!?gESMYndGp?`S%&e-tGA^bN}6*C%X~ahQ@vzjfamVQP)u77KY1KJfzaFm}85B z=LehYk{0{^l1=f2Us*6@>ruY+pp$kj5bdHoF}%`?Y+KkD5|V$~Nfh(G(d zvuE{%z3cl6u6;7ZZL$+T^27WY&%)VfbkDl8%&Bi#Mr`eZ6I9RV?^fJrO*cEdEWOZ5 z*O>8dJ4@6FXm?%o5BQ(95csmtO7v{zPrMCt>v(D|YtuyPp$!I;JhRP9Q%yGBOVe#G zMN2b30{<+{@)I^M&-GsSUY;MwEm~d}Df_d$D5%{m5>B;xiekbWJZ^6m*9^b4r zmwze*0IMb*prNX_ILRbANj&s4`O`;?x{{pYMk-m7UEut4Tl=TR-x8|?Q4$6lt!m1$E9dn*UvwR{pBe9XE~;O7ps#$BLkHVF%J0~wo`EO!ud6<#WN2)k8+f-1 z>c$r4^%ODZa4H+W#{1*%E7$(C2>3#4^hriad2@w9?<_n2bl$7%-Mu-a)+a?!I{UKM z|4&H&u1-XZ`?~*mQTU{#WAu-}H~sjreH~pVFO;C9dU&|#X(Op{MEZ$06vV9Ecv?&Y zF%DTFV}aRSc#Sq?DeO~2lZ{T2sm5<*yf_#4CDRG1@04A2%?vAi8h%;z62SRrDzcE{ zJBNsy`<|wTZtPW)o3Gt%Rh*V|pjSg9_=Aa;FDpj*w}$2X2b-0?SMw#$`Qjn;0Zt-F zCnxS|Le~Y7Yvme*m>sz%M4zVT_GX9waMmq5(dcV6nbn`{vh&+~qZf8NyLqH%*VK!~ z^QKd`hJE^UL}##-zXvFK=X-u=(Zxu%#&&~7_8q>8rMH*;a`zn^Ivl#t^Z)^GhhGto z=5{o59zI!R@H0jtn=O^D>1=BJG3HrFU$H2!WN$|r5of~1_|VM^(m#y^ZCq^UIqU4o zdNSf_{Jp)krnL0-PYiX$eNS~cKH&|jk-)4q=8IH<_K15iVt0mh5ff^w(1n87ZNgt-pUbPI8hzsA z9J;|bb5$P&(P6#DU*CxC`)TAbTfUc|iP4;xXFDAQ(W38ts9N1mxYr&zG0Hu9vt^A5 z%ahrn$^qP=g)dQ!Q}A3%FhrNYxH=YDO2}}m3^k( z746py19EQv96g`#@^kxZpIesMP@jBlQ^E&vT_O7U-7osa%xwt z!nu-~DIj82ioz=)0$0AL8+tF?tF zZ1Hr-z3{aKb%+brS$por5q&szBQ&hD%Y|*_p%ZI;Znt9Jak!Yi;~fng|he z>8W@a)PfgTOz{CAq#y3)VVwk+DawVHJN?L9^eO?kjRJ}U;9dcs4Iq0gh|Q0|fB`I?kPg&2LVUU<1c^Cs;Qjk$TP=*b7QZf#6p~F-UJ2q-J z74SsZS}RtGjswZbhcT_x0csKsKhzIzx_$DLGPU>n#_}Kmm~W;sWH^JxI~}kzQ0?IzbGKcNBh>H1K(pd zQ^3F%C=nOh#YBm-0b>EA0b?i}paG8&2*6P;bc%v(6(WBcP~r%_O@rU)Q;?k!6)_*fUE31lZyPz=G6hH<*uVUl&u<|L)TT&Kic}0w(J{V*Hgw*G1 z)Ds{wVQtpk4GXA5!Cg-PGeyHX@-YY~dYp*T8;X+yhd6e$vb7H5E}f?M(H0U8z9!1pwtebk;wT53&%j6C82oE#!?Vq=Wt z_opk!G|myBHu$V1Ow7+;rACmkgt>z^Uar4^uL_yKhxXZE&oR&d6OW<;Qaogw5>OVP z!UTX374wsNrqB(ne1Xwo-tpw*%JT@TIoQoGCXt6teSvabboE}i>OJ_31Z0m=fe{Ak zbjD$EHY%ajd#}FVY{*slr;*|NJyP9#Qx!1VH~@)`Gi2Jl{aAMCEN9zzsmvXe+Ed&{ z7Hr=^Qc${N=@tO&WNdH)&x@!M$i5pu#(Hs4{YbHlj@rowweScZg*-2%tj8mB2ACi% zD4K$eTY)jA666J#J?yws?C7zNpge$4WJ3ZjqE-T|xZs9$Kr}OLi=OA_(&rYf#7iG4 zR~UI5W@GGNjOPc)l7X5i#ge!;HP=2!Dk(KSjr-~1?}D+Rk+Nu7ga>Zy2{~LC8w=0@ z6)F<_L&IdODUX0`NTCEMBG0|D9DA>4_1>m!^GrM@e^N+5`G&cg{Rz|CCH zfD!+=GJbDDRX;XCLeBSEt2aKkYR~l;LJ(=e&chJEdS83{YOeO#@MVMj52nRl>HE|j z_)_;rKJ{K*(A5GgidwA3BL3nN%qj^n3_?!j!*eu-5A&mNWrXx>)Cb%5XY)MMZM>HH z0@BScV_jmVl!?eKa{5fB6}912Db`Q`kQgWe<4TI|{)k$*@rV4^t2H*y5dmjBi*X9v8a#Q}hV@d5uUbLNPbo6bBMG zIVwWd9YH};S6r5=ofeU!S_&DR(BglJmabT;E0kElsTJtbEb17FFP zC1)9!od9-H-%r=Gh57QUPr?N+97D||k&6rT;i8TBKs-Cf>XrYh_lMt_V=h|&+Zb0g z6Pn^Fia|*8%)q0dj6fj++T?E?eSg7%CZkKijhl=VfH)^)tYe-%>*k z>R^pZlK9YCCQiTY+blNrZANKkI&p!9zkM2aE67`{lweE7ft=V91J4n%%~m?VN6stg zkPQQaqM~jt0oA*IHf{234*yxb|}+!tMOmp5Rw=e0w3yv3DZ>kG)#zPhG5 z_jTM!NTLIP0GcM_B_j9|on2iV96o}t62VtD>?SXFX*hP{wecF--AaV+4UXMgA`p`e z+8Gw>WXC9{wPrWr$9T8|K6Z%OYg$Oym(pvJ)4SiR*Hl~LfK@LoqW4H=uSLXfL@;FL z_1m)Zx83sZ6IQ?JW4}-5^d9Z(b~ZNj9$RdO8yuO6!S3Nh}9>je^P)| zdjd*v#pii{&3du`fEMxlkzqh@ri3?z$TB3RboR3h2d^v-q^b;Ncnw~6985JFysFL_#IypB9}&b(weXfOxzgrWNFID80K(=BjJTMwrp&;%n;9w82(Ke zsVW?P*Ew9OJ@PT-WDO!A${BgzIfAH&8m&g_Uk~#LqpemW-kGUp^kNLo2qE zic5k4FW%VL^4MtSmv%O|o(VLwK@|Wni?Q*lAAuL zI=PQHZS{HT@SjQTJySc2hK5 zQZOh>0i=+gJ#U5&%topL;ey#H;%rRhTy*4|*P*%i&vRb4=i(8~(670e&Dc(dPM1HV zrLf3ss8Z>dyq*~8u6z1&_Rz?cT-w+D8lil3;C-426Y&w6BO8pRhUJ9b) zgV@C1Pl&ynmwUbO=YK5?eqI{>wbaSO537ng*)tQHMPr9Vlb@HzibV58%f$q^yJJbi zmiM>!w?g~ue-~{lKKnYXyZVDnt7%{PP2F>2mF-7!b+e742+b#sW$WGDAGdxw*iY-| z9rL(u<$$y2|*;zE;;nM&Z47duR|5|C7#u)X_4ZRp=+r2cV@5mx zi%EZu(6&80#%>#YT+O#%FPjL~dVJh5`(tOCa-Ndhm%p^lCY@LxH2i$l5m&Y(@ej1k za9%rk_*Arnj_s~x#*bNgyi$O??lM+o?)0S%rSheon_Gg;q#XZPj`aRk-nh>M{sDXa zx92V&0Lp;zU+h&_^hAn4+!6bUeK*I~*AFCHHO&i!U&JaZDo=!EwLT+S+t{o$pd;$5 z%~ywE)5PpP;p-Wpok#N7$AheP;ogLLv@Hj5U0uJC9#%P%@_N>{L%1cV0`Xp%n3$|S z%P#shdm|9K{dKWuN@$h!cjnAAeEN`DzetY#J|GkZKb;kGD?`u~ ze@VD9V~%=jEHN?mCU>H_xy8D8q_1zl+4(FcOK5(jp}n)UcYF~OG>FKs5P#O!yU?YK z>WTM|0I^?T9h{ubBJ!-2h?wc(2(xbCK+aTGPY*VE{?gq_FlAw8Sty>oh|LhTd~2ww zsqX(XQuDe%JbeMYw19w{nS})e(|m1g5R0E3o0{+J6Cy-x0s%S;i-@oZ;c~W){OFX` zg)_Wf#BwFA#civ$2teT1oUUe~d>FN`iC3UV599JEiR>IhZUeV^tTB_v6ExP;$vcpf z>)9$5T>cMUK}uq@BGtfyiuAqeJE^@3ys#ENLY=yQ@TnWkQ@-+Sd)WxXn#!iKT$VbuO${tfo8;%SM^B!6dNh46*jSZ+or}ED-k4jDaE0)gTFq9UH>&* zrI*W_;z_2kTi!O*zZK+s<&9-?tsVV(YkCVyk_Xz_^dD3CO>HVnc40w7A-6osk?j1q z8Ub@NjlBrl>g?=AT4)IW>g@c1*sqWx+F$Qg{1igC5LniS(6PVZ40$nv5HSRqArK95 zW+6ljVPuFZ3&CE99t!{fya*79DVuZHRWW#(^$vBMJMR);4U25^r+42c$!|OVqweXw z+ElXfCFT9a_di_KI{Mh*L-7O4*p0T8|AH9HV*8mG?7pk(Pu7<_`j$((XK~Bo`T8a_ zuHgL7`sewrMf7)<@Stk!}d_?x3W9>g$jhDe)*H1udZTV zAX4R?D10#ee?yG*ZZziegEyWdd)DO^&I~(&+_CApn{g#W8yum4rVSpN>}6$cH!Q6lIT1uT{p}xEnqj_`qoSCYm;P@*%Uv-6f)t+KI>sLZP z+VMdYx})N{ByY#&W1H$u{L#OzXu>52|IT;lqrq>*1GFvLhW9AbTi@0E#+a?bD|d{8 zwQtW6EmkEetGlhT!xiP!OaU%BKm9mu`wR?uBC_`B%6>-9vc=sM$l&k!vB{tJm zL~?3Pd7vu$5b$}GL<;YiE7|GwP~g+Qw&@;v@6sxnOkpaOEt`hnAM46pX$38(((fqSZAdI^SSvkCASy^mIT(JSs!W6U(FKYA)Z zJJ?3W>B95cq-9*LjQVeVPL!BN<{z;jXqUIWQ9K2;Vr+^057ZAum#_9mF zH8&PtZv31ZUsAcxv1b3~-n`JDXlfp;7$`7mcZ(=byIwG~`v4$r%0Np`u{;&3sQ^rg z#zX3YjE2(!bg+Mc%cgiA`!Mxc-7>=+Ke5zGE{Z(oohfxNU~7(p+Wt87D$_~dh&{^n zTYn||{0yTu;O|H*wbknJDX5lhcZxLYJ?0&yXH2;W!s(e`@u|-T+VuDI2T} z+x>AOpf*(MiD~Fg6RZiJS~dAJ(EuP1LkcizJB*{V0#7pt8Vsy4H*!0ShPMPw z?UU|$2-Z`XeKqIe=+J5o$N(5LroWYZIF^ReqJYQ9-pyuifmK*7u8bEhP<;IS;ZovO z#9l%HN>~^%GD8UnG6fJ4<3ysNgtJ70IT!&sQFM}$05-A>lMWz}1J1-DIW3G16@UjQ z=*w7NjsBAa5%z>E4|m$dbcMMbfo-dYipHv)3($#J;9+F=;952)&k&bo6B%5z1_ifZ zVyz6@WY)pgnoq5Wa(g=Ca%470`VP2oHg=&2N2h|Dna~D+fu-6e>Ec}IfG!Si4xp`= zK2tiTEiQ6s@O3=NMY(VNMT9|yOO4!AJ=VLZ43!8=qOg@rnvcTUsHxp@4vqt-bM zt!NtdTyYD=oQ~Q-Ls}uIyL?byfRkooi30FA1%Hz6BAqLJVduGbHenSac~bOTs*WiJ zv83!J<2Gz*GVW2EJZWHp3D9}yV@U*JN>xIZlBH4HBL1vn$;>vilR zKJCQ*6^b*00DERC^d;?ZpNAO>7s&xo0&F-F=fb@)L?g~1T`4AXlI+f}l|hxKe$(|{ zPV_%ULH00F6fQQ}%|isBP52mfDzX8Y<##se_Tg*x?6Wu9E}!ILchYe)$i5vtBWZwe z#g(W?$@+y4rOl9*1b$M7qxog$_fp*_Y1c6#SE6Mr)_{v8yucA)44I059eh}R5O?|g zWvl))Uj`(>!Hfy8>-hwI7Ur@57sw&Z(9li$1Gl3hw&Hw(_xpsCbNV#luL-UQV_SJ1 zs+=dnA&18p#8f7Z%=4>$;c~(3u0Mbtnqv=P0jG5t&TedTj>{gS(*X~_aPq}9M!p~_ zT>TtzkctP@#L#L!CU*Cw*Fr~VfIiPPmU~y9oH5MANz+ls$+G)c7<(phMS}FAtoKB7 zaC|!IvcG&}IlO8CFA`uy02pu_@>+Pvu!9t6Xk;YOn}2U({arj8eVYsHV4=JgWIO@z z6pgr^MVO^|sTrm15>?!zSD5~3S9F5$_AE?sGh!fy;%SmX?xUO#++`jFaDe$>qCFFr z@E8R6D0vT;$#A{iY06y^`pV*f5q$LXzNq=;&0*IpFhgcYZ{TSjwC)iJhDhfwB3da@- z1zAr{2(b3BYnPt%8QiHeHfB5p>!PQJCV9A67$3pGcykEDOaeZMz!PA2OwKS1an*6| zgLRKyvIDkH* z#C*8Kp2ndsK6g?oJ-e&aa#yLVed)Qy5~q(PW}(jp+4hAG+TLblnkknO=e*Z(u(#amF>G(9+6)j_OYC`SRT3IMT-54%e!6#y)4_A|3Lrcoxlg) zvv64~ix3VI2Vvqv%L<>HgfJfNd1=KsgZS_xF4x}usnW~bn-ve;D;_A7y|jP%X4lJd zrAn@S<(rSVw-S|)@}HTM+u7!N^ORn(H@xEIyM0r7)sXb6>E^4Z@2@%+U-3l}ui8I4 zY0sQX8i?&z@=n4#^*(g7lFzZ-={n$k#<3$yFXQzg*Ed&pz8QM?Ce7|Opv?81h+T5O zp0e-;OqQ8U^8YI5n`-fzkj>o}^~QyY!LnVy^}|=SstkSJxRAjWbc_P`l+uqpvC5$2`_`9&cEj+@3a`@`b@HJuYb<*C4BYr|2VFN$i+Sd1! zT-4SB@6I~Nj3FlgbC5dMRsZq1kMa_$VN{Z4?S)Ed*^B zZfvwc-MTM!pIrbicI*ZkN}c2SdFLGs8gz&W`H_KjEY{uwA2jcr*&qoT6nJi7p-kC# zT>z{s4dcPV`N3EP_T5JX^>df}(O+Ea@gT?n^=BayTDsXf;MoZe3b#g6vSGW=Yo|c$ zb~3P;9D=#Q6tR3`1lJ|Zy_yQR!ht*&2G*1fnE)U5ANTlJ)*wsueB;o#>GYXN2B^pf zA}-buI1pJ7GqX{4Dilkj11rzpK{(`XamZU}I^b{7Koa z=|ef+zv!c`UETOqhg3c7@l|_E&3Y->jX%Fik>LOKjr>0>QvD4J_d=3j!j~@%n}aLl z!`QB1dpxaV zBi`)ZWL_K=x$I`&zONI<3oW0sz1@%aZR(y`(2g7qcYq!}e*Bs*1f^qd20@6*=37(i zu3dUhr-au^S~N9RpH1eRb9V85Hi1Uti`s=N)26(CtkhWZkrIeMFsOT#-{c7ulk! z>k;=`Actj@Rk3`(GQe2awbHmFP zejbdT!=}uGSN;Z#$QTn6fQ`){r{W9Pn7M^U`M;<4EkDMFdjIB*6UgQG2yq;5z) zH#f(tpJ6L^bCdT{k-)DHxrOI&`xbZ^U#Y!yz4d%*wj!4j&*shWa+>}|iPo#RG&_0a zt$ZY&l(!|Tgt1lZ2IPaN>?^=o|8GnK8s|WW9({u z^2Ug_Y}5MP-^zZhNH?wcfluaTDw6fP zsYrMkePyF$BHOkk8;K8*6c9-Vkx+1KVgyMIk&F1hNA!pfXW?(Gh=hwsricWJNY;p? ziT{qUP{Q$FaO14X@)7%|Zk$^~CB*;Ijq?t>Y4yLujk7Ig6PXp?_nB>+q;fFpT-2%u z|G#nLtoxmQY;4C{=(zKv2M#$)F~2kD@$33B&t|yw-Ee*QH!K7*s%18EczypdZXD!B zzQa+CQz2Tvf#F@=Y^EM=yJNWU#V5vLnY>NaReLVN&9VEo1<{NMl{)q(Fmh^S(Ac*{ zoFpMJLQQ=3Bi?0`mGVY1_)ODi*raU0Nxp#UEz9u8JNa;fx@zz8vnuSCsEQ|*LW?=i zH^9zJZ!RR~A*jNyEfBnw{JTg6n{6DgmbLL1fB%m+@_!ep$O#)K>Q-O(nE0R-Go*mC zy+7i6-i4ZOLU>(Fi_YHMFKp+)q$}o6!SRAgUdEus)R$s~%Tr$u>>Qo?Ml;(q-E_>x zb4Q5C@yTYxv@~BwKVs8MOyQ7>K?hp zT7tJn%KU)L2~0^}rcglC+;zZmVOaViVR2;TblP)VNq;8{z9ux85u6gg)XHw>7cP!N zYK*Zxc;UA91eHV{PVJ*cYM4xU(Ywm&ABRf3XZadu!{&Mqjenl&jrr^`IhgQyq+;~K z?U<2qRpRKLsn$a;3(pM~Ek0S6_@90w|Gz<4_#eJV^)I<`{xK}Pt2mu!e(>>;>-9|! z^`{@vE0Uv|{=R<8r=3 zzeQ_B$8=%Pr+mlR`qtMA(?v|F0y@sJ?XBVrC-Go`libI)8vU84tjh&w*IKsM+szbb zekyR@`LVq*Wab%L>WQnFWyja7nUcJNPtM!Cq+umjg9V?GRzP2)+e8!Rq)J~UVX?)j zKUy&8(^@gqt^Ds56i^!UG4UBZk{Z=yO!|23<8J6k>Y(XP?H125|959Ej(&|(?Yxz= z=k12;<5%R=jC8$^>D+OYcz;IqM0k<)@5R(P(*VrHw4$&s%TtR^SCLC4>98&dye{ny zjtoPQFFQJmTz5z)0DC330=VV%8C9w63FHgsYXV(Put z2ciL45(;LOzqX6l@)h0r`EsiC3rX$Weav075{)gXowt20RP46vjQ*N{&PfZxt!8!p zX+mlp5Vl49;_;riFHZxg;a!4M)9M&;MXrCg$R}0Ln6GlFJmLC5^;9dO{hR4ETx9_> zL1j)({m*MnKMm&hG(1om96W8TewesJwoCOy`P)763}{Uo7k>jzluBf{??4WU>9qX{ z5wD~pU4yub^l0T?7!Ol)nL z$4XnnOl|oS@cI|E>ejwdsGDu73fvfFWd@|P$D}u)xy-ot4jw%hC63iHRwDC3{bOpN zCVQ`E92;71tA@5`ms$vT@t0IXRF`RG%1oXgtLT{utGrs-{GM+DRSwo?0}7N)siCYY zfXR+VJ5jMRv~I{1Yqa8+`sju4J3ojrWBTH#7k3cLUw=&b6J53LMLQSVaAHYHlpVL6MOF+)YSj5X`dt~jh2IS5D7)P7!aijLFq*z z(rYLpAY!N@QWAPoA_5{Jgd)`v5TwdCAWcM#1yDqdii(OF5fKo{#@{~A%(Jt*v*mr? znRjRQuVf~Fp0v+(?)$oTguoEVsXOOp$W(&i5N02-C-0RB^i$1f`M`{-gzdScY)Y?? zBRzC46D~uCtI^?G$Z&f$Je!!{#qqvnaMJH=5cxfNrV(?V1CJjI{f5L?02n(|Xv&ly zb5HzP3eFNp|4zV4@pGgU;20U+$vLt(6MHKs)%QF0#qP9kok&>)z+JpRl;<<@8v5wxNrPC;Nb3+2M6T^v+20~W!d@W?>b%}{azs6)Z%urT>d zI6u6(BNQ#l#l!-j6+PL$!Q;^wv;^P^n3$g=KR$uPld)2CU<-gCK=60~2Jtx9vj8lA zRHC}B}vtYvjR)&|v357e@rE;)wA&1tPLkNeW-iJaYKA!~)I5=-IZWBVPaDhM>u#Ae(1Hcp0l2u2NNgv!* z0MXx69N6YF=NXmIfSzB#X{?ASKu9yn8GwTey>L{wM^e*0=;vX&x}>NryZp>Ec` zfbO=;K5xc3Z-K`~QW8!#i#c*}-jppr+|p1+6$xsd+xfQ%z5_TCbY-pLiVPCLhW#O9 zlRut6$T#*=VDgj;SHi`Z7q)E1mphhwZUS*=7|>z|0o*bbM&-R`AeasFW|dZRvCFLU z@)X#;=E`u3Nb=1{IbLA)k$1&gL2L6K&{Z-04{8W3qug$f9O>ftg1C? z)q;%RpJ&y;r)q>IKRhjf%x9o07+8C;+aFIZ=ZGFSQ4uLofzZVou#&tPNCPI;8;_O$ zR24=!BhP|sGT;gnM9oQrjJMcDM(qw+i61rLmDn zE=+A5@Fn1kB5*(07`spP4iohx&C9;jIw$YTt`V0HC0+K;zw8@P=h}v&Qi}G{k*Vb5 zaI2bc%!bI>hNyMiDiP}q00#kJje%4l!VQ=WC7g!T-iBvujp@csnV%Y-*tG&T?dP$bZvQGPDJ^*|er0+7$JFhyhlPdpZydvdg* zwe}Y-SQ1r8M2Edc=V?NXhF2Zh$UzmbB0{hhkp2dH&7{mNor{c>MiBwHb>p?$-A%zO zsb(iymnX!@Wml}ZsXI96k>2a}4^Mi%zrOt!GR&SydUz7mgG*&2Vb-wYhD@PT;?}>K z0r!}Ogf^G&;XDpXnwttT60nNt%kSEZ6_ZpGQqKU*J`{TXoigvACpCE&#a8LbQz%p{ z#Lr|SQkmr3yjY{L_J*VzIu_Wv^Fe#@=vW3unjC@Gf>KE-+65g(XWQ)F;}+EbIte98 z0ezqjunlQU1*M4qm3r8wpi{dhzzc;5cE46g24%<*HhUVZ09X#I4c>Y^s&9+T(ICEU zd|f>sP6)Y_3yT9XLm)tn+eJGiR%%F2Wy7T*L?IiMPb$9Ggwb0`CQ}eL(>Kp)Rc;^6 zOs6MmaRLJwm_k-|J~IW87yBxySIZ&Ii%=ZG!4xqtm1H1++}yX1Gc5CdLEA&)&c{dlKYCYCPu(ghNM0VlwO6bybk^spq~L%^ev60Cz(M3}-)uCsT!ZhsvM?gOqwG6h zWv(7lf=XSnNWR&S3YJc73}_04v@A}qZ}5%e(PtW+$~mv!e-ep!5)=}GGL5UMs(jkJ zb#Q1zPf!2B6#>2IikPy==hsl0)?t5Mg9C5Y`c^i;P*zEKMMF#d-Cr9g`?!2q1SU)k zFK;O3FG?0KKYIM&=YyRGB9iqIdK9R$5vhga46t>lm;|?}*ef_sU$r|5#o;tMAzP|B(eFK^QQ6T>}Jo}eU{^aH(kk6D* zXZ{srdnAL(Ul%y@n{O%LC))TlCXr0$<0IKU3w(N`UdBl1XU9C^XvT1s=tMq2T57_Z zi4gCvuto5A_M?tZ>kF9!jPVsl$$d88&2YbgKvH47)MSNJRGx_>k58AB__IiiVLlq7 zeU>_b#3Z+n$Y1vmQ@^sjA>y7l)X6<$zLUL>-p$vh^9|`+J6JD;h-P|`vXW%+WTH#r z!pjJ%OYdJlJIcGVWtq)KRs6^sU)`=*!A`d)GaB%gy&P|SGM|R+X(G-R;`!i+ANS+) zqLt0%zaz})e5SO#d0*&n-0bhV@?Va$c^~AnrvF`t^p2>!-}k=-k?fZ;h{~4#W#X)5 zDovr#|34(oZblv;!aFPc?%urmyo>U7;*vwxwHJMfKR&&<+jafbKU9R^Hpgz}>)W|v zTK<#WZEwfu$_`bI{~gi7|1l8B!;OUCC(aVLno6vy&(kgcl{njWBpr*ArqBNsExaq) zoz5ODb`5QQSN8vo*1W_$;^XD5D~IgN%MW2(js&dG~S2T_Vj=*AuH5U`yLtKiH`;O73n3H=<-a)!XT3u(!1A!hZ@4(9=35CHH=A!gsEUbh9pXbI-Oh_Ex5KvwS0;TQ>(UtdxL>wN zh!2q(uPjaQwdPBA31ix^-PCf^ANQ{1@wMhxk4^k|(EM|kCfic#*z!Z$|MkS#e$ck5 za(3&l7kk!B^}O>#czUSUS>AxXWx@A(zV=*-w-?YnqH@GEr`4Xt-Vw4WNE#x zY}5z0JXC^#0=o)zv)eBnRoriT!_mA*X~kSK(ir{(mT1_`eY8|KY%L zQk#`_dL!{mnfZq3lm9M6YVo|+;@&keb?yH%h~yq_`A6G-pO$wY{bom;(T)g@yWR%E zKRXe$FGq7`y|42o6Ph+w$BqTu`WDvvv6a>nLbzSRnr70T^h3wSKO2n zuNH{27$%}k!ocLCOOFeoQiTKE`vK4*OS_&ZG_eDQ1OWgoJ=BG$vZJZ(o2{AH53Jm> z1S0Xsxi`~LAd8ZHxIIt=S1Oig3kSg0Ioj&fo|=&z=B@>v4w(6^Yu!29zbeirV}{2q z2XaV5q_Zy)EC3kW5*T3kq%E$tnQe|K5?-gLbrTiJ4966gEJ7XV7bbrh?s6!JEPiee z;{iw6QIXf@JoRvya2E)JB=E-^32&er?sxj*$obvq9+exHa)`_L+$2+)81q)7)W+*f zX!(Nhc@|jyI1=mhIe2@Re;zQ+L7NZXoR}RRHU}sfugEY!laelQAHqtha})$@_eb(vP1#cF);aNe~{s`?&NVN;44<0n};Y5Tn4yWKhU83adPMrT9SMEKY|6 zD^h6Zl7p1Cfr=IxHRmzU61o4ADt_-r@p+z>%-Rc@^JWKHVC)4-N!c=8_$!w!!ayXdp4$C>(WQE1=k!-#p?6D{%x1POgLQ$ zz9qM7TeYNZ)$wyUheRrV4`)a?ijk#EU>`21 z?iVl^TokURpEkDmQtJZj7&c{uR*Xv5j+4LMnGclxUmyy_v*3Tfk$|x&>YfnQ8Frof$}GTu^faR5hM`7BLK{+ z?68|Ct$)f#pM}a~MDPgMpLD;L2DC02;YUqtn4t`cC-Ru_T?a#~%5V?^dk}(&ve71V zSO^J;Wn&}oFfk&S3BauP#2lifdH%xnxWRd(*i<~`<4@dC%5gmwKk1Tfl8_W%8fq^Y zvfnzikOPYc0KO9aFhMAaM@E})Pz6kcAOW)#LPEr_$UQMRTt5{cHIRWP&0rtS}yi<=`rT@JiBQ6Bf*Yo_AOkGF`>p4wKm6_!=<4?IgH8 z{m6@~eBY@c*_zN$RDlD45N2afF<=D{DgiHsEmclE7KxaDQ zB@=#$Uf{-r3o>AWOgO?25aH4(gFZXZo>5FR*aiqP(K~w3SJ}lDe2&IIbvL23c$^|x z7GOdLWFSxwI(L{B*?-w5{W40^3yL5iPmz#364H%<5~RbBOvEM|kY%8vsHKi1Kno~! zvXdMf@cE|uB_?KraWR32n#7a&aPT$@S3nTDB;);tCvo`WW&h9b&@dw6$Q}0r@?o>7 zs+#Smb9G(qsW2E9S4hRKk5oRB0F3D%Z+AR2dh>*_fJD~_?ldR<93G-m8T)0$FQ3Q6QEGTp06txRP!z=+!Q~O) zQZ0y6;U(^$#OcZe+6hh0a zHA))Bs~9!B$x*g_&+F{`h<1b5F=J)%_Z!=l zE~a&q#uF}zX`oMC-`)D}-~uv`I%273G;OjSU=kL0`xPfZZ!c6_%px#<#)k$nA zT&kGc@V)R%UjgZ3huKlF;$VpS{T}S9+1*nsa_0sK34*)BT0g9B3|}!d)keN%X~%Xg zP0c)OHxRa|`no#pR1k$MPr*LAf=X|m@oHM!o%7h;1WXM?e*6d9)zzJUe@Z#$0@F`dZah(^hl2K6;MCx;pX+Ok#f^o< zFR%NBxsRNE{pq0{KT=YXbArG>vs%mJ=nqdaJBpA``v{1zZyqPgQ#`@XcN7zfnM1Q{ zR>cqB-KQ)+R9|5u+v-A1#KEPdrL5SUcbWv$V#d*@*FAeS$fls1Haf`#Y;m-;9^Lpo z0d|}hj7Yr+?k}GYbygEL@sU&*_+J8+`V9l(0D~J<;p@b=q|Ov9t)vv8-yY zw?gG_jgU`kra@y}!qC9{^i9W~b0~Q6+WLKorCHxI$lA$sIYI^H{ZaVVX9Wmvm1 zuAUzSTAkx8-DGX`B(5&AP2UjnZxRR6Suge3^)04zL&K5X<1g)Vx0Mr>gb4HrMuk4h zJ00KAZkj&FX*yH?ewkfXg1<(=S5OH0LgbD0g_n{fJ{?)V53WD@%SiZKgilBQF30hQ z|0O7YJARvwg!mte|DCGd7UhyM!hdTIPToFFiB<<M_vgx+r1ohSKamJd#hkDYSA_Toy&38SnK zVXYO7#QzeU#7eAo7Gv-ID}B@3@$qq!xoU+99r%zIti0y{-%xpsdE+?WQ2AU_f>s^a zbzqKg;v3&kdBQb<_4BsY)l$BpG9@(oGcVy*wo`JThu73!L*-6LfTs0AY#+~q*3UOo zDhKhp7UO4rihLV;^&p@>6Y~eDjz9V1@R9UrglZEx1cL{BGJpf~42qz8*z0H+A^khF zP*F%oMk-tVjUPXnei4+Y&w)_;EID(zgi%B9YXY-_wTHk1}_q%#iB(pWW@BOFG*I6j7MdmPn5AK-S2IcP_ zTkKP~b%eM1QccK%J@;NBnjo4$#5Ef9M0#oQZu!rhOSEBQXcPv6AY6huBh zIF2}-{1=?exk%{EMEZaYy=x-LVFK*0>F{9# zT<13)K|%J*eXWSwXax`41;N=vd)q9Yp1^r6-YD4l^CvRv_-4@Pp?^}@CPMS~kAJhV z9{Bx}HyOh>R31Ml;q=>PWrP2ZU2+)V_7uJ@^mh-AWMIoFUfyOq=wuAND%d8mj zmA~9%%*hoD&G}~lAC5osl!){QYj&$2Ms8QJ=X%=SZahZFBt0VwpIGgX2B|qjp<0NS zBi$8irxs`FsKlfd{a+Q(=@F{-qFTcsUuELGRPpDor6%i3>Utdy@kQnY_Qy#SoF%OkZF zM>}5Lo`aP%^Vd<1PJX9-zNc*BRo+4`!xW_l!2N)DZ$s?Rl%5(Np}kMZx9F=k&+@*E8}ZdZTuty_p&6D=J?h*(hf zn~CkSqJ&%242CpX9&Tr+b+GWIhh&vwfE~uDK!lUvg1kgJ2$QbGrmc<%ZNToOF&-<5 zZXfS?-%Y=;87y*Q0b!v^pu1s$@VdfHiaUNy?hd{0tGD~Sc?%U&@$CC$1Wnoc+tbll zU4Cf7Gt>OO+rzx1PGwGHu1K7rtIruX{Ce()xeF84EIEAX6{zVebr6&SY6Rf?Gn6UE z@C4su{1sF)&A`s=9g_Ky)HbElGcp$t3I$Iazpi>&rP!{N>g?Ad zy%=|Ps1o%3nyKk6^*vAXX&}0qsNsn*G;6$cC6H zzW>h{s-IGLvEExF4xjqd<)?X?{11ZZcN9t=tuY7-MQ^_cTrm08wFkdD2}HG zeON=CL#>~$%fUmGX9;zVB67%sPhS1m}7(hpe?n`(epShyohZ#~cWl#}49I#aW zb+8k#?WTwd`b6%?)(|{|3?m9r61gt@q-XLSUif4{%6YJ~NShCAcu*F`g#|x24A`YC zu&`izx>h#}>1TU8j>dr_C^(U7%+QgjKe%LRBjmAECh-7;X*CbG(;26k`+S&t08y_X zo^jMTHE(_RC)%LgS0WTV^jXpZR9N0C8L)e0K*d*Dn>ljXv&KfCnuO{&Y|A!(x^x_XaVe*n_i^`Y zVEBtcyte%oc;=47ZlBT9r(r7YEVPv7Ob@-a{TB8mjV3rONMtt?9}!VbixzlOiCo0B zf=_92L_n3CNmQ5TT*A$7;TaAJtT4H0zAFm#;IZI<2HY}I)dM^nKz zu9e_l<$iQ})zDJ}PRiC%FPQTS8{DR^i|qXnjA%@)8<46lp4g{?k@?yC2y-b5u=K5*khV+K0HY)eE!{Qr>$hDLZ<#aXX)Ku7EftO zF@G)p7GBJD-MpUkhXyEyoThd-ydFeLYz9lPsyo$#L^JW3R}g&fAiB<7eph_oy8~+! zw*Ugtm~4s03pC*|F5E-zQsz7sIy^LG4RTHhrWJa~OJ#}9>q9U#NREpzE<=8(1NKfFS2D9WIp)=c|RU)#YLy_xCmRg4v~QFBtpOn&XSA? zN;K)UqWK-xGZz=DCipAZ$~RMwi4D?FFi=e;)P)kv15wLVUq3t&q7V+T4)w=FvfOC! zAlP;!rJAm5%*_-

CY_*)E;+IUW^$>fOUO3J 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

OhC3WZOQCKxh-RUB;EAUj34a|WN8 zbPMX|GF*wh^98_SIhH&eXo-cEl_a_MXI}PTo-YX8XX|x+DDq4de8deV7%qCHU68}w`_mlS2;U69Wkp)KYe+3UuulZ zWZPR?XiOm-qI8K-3ldop&^SJG2R|F+FujRA&N6(t0JoR0FWEwD0NgHyJ@}9t1vwJH zXdpOK0L2q!Z8=3MnxG%w$YE5xi0ircj_A0GLrwwiw+aML;ftM?v!i$X!wH(h(?IfF%Rq zOfih`A=YBZoFr$^FW7Qup#3lk4U=!#j z&3SI(#T$Ph#(4WT>trqJARVFg27rU(fh7W98G!&KJWhZ+DbK(=Y57jP-&xFDE@vMN z!k4o^gkC-+4z5`YD0T2m34KtarHO^ieOnyp|_;? z=+lA#{-LZ4(KrzrAjn!skC_T-P4?&XYp=RSqrWOnQ zzDWfUZ_)h}xO{DhVQtV4Zo=Nhdy^OpeE~2_j%Sp>0c7SJ0pKrz#>v^v!V^mh@tXxj zjiq3+0PJQ098qRR3!KS;w<*Q2l7dD=i1}g~P;w-dsnO$S2GBq_z?UvO3YZ50)RKflxCuwn;JFm)&fA(v zL0<)EGQs>T3|YtZdwDvcpMwtz5_1H8GXpnmJancJ4L@UC^mw@9s~8?f^EOJ4ol#!S zw;T!mZXKM(-z+o+Fd6zyjC2Y>TE5ri0UBKJlyk=BE8ESaj1d9DoR8&5!uy4n6Y_Aw zJux$TitMy={)*hab||wo=wj*PqA2YUqBJO6Qbw2Q-TBy~7(k1IvP6I{1!M?VWB9-( z0C1N_|KPC}48y)Vw8E$%JU(wlo@BFaeT-KJR z^8sGL90{l^g!JXW0s_k;FjUSg@Es=tyADqbpg>1$uuN9q=2aec%mRDTh1Kh;xh$T z+pJmX^6l%F?v`|f?#_>$sGSp?7Mv->00HDnTw62d+K1KWi^ic!0)T`Se#VhEwRb(V z+4W*6yhMOUEd}%B04@M@ii$#o0L0(*cx}cyF3Sz8yQsa-xcBOB=YSiZH`kwypUeRO zJ<3z%^xo>C!bR6mfObeKr|97W62_A&P&(0Q%LC>K5v72YM_%#a!7KK%Qg{rEgctcV z8u1#uhc-ZXg=gdo!OE2}!a|zELy*aG zG`6dGk(^=8qt%SYSt8~v0!$Gxbm^C+xc26;9qe$o=1BY7`}J-|#of*gX)Xx4ohxM@ z>bjjPV^1c41ze6VSzqVkVXNomMj@yG08u<2z%TiH0TneDZis6M z6TmSqQYmN7Ua`$*1ki!rQ`md4*z2vTej+6(|+vF@p(rH8oh%!YttT4FeVSJd%k&-m^ay9dv#6dco@hIHyY+o=A0 zhU)3Bf}-z>7@+8RW=U(^x_#m!Im@_=3vy6bghiQNYu*~w)OQAyfLc=I$lMnzeXHcQ ztM~Yv+4TI*i<_)xUzd24{OWkur&;2_@y>hs_S(xHbLz|VSAV&81#WreGx5dG7q5Q* zdKKExbWs2Qq`kBaL7+4`e0Z`)LE{eM_7*n1{9cx$)7ABC<}CA`TNBz#RUN_(hn~Eb z+%Y;SvVQpr_nMlTQzuVW382$|BnCopqo?Ds4md z{M>Qjl^|5eQf1p!j?k&dDPxhcigL~3Z+E|qwlvkzxyt>mU+2~-3TvKT$zkU2M1~(u zJMd8vcWa>gWA_3}?L(=_8*;9xL|m~d>dJqnNETOLkoJEZ96r)EV01{f=<;a%C&eWH zbctL+#}4U2RdUl;Iu)5)eDYN1$k*OaE7Qfa0_$>B!PZz+*)=jb_0@@AicK|r8=4g* zP0x1h2s@F1?P+*H#~r6PD4w6kQY#;MpX;ry@0xM;=l5n6uS>npdIo8Mb;;p-S3fCo z0+6i@{dZIUbfLyd6q2%X#`)nzXLP6u<8?`W1?s&COXkdw0~o zp{WkcV?USID}o;=1{DfgOJ$!LT~VvZtbatSf!OI$gObs(#-X2sgKKI>yWc!=zdW%1 zIz6rRljb}?#iM%1dvuQvXqAo9GNM;)@9&=@>uY~%93NcSpqNmmfXWmRO}%Rx6liIW zSHrNL7G+@{Qu|F>E6MH9B1PtuTPBfP+!G)6?u)olt4RD!(Zez3(lV$_S{K&XB5QeP zT_n~zK5WeqpyD3R!arpxl}u@)s4=G8zIT9_7xGTPAzH+Nt3>h!8Nq85b4q$XNeiql z5&Zfds~*xrAdYV;7?gH$8mTqrlySKl`>FFQPt)JJwJ-QG|1~H1nOkM~JMw#7gUsG%S&;RW5A^BdFF~ zw_rWNH0~$4ScCqNOa92F6G{dqlqgo#D>O<5G|C3NYX2yzw8ly+ty(1m>@tN{{T~&T z7F)gQ>30X#)GOB14``J9$v5t3>Rnk+e+vDj2DD24BT6f}=wFXG2K;{`j!icIOldtk z8~^u391oiP+Yv_#X!3u%h$Bm6nE?C~oI(Q7!2G-76b^j;hlt~zZe3OjZ;}7&OMio$ z6Ex&}`0s{O_yakQ{1b6p`v-Eqz3u6t!7}w3QQi;M zeOgMP~y<@Wa&+i`bKDguExO(LG zo&-h%vZOj`%ub<8^7wuM>ne~tJg1lFnXmg(nr?7O{6d_ldJ;B_ZJK32pq9OT)uDTFC06sS?tEMpTl-Ml zgyF@4L|ea;`c49PQq$|~HKT9!&c|P#WFbzDlHW8KtiD{a_0E>~fuB$62gB`=G58c8 zV$28f@>xIi&jGVWpWe-~zI6IXuZGDaU_^NFjOl}{$)ytv&#g~(Y_|;Eeex~jKwyrc z)0q(;VmjrJL@$iV+P>TTjsCfLk+|r0=>DNY2KDRH&b>CkYqAwDKQ~=7(!8 zqjl89dBX|1MY1#-MKz1PW$r63bHnB(>($NsJ7&Ilqqgm`-C$jcgY4>yDuYYhS}xP6 zP4{Dez}%PH^s|p&`TgCSZ#S>$Sh~7g@YZa_U~gph;8DMI-#yZzhTv#m`)P~e5R2jH1K41qw?DMS6fb=_f{PJkfw4sA$wjhqg#yTl&o&0&b#ms@(~xWGmSmZ~H?ixf%dSr){%iP~(q&k<91)VBy$AM9 zily_hcrLEXK>-Q8Ou~H2@!zH7_?LI=xc?;CXY)>X*J#Kox=%*7e^`4YJf#5J@|DE3 zIndNJb}}DKX96BHuAWTym4TiV(}wgKu0T`<#=lv*44?5 z;vfq+kdBObdo5c{wwFc)S_?oo65EEtyEwqX56Cw@IETAEO2!x`+qrqFaF%jy#ut<5 zZ5?c(2sZd5FaaxVy~G|7hnuqncP#)gfR~ufXReSk#_=#60PrOl&Hzwe0Cfc- z0v6^=uzaPotPSf3QbP#F90A0a0CNCjiaghtgv~gJ4woq)0LLIuF9W0H%J}iX6v5_M zQ#0m7XWYgxRRYwMfNuQULT19@DG8pP!3tMqh&CRx5ynwZzX2}3z`m^Uip#?b-R$13R)dY$yP80N`&0kf#h) zNJPOBxQ_%^Nc?pKOgkXYn1(NrppXIrg@@e)n2waK#!<5t7di8ho#UaV5q!A}q4UOk z0hnF@Y4MP*&SL}#&X6!7x|3N?qWYpT9L58(MWCk`HW>*x7M|;Ig{kNa?KM7Xz&YZ^ zIUFQEgb0oq^U$*yppwHl9|RdlFs2Hu>cu7qCjRVjPGPz&fDuB_{5J3nzykz~w-WGF z9;8BJb3DLrT-HQMe3>BPe%gV?%^6<{)*cRow8X$T3G5`v$o-IUH!}O1H2!?mW^Jl4 zL^+ii%Li?^Cl^Q$&LJ5X5Aa&dAb>;<`AGwD9;;TI1t8@ahtwqSwh?3p3$f>jba?1a z4lqN&NMizs9I*!wp#XW44$k9aF{0@3IidT~PP=y&81{&4KLs3ITROHS*r_=?R)EVp zVq(c--5=NXNl*Wd zkop41l?wtKSVIC46hMkn_fkM(Ag+TlrU497fZ0QWPD%+JLIHaz*vA$x8<;!h9NsTR@pIPUA13|xrx7T!p zPS-i@ilQn6kR<`e^Wh8$!&(yIK$SX(q01$RvoUkaZ6GQg-%aAQKP5p~DXQt=(%@KQ zoKnG8qv^ds=tqysIm5yHYDrS-<#mUPKaJr2Pm+hJl!rf~J5DDiqKsrY?9Rh&<)Eq@ zb`%2|5?~xB$=oAsiR1!Eg4ejLSgkEFK#+`9cg0wob(JVDxp8jYTfy%7=H%qa%P-Do zE{eXkt}U)8rBM1THiOtzuMCJEYTD8-!K?-FYzg25fSUzOju86JQKtv^H(qBVxbl-hrgmG<`b4i7H<2?d8OQJ)*KUpH|r| zMn<2;Y->uWcOSSORdCSt!~T{b))2wQ;!5pBNP6cTP8R}sMWvEA<^UB5zYOkFD+-HjbU@r5Nws5sF~ znabLw$lX`HZLf;%%G%jG<+!B~i6Yn5wsV|> z$nQ-^E)P|--`mN=*7vyyX5~ z?nXb!{qcSGC%w2ox$nNwi+g?m>;~LZk~`yl?yGH!pe&?|;k@ z0!C7HDhKoId(5F*1yqAl{CK^3hsm+WO4;Mp)5na@xHqehF?x$LYaPNRAn(!e_XK3f ze=@Y_;V$)inJ+pscRk_l-@jq=ZPi5>};;eOec2fVDXxFpS zBhSjNJu6?f_T$rp9xy$=9Zl4<`>^M+b0t+QIN7B3Q9nrk~ggpnyouBcMF*`2~KKA_SuDHXUY(NI8 z6QGtX|Bb`Tck5odg4u^nj%Z3jO|neW^wk>o+&m%B$hn7%d&ed#m0e{%7g#W!k_ zem>X#^2YJT8*kkUMh5>IAz1`a0_MJe9+37&x~(~3P1l=0_RCwFDa{H+^$!JC1(~Ib z>CA#S)!Z#Ej@{5v#SYV&f&?Tah79=m;vM9#k$Sy!ByE2frw`+#IkhcznN%(c3=rT|Im8B*e`Oxzjy*dQkD{_C)>Q zL%kGQasC2L$4b5bv%3oUac_*qso}mBHN``nA0xw_t%`RIWF?PaNlI~k#Y4& z4~tqw6!mG^>2Kc}knZMLbRKq6t)l9XvBiA1lrYOHo8u#lE|EAv$S*O*ve zQCM75%)G2HIQnTO&twjrjeR-r`xRr?14T!bTh-kzTFRY2$LL$@wD>J*ck4qSw)wLv zquvrRAs-)g5vKWgsm--Mw3H{f}Sq!MnWL_M${)#qWRo(5m$2|AzCijIFGlmVtB_6 zO1MLy!sVJ*OQQ&`v@1k-NZy@D_6)Q?C@q&+k<(~8RgZm$2EpC&Zr~+{pof!t#B|ug zdIFCM6gRZ2B_C~H2KN)(98_m;-<(p%fbR@BN~DrzN9 zJW#~lVWO!ekoJg$4MhzfCfy>ul$3ea<2RvZ%U0$8Ph}n8c_uR08(Z^se5Uh(Y3o`qoq2ege`3jzC6~({i{ur-FIq33eR5uKGgE(QRj*@wz{9e2 zZB^%5txL}fv;0^0!m+}>P7Ut zPUEJUyh%683w)DdQd0UR)4ZzZ%^qHp$=khF9f5E6*>;z{&9Wctd7Dk3rtd@xwSwO5 zcQroqF2~LKUP4LH41p#FrONt^s zeLO8r{ps$g7)auHDGM^ko*7hISXRdRp?tXFEO&pf##y@yUZ2)iXMQqsRv=qAUY(Jkz1fF*Jq;J1EnjpeI5$LcEAimgh0iVKO0Qhc+ao=TJ*^#E3tiAP zyTtADT6yMO!>VcapSq`roBkb z%!xIlynk2o4%PAtw?lP9uj=iev$g)sBp;!ZA}qGQ@omX8`K|FYR_&aRosGG;vb0{o zZ#LOx{;|ALOMTnI=?~AA-v-`3cW>-3_mN&y+UwrCc;32v_MOU&%fcGxX79=CKyLV1 zUt}LmIe(AMdcLDFWW~a59r&)k9~b3~epdHqu2qifpS$?1L(|RdzwR}^bUeT& z)b`wtovM*7_EtA;UeYaWT`@M#Z@uWXTrPv~i!-;xR7KtN%YOT0<)h*1gJ}~-I?u1r z+}?BK%JSilwPs<%Z-;io+jRzP7*{TTI4#S{(KpN>M$=xc-u9UG&;n3hrAwFuX}Vq* zyjB%IJ?e4A-QY%*rKJWd&;!G=B$h^9!q@tDs>webHSl-g68lF9H{P2cI5=i6mk~Qa zVVWYBGrbd2%EOnb%uI4YIihQQz7)eEY4uJ2Mb4eGP>aq6OovLE zHsEJyF-)q;@6TeEEZO-s@rhP2nE=;iL*AtgXOv~=xzJPlxa-Wko>@m#U(C%49F*Mv zqUGhg!=@WTorvMs9fcQ#?4O3^96tJxlhk@_v9U9OxvDy z{p?NkC~o%ggVQn+{RA3U1DbbBZ!p5e#JG1(DRbhel%OI5aaTm1s#vCGSPh^tQarl- z>(<7^w5g9fY-6Jyyq32TrzBMX{vQ3CxbT$*`bE<6*z8SN>Ypb~5^WQ*=(Y8SOWF zuyAuBpgw2%Bv5tVPRr{(^b#Wt9;wdeK84994J3>_~{Vr?Um zr;&f<#0MiyKNAw{9uex^or#(YT?n*-V*Kh%)G`9dagDH{efkX*Er8TBjQ7 z*^>&i=utYC^>(6EeWmM-%S#1f9b?@j=V~78ReFQHUXnQ7XCr9G#IzqwW5oG$(ei^0 z8b!Am_li5N{AwZ8gXM_^<)o^;NfLv@fu~7*alI%|zflOor85nNR}r|DXY%beS_Z4g z3Wq!iIb(@0V|-6D<|;{gU!MSCu42tbNzy~D8!6767C;0Yo|0d#mhyOBVw&tEHyg`l>N0955ew1z{BF%bazdL%eoMltFl zYj^_`b9D<*JaFmrbRGq02|$$xB(TYwWP102m9&zf&nHzI>WH64V%TB3n6)TyhRO~> zGDAdMGi!0W5>6%z90M8WIzZN%@$lHv{3CJ!knmAFpIuGUSv+je_O9Njoka5aN1%FT zOhQVVAInM%vN%#?Hpi)6cFO6BJ4wDR`_7pyO_k(rm^hlf#uR0AdSQBGO}I3TEgj{q;mta zDs^IUs05u=PLPoYIid4+!sG2`2K(OwN?k2}V$(_)HQ-YThDz3r^${}{lJx^)#7q3+ z#mwN4IXIYb0eClVF3yx=`T(d#0R`cJ6#!15Ks^D{FMy0i89~y-y$9)DH@>zL^d#71C!Rkm zw#)-A?!gxd`JPhHjsnssz?2J4kpP$w&Pxa4M35dI@s{kF+{w_R09w5>rabKmU=9Tv z6YvxfqjLe029O~=i*+Qzsnbe(0ccn$})E3Z&!&)W? z)u!Ms;$owBsvv>MtbM;FN)7Ew9Q zLb%cyoJS(2LUHhThSyX^yayR3!y20-nuBb=O7PVZz?dGcVc_X!GV)DX7TgW%Z|z@1 z6k1T?kBz`e`cL3Cz=#pkV!MTCZ(H)=xw2#;jHS!~d3;~j(+awH{b&wI5 z?ZH96`-_cfYe1Geokd>F3srsUV#7O?)q!uLKou@%B~G^!09bHlwll&cKtpkfnrN{H za6skOrqvS0*{0+s#z|j!I^Qn6&oigv0BR{@rkFB<$%19X7A+BEEJRe4JgX|5+0Y| zZ3T`+f%*JpA3R{XTaU?4?p=c969?ihrG$tpuGr|$_di-&VY&q6%$Vd6+7=YdW@VkKCbs{zsdNV$1>33ZeG+XjZiX86*r+72WV-tV>m0y1*EQDL6GEPzut95%ZY<3n6 z)?E-aH#}eDP#AFJUfAk&6l5i-cx1DoXcY96ow64)qUBrie49Y9C+7WmptSW(YtH38VNRe>MP0@}ZPd z^s{lih767u3i20A{A`XN{s7IR;vcTv?fEHgjz_(Y4%&j0<_J!#3E!vElKxGUZzeur zHN3${tnz#{Y(~MOQoK1Yc>NFXNuaNeFmX}rC1(>9qmd<)*lIX(qcCCBC47?r2pdYW zqdfH`4S)PHF?^~DIvXtM|G<2JC7tQUnFT3^1QuO$`s3w_-KKFNk|h#sg|`sYT#LBM z_H`fLkmAkQ|0#(u0Sm3u<9P=(bHTPnXRSEC7!ldyazqVq^yI@qwZ#YcuqTl0(48@b z58LrFe<{U)w!r7q-1H@*nH&jx*x&kc6g<83S~K&Oo+x8q3UI?UuPJ@6RcVHnH2pce zhv~e3uCQWia`HxkVMKxN+W_rL>y4XTu=qP@I<8`n z+8Hx{#o0XQd${C-acSw37U7evTHI}x0-Q6tq|w+GDssmG(-}*&m4cNIAKKss|bFRedIa@{$wHi^5O;%+Y+B2-TKHYMD92( zITf$H6%hn&OrP;O0`P46w7_*43Nd~8WCgov zX(*aQ6D~ZJId{;Pa~g!4MVZ(#8_lU)G3-R&1yggjIo6y4EBgY{LU-*wh8?Erz7&PT zZu#vKJbjwLP#2gj3i9Iz*$#p9Mw=iN;S#`9c#r#im_E~Q(jPUx6*IMuhOw1EH+Sg_B^G9biK$FctRg;{1hRi*G6xcd|AwY_-EK@1!^GIHPd;X;TtKg41#?5;SH;1l za@nOsVJ)1w^UGOV`E~Ul-8vN`OZ?_Gc^&2&B4vCO_#++NYc~wD0(9P-JpQ=x@XH2+ z@;M#;w@Y!Oc$XW~)z0HJjfdZgxN5_ex8E#hbd(mV!PGR$Q}`1x_n$d86|IHj=M@+e zG*x1uT7%zzb^ELHmj5nav((#A6EW7aQ&j)jforuiBgLQkdE5miyc#rvjT2E%*f0aM zPsZk$eS7oEuL1Y%jiD_2k=bLRU_Jtlp{>_1uzv9MTDs=y$zyuz*Vd#1wRDggaf)l} z5J&SPs}4{Nvyr2FSde7%5y3MCsRMdv)|p>B^l(VL+~~&jMrQl)QN9#f>$t z-q4s_VWumrp`NJ+G^igvW#y2dd*tB`tYN1zK>ftEZ444qYP_p_>PW`mQFOp=K)}w^ zL1vQ5x^Ba&zq9((gQMV5{r-VH@cr?#Wl ztntsZ#Ts^>K09v1&R+4%UYz`P6gJ~5aBTRY;Xtc9JnYWd3x9rCCh6e}8Y7$!S`|X#3(FTBXKbRhvhUO!Lj5oy z+Jreg_8MDqt?_(u^~dDcFL&zMw;4*_pO!rvFOJonoBH(IyZM5!X6;1gN>8HHrdwmt z-_mbwu}YFP+>TVgN0Qesnbo*|pMCA%{)xZX5p%i?dPFj;8l&{%qoVb0Sapl`+nO-`sNj5&a=3-kz-%9pGjkwFn{x6>Ms4UfQV*ISDU<*m zJ^=s#0|FF47Ebnv06{dVmb^03Pf8PXf++snLYk@|u;kSs6YO22=9c^8p>Efodn=cm z8SKXjx5md(Z^!I@PcBFj4_Gr3iwds)pt~2`SahXKCDVt2v(DtGCvs4X$9I&vz8~lD zTGNA+p@G3uQpK&tXHbVYV?YRwWJ2Lq5XW>Ts=4?!&%}!==X>~;=x%>1PlS12*84b} zb=Grg+30nn_wD_#@qoOTTMa0xnrhyXzTv^$mPeomxf-}?MBsfR>Z_?P2Fb4Y!|eH5_xOD_qg~_ z9^bRt{<_gtOoKrn9z^`=Ei8u}$I(Io!c5!Scua5lP0`k@T-B-*E1gTxo+Au)aa->3 zv_w>b=zg+%lSQdS5G#e#FT^$=d*2Y&sz~3{ z2rxx71*${_;2BA>os5ixJlls{ofnSx$58#BJiWi;<$BWp+@FNgK3{l0hFj=VIHq6T zK*-3BW=f&4eEN!=T+7d)P`WJ_f(Dkkl)6N%gA5-pT~utJLWu6Ja@?c{qsa|dB|U{E}k^MOf~gVXDw9|(UoSB z5=ZkT&*DVQU;q$Qia3>OeL4lAWtTM&Np4isHjM8Oj1@@h?f-f}iQQs;IJP#ea_+od z`;L9c%Az*ATIgj)8R}k5g0d0zy^^Lp5`I5Wr(R2@Q!~iGx-T2Y8zB5#G4SKK4-~_0 zL*e!mr2eF$itcfr)0f%Br&zd@dE*4i{7vj0saq<8QyuTNnbFVIUbL(68V!k6t?+n1@!I4Tri2Tuh zP!*3(-t!^xGAuuYrAL==MM$DX^jW?O9&e=PLy}Lh&Z3e%x)qeKr`kvRi&T2NJ$(N9 zU0;^J_&bjt?TYK^SE2)?7d+k>&R@@rVFjSMJbO)*L+_T1&56v!N1*%$l z_BnGloNJ@csbBE?;5{Fj*UmbJN%rgyP`**{G5WktrRT@X=Wi5!VV&21=Q(hr;zr5u z=nF;*o`X^IHy-Y@E?~L5=<&)oOZj7h%v8LF?w-H-NM=9C%F=5%yW-|!jhKse7raJ_ z=5JP>*uRM9;BFr&hdr^6x#UtAS*LV=;FjzDlHL)h+}+JyrErGsYM0mNfLN)s1I}c% zn`S%~<6+N7`jKdjtYTMmm$51ZelVXlJ|e5lpH8riz<1tfGfXTCDM@jvgvnXBHtb&~ z@wiy2!kQ}h{ak61EZO_3Pn{A(KcrcFk%^M<&}&%O|D(Pa0AuTHzms2p*C+oP-h^`v&yydTIu=PJw?gV(4yvW=z!#>|OS|Qi07(6Q|BaXRdl&IE^5} zdW2xkSsE3Rx%hOt##~gQGG=B-MyvpstJQmx?=!!j=lQN^D+|6;Zs%iM>_+98{a+X2 z_P(%Vx8I%lw_X{y|2r;@wQz>Lw-CqPXU74Y8=5p0td4~kVWDf@uOG`ljTKnNB3W1zA5KsjC!~%OHo}S6;Y59KV!^lr(KzumoJ28BvIZyB zhLi5c$xP#9mvM3|9GcHWUfSfKx`~33iK3l}l8=dUu!%~viE5h3p<)xY8k56qChGkr z8q+44%O*!yCKx_bEosxE>ZaO8raE?}$9zoLy1}M;(Wd%orpJp-4Qfmc+f0r6O;1dl zo?JFHW|?C7%y80XChBIUMrLMqX68O-7Qtqg(Pma@X4b`KHZ^9pZDw};X7(Smu6w z7H6d`{M9W2j4T4}EYA5@oDa6R5N#2ZW^u9D;!=&p|;|AY*QI+QPc|`NIcxG zH_h&Sv0Yz{-G?^2{{H^H9FTYr;YbhxP9Q<4V0*ys?M4MB$_Yjj4*A)C4z?eUwx39| zpDebYsKkfqh)JSC4j}jEA;E0@eBRWbk9#B*-hn`HrGQn6B6i0Bt0Z=Sq z;8&x=^0dS6<$-0E!wSpcXZgU-w1GA0Q|pR@i#~%(!Kb!1z{`A4Q7UK`Iv{2R%o;g3 z4?|C2p62^0}a{bf_<$>k1xm4$mEfhbZBB+wpuK@%-r!Og?G1 z{FI(YLR{~ueG#P?P8fK55NOA9Vrn+|$p_LM#Y-F|Y8@rp9VN!_GG82J(&KHKA;^6? zKuL~M{U{`()MMv(1VtAW#Y2zLVfJ{H`@^cWPHOGLYPC?=FHV~25NLWlZW}KZ5+CQ0 zV2&PAuvcIoMiE3r6ZjIHq|%+GOPr7Ya5DToyd&at0^=-bKXPn1Ue3x9+nlUiGA!}d z$?S!bx%nthyR+pBJp7|Gqmc;E<4^48e^0a2*>rB8lCVkyoD5w#aTu&YH(`D~KF*8JTlwB!EOc zoE#s+4uuWDu0X(4h&&YnMnR8@<88M;ojyhf_T6lQTp?plCNMXFE1-cKh!_4dP?BsC z1i>`NpHXt*|2?L11ri`yV7G~|KliBt<-%8+5UMd2&ABLo1P$^~3L>D$@zKrk?1c@I zNr-EdM#6GU!m@e-@FE_In9wCVh;EaFRS9DFv3ZdML)8SAebT_(n0_+^8w9~Nf7UBW z#-f~65fbNQ9M64mA;Nes@Q;DQ=m*U4iEmGV^ocEYfPBh077ZAo0nzX=Lm*z4X)l@* zugkHq7zt-!5K-pGPm1wbFGx_U2}3-H>I%X!pfg599y(z113KR5ez9cu(Ea$5$Abup z%R|>s!z|Bi#CYi#4~g?opyYx>fKd8GXb`~91W;B4um>bDk%UGNs(c~x1n>YKSd~dQ zf*=6fBovcGPb329FLt!}BUErsV*D|Nj~;=D!h=*pCfSMvl0Je65BF6icx1k%hw>+& z9}fcJ)8XnLyL{aU_rG@6@?1###G5|WbcIln2j2LYn0P_XZi+goq>u&)dJ zlX=+brS>~-6I~98CLHSh_MRW)MIS?nlf+aBP=Gjd#REwOflve<0&xgRJfcc4M{wQ& zh_M31t-e8r|q|*$bM=aivF7-2|=@+44-Vl1Bp1;upnnUnMG7oC;D6|87D)Yepr?r}&`6 zzk|sT306LHYbyelk%(c23H{lXr6%I>w-#JB{e^e>3J^*X##A;eta0@ zo21AfkZ&zu@8MmWKC6YF)4LiECY&)s0Eh7;L+V*}LcEqf@nnUsA$10d01IhyY(Rn{ z#hbs1AiSLn-R2T<1N)kPji7wr4gPw#X->Uou9hAcV^5Db<_`jh^0at))W?&`-{In5 z_a+jL-;ZOc1hC(TM-x~tu~g*$BWsm|-`@A8t-QraJ%1H4qd80xu?r1raS0 zU2H=b7jJ!Cd@;w)p!fw>-1((Mw@LY2zCVP*CP25(%VW=j@&WA-LiT-*rhhijfpiR! z;GRSbhl8->87LMiBSw&RvtVnS2nH~`muzfD~tvg&3?@%>J zdwf1FJ?Q7-#XFz4?Z3`J_P+z1;H|2Yy*NbB3apY(&~BeOqCa1D^=DpByg}|yFyoYc z`x$wU1SmD3bn9Dqg1v^l8py3Js-Afiq94>18iyf;BN2qcao zv274U-;gh(uCBiPzVe8#bUwm&eq!#qp#wiYbJd-{+`-+Ov79k}$@KnEM030@;iIlN zNf47@&LnV&!=>^`2vmXz1M1KWu^pc@;gnrmi4pmi^Lrqo&5+|LsAy2UXxP-Dpm@XW z;q8uOxsOwRCnmvRE6GV$FF&}t6q|bY{EAxQ(1)Z!2LwpEieR2k5M%<%ek4J0kRTlh zNsljjkzj&=I#3hPh)be~1P){%*LUa_U&1Uuz0j3$ro;h9n^+d5`|r~qB(4Z*gi^wo zTwL7tSBF(J#*|+|G3kIblVGm@%be5Sp>uIDL4xAoA_+qZAmeXyQMf-SrqSdB^0{v_(u$6r4Iw;6G2oGXd4tG4mef; z%H;UaD?^bex{dx=(dOz2BwaZ@zWe;JN#Y#oF^B0feW;3Hc&b#6Kzd^lqVmyE^+h~R zoS2yp>Va~H$r4djcqgT?sKuMSo11*FTRj>fPvDTF?W4{YCvxR)+P@%ibHGAXTLrMc7Y99}l>Qc^Z{^zm4LWl>OyzdaslS&Vezt}?NLZ2D z?6$TJZD<7%bb}zG$=3<&zs>g@8~~^TIjovWg42i}<`c-G32buAHaRRjr7}D<`MQJn zHX+kHZDBjPGW@5ar_nYYo==pcL!xg#Y`fWigiOqh+c_T|k@qk{g0oIs#dCNOB3QMP zTe)*2CE~%uh=RWnrMDv}c{>j*BPD`>(sw_P_+8Mjx;;f>wsU&m6ujiREJ=3-g?olPpQ7@XKIu@dy>w_Au zMRl?f&3St*c_pH`yLnd8FRY^9-Hv|l$0|yRQZ$af_tW{qVD!gt(F1>?2P@tyA4(Cs?7@!F_LOzQdlPkEX#m|?J;+Ff)#CA^Ze@>45@jYfKu5Qs{|Ce#y*tdW4T}ump{|zt2u3BoY z9f_MYh}&4mCIJ8QaWKe#;@3f(_;nogHz>JxZnrua-qX|mZ;G3I9cHf!KT|)aQ}*+G zNpF2)qn9o;;AZNB1e9Il-^}7lgG2ByU%!O-2uKFy!<}+&IYUp=wt5>*Z4IkmI0buK zXK0xJd1$yl^5fs7K8^RgEO{v|Di)gkeyzN+X7V`?By+PQ2KxLS_w3JKAD+oAyyl@j zl9*^a$o#vNJjudE6~y?#9!>3WKisHaW2G*!+VWs>a8Ba{`swv4PF!1)8~VLJNF`@P z|D--KSoHoM7KXYvz0b0+ae1`P!W@7e3(Nb~Y1Q=b=*F0JX2W1EDf;*F&sW{kkNSQw zUaPB?{c5CGJ?@%zAitUD3Eu4GGOpVgsDkkbxKQ&CJ3Rij*l*8CW(#sdx3)IQG9)}L z;HalN{x~S);*#Nt^)BeMiEVgfciR@r z=2F_`puqiaEZoBpCkqjW9v0%su4?U0b|n7*iI0ao`l(SzzLs?-T=Dli_{#8TTRV+I zgLw66V|RZ~ylOMFZ{yONHJuig!Lz;4o{ilR7$>yNiChz-d|NSPHPjVF80h* z0&|%HRC?f5Ms6q#-MDD5M6C2KbZe`$l)jQewt4 zNxy!#9yn`W^XhuZu|(|doGq%|b@R@r_Ud__KQz(ORR;F{Kmt9V*$9~bw(dx{) z^L(u%GbosR@;WPkWCxw05yWE{Sei&?5U>+xb=~WnI~m=bGi_R_{s+r=H`pE zTD)0r0LWh9ThuUE)UQjyn0FKeKL%yfm=av2Cv;3qrN3;>2%LR;#N;k=Zq1nRt3kVC zBlb$8>CcKQ!L!%d*?&#%(6X=3!;VdpJGRTdT{k3;?hHmLQSG>qRC9Sryq*vrlOhVDr%GBiIWLmhVe8RC$O-G zid_jjup#`0@v?A^$-2Dn(5C3QytEsl{5x87*jzv_Y(S43HH1`BBcC1+ICx^Oz@Eqs z>XH?^1yRt)qgl?Kd#V(pi4#0ra84re!@LQoZ0B%)^KC;-! zFG2)Y>_11xjC%~j!Fm{hglxV;K3{TgC+RaBBKfemnG7aMbQH*|KSccJ1#34N1D z2+9h6(~nI&C{TV2+Tso^lW2-ZQ7CEs!Vs1!`LAd>4~$T10NDnF7Zt8~JXr*!3ll@@ zh8}W*;(7X#48e>UIS5S=l50&Com-cKGUs(|u|^pZp$El7JjaF!$pWhW*Z3$0q`1Mu z#Ac^pzZCgFyv6(Y@MUp!??s#)*&(w{M4rpOm)8bBCg=tNJKaBU-LGsL&MF0~oA>fE zcaXZ}3^!;H*iED~rQQ_;0adBka1DbZgu0>bGMQ(DmkJt5nQ)%VOU6AGD7(`_@+@k} zf$u8zk8R8{j;E;Z%Hjxzy8cx03a14Bn;A~l* z-ve`(;f5uF%*Q!3F15YD03P=2->hIxyUb@Wv-v<3R#tkX#S1`?M ze^ucYJ80^lQY2X_`Wc!iY8BE7Io%bSR10;)jaP?&BvmOq*;1h10h-Ob6K?1ue(_5> z+N2XM8}cPGR-yys(?5vIa?V%@qhUPw=Zm9+P<6@`huQ-70gryS$+T@r&4J;3rGwSFu5+O|$CN=N7O)t)5?mx_}I$%#I5fCHdTbD<*i9 za4wCEfYLJ#=pVA$NXCCu-K^d$@ANeDy{Dp*FvOEOkFv;xgKH+P@HU8VEJ&|k~C(~XAp zM3HHQL(MclA%EH+ z5#6wDje7#78NYajl7+d!TMvcG`x!SDEyx4!M0GlgRDnh80C!k|zTh%q)!-q&Q|qc4 zRc3eY7Xlw*L);)lz5jS&e1P&T|8uJAP9$`)`jdJ@t;6NDdQlmP;hAbtGjASHjKf;R z-?S=6c~j%wpD*%`k$XRcKCrd=d8}@cL`mN`Ih&%HIgdYSqt&S3+&ViVvO(`mbA!(0 zVyk{sd*8dXe#rKp^nqdRyy@k2dSSs^P4{~XH{y2baRqD>`Z@J>_c-sAyD|Md^+%JB zb?=}3Z1pAkOs!yW^VXXS*?ks?nseH0*2m9k3k#xBm;uCTYwNDG&yCAW14|OyOeLU-rW74c;mTEzk zT1%GtM3&}G76;sW^mw+8#35zRY<>1|S-pa6qaC#qJK4*EvDo7|W}Z0~5jj=`IW{dh zb`v=cJ2`lX`%cI2yLjGri@5JmaNn!tzR$${(>wS5By#g|H5@P4b59V}hACiRCIv;A5?sdu3@+f@!Gc@?D#f`Gx*vvV=2 zkABaBxoogKgX<28%bp_fJR5w6eY+%o$3UELiieX8z#P4U0T!$tWKDoBaLxy*U_ly( zyKyIzaff-a;0_hskr<-s>hnMw@c8`j-o)WuQ=vOKOp%j;8;S#OG?+T&OW4egQ0pOugO zBrE(4DgwPK&PP@R6;@n&RS`T{ado#MM6xo}pz@|y<*mrd@WRT-SC!F|m9e{(1j#Cr zK~;iRRZ?VCN@3NVS5;~3$*PRqDzfC0EQ2RGUQco(pX3)lDSY*$c=E}E-6s^u>N11s zagre3HIvnKyVX?5r}YL;8@--3MLumVeERCu)3(W{9lK9yk~LihHQin{ zJ&`rNg*APzYWgQ@26k)clC{GIwWD6OpCW6=3u`A|)lN^=e%-BQNY;HfsGIYun~$tp zEUa64Rku7@x3XKulzg^k@NC2D*;eGU?ZRifub#0cpZ(i?21rpkQA19r0Ukv~6j6Cv zseDsZfjufp>ba2Na}n?7Vo}ewWwaLwO)Oy zUURP=Bh_%!utCSWL6;rXpkLHr(Ar=$)o^mJ0V~yLV%TWr-DnZjXjRl`)7oe^)#$L- zh?jcdWcb3x`-NN73y-1~Uac>Dre2)hd*LV5)y`~VU zm!XC)Z+gGH74v3oBGQq3g8<^=ENq^RbU4_WaTMCw#?#uSx^LS!1Y zB0*lVFky(%+&Rqp+&BI;FD(W~m#S2a_w>h@kyrCRF^TN}Mw zo1$8qi&|f`wzf^RcI>s%q}sX++q%8mdZOBTi`x2H+xn;42KL(MQtiWr?W5l9pQ75w zi`pk!+oz}6zwWg&*is$e4Ljz%JLaQ07K=KTT054fI#vuZifEJ~=JonsM+NTn_GMJo z<<}*|*Beh?vuq_-ZBc1bw5sQ?;l(tAP#$n8w2}g41D!q;T4^Utn1wuG*Lhs91=0z+ z%;3I^>N;rDrRdY89Nnc_+@;pmb#R$mldtPYKS-7aj;D1>+6mv|h1!Jx`3!;oejLnr z`i<4HfOT89&2+bgPq(!+1P%b|1ezWn=k*XS1~iL|Jk5IRxBT`Y&=bIVdrrM4u(;>E zbkBw8o}ikZv(oQEYkIh-+_FrhTlCu_ouCyo_h06_zf4G+dN0waH_4|r#jf`bJG%F7 zac>%{H$(b;y3zY&>0So{;wY*mqUN1?Cn%rEox;~!X4F^i(^nDQS5@3sUED{K=5avr zV5qN)`roUTLLV%@+Xz8!Fd;4dABfW*XhyxA%OARp`g>R(dVTueNB8$l_jgWz_#5&b z2@D6LBoizZnA8fT7grDd|?9=%*dXe@++#0>Y zGQC?YdYRpj%#~h}`bXj7&iynYb{ib*+q+sbykyt=H-u}4FlZdYRm+YZTud8ii5`&r zJ&d%6NrnI#U+91BMvSS$32h(r(&>8k^!VaI3H(uV#-kH*;{RzeWx zLJ+rTTrOBxTpB{sckr<9pnmP}Ujo9Mzt@<9NcTgWm+2KxN4PK{e^3w|`@XP}Pli`| zTb7}_d}B`SLMr5sl<9#BzXv$AjFU{bECY0sQzyZEGNvQb$9+a@abC$;<#STuwmJANC}vyYi{!NU_d*YX`LIx#7&G5906*Wn}BF=kw;6sp=j zF3ta$*ai`0fZ}Oj7bAo$9xjRHGzpRU08aw*-EB4&am$Y@p9%Z+`^{WBf^mh*KAQU$ z6|T;N^M?S&Oc=-7y5%=12>=`bmL&B!lKI-tRTXy8Fy1P-aHQ<@Hz_5;q*!5Vlt7af^R106mIk@n-x z_e1>o0!R{I(!h7l3d27dh>iXdNEn1OXEgjK_CvVR_J{s5Mw3byD%Zj9HO6Jq5$r2~ z3KJPf0i{qt=g?3L0mjdS-={WnMkXCmU@WycD+;WR=e|z^pJND^pb%GO5!wXqb2RW# zEX)!6_MRa^+K=nDY|Bx02p1f+K%{|H{D2iYQsy`Pc>3V3-L%umAA#iIMfIVjV&n>8 zcI@{Lmk@x9I(w7>y5a}dz)S?u=G9T)qst5DIN*Oe_zd~IEGJvC0urSzULzpnX<%6f zV7l@P0W4hMR4fO;b_BSKI@BSA>#F^L9e*!e_D6w(kjuc&5B9w~A+u}-Xf+)X{*f!% zVHu8soIyk5QQ$xT3ShWe2Ec(Rh%^d;p(Bstx!EX)Bom1RAXbb8el#Q=00L=H?*XW| z08}0Y3&hOXVc}O$2xiG3@9!Zv{|`jRZ`teMqN`)`M!gAPXOdGbJu7a zvS{ezuXCL;AM^gLq6Y=PoTQ6ip{Gy=_L(q`5HOYwmn3i-qQJ6fgg^*~d$sa=0Gy6l zU4QV4OeD7^VOX7Wd%2216hR3kzdH@JCj$Az)E}Cz%fL`+XAlNGJYY zJ!331-v9Ga|LQ&idX$C4;NignP%9eb1{+SMFUg`eWvPEnXg@gM{SwBCEDdz@4Cp+b z`&tO_<{v!O4|x;~4I_VBy9#g(f;kANPzFewjEs@#v)F$(v9kG){ZR0W!%9*nV8+7=H)?s4E_PJUUjrC-~+6 z!6Mh+&{A!PY9Q;mx^L}KrI>&8ZHPj96xT|pU+0f+);Wh<>jEc+f7s@0of|0k9GSN- zJ|4C*H!-qsih@fNQ1TjGbS$^NuX%2A^rv%`e1{k!pl#G@L~jhMME z7=Yj<(}Emlu<<Vu@9AzRtux5H!)NQS}B|L{$Bpz6;_a z!IW13E-<&Z8h?5r!{f!BgwpOgm(eG#&(43D+`K&g{M=v#+jnZ~%5;n41LoXH^`|Iw z16*#U_hE_n%JQN-*pL32yV|Oo{$_!z^vD73iJyAn#}7)x>vz+-WgJf!Cg_AICvZF8 zGV|hYQMh?(q~yq-KOy_lci0x}mFxbBBR92~Sg5c|2o5fFlZitp5JfTp(V(-)cTY}nbul@1g&vp`r-oLPJGnww6}Eh}TP`P| zWzu~wnzWpj8NF5XT!E}BtyzB0rjTi)-Y^8bUstkut0HRN)CP zglJ=CMKc4ztq*eP-wHz8M51ttIh#$b_`~9lMo|{*y_M8I3WF8JS#N+Bcd{D6ZyPt9 z?6k*jIy)F{jyh>NsII@9DVtUs9*~|Onp=qJgGl@yD1d~6ZbNvutFVeTX2(k3y%|_6 zedk`w(*D$Io(ehS#L(qgF^)WV0uU5G`C`i}xMA#;_tn-hH*Nv-oJNmK9W~b>Q-3l* zij$^+lt}QiXG>9v`Ar_j9{#pzj48Qt>*HXG@c1-eYb0;dNSkZ;*(9l3+hG&!wkR^OL`8Uc^RSZJE6lb-C>|S}~j7>+0?`8stE9NEferDon|NbT<9i_tkFM zsP9Cd(5R#D%|hR6G%*7L;IaAV>ZKGu9bv+4!97r)+--Z9IyM& zvCQdB)ZhKvjQ9hxAG#;LaB!wjd~C%0y;G-^8%j=fL@X5?sou@8vkeblY5n^ziup$F z4sW;PB;z6fu)A?gNtQnMr_I^CZ>n40*vY=AuJrIgCGw z@d$4~W*dvJz>^+GGPW9Tf|VNkuc^sfA<@d)I8+ioL7~|1dy>%qUGzSOnFoA>ii4B$ zV+9(A=0A1VjC>vsG=;su@I9`qymJ+f)qsVE-#(=c&CSide*@Z@%Qe7($GbYbEY;yD z-*R}d$w4@2%fRk4SkE>&bDUjnCh*^MysNAG-aNE44*Id)AR>V8*n{ss*Ve;&e$yU_ zerbTG_V0=YJ-m|FVOu!$8hW|j2Z=t=w5o0ns_EBzc}Ac2P!)`WwSr%r zqg5FkCs2I#p!0**mU^}L;INIMLtAv%f%HG7C$(THf8*k!e-CPxrU)d5VK%q_DnI!3 z$=|1`Kp8{bb&72)Tw`^A-P)u}2=KV9t*yRz@hsL2y4MF?AJ)4Y2n}stz4MFZ^I-Ua zgWYi*t-G%$Xipqv@3bw_#P`3!z&6GElhC#IhZsFN#?SsXl{$tGvmEZWH5HmUS|0v4 zcHq1&w5uu2sIdR4kK*o#_}=aw$A~1IH2OCsDcQlAYC6P0K5c!0c67}7yDDZxBK>uB z5E-M#Ub14(EA9@6aX3&M2b05uGN@kGt>4qH-WEV$I2Pn2t-E+pN5liG?~hF)qfZL? zDNEBh9^%PSEC-*oJ;~tUmU2mR{gW;n1JNJj_uyuEO}CDYBqp@GH?2uWpq|e0BFn3F zR^}-jD>Fz4+dnR1&_Ut2gaS)6jupsZNHJ_uoIKF|^OX4wdUvVj^A|FL=2^1a`S)2Z^8uh6psc=f);u(^xh1$m)OOH$C-exb$Vog+Y@uZvGFyspfw}@Bg-!D~HSO=nvKY zcl;*%O};>j&xaZR2fxWi&dS2$WtqDLS^M(;Y9LNI{CinN`7F)>HT;)>$l*72=F&LS#V(FkG@I~|HwMD>3`(nl9x>-(wf&7x{17_AzGc-Q96g;R43Sido#`9H!ZXg zC}A@Kwd^-1Is7JO$=44LGsXA8OVX<&|KIbQzAD`_Q{ERBykp|_Y4(5QHwB)>{x^P; zzXT+VmW}dCIy9dzIiQUaH<~g1kAXN5c;f1R@tgi*AR4$~|C@mrAGy4<@W1n$f@~G? zpZ|y7^h&ajt*`bUepBJNh*{8o_)QhA2wcvsz9B?uMfFm(p{W17RaHG(?N?2s@_n<~ z=K1Phb!}Tqzn; zteUp@+3!Y<8RR5ZYHK1$LB~W$EvIB_D&*ZqFR9SaGP=g4H8sONa%?t)U}dFq-R#?~ z17EMG9yYJlnMu-H(Kq2o6QDvz9RF?q7`=rC=8JEya6aW^&E3WFysNuEt19bumugu-duG2d(b?ZwW>^%`?@8n71zGWRy`H-bDkalk2!Kn*_ zeq9H9{JOrm4GK~-*0U!jI0TNsAN3wbtOT`4a$s)hA|J^~0oQ zK@^#8BL6iAsVV(kZkH)@(kldz7`>j9XO@DKIqH%qA|kJ*XocTw=_Sa53qzP?j{KqR zw!5=(U(KdPx@bg?;-QRBa|blFo^;1ecM3@RVIl1ZBgN|Xa_{!$RCu#sd`v$fRz3+# z1^{ho!m~sGy*hX2b<5FXl+a@cpqJ1`5L3JeNpbi#*Sa4eHBQZpJn?@o#XdNAxx% z&NaVF;u)P}nnnkI;Gh= zZx%8|L^A+8=20<>VXBQHKO17#Yx#J9nF&;$12fRO75fRL^C1b9wy{*(ux;DNSq2~@G8}r z2;a=;ir1TgY3GCCV0V~=9SP#%N9tgg(&sWdo!n6iJ=`RMx}6D7Wj!l05CS-k2=cuw zWAc{4C*q8Z;P&J$>@)!oq=3QpexOSm4j{cnH1AUxgpdd}Kvr5BqQQj~-T6wg?k4~l zwWgx~o*%W0K)0~<3E(VDQW^UZoR1C?nx^i=11f( z?IL-Rf8$-e`hGsgTub?1?|l!KmAxi-4p3-2CTxkM-4MVK*WJK3zgGgc{h)9ys0;OY zn7jK$fV1HU+@hI;_#?OIa3?fpV-c!Sq36rd891X`Fl8vkEw_vi?}lo72ZuP`zKsTU zP&bGEB2gUd+a}V}&xsv!zV5R$=P5GI^sG1;Mt>Qb$h?k1$KKKdNpN_#G|(0uR0IHF zC>~Y_FsjQf)(bLXh9uFT7syceked(?Ny#mc!)bt7qMWH5p#C{F9m&Q7x-wxI$^p`2 zU=gMsim3(mBarVW88Bfn;*pS2fQtq{N4X8@)Q`*q-DWe9GJXj6P2}P&)ESzi+66DE zW0#_6a2-FCMM#{8Im%}ZZ1oNa^;7c6N^U!^6sn5~X6hXbIejTB`KfsFP%=z{fp8Pz zW}{>6nj^SqfC&XSLx%^T4nNRG1#o2XJdk%)suM@`p+?xDxWlj)H{`mu83yh}a4N=d zU%C&n#saxnC@30C<}Cj)!ABWLvMBdui-4kSWEca)hfi=~#z6&L5d;uNl)aO3iOnfP zDuY9uU^??k03Nvw$4?-D5DWyzPC6dc5KJ;bjF^=!gQ1Yx1-2glva4z#$7fIDusqbzJp!H*c@-Z1`&jx z_b9le55s*<4}Ld6?B?C zhB9;jzgm=n(L>l3#EbUv^0M}^?>I_*Mq*Vo`L9BtDC~i z$E#5yqW}M4n>gh#DG#l2+Lh2(Lwz$DUrOXosDy+L%1njxMhI8>gt{Ck> zXb2gzQ)rRMHIvnGq-;+QTLixdMFe2r=+kt;Gk&$B9#n^ztr1!5|-LA!x>wo*ggBi{;ng3GJmxgDLoe)8S$Z{d6 zz|80Hnjv^u+de22z_YR;(-)Eh;v)h7&|f+JM!GvUt5&JB0W+oMnoQ*ZKtxCYlOb=% zvu`zpAXre@q5uWRi3*RI9o~&3Z_8t*BM8u~E9mkhM=Q>^4hh?5%iA{*%G`;+b9mw zVBfKbj!wZKcIHB8_FsMnJBWbVhal169ItWoU3EK~#njS(qW&A3XRc?+q$bP=|M&I` zbuY|bgh_FGCp4xJAtl3P1O5v`2ckBeU~W%8ZmI39_*>-Ty%Ff@cqc2~D&=2W9su&Qfd_*Z(Jzi3B%B$}JI_MK zRq=9<6v`)vAhMj~O6SFuM{rq*HhCwUkqZ3qf@_Pihle2RLb!wQsV@a{m~xPRd#l7z z4iIMC&E!JG1A9f6UKmwEIY)l4X6Kz~Ia+&V7L`#+h3Sr*)D@*2b^|44NBrK|)bd)} zlgX=Ob%N~7Bz64=Nc21RxGGF=1b{pYb+j1)*$T&O36Op9#sDhm^b-w=X3A-5H|_hP*OD` zZ_+RVH)KME15Y8KeCY`M%rII8)>$W@Wl*^4$3)ePy!8M416eoSI$=W5?pN`~zaO9- zPuCS)+j<$;i;*0kd~r1pc&_M(*~dH-wcqKdEha;9{AEzwQ}-9p%bQDo!tefsgF7ds zsqUeF(I-o8T|~&~ynxGGM#m9&!=l-`7#+MQsQTyiqI;6S=7qX6gJ~m4$Z?Oc*aWc# z{jXB7Cdrtz}BrGeH)T93**SQ0?3ZtMnP;qyR&W2L@0!Yyq+t+ zcjf)xr4Oqm`fA-Xpg~9YTWTuxwQ{=Wk6CwMLbf2-n=e(G4I>6C^IW=I)1VFL(ysQ; z!BGLh40tu8$eHophG|R8xfJ^$44bpZ*3Uc&Ef@#4f=&MIXPme7JCXhQzxVDhZRlMC z46od>BIn4rc8vVJ|CTy4O@nTknJ`b4(#`ALE#j%l@%z&KKDpUBQG(Fskmn%i?4`S( zQU2S0r?L)AWeY0*gh4yEH@hT zBr0m=TU7`@NC8xLdBM$jVt(qqavU+o)6H2S{_DTG)75vZ_7OjX6J35QEwYY%&Tm@s zftEgdItSji`(F2ded%qSyGsha@BTh@J;R^=xK3V|I!B$K7~|A`)!zHfugWcpNPiw@ zB{uY$9sjEK4wDk(V|C2sXC+n8gt5HmI6JY`A}DHw;n$Epcj4`l-dD+jyPIzgX5lAe zceSVKv(LKeKj4#2GtQAA8*~22UHbQco4KyHCD+$Vs_AX}D{Aky`M1BkY$d3PrETxN z{ApZBmCnb1|AK!PRF!~HM}N_mE){>p%)EEh>Gr`e{uN(Qem}VQINs^Y`{_URi?4&C zE4Kx&2mWLQ(H?&LSGe)t^{3n0rK@2se>TScIYJCM_C-F|j^Irm`^iV2hWR(_+t>3><*&?df+`V1MvwqcX(d%)F;mr>rA1x&qG(BE z$X%t_+~e35@!CULz$>jNb=+dR{~Iy<_*z|Icqq`|z|m;>E&_ z+gU#r>o5$gM_l^Y#q zgZZc=QasHFb2xv4_KIBU0Z}nv8r0M6FJ`f-O;_Vzxc>=XIl8v`jgm*d5II>f`S5rGlI8AWT@Gr9cxAP z&(*DCVfK_7E<3a&6XeTL!g*fHCUron%_1b{V9=i=h~uZe@1IKGPe)?mo1~_3U^ps$ z?C$RY_H`~J)^{>-N{FDBea1OkvuveZV(RTS zw%R5)C}CyD1nk~3(_QKjcgUT6qt-X>Y|$po(sTs}drHH{(R1~5S+$;>)UpTX9et#0 zUHt<7+Xt?|{@s6v2owo2oN#%Y_lj=?CnDVbXj@}uebo(s_dLU&mRrpyG29Gb`MA^rzI|d=QkC;KFO#6lhxMl(8SXSh*^C`@y4P>xaQ*Us?<|nX z9g4)1j@1``QJK{3F)T1NMlt7$l}^@loI@R%fzu?zZQ>R5*VzG5$MrO%QoIQEoIW@a zdc~P9i8GfH0B@m*?B(0oN8|Ss423F}ec`-S?DSh*@*;RcYOMT5nWP>rVw3$5-uu9= z5ZPICH1tw7^7giHhpz66Pf`lJ4^O4s+=ONSC@YL3#>tMsij*UZP;0;d${olzPh~OU zGNW3Rz#!z2TvaLNIP${PA-rTsFQYYI{TlfWcUVN&NUrddjiNe{1L^A|Fb((O6bzgX zk!KZ;^vs}*kAMJnD+h_iw8KeaWjh>?>M9Wxtu_)OGXqIAsc_RZLxpaO_xqMTRJw-U zV-*S_HkM>P);4OuLSIsIG?}>@yJJ-L2*IaF(loZ2Bo1XDIzt1fIASVlbKV2?5^KWB zet-pD2iUSVO`#mJC{Mqa3WwWaP6Znr9Oe%zzjN()SyO>1!DAuGLcSeQAG?wWf;mXg zcR`jh`-@2iPf`Wy*s?P>(#F(wK}MQ4e@=d6gY27|yjs!{)Vv~BtoU<0j~PD=GY~*k zb=BnXOpZ*>DZt8VoHznE5U?_2AHI@zIJS+DK#sg zG^ChgpYCQ65}K$U#48+HYn0CuxS6%3!sR>3Z>)yQP-3j0NxZKA!E~~>sC`W40$-Vk&J|emT(_h}^ z`@Eh*kID~ZACH#XdG$u!0I{1onM>qgya;mWC?O^+d^-Uup*xD%&FZOQ)Q@2<#chy% zbw3EO5OT4k5w2Y=2V$8>gS22SZPGRt^bPuYY#tjG|E)0iz2741pFeMPvqY{$<%e1a zf0f<68>146WT>zC7ZU4YV33nviRO#+D&f(j{wdUaBBL#|ynv?+9h8Oa93BCedSL`Y=tz0@q$A`vXL{CMXFstrEd{y};;7_EjuVzjSGhwir1wgu^ zhOV98DYl;C9M<3kT);elU0P(rZP{Xl1u_pg82(=CQxBVuQkD0#ewUWTQ8ZY3dgSt} zHrFSw^80|HPe#-7;H|Zc_Hdz$IRVN$LEu;;%-|ilft5~14N^r88pn>aO8rTD1t9(y zLqqSS*$Q%1c}i=Rk$dT21^L0UObdBAnX8wH!TW^kxJGwP^l4ZZj+GAWSU8}kfhJ&r zk5FeeF}sFvyQycrP|X*1jf5%7N)FLGtDn*|slje#75xnq6gu*1=ccA5$lAZ)P_i;tzW#)^ zfvSS0StujmS4+o^{#nFB%|N|ywY}|^HXd94AHS)pa{V>Z^gS{M2Qn?UC*O3k5y2pB zr!R~OvT^rvl#MU8-r$hHmmg>vmMitBBJf|M8o8-{QnSz$Y43k@=?35B_JUG@W97`dY+2lO&BU%)Rqo3UZ%mxeXdem0j{p z#UfB6PFr1*Xtj2$_H|nsve(7Pwc~qj$GXi%?f>zc`lUUIg8YV!T#~rNQ=?nf!_|u` z?=txB0P@>mi|$hzsRfE83tXZ93DYs>uZ_A+9XJh(uDr!QV@DmUs=k99ZSSh?f+_l@ z|DS%-_mcOm|LZpmZi!)Ul>8sR>1`)3(g2BOL1O>cZyG3yKJtJ3rixBO*}16y@ta%) z+rxQ#|6jjp=Y+xj|M8oK!W>;QWPZ~TkIZ6^tU8bEj{n^fl_fGAQ8BX z(KQG%ZI~C7*LunPrkkQu$JY?BSW#ctz z4txbojvf^NVdN=D4$0;#5iJu(7)WKA$z)lxSAU9udZ=Ri$iGxHIxj+|jrd31zZjUbZ`X*$@%e zEEDvjPT}dY#R&art=WYI49AAdvlas|s_a|lp^%;GY`&49a*6n=;^yir9NrNz)6i+` z4P~1+{>(-kR}X`P9|c`lK`=(Hl?pGFe-r$U1+Wh;{at3OFIrpoa`*gp16sK#F<7c- zjogy#UC{YBhgzObFgtie@Up}HwHR@^oXcz*U&DckiW9vSxsu-qXrdp30|{#fyWSC) z6m^x0x{7XE`>`R$6s3*hmKMTtbpdAsi>>Vhu`q{{Yrq?*FfGb`Jf^!0V53Ci=AN4h zB>b0=0e9x~%%}4${z2O-2StAv3@eh``zPNQN8=1XD;~M(dFRf+9G7*#C3XvN1a}?x zfp4IOG#v&k#Wsc{o&}4oT*J?>ft1J>KvIJ-P;%jLe)y!~<(NvP*77HRg0m+FRTJb` z{?EGcm#>m;coLi@{Wr^JUO)bREL(!*NcdR-m;n=jl6VV9RiX%xDiI*okD5(!JYr8s z2{nj+8X2ypq^gEVZ4asZ&*Rp(dOORNBjik6Q8@bf);)9O-t))%wm2T879AS_g9yBA zk)tx3ZJEgn6(guqT-eJ~8AV0(cIInL-Jo0((7?%b3OhgO(NT`eEmrsx2+UR9%@R5P z`}%}2QTu1#y`@H6`J57W@j=nlt4*^-{z+R4sHe~0iO8Qe)Wv#Icd6w(^p}L598S7OO9B z^Ki~ZixC|ED7r8w;Kh`tGrl#g1V%2 zVUl))n%hO&+SE}0wWRw#8$u?5FHUn!YrxXnu#bapl;JE@=V{G`>dX-hYw~%03SWsO zZwaucvd+Ut9@uB`+9#XGKkwipdG9HJ4W>v-0b)FtpE;}zh}e1(AdAQQ=cMm-)0n!Z zSnSMm?7WZC8asWVSxCt)l79N12 zL~LaN;)sZg8{r34fEkJY+n>ZToM&f?5cc})gx_374>thA(HI8Te`71*c;;m2b6$=ZbvOZYZG z0z=Ymrz6nlJZV4xppy2fwh8-IaFO~cd(yo5oJ=L-Ngm^W8D0RD#9vrQeo#NZrT2bG z=Q+F9b4hIp=Ui*EJ-I}H?=>=IBiu|O!4$*J2a#aLodiwb+2sQeondZPD;PyNo}h`0 zG(08cBw}(XY>i<67i{c(rNRs79B$eDA!mau3%# zfQ=dkOsRn9V!rt>_-g!KL{2KmYRL4I@{!?ueXt2pz=3q`G#!3n>j^`SfKXFx?-fgq zi0zbFiPS~*UCBSRAiEer7aaENj(lfwmK&P~Q5yvrZ{nT(Dgz54U7RiuYj#Vx zcu(Fw(W_CO14F`59|nU)E_q`BJQa3M?5j+ITxRp=H7w6oO^O68rDj5Ohq>zH(~z`E zCPhQm$K1L7ggu6B8of(Kb>b;dh~a)0=>gF06UZdW(zxy!cg-Kl_ZAOV$hxM>4b-3I zReDqnAK6Z0bmVjE`07G#3@p708M6)jqXO4&(x9tCJno*O`0N^s-xO_OTYV*IqeGLH z{~ur*cB*zqo79mg;+J>`inG?uH&IonsZwqu=PidxfnZiCdv8e2dO2R~#aUpgo& zv%p+iT?h25?eRc~S&_qE z5+mgGkCLDi>94`%6S<)oR;ItWm&NlO!TV*sK2z=guA-$CwEf!*oaN*X6{OaD{Op|Y zNYE9k)s5PECy{dPb8XCZf!ePV*)ALNpOuGh+mc6M9K=_djvy$d{qE4rx{#vU^yZfZ zzwR{*i|<^{_;od>XO3v&`DN*JoDm;_1BLBp@J7U|rv;3}h^tNsB_aS4p>s14Fzs zkwWrYtHY47LEFkwh?%okaWy!ell|T7RwnhzmaOeSg02$5%PX8PEDz#LV?q$9~ zaMbLuaJcrqM0wG2Eth3`v+U@#o(rrD$J;I3AQD*W+4seCgzIep8Qz^JX#Lhy!?`1` zUeH?0q{51B4)z^`_>sW%gT5A-5GskAbe_nl6+kY4yhmDJ*FMpCE-)W)Q8BuWr66ff6r4(_|BY$*hJ14ut9T*V@Bkw60>H4Lz0ATT;l#U!93 zamnC*v8Mh0`MD*-VWELXg+(HB5OX+zT=$2lH-9w1A{4}=yLY7- z#^&s+3A${vI0AZA>~>$PRr1wiO9)FzC;T||lvh~P+#5=kC}MP(aZ_<`d5I7LbHbeY zDs^FlWKX>un5HbaguTofAyT}4l!24fXu=E)-)XeVYHO}CFrT!v%`cq%k%N%cPe;-W zm@y0@qyQs_|NT$(s7?@b6s(a-CctQ3@zg=Qkq(urBQQM_S`;7*mQcR zXrP#BM9-ak8Xgg@Jwk_%CIy|VTQ^N->MJyaVYEjlr_mbzclf22#rmbY#%U#vDIPgC(YE6g=y^I3zM4%eak8aUk9L5+>1U&Kt*j#V^R?!Zj@ z1u2p>9Az0AzEEUvo27FeK+jGEwhm_lF3p0)L3wv%=e2m)>NnjKX`~O+S<6mDoseF* zlS0z^X!BNMqk=PKI#=r$Wv1Z3#P_&j={SE|fW2S@uQj#ERcr$=jBVa&ePxKfEbKF^ zyzPJ6-r)$Gfo))9H{V1`4+ClS0}?By7JHEGFyxg^{BCi zUXx$;(TB>0-FW1f4@Mz@ThiN+|kz&?)?srF@2MjZqRBUa^PO+!vG z7gQxQz)mj?WRENr1lAEehxx9K^2kCxL!=&W7-Qzm6y`Y+4OH8PtDDOUR%%9v#ssdO zD#U^w2T$QV=YGyaTtWQJY3hP?V-~YQpDjjc&()x9x+U~O`s3Qt6E%Il$^7G~$+Pan zsR!K0Rzf~w)Ny|1k(HdDNZ@ii}x4g0OCCYwCBDA+%6KWkOH9RJa9@Z{s8%U8~c%7qqs%- zjT(^ZKG5dy%s0UnH3~*XMxSures{m|VP4aQ&BL%ADzh7+8sp`E$UQ3%Ce_q?#X4?G zeijR_l%4i9^@%eJ{C=UEc(}t;Uw-to^~}TLKF}s;KSgM=;R@y;C*JKqk_XE!rB)Bp z9C*}Wye;5r`}RBSr`o?);AydYkxNt!tfY!52n6Z0@;nvCq{AUQs#KFY`lwx0_@&b{ zP{Z=@4!`mZ+(ZyCy!_>qG5$dqx1!2!&@5K<{M4ZJbEDG357dUQ3WpVE;$4!R49x6{$&G;A~1|ny8&*umB>l!ciKwB>rN6u5$2EfpUpnFx;ay=?d@}qw| za8Fr+mwI(t6<~|p@ zygccp0y1o0i3GI+?+J0Xjghx!^;J7iCF?X8SSs}sS2qB0?3vGrvv`jm z@426%S%@;WM(3>X$ObjsH>k9ivIXfCq`z4AEx9a{Z-C9U@br62=8;L_+fvaqHT_|E zLn4i^J4vPMdCGgM${UY&I)964V(RDdr=!T4p2E3D~vEU45zdC z6sW714PY06Dr5QR0@)fcdW7!yr2)MVOBhYOYujRT;j^zE6k^;oT$Kr(eY0XU2nUI^ z7L|+ODtyHG6%VuFMYOlLx2fZ|2hQa?+7Q>kz_ijDGy>E;UZ`W(0ymw)s%Sr(TQ8p; zyO#40GxxysdwE9qu)-JNm28%VRKF7VG(OL`#Z3pwQb|t~x-bO}rhr0aj|KRRByVPr z1&(B=z}M3Imat7AH&56=D>E0)xFvzRQ2L_HQg%9*I9*pS1QSHsD97E?@Eb3ySC8Hr zUNhWPp4h)10nXRnQVJjw`;px@b8|+hz#*|1`h{Iq=OaQ{6&cV0W}bD;Zk13^$_Q`6 z_Xb2-+4BO~E^QpW>IK@pE3x0uvTw8c3ctha`w*z!d^EjxOTF zK|3A!Q=re~hP~m@lCoTUsy`XNsF#qqfnSHYf{cX8+QK z4i7&bQu#9$VoG7)*Jdj3t$lR45|bmXp&mYP`uOZ_Z&QP(U!}GU-+f3nuh9Wl!9Uj4 zr7pn3e^!DAjPH!ooz$cs$~kw&fnzA_=sP)%s#>{@3j=`85G#VQOX2_YS3i?H6?2xq@y@;#O;ToYm_S#vI4_xcw*sa zXxH~ZefJ|zao+Bcm&0rQ#92i+R1QrN8$=Dn;XNJ-5LqKHU1XzDTc9hEY4=oW==A(O z-NKVLi}IcuH>yUJr@7)1Upyk-k0U;)0N9nGwN4v|jHhv*lK6Lf@BfD?tWg}~2hrd@ zeOmFok!w7J0O;M}YJU@|fzkCA$tfhb9(8i>AOjb6$8uPlE)2gV6=t@H==YJB3Y)rW z!M~QO5PU=d%zxB_;onG{9ds;29vR&=TXSKBF%bXqdrkS9OxNnBP@|RO3F$sYOAtb0 zaKg!A4pJOd)2qfrW&Q0}cmoGAi~a5zMan;Y5|j4?>r z(mzgxDSb>-8vD!p#4gn$0U9{^uVJk?S30EXy*tZ~SQGC($Iz!dqprQD`WSgI*}&Xu zYIpCEB>2xn^g{Z!zf;q-@xZ2o0FG^ZaOW;7w}Fd3XtaR(M#8{q4*VH-wuTw_i-D@9 z%05XSqlt#U4O;7{JA&DTEgw1OJE5jBU@i|dV|&$okc4i7ojpPzgNiajDZa#<^qHyk zxz88U6q8MIx6dhMJyG>C`EKfOYNt$R2kHxTS2|9g)ydPkfQ5HKQNKMjSN-2u4XFM_ z1cZ@Fp0}Dl;qvrum#qzlbpnzKUd=3R`s#a ziH6lIP_a!Kux$uh+e0#;C3%jp^wX2dHZ=O~z(REcx4cxr$~~{TYg)IV2z4+)fAc#) zw@NE22=6w=!M}*v{MogtvNU62d$Uh%9~74TS*|>(Zc}@s60&CJfUm!+-;)2z$Y#BE z4?P_D{2)|m#%drq)cj`4`I`q_*@`%eWp5f$8XB%XpjJau!GbTQ(sMIls@l}N3+7^Y zhu9BV`WaWYitAS4r>a1UABYbsS`4^b479&=?Z)GJUzUxA-Pr4?>HDC**CSZH4?ib1 z@$Qg~V;Zw--Gl|L)eq{uVfQS9{AQnIYC;1;@81`7JYDFJdTCwV0fJaq&?acSNe2A3 z`0+f>(OX>=Iz${%0-Cr8Xi96;1Y_Ca`Og17g}rff^!@JmW(X(B z$BQSdIeV2W(^Et7vy^wOSeQ zns@2%+e-#%?>w*sx;E>qikX|;-i+!1ug^)oS)?HRbC)?rp;a?R7HLn-(*xFZ!+xvV1tGaLBlb? zNk?yCgrK(m$nhk>)VDY9iHbO=op^!Z?hpIYASq5K#>c!6?F1Vkuzrk{noOe#8;($KvcPpAtZ<8(oviKSs zd0el=R9ku}yY!3FgIALq9{rhMI1dBn9lcZa^euNK(q;BBHU~Nb!B5d}H5_MD5P7f< zm8oXxwwSsfn(*gEziBF4GbnOT_J{t><`0Oh9&x)b}*HnSNUs!0+ ztorgG=5(;@ij^5+N-A#_6r*%p`Lk2Wtzr&dXvkn8ozsW(Q>pN7F+P#z{3c4TufZYX zGf3=)(J%UElY&NSA6C{nBkP_a$!;N58q*MhEdV2c$N>!$P@io^#r}1O`s|agb)F## zHl+qFt}f8>VY@KF5CVH&&n$KdqEYwUCs~#)5Z}(r(--Zh=w0<9o~5}CEK|AaSdLMw ztD$o&(QgJ6be2Y(e&UGasxW|R z;vBj|b4moIOn8~ojSP&QJRkuvZ%Pa&*en6N+#91Zs52;GkjTCGMNf4mO0$7mCI`)2 zltv&X#C>6P>H^i*?&TeBgR;&XN7qFkb-v^Myj@kfNTg-J&`-|^1KOL|>7%{LyIeOI z45AljTviOongir(+abujBAtOkYgdSNpF)#|jwdLN*#`;&Im_-@Ys<1w$rAZ#9q2pt z$Z!yD+nps|^yn_UH9Mq(rb1*gPn=qI#-CR1Q~PFpM4PS<$-x(mU${tXihSJb=US{S z!-%{g-Gks?HaKjiMa^jCV>W3CfU|lHA8pEg^uX>pQGk5wo@lt~P@FTnk@CfcHaD~v zJFrE{fUvsUJM!;3dMmhcQBdNSDg|Hw)hv19a)j~yHmLhxBY;7`hN&Ty(ik-y-Qta+ zkSUfIsSzT3wIXR2j~OnW1^}Pq=eCH&(ESM5PgXQZHwdCF<}_P+ZGAOnN7c}N?~>k& z7H@~7(k#A1D!rJFWX??%kOG~2_BS&3S5}?GkTz!+T>^F4E{_oZ+?~j|P0%eM?t0@l zV15_?T>G*Ysl=X@b3KD!)_6*|BFYjV1a)8T^dMG&IqI?H2S7k48|w*zbp!ZC9)7}I zVT7w*GQxEIPVY$5jlgaP#&B6hR3-o+>O*`$cx`!;p5;wxw(8>QHt%v5S18(IpZE8h zXLjB45}b5%ZJI9CX<*sZRC&QgeeMTmJ)FOf>>p^>mF};OczETynArIU-vQ8uYxi*+ zAcAb+o0hxeXX%LUo<_>)j0oUz zjt4H;CRNDZ>}KW>A*j|?R&UZ*Fu-N6d-q8r!%&-d;jUhL;ph>HxQbPHx-xq$y@;t| zbVK`t7BQjDPVhoo%q*teN-PLUw*lSf;KyD#`d~A z%Fx&TSR|q!(P4*>G)kv>6__B^H?`=&q3|=P3)*7*1kXj*nv#;Ij`2I1y9^)-Kl1 z<=%98gmrz6S#!gOdO#+~xQMr@DmG{Us;G&HdUMiWpr?IA>W*OvX+ZVH$n}%{i)cf4 zZ~WExHIMga*g2`zg>@saN7c%xinSDSJRPqOFqiv>Av|P`Zr0E5tE!3221bFpT{bo; zpn2=bO&Pzj$w6&_ZQHMAt4UL~Ux>JI&~2ppoVE_KCBBL6Pi;E0YtvL_jG-DE=dk{l z++T18VK3itSBm%5w4rvdSB!$xs#|B${bHK;H~Ta6vMIO8atHYDT@i8?(q+j zI+usg@3i1ClE_|Jl=4Z=iUdgPJ22n^x1(Tc&W`PB$ia@iqDp9%p&uUQ)b>(%S>Mm9 zt_+$F00pOvcTj}AluJ=7xlW&^U$=eOT2w4qO3U`5c~mNG`qwveeq7HP(AAUfWtYS3 z=SlJPFBf~yVE`fUxY@v3W!mC1u};`0Z+RQjkCI`}{Yp-2%+}CN-iAa=((inPvV$0@ z=Xqodtc0*?XAq^uzb~5@8u#>YE0hSHjm7q{Z~7X|4IIRF#Wk3@GfECqNJHvM`H~*h zEbU@xY2TlrdaK>TNfp^23z|7L?mcG(Z!-JNm2$GVvx=VX61v_|5l?hK=i}&Eh&5Bc z5rU&>2azaW^syZd1I79G^{$JERk?ky$IgM5He(x^{D0eW<)CC}V6pK^TRndJnn{V; zG}5Rlhk(1P2z6>dH)?y0vUKLOpIg<7sH11FSCWxM4DJd&kej#$HI~n5AhweqO2f^~%eJ1M5mjPWkd1-&H?RZx1U2*L!R_ zHCMkUp?y-lW_pNg|LPX#ZUieA6GT{GyM<7-ChX?)Gew$3#WgYs8< zUozFtZAvyRQaCW<;ld2X{u2gMb4topF=&~TS-vp_WlnY_FAgk4*_lv1v#mI zZZZFUA`De1?J550?%Dm&kRcL-pv?Sh%KLp^G`{%p=3B1vEaQNG*6T}@7p^N$7?hyM zr^*fc1q?D<&bh(2>gT3zFQ+BF9*58$yH#rS*9@^63g3LFs!=XPaTFNe^sdH!R%Rsa zmY1Pxwryd)DN(Ba@?vo-xdQ&}aZ%prW+vX;7No>-RjBkduzG(G`(u%)s7M9UmIKkQ zD$S1aFCW_9*birjWlw5L_0I)iuIE|HrizJTkimp1B~>K9hoaac{JE(GlF{>wab3ixGEEbB*{h^BVg{Pfi&b`_{?N%4mL(1=I?0iMOn2LSs%N^ z_6xfC`}{-)NpWP(Lujh9~DFy@;K?KU_=P}_zkP&6HO38=z zKa($ArL&hx7q6PMyn<}w)s`O<$%A!-ty0>|ssueJ^D+-jf?G1C@V>L&GSv_7o1 zbfrTJdxdy!WoDVr%x30?0z}UUx2~A4_Y=p#A8hJwVzI%D z-iLiIOc9h~m-B{F<*XPSk`5;5-10;IE z)Sev>ZxlefnpmX}+0O|JAdR&)#>7i1H!x zmkFOaO11=)UsRJvs$x~*=P{BYAwWSQDa!_^@@jItfTOn^09j0}Rgwg05p&e%Uy|}4 z?(0+94rhwOXCFU>>biaZ^ za8}kgvfdszBaJlMx3YiF$+&GwzI3=Ok^!QS3-C~t(ziw`TnZIk+%@vV*^-enlPg;RfF4pKner9~r zygRR~f92wr=##E{wZ51)CF9L^$dYEl4Y?XfDv}xY%cbYWzYZONPERj-lGgOWV5r&G zV6tqRgn5)ry0`T5#rn_6bFbUqcz~{{D})_q-~w$vSf0#!cvP^ABd+Nf>J7=OZ8&=x zk_tMvLAQ4maXmk$Cx+4mGm)VE(+LXUsG7yzElpfK@Og!B0JEr%bq62-#>^N%VJ?!M z0}6{=LvkNRQzR#3!z705QqQtK0Zdqku(k$j_*TMnZ*naZ-RUuKuS#Zk&g!XSNCY61`tBZ<|qt3)$#bE+VEp>Q*fx-fQbglrH^ zA^sPBso>zJ@Ty&L>#Ye7A;+rDrY!bGKeaSn%iUkw9E~z6W|7XdZ#)W4ZYEq*+B%Be zmbMf8Af0Z+?!u&ov*gz<99}YFGTVuKS0I`}gmM7xS&ufgU*%Di z@}07ql@SH%wAn++AJ4Y8L}TPhwpM2>;AR7tNq+rJcX=wRbmR?XeboT{=Kd6{|B;b$ zGg5xJ(wHgba=^e&$N0vWH}0hb6$TlmuYy+nk*4>+xO@Yj*u`v8uP}-jGrGYwIN5KU zo|MltHH7Dd7yf5-sKVs%m`P56c}oY2uQ(m6LMl@+tqd^D8v7&2g<#nb>Wtz$p?vLr z(@QGmR|3qhEaB{$Zu@O8ER-lbmB^DyK=%R7e^Sj~R9L(P5R>jv7` zSK4f;?9bb1Siui?`&ls&;%yPHh!MSYth9?5w~M%9*I7;nUo?qgZ=7!fkwu@^VsyV( z(EDVsX=c%w8M~r!N}1}0X|`%N8!(zRJv#HKg@ElOd@}f|x0B%Y+u8x%i-bxDzhTJo zK*ym<$E>cf9;&5jlTxc>6Pqq?ficXqgj*1|2-z0$M8`*gF25>Www7yH4LrZ!h>T~s zC5j-KEI81s(%cAvo`rmDaxn~|o7lc#PDk)_>okp3#y>@a1#}mzE2Gs1-# zb)w4a)P&a=taoFO_qi(X^Ap~euv@PLZM|N#_147Jdsv_TAfKTspGOlu&#=DZLB21l zd|yxazQg*x5Ayp|<@fJ|-&gFmZ$aCBRc-q-u}z9)LV}ryYNo;@6Rqa28tku8?XNZI zucsDZ7#v_y9bi5guu(10COFW(I&jNmpo>}%BRI&TI%w-;&^EQ;KpDMP9UL(k9IduJ zE_nN{>g_3$+xMx390(3MR2_17G9*VWlouSDUmaRB8Cs?mRv8?2qB`u;8;Z6!E@j?O zow%XN>8@kzZjkAIWy0N@^QM*UO}osSP7^n;bKbgPd&?v9me0hk+ngT3wjN=b9#In> z(VU(!ww?)@o)0EGQ#rjJ+j?bXdgV@d6>xeN+j^I0dRI?)*KztZ+WNfA^l6{)dBf@3 zW9!?O>HB`d_amp@n62MrOOCr1`xK}DlC6JrhQOMu{}yL6b)EC}e&+4tOz5|X+u)Zu z8@2%qlL1JsKsLKTuB^Z_lYxRuFxBHp&nVGK9ixhxx#`c?RO`1)+hY`?)lxb3;$~yUPlO^ zE`&Ycig;od=E@0mFAUoZMKR8UAb0@`8gL4vy$ed?f-;f;O_!u$=(|}j{q?js*IWVT zwb|Ez$hMae*Y*(eSvs}*h%`WSApnV)7gPd7P=#PM0Oa{a1x~cI{olV1-SD zM7jr+x$iW=L?Y|J4iGRcc9;-efxse*jY%g1sB2pAXV`mOWc>5)XewS7h6{&dH72v5 zZu6iu*En%|-{&v=ElJUE*Ly$;?JGX#R<8~ z1r5PLW^pXf0Q3+ob~iLIoSPtr)ksArRl3FABP3F@qJWoR=j@Zpr+lD55riEWgW+7u zPT1U|W5s}#?1@xYTthcNR9PgO`yO>cVPg-(c{$}fw=X;bc)%sHjVAu+raz@k*A_t% zPo)^`AAaD9zc3G)$chsB;#+6Ozs)6LLH5_eFh_PL3-%Do-GFOdfT=CPp;rIGeL-dW z^mHt68*?w_DKriJ*z%PR@MQ*7ukc>#OL19DVlxODqMY-SJ3@<;q3-bXrR{C_l>fb_ z;e`>GiIcS7db@Bk>`QBI^TmjUi2Nra&mst6Ke_WaBO<;!6zo4OIQ~*Vi!*6eLZwLk5(2ggnK&rA5y}h`FK&2MY>-oOWxAv| zggIcoM2-t?9a$>9UwnPq%Sxq`3WTo!%5Sy>I<=Lqq7f@-&>}!SV)~|lL-}*1(%X@6 zLo$eu4EmIjml|mtrNV4D9|_0Ol{g08Rzbu%qB2O3(0Ms?G_%{$%_7I@;*6?-9LU`x zDOwW49iKav;~jNWOw}R-PYXe{1lrA1hzYK?F0*_U3wOrS5f7zA$-qoZO&og?*vZ&Q zg*kK{7CH~fm>2xhhLm4KlC&GL<{|8LAb~RhBW)6l03;{+sZhItlM2F&1Tw_Z?Ac7t z*oI?r3z*cAv6F=(U|rnW(;Jq`qU=FskxTWtH(22xO`Redb7e> z1M^&Gxu76)6Ii?)j*GtS+|R%XfuZ5rXsPX7J3};}>S=y%2kkQu3oIZ!I{})|)O^=f zPYVSpd`}e`@`!)*nmc0bQvZOnYoFS!wd|DqLxDL;`}aIoxH6zbjaK&^f#;7vXQk-* zN7=58f=>il^C5hIJiok;T$~WYdGINamL(p;qe16q$23pIo)g9lUXNYLA2;A1w^ARs z$saq5{Uovn#sXj`h~hQ?gZR+5BG!e zm3n7}3jDgSB_O*z*Q_njdLp>S-LP~G`x^jVIT38hN1j{eWOk8mnVop8Tnn5tPvn)7 zqLeYL`iQ?ozuI*! zF=(tk{}C2*v+eO*le_cVr$vj3gddkAzG-4W6m%W63%UH2HN<72_!-ije@9MpC+6OS zf*?#74asu^{lRRg3&PHI(P?8q8n~UC{36WvIo$-xl3ljL&Lbj^%I_VuWw|lOPK#h? z2<*>RdA&0NJETUo;QN zoPQ;kkE{?l4x3xKPR-c}{SY0;tQ+~(>&;%4LCskJ3*cCAw?H!VD-_TTrPHO-^QsZ$ z3%lbOr*C5!I!421%kMBp)n(mp~AWlhF#tKGCLsxn;Pf2{DY;P0tr?OrK1JV z6XzKjo=E|Nisv<|ALOc*x0BJuu{VCGze!PV-`kvNkD@YbbR2A>LAyX_i*$#xMQW*b z9UmJW6J#~)U+fA|=@^(n%6IBx=?d{_U^?b`7J%@Tek$u%%@^D3j>g@3(9fD~fE64> z?40E@;T$1ar;2I~05cv_dirFxo=@fbK+nE&OFlnrc;n&4IpU2Jm7pgXIOgSTbCfE# zEj~@PrBoOtBno5KYoxGsJ>t;^KzyK}@NVz$3Vl$Fygd$1$AaB02BPiJK%eL|05|?= zK(>wnbB2L7U;=pOik`T@fQKWD-F;RQzh~rG7%!0IS(GH(HU$t{o+oRn4k@_no<&BTY{JB?GbxlbO)aGSu$=%7qPGQ1=GmKz$u z3iv%}o_Q`yIC%Z4(`=t`s!7m*Si!ksa0iFm?rSg_9Ja4Tyb}CMLk4{MTIg?3}Q< z-o>57ZcTqa_CM1>A5Ft%L%%(@z*zt#f7!^L$;h2yH*FS2!Sds=NH7G8lPFRn_S4~H z0zq%8Y|sw`DMz9VF_tajT9fEjs+cj*)zK6~%4+UpdcD?}DPIC7SP7<%;=g<}K z1?ATHuur!*G?c3qsB2V`^N&aEuh*O2y$0L{-cYO@?$2NyE>RpI5BB0tHEiJ(wP^3T>|W!0bg8DvEZ- zwlqE8gwh9n{lcsbwjhI@ynM!io}}l)4bO=d0FV}fkoerMHn@OccFj$XJ#Mp_2*Xil zH{2%CUt|!WOk@z)ew8+*-vTgVp(<%ys*@-1pe*UxgTb)QUH)?d8BS@Pvdhi)Og&WK z^*C*@Xesx4pIs*uxxlqCXnhfH^4MU~N>hLl3 ziRQ_R>;_6e>IgtY2^%NUOZH)VXZFx0d5Q05c%NzPPfcvZT8ZY-yPEu7 z#i=t2WItGzxDqjF{Y*6Y+8A%C@ryy{UoW!W+4UF-W9~O+ zkqbI(!y&be`CG{zwL?$!oQ4|13L2BSp(reZ-;o6zW5&kt#} zO{H?1BS0589ozvRurlOn@*r}&gc)10xj4K=>7l2RW=Rs)*6rU%PJ}(!yyG0=*t+?2 zqT^R{-58_OhFX_U{b_SU>cb7emq&?XMlFp6Oq&EsWiNe6pC9tkPfwqyuSF@$&AHq$ z^#M^c%kfR-BmO`1p?rmXs$=rJ0vYVB{kWi~vftDQQ~m4kfgvN*Ca9UUDWZgcD`Mumml{rLt_r^viMeD%+$ zywA&DPRHA+LAq)dw9H zq#>PMy&~lY$DbvRK5^gAD5*?e=5oqR6p8Sdu5y?vK-g z;hO`}EQ!A%v3phh8*R1816Ay}4a$=MNXm<;gF&d2ZyI~)(dTxhPw|Ww33;cpXJu=S z;13V|JD0=XA3VCRq$5CYtO8m8G|nt=F1&m1%iBQk(*v{nd5(h=iGbFlqhn_?Q58;z z_lxoA>G75Kva}fZ{E)q110~2!R9RMumIP<6rSMiAgED94T9g8M_x3(PY4-iSVW@xS zHmz|DD?Em#tO{q2gPtAJoc*Ar1OM)Sg5j*Rql$Jxk0^X)YvIONMn3GKtqFV0TH7y7 z25x!Um?-uLgQL0gozZ`q$gKL94P|AqHC*cosk6$xNC}%cm^ZC7vO&Pmg!-QdmbhZCg*zfTl!v0B<|0?X)SZhvv z`>D|Ce-yv#Uf4Grox{-!{ zh+Eo|-=53=D(pY&z+>X|kFft$IqsBAj8DvvR(%Eu$oQiXZ855w@@KhLZ5`r z*VxGX2AtNQyy9`tJB3N#MzeF@YIcU@(}#9GV#<59hiSt85Cd-1J*B#P=Qel8I7?Y{ znI$oPe?LPd)7Le--8N~$ejS*>lsnh8RBo*rUHf-T8Jic|PiuN<_McLXbRuSgQK|$d+K7(-F?_!i0W=y#{ha23hQ^E=*OJeAHdI{L0KCePt%1z+{E#IuPaL?{Ll?Vt>BXochO69r4}rY9+TM3&cd&zTB=A3Bq|MvhV2em1eIl^v2%;&>UG-OFL`qL zMXB_4uQZ2?3{P@qzJDYbv4n>!JZxnzJAbJJm!?d53QL4DXBmA!o=p?s<2KP667TVj ze5}L9hd7;2Pk7ME><-a#Q+_irO#dn{iPT*Jo%k{w`2sWFuzoT$xnv`mn-}%KIvR|6DBr<--v&C5TDt$7JF^;3TL1LwDb3Kx?pJ!t?a=`SqC?9#tPal zNL5y4-U&T7`Niwx>9ik`m_|st@6G+#$sFtmFzoIG+AnT_Ab6v=pfMGYgA6h}Xlp>Q;Jr`o4# z!%;LHq*&_#Df`Id8q~4eobeZx_~=^YzFem}B5Hv_`1ia0Hvr~(9Nc6cbmo9;_gI9$ z#aI9f$917xQs@MnQHltKZth{`IK?5?MbVZX^t%s&r>?cCT zF1jpMLXZliePS#;4Ri4_AmOZ7Z1n0BiyA;Z&Er&IPy7U-Hx%8>Llj$gC2+fw=!NBVSaMFd^L|}ch=;yy%sQ!eM7pQ4FJP)K$uH9E zTT=o;H4Xt)^Km0P!iE%s&ZnP{I~)r!Mx0kJ4cwDvW|V`yI86|9oYznky(&*Ve8H{FejJ*@hl3C z=spnE6%coxjQxrc>woF<2>)v3qLl4ye|N(oupsqqgBq>nO*h+TDdpN)-K7$$6|h^n zn~Sy$z`YuH0mSN_*piAogM;~Uet5@jUKZN1URT&`gr5^A)jcbwNEa5@pYQt36j4#) zj4}c4Y{@$;lbh~yTA=5CrAVEXRB#yFkB7WYH8)m!e&uk7x%UG&(c_!zqy76P&ga4t zC{<#T@9}zHiXXx0%D+Au)L?MgE;2wk6c7d-XtD5EyOUxm$qsAEeUaP07%LvNM=XTZ z39Ksj?Vs{)ra&|m>ojkx>u=rtaB>PV%&w#wG|im+>C?R`O$u|mycoLEE-3W(lsGgt z0!&`QByD|sW5mbDs?ggb=r(e#r1Acd9gfQtWN72c1!K)!2`>q`3FF4|H@FG_;Xg(| z%=KU@7mQOJFJQ>>dV+-!2j-#aF);Q6{JAxhh`ujB3ru+g;P%(%(j-B73MDDV znwuqY_i+qnEllLMdI=lydlQhKBi5M6>c*;8c}aEVW$a6#$VHBTtKo5H@L_tH5%yDY z_sUe`#@Q{EW8n%>0vF;XS==G6aWFUa>SZg>qPSysBVP&DJ8N;z7j7_GBCo;RwKIdR zELdqQX!t9mlt)0siqK{_`&|jKyVTZu9{r({<*b(R@g}3H;Rbq4F=D0T&WQwY(Y8BS z2$xArcx8DL0>ncU5>tR6WqDI>6djWVSQYJF)5<1?1_g+MwCW9ytYZi4953L*BG5^W zfsvU?dRt?6%EHm!6DVJORKhMY&ECSmHCbNB7Ul|-LxE|xxN>mDeIe{$i|K5p61fyY zk+fVN3V48R!q!c-Zum3P;jGe1~{3|XGNOWR!&EYe4n*rKE**m-Ef9WC}- z+je?=H~-EfjYohHR5E_DiA9T)a<&WDU~rX>>|IH+<^fu~vZN_nAly$;st%7tx^2vV zdmbo;s%iz7up@tN_++hH{;HX0)J1kG66s~7})y}JY!dCD?V$0 zi0Zq9svNl(P#>_PoFgKva35;#qm}#B$|)cN{zg))HA0=oB3n-gbXLzY`sPh0i+k^k zWJT@R#Hqaiqp2*X!azfa=^e?3JS-3g`FwRD@EMG!o4nKyoQCva{?cNIY?n^m&1aVs zoSK_i|E9rjja=fc%w-w{fG@EJD=K|uL*BvxDI&z90mZc)r>?i*Hwy#*%Bvft#a8}B zzWISt#XQm~1dvB8>F1x0E2{^f={*VNT=a@hR^3Z0P&_EkH4D}F z6+;JOj+lhR%mnVP#xR$4QL`2=+Lc4@_XC0EGQI}srP3=}4(!8cRX@g^xuR08&sxSy z2-BiEsxcLZ5!>V*SBkt|wJf<&3D(i@;;r0xk(KA2r+-xWUyI+%wn)_g_*P-n)hVRj zlY;uBn23?vSchsYLzSAUY6h`u6KmDo^xPTc6+PY;^g?Tb2g|+EYq(r%gbU+WVXVn* ziNO^$pU+#)vn8K_Kd&mW)Egy^8(O}-QMeLo6B8DF+~B31WBxkv`8Rx$s7<)4C;N~T z+Z;XXtJVjv5s~D6Yvp;ssfXc%^OeBv>O%UuYL!U0!p17Av)3=`ca$-JZy=tvL7C1&wWAN zss~r1VRG|8V{}f)gL4w~jH*~)`={KMiLASgFPMS3iVC^S5xJbB*@cw^G^th25;3Vcn2J(@cjma&D^t{~WJnBeZWSRS@LpxuWg1;`EQ5f6QtN6e5`IS@o9HRiv zdNAG7i;ryC&f_%y?(1~hLPkQ`D&LDNIIxP}(6kAPe0rhXn_3vSUHlA&f6A2}8>oZo zJX5f98THo)wSS0gszTADVUT5@uO!>y&!)+rqLd#jlh)}BzYBCMAx+;Kgj{3cD!y>n z7wikrI$IR;b~|PliSjn0O{yJkf?de4$|49S1_mLrsgQk?6QWOkik(Rd=9Ms0wtE3C zEd2DY(7iCw`Y%!f8w#~FyS0vzz(UWD=*r+ckK)Plg+=Gqiv*953M$2%quO;-AitP4 z1ufmM^2XgVXQ9Za z;cOFAcU$@fXvwO@G3V$5kMO%}R&6NVY1aK|wm{`@)+=nAXG@ay2X0&)Z1TlgRdfEb zvVOUt_H2-IVho7?`u+`DU+>+a{=A{Vj-esS#Tzq2AA725y*XZkkvADXycDT+aN=;? zc0B=*rc6{bvZ^hCa5{U`N50`VIuX`+?D{pscHo+KjOEW5KPt6E?eSe4R*B2Y{+Py= zkgD*}-tB$I(no0pOQ5*?+txv)F6+!SmB#UF)mkG~z}knSYD&H%d_r|5N)FDyueI%# zI2_c{GCn_l@aXoAI2K-|lCLHT85~xR3U<{WQ+N9c#7AyZ22~tcA3)wwu?nO>E14Le z>UVB&nK40N6RaWCej%O7^%Xx}w*`va+TdQ^;MTiiZSKu)C78fe-l;P9(AluPa zdE4%z&w`5k$o+wQR(8L0-{Qs~z}e5w??zE`47Dm}X^XvYcD8o(YJ2gg@WMH@^t#(| zsNq@ml_Zv#oaC;hT7TE@%#hg+&MNO`d9^cbHV4OKTs7`Wm7G{4M;v_<2sC_W9S(qu zAVyUSJynUia}~}k?r*=XJY-Yh|CXPAZG%6Ouao80$^*}$`J-ix(z|t>^5#T!LzR3~ zx!s3>vvd5N*4#pa$}VH)8XC|pCUmC}9_ouFA*{4HzYSK0A@COc@01Mo@0VSs8N67! z-@<8WgeevE6_2ox2cBLwvS6z|5rayUPHZyzi0f}8Q{>MRmcY0t>>~pn+dO9~hJ7wwNPULs8lDp>kl~aG zV_$Yct*G+-tmNy6hrCZ=mjUR7&TZx^e7!3~a%Uzp`l1pA&hRN-iq+Dkw;&j4jh}t{ z7!Oi@%nr6ttcpXzswf4a4OU-%vBQ<=U1Thzgl#1^^YcX z_d0bintD(`J$gf>e50QJi?CnTed_;K*#Cc5{5C6f{Jd^cfG#c*!IHP zRPpO`l!)CQpX)rn&7DLY{Qmy2{Q9@k|0?Wf55RyJl(zr1_#L24FWt1Q&8RpYpu?=X zyRC!LVGq=0y`uD6m)*)bP><6o6}xLrIw zLTZoYR_W)9qb^KAoYQ_iGP`&K0kVyA$e2yowa~A3vUH=gz5ZT{{Mo$ka(Cx**!BCz zfA_EBz?|V&0>i}vY%H7Ye-^(p!`+guEaMXfoJ#a}|!GO|rQc&8&+FLfylHRUS zE0)mr~A*MmWfLRwh7xu8vq*xy%aV8ZjnwFgc~MCo269wG#$P+;AjDc z_a-!J5wzz(e=br~>P-_x(z}5qKna+hdy&{9UG9IoB?6`Gp2i5kGPF^9z6RahPZUXE z<)b4L!76fq-665;u<9=&!dVb;LvuS0n?-IsNXE>*d+F<4G$AqC4BcLBaZY%Fg?IR~ zx^v-o3s(Y2^k9{4hLPLTw@$y{{`Km&D}~$9Iji-dL|nfm<#+I`_z%`(L){0n@)}wZ zTTArGZA6arOqp!X7kN4wO}^Q4QX?c*&U-e`ay z-+%GYfNYr(ShB>o+7D6Y6@BQlEMjK@jnQ4xNju_(3Nbkt>Iz&tbodv@Uk#Zbmjx@W_=8GR2=T> z?(t`Hcw0?YSyw#zTgmViu5WsrQcchTS>UwU;K$P>zycfbT7~D|NZT@fjwWAzpPLHR zU%nY<7N^Vj+*E9z>R7x`&UnGkjN=UGz9Aq&HCARIC_McqLFOE0BtdPZ(7x|{W{sU+ z&ZRR9mSZj8=CbebC@o>%^KuY-tR=9-?jzV&k$#nEF#=iwDoU_&jZ&-L`-g@0a4h}TSy zQxfpJ^18AY}Bp7y!ki|_ZSHfFrPIW$rzU zzq$>e2W&T9&XYtckz66#{d0863aQcuZS0=J;G|7s>-!nu172P(oQfaHPIz!|1H)cT z2@jUpk5iTZpr%uG;M>N5ZWFwugF96+|mQ6MEoH-rzWTih@(3F3(df#q?RR+C2;T|yf( zT6SO2*#ZP0SY{urA8?qIZc!h4&QbP`-(UJq>is9p287VZqMyIg zdtvbQn%BEa8+UYx9S~!5LdMNy7S^%y+G^jl`Q; zEZnXa1pX@APK;8p=)yZU=y3fGU^+txH?dg~ z0sOmD(^>>SYt^yg!!3jc2}XGO$r2NO{v+W3H&Vx0#cd{inN-z3n#X5j|) zsRFIZynScDX;*M;+nOTh0HV5JDIDm6Jp@>SYi~>dD-og}xd;sEm5owL)@fg)O$Ot_1eI-^NCs&|QNJ%V_98Fi%xnk8LMP0vH< z@mdo4kv^F&EFb~2A^@XhwDHE+U0b{aVB7>B8WR8*;zaCQ=FfCmqGIVtAjI}1BQ*jn z7DPw945$ZRW|M!&D_iQ_bIl}MhS+nx=8R<&5zj|l*wMKi!N&)%7)-aw21`zX zfZ+gY!!cZ74Yc{RmktN=Z-Sea5G(=;!bb_xxOU0yOZE@A=sn>ahFVeCICXg(XuCZc z0J?y?xb0p2fwi*ws{FMLgO~-N0Uz)JH(oirKA}DrFOO3_$8guDX^vO=SwQeNpydo1JtqIrzh!r>y;48NSgnOgvr4)ErNw7AMEbJ{t~zHp!W z6+{`Q-wIJU6AR>y%{eYh7M6a*s`aM3lRT0xh8h%g;O$IA=e(+oTO(OKP6QRvmHEUi z4@y)!!XwESogXJidxE(t)P>Qwv+__YTG<&5wF61><-z6aoAtus07RUweJoY)pxLn< zbWKNwkG+LeaoDz~(T-jW4VD|J(kSHZdi(PM|N7;Dj&z=*1m-Fp5p4v+al)1}-CSj& z`?%a0-|A<=()ZoOZ4p4OZF~?NPCNjpegIcT0DN?0u(|MrM~zqN!BU2R%MTP2k`$}G zKWOav6i!1nU8*YMNO9NgD{G}Hxpsuh4GqipChsm5`S%=heGJ?f=xRJ5-r{m z!`%sH7N+mn06>W>WH^Ks8w2nJ%cs@lGfHERFUSW-96B}#U272jX|(37$$70GRbti^ zAjHJ+=zTJ}bY$o$x?N_hj_JlZuHXjt9?&@i&NvN(<|ZHy5)_%@s7Pf9T>y~7LT=o< zPPn)+LF)Y594l3;nyN=u4Q>)|o2t}j<$w&5f2ZX#d0$GHj;D|+yR6<+7*|sx8$#{j zX7&&+9Cb-qUh?HZ=1JNUl_55s-arm65a&>IE!%cC2 zE4aT8^olwHy=FrQ0Lu4^-%BcYm6?FQ7I%Bt=7*|QgqJws_1unFF(EVsqQfT8 zeEwSYP(#p^r9G5j6N8s2v6&a39d6GHTd_79#<#hgrr%-Czq+oznJ zvY}lnO#8qGm!i}i5+%l>NqD5ELzenjjPh8f9x;%ED1gGzy!iNjhb%pZg4c8s6%#t) z2wn+C{Cp8@%^@+4F%pjDccwGA2|}dFg6GqC?smmTj=|E1$~$`awP_Kla|FQGoDoNK zg<17;#~MGxb$()tAMtraprWqku^>v102809rpP4!EKg=8ofB=j^0H6dU19Y{M zp(T@P=ztRP_+@%l8N!8>I!%#fh0IYXkc7W2W{{6B^`E}oiMR&4lKVL=0HS}l0i=RH#hs7Mtjz5TfL@)u2bCfU;;NtwUb9m!KHnR zl;0zlKUG7NOZW03Aqlr2c}tYU_8(H+luw^N+^AU)zdN9Ox5V4qlP7lJa>{6NEaTm- zgNA(yK|?90W7Ym)N5@~vt)S!}Q;1~ZS>l&&I1%ivT+Vy_SfWU1dM z$IRranaTXmo##o2H{?!4++xl@qU7jK-?7U@2*=}f`p^y#{kgerB^6=F{TJihIs1S9Y#aY@IKCgEtCWeLw-rXVZ{u;L48)i7#+gqO)hov6ubwlWLj+yfg2j6zU zN-3a6NA%Aqu*~C-wtX5ocRb8|dUQBA_%4*Z@n?6JK4)X^&u-ob2AzWWRb%pQcLp>vo|$EjwdHij0mjYu=Q&G0etdRz3<2+ zMHk5w%G%6Inwh&AB4^~8J=#rIUSA(Q)Ykv0N_4no8yl}?vO@0f?%(}0l>7+27LR+^ z-#_$jN}mz)ZgGe_K9n4f^_C#}uaE*d=drEX8WQB>`s|DDYwV2Vxj#cR&<&QeOQYOQ zCm{bIaT5^OGfGhB1}Kw4!{cDjc0rlDdwaA8g+|B?zU!qCa-e4vP!0w3Y$#C=ug4!-k@_54aV*XZjn8`%=+5 zNqj~xN(LTFSXDU>yeNI2C4XZuBNL#}f0`piIM`NslG3_ZVbQ^jbp;bW<5gH4rV z>&t+p!Tc*PYiHZTch+a$ zzpVTA1_x#kFlnt{=pnL6y9~89EcK;{TzO{l>c#i>*@`}ML$4ZFKazAF2$;4t{TQqG zPiF4M`)8)@|1fjGKj%KQzufvprZID79j(8Y`X5VQAMSXyvpQ0IrNHcU+g}XZEtNU6$6u8 zPSfS|`Zs3odxo{`e=u{E-!q;6Vdk*$lK(JsUMo*M{}(g&PIC1hW^OeO zJD`{STfc!7%-s3+yU*9AtS|E=nDEn^jiUby$V(;v8RRFB|GXEu3fviD6UOX(z|wE0 z4nM`4SP9EPuW?&GDr8{MUd!nf;lNNg6X3zWO}Oob3(ODy>^%OGY{PX1Gt9$|J_w)}Zs$ z8;UgNY3%M|2C@$@28E(RzvqShy8J9PS~fE9R-19{=iC^*5M*4gZ*}!pm@5%?&D8M{xznZBcec4CGFB$L(&P{GIZsJK38F+dA2w zPmnu3SkAhAdbn0zcY3t(a_jVXyHAcv*`2&iJvmsdqn=Xsx2RMABMI=&eoo$PobvB8 zAg+`p+NEC>RChWKCHUqb8BZ_aD=s6V<7xFW>k8g6uyj>2wn8}O(m z8ZMSvJQ5SVNzq1}H#%MNqu@)WX6=|oJI}{8b_i|RKJ1iZ;40>K(ok8zuV=Nc8@vl^Wy0RlVUp$I zm1umOj#_R_V>Mk;jJq0Q&OB0lncdT5OmwR_ItYLmvWSm{prI&4v6pP<#f(36zGB%p zIzBYy=_7r9jb_P$Hf(IPT7b6}N7cIakqJ;4on!3B&!l~nO8aLG;Z3_`ZJ7Wn1N{~h z^PI7@>%*z5rFq`CmXAW=aEQNMKx0F1N4?eOp1*`_g7T#c-HdzQWsDYXq2Z9fgB5^` z;<^W3&m`Vk!hn$U`Z)S2 z>4~c2*DUY#)PcTK5b}50P5W%TqodX5t!FMX)O<}iCsoW~$#bJ&INnr25Rkl>Wd*>i@M)x1$)%~luDl5OpC zcU>cmve1q<4NX-y>f9c+x_Lb4(X5DcBUTpkr5~dp#OXz1X%L#(BJg3@(2~IMK_8}; z?|KYHz9%TVfB#WUQ2IG}?V0QWiyoDK)=hhJpA9QrOBb@(33+?d^Gaw~qV zWysU4F=ujU;{H;qc+cXZu5|8pnqpam-C5xapeqnWGV+SyK_$ zhc$iGqtUdKrV??}AI45cpR$LW$}WAN-9~gFl(-|`><}?e)PFM zrMbq#^rz$3qlwnx=Gw3iKV6QGCdte#^$DgMZfB0C`psHiWPRAUrF#5jB&DUP+;r31 z>3Di-xTWRghfV*eE42N1c01)|$149%!|j;40~kq@ zlD>8S`1l(D*-D0+Z4=H=<`L$t-CV=l@v4*sRBCIlxY_R{C(0uC$JTe3hJU9-QI^oi zSN#TNe;(yhmL;g>uLkXg|75mPzRRb+8uBpP$@xlIQU3U9IBa<5*)e4mgKQf~FxxFU zbFyYw&F>p?12_Ycbo80v5$^wNajBM4Q3U^Kt=k= z0Hv+SwSy%_m42|q8a7UGyL10TWj8Vs9U~!u1En2+{}epF1LXt#bSTgWV*Z_aSMA=9 z-^#sIA=0mVn`iotZMW`gFk2qz_ZG9P+)f$$MnzV_Jx>2#B7$bFM<4eID%)`3EVyuS zeIXXBD9T>+iw0U`5NFeeW6Hh{Ux=or;po@+IK%PrmS7G`FaeF=n_}guz~35Wb^#*7 zFoZx?0%QSfy8xE0APiU{;^a|}E%3B#n_I)}25}GphkSxVYF9AnD937|V-GN~MhD<& za;)|N+)yHR4Hb7FA7|+qXQ&)!+!|*x6=!-7=fWM2ZH==yfS=%yrt$z4BIj`?fN2Dr zn#LR?k?=5$`A&F3P(O2MYeKMn!d>MA+O{kLH}SqQG2WgSVn|F}OL#bfKvDr=YOV3A z%5=gQpk)B_syyTk~U)`Ns`ef>9p-gCrR2VNitjC=V14o-LvPtd-iScf%|0M#-M*0ddOE zxIU6w7Z6vE$KM->yOkYxvn0M{ApV<@JzW%cC5dSyJ1>Wh*@q#KO7s|>P>(0p@e>k7vi#4D9)~G5$qp;x}IL!)QEHSJE3Qp)Zf?FX8Mxn6Pq`t|NgyE=X*uioaQs zc!V#x!{^d&>@!)L_|C=nYbA+>d*aMq#y6m`T_TQ-0Np3r$+F3%qSP+_g^06KptBF#zv2ONfZTT@JAU%oeHj7C zM!HEp_xDe_zn?mk$lrG0S}3?vD>hLleg>Pwe4y&JM6Ps9BE)&J!wj z&W*U0HxkqFghwhiPsQF-!0DrspAnps{N!h@+<-kPXpY4AeQw~5$PZ?Tc>`n3y$+;o zi!*zl`$&qmN;r#@^mR%!QF!pI9d}U5eWp%463RUhdgz4R;TP((7b3GSrjl+=v4hpDmxA4yH#iYEcl6rb z@wCGUYBX;fnm2CuI1I5DF*ZoK7J<7Dxzda8(X0vXBWm~c<(Up^lO9yVMDcGnX;%v<@C{QL2>dKspjXt0WHtz^DOu$WTDViAo=(iRsm zbTI_nDpSNZRWZy&?4<;UQgN9yUG@jC5*JZ+A~P|BNzqoR&Q6dpMUxp^ik`Ha{=S60 zM#^~C=-|Yc39yL7QJv#B{DPrJ(>tMe&~cCK8Ii3xb;9@}XO9RSC)8z%74_M1$V80X(vH8zycY2#!OMc;;D=wDf7L8 zV{P_{U);~!B0V(wUf9kZC!dw>f2QDYRcGfA%m_+{N73IaU?^rWx9K8_a>LBX3rjF$ z+2Qjm3GNaFHf#O4mGMty7~( zm!T1`9uF%}FEJ}l$t=FWm_*Y(`-1jNrSmYCTYV$mX>Gpp(1p^QVvNfNBy>u} zvXorXr5KA<$bk>op#qkzny!8lHzg1x^;m%_?9K}^r_SG=ckEJWVodsjAB-eW?ceb!#NXUGqrs)b! zpWT|bL-){{Jr}|bU-jt8_sqGRW*`4Zjee|REEUm~O6U_w22+TBAZ3{H;T7|G-B2Uo_gfw?4&0WokqqvV%I)miCK`Hvtr+No! zE-pC887$bcLc&R)#ag9t+NT`5CL74E{{JX%}(8$6i6FM z>as+vK#T!n)=4CT(}fo69zHwe@FO*SiGsC)INYFr?9AF&=4o!oq1aP)`2own&KQ?` zaNE_c=Gsi}{SIC64@y!KRH(b^CPL~OE9kofv>ll4Ju&UWf--2zZViW{2~zaJz`-`X zz1268Z7k2R*Iqcc=R!v59l?&1dtcV3>79EdL66Xwqi8xGs+i-IjQtooUctRVLq`f} z8`N>d@5i6wAAW&dzK1I-LJvPt?c*Jaf3|L4(o1xM^p4B4F)2z}bx!*7ZSjXYP(2}y zb(YTlV&jnVF47r)LN|W-p2V7f3y!+yCQLb)pk}Qr2;D{7zvTyBs)}i<$hveh_QHMn zNrJBTfH_~NyT5?J##q^CQ*PB&gKwLpKioMp;UKSoAv$>fla);YO8Ui@e`(WiP7mFR z?w~Ia)00WvK-JyDRY%KzXudM?+w!N)>8{^i{;c6EC1Y5qn+}dL@=}}b zS?*H_G9;$YC_vmI{%U11dif&EC1Rti)!6w8*(~}_)~E{JDC~9ri_qYGc__EwPjnh| z!rDI=40rn5av1vGD4H?N4|z)8?V0`f(c{0)63ODC#1$2nmy~MmC~xjL{V4O!puVm? zd->sSTmAwKukhgYcUBw=iA&#gOLOM5%-0z;-g$r5mFEq4dUYkvEehvUg__|OH$OPl zLar(Q_SK0KnGB=kRsMc%hw9_s3a(rtn_>)`X%jFZWv*Ahpr@RRbCqOJx7SWP54vxf^Yj?V6l^O{q0+Wl29{ zQy+6jFWm5cKc>3>`E$#d`gvLX<@pYae3K0mzaM+>#q^yOzG2B$$!hnAl8Bu8;w4CX zrRDtSi#p-(2*k^GWA4YMmvpM1<8j~VM|Q5i@csDMdQ&5$ptvaGnI>UK^TTcA_A5Yvi? zCc0C@NgiaRz53ysu}RGu=H4#2(A@ijrmKH&aBx5`X+SS!Fht%zSc!yO>e5Tg=U3iFBY}*_TNe>l40~#3EUhN0PcYMdV%K9z`ac7f|h@}Gkj1`rlK23))PncP+%yUpAsFcn&LgBh))-`r5kY3q|j<)cr zD)?Rf?}7sczQ5N0Ha%nfvj07>`k>6~+~4}&Z^O3yk^Z;lg*&VIpY*?Jlg)Na^8VlJ ze>+q=F&AzB>lyH17w)g^e?vMR>?XARuUSe!>mL5U)&K4pJ%aI63jMF4?T4dR{?z|Y zc~>IVUtaJ#`rpou6A~AT$8cvl@bSr1f0_2qH1xmHXp7G5cMg2inX@u2wo~@GthzJz zlhR?mCwU92-Qdpj>;AXD^T`>7Z}6dsR}9y!9ywgK>g}EBtDmu-7ELi&u>MfFvC&`7 zH%H^2T=-_CGziD16vRCa-rhobQxS5i|;i{hRuRI>LPdqo;b+7tr z+j7;Oxs!+yJ=gFxc|DcJTf2I$6T2;YtIQ4t_1@s0%ImGRywKHqle}*Etj6YE(B^ed zTkpOE#WVQpT79+_urYe8tlkC_&@f)FS=iSuh5yUQCE!J zsOhPid`8n-Gwc7q{ugzZGR9UZ*!JojSez8h;T1h^btGORWzVX*!U<}I1J^Gsswy`uRqrC>j_a>+y=v5?j<%~g&e>XZ)nrh;o6^s~hIhMGm>TuOxVmQ; z9IUD^x9`~_h|A!ea=m8Z-4p9olVNzF>Y7zp&t9Sa3H-WirFB|QT!8xtqkC1AwxvDs zqPP>rk6f?YH}xch)|@bTQFYyMuqRQhpGoMysH>y2Ldk+-EowQst|E70SFB~u@ zt+w8{={wkaP@$hi?w((>%IH~Ym3x-;!5cOH_RkI}=vR!6X-$@AT zJ3)-hah>N@mz36*$zPb`wye4?rL^xP8K2|6#_gN5roJq@TRDriR)2GJu#40<&E2y9;RL77bs;9mv~u z$ijQN)9ta&rtf^InCJ7z;$CUp^ZbxoQ+;2^?#X+fpNV+B&XJJp{HkL0X@gNaF@rk^ zmG=E-CGmNFlNa2t_U#iL3?oL`(_ATrC&^x&;ebM*IzQ3El@$tv#SV5#g z-I4sc{JFd4mF&E5Vd461Yd;Xuzr3fQI~IhjJgn-qZoGt=7etP*T%k9s@%;B4%t;E_ ziYRBs*R3Oa#G}Jo48C4=X`)Ndt_68Q!~LOGI=Ac0?))N#AX^J2xKvFtpbOcHQ!mYN zJhNlB1ne}SI0J2^L9GF2Qpd~Nj6r?^a&_)=#3_2cc=lfD_@V|J_o9W6bVI3s+`gG#U4 zVTNZzK6g)aD|mmRxT-Mxl7_PlD}QH?T{)H^LAMT^FnJ}JH)rrcOqaRQ#ehZAHa@=7 z6rp75Z{#aR8GRxAYxN|oJK*WoulKH;z4hYPIa~Tpa9i6=PS~A~$FGj`p?3PeSc#4% zBPSVskqB>jUzFY5lKp*6r{KE}P2xpSAJEi0$A~9lHJ5hh=hA2<`YZKi4bP7ss`)Ie z>chsXR<38K`uNR@qwB92xNhoA!8?*P+Gsn*M8*}bWy4n{#I2uq_1%_)2FKv;-i_%BUl2Y#wV$l@+9U~n|$|p7gB$VuU?3F!_zKV#%B|EsGu2I^}`lRbz zbQy7VqBF58!sj?^SViLwiCHvCtp6^}X-wOWcIV5f=dToRn`;{XscCNM1VUQQT_ud1 zMY}(8 z{LZ>%jwbdUI<#zQO#KBKLRe|?nc*9+j7A;_Jx@1|{X(r<^$-;sGO%KbiP+E>a{}fv zIqF2~n28290au4d7)hYf5t~?v=Z&Dv-SJiE4xN!+6?5XSonN)l*b}AYSB@!`8(Y%3 zQ>Ewz31TdTRno`~fq&bW(8|f!EC0}I??TnZnz&Us;U3#Y1dEOlI?mXr-fS*p(fN$o z6g^C+^OcmTrs$5?m++J|sbo(TAyyc7x|)qE8J~;kMhbe%WSUsb+$*Mw#k65+hq^e> zAVoNHa%j}S@SD3rySM6$CQuhqh!e($RkPekdc0t#Grl$RBy+EbXrb`%uvk*^`Jyn643@~AgwOYzNu{F9!61}b}^6U%vy=B=`J9}vKZZ%Yh zjIYEdzp%fVcgvXTq~)LFAd!|5HV8Cohn3pKVq7aI>QRqc!D)uz&2LW z+zJ@$#WX^|u%{Tk|N7}uFzSkJYK$9Oz&27cRx0TSbhy4EokL@{ zx+-?W5)4O*t`?zv1+4WHYpgC86YW@mvCiIO9~geY4N-AZ2AFCo^A(LTja(ciU^__A zYSzBzp5Y^3My+J~W_WJhx{TpK(6%TUBP589m^K5`TQduBpwX5pQRpXTQRpl+I*UO4 zO4!RN`Z9tQB}JAI>y{Eo$TEhhnAImlLdP*#YMrGtMi7mjNMlUZ+0}GSJhCGObLC$6 zE4Np*DegQMeChibGDSrXRxurEtkr6rT}tj(D(;C8Zj=(;Ax0AlV7`(Nw<|3HL!T

?h1Iq>7WhG&wx$E=Z~vD;zUtw+j)!qud#=puO3zG+pA*giLkLZxEir^m6Wzr^;zr8Rh<5< zJ)f_fl#+b)pzjNk{jo60wm-nm9GgyKtV}x|ns)pvF*;6yd61qx6n$3p(QV$@(P7y! z-r0Qw>-o?<31bJ7rU*P?o0FWje!t9{Bf=1jjRf4a^sx4}C%9MgSQ%@`r_tXw8S=F$++C`8IaFgjaE8ZNC6H1 z%W3>C8P+?_`j0_gRHHAe3*btME=98yGWEVLn0dV56WgW9i=E2G}_B}}ME{%K$G zddJ*PeMy!TvgBxUQW(!as|~*3ljNGp7EMGT&y<5y<~z3(BC&ypQACZrS2Nh)0L6x( zZ;^o>;uu@wv>{n;&0AHfF^a9PE4B<#Fqc5$ptEt?% zuGpF35@(RmRh@;@WgrbQL|q9U41g1l5!(goNiRkFQOil`W5jBD%aPV{=hjN+?s5bg zg_a6ebAkx>v&19Ru1DJ{Ta+1AWM^}qW?(=+PFR)){4b1W{8ftg!Z5l37-oLhz$2%)QIp<&70~c3DM2`($P5CL-9! zW0jL#pll$UBI=t62}v|pTe5|DcEYyQB4SC9U1_ASy}~u6zIjlNh1;1K3cGj)3KKi& z2D<>BovN!2Q_JxRKrSuBPy;$pD@=8YmuCP(4Wx|YZg@3*T zih)cK(b`K5DRF2TtU=*aHe*>TTpw%96cl7*!Qpm3E@)virpzRb?J3y5W*wM(w784o zBmC zyuv=L!e3@b=#!?gR8~9H*rF=r6Y37>K%X+e#~2C;Wg!;m#9L)$W*x1r;81lkk&8J6 zg@?Kfm6E~~d6lENLaI+~FmP^dg4Tjc65F&^h&tq$@rE*Ep`@i)G0?59tXJ#tu!#J| zihgC6LXasY^Sr3Qv<|~1WwjkrG(y!;h3V;&Ng^^WiSYL;sW3GwjVASzI|iFocAlB7 zWdc1bX|*+PunH?y5dJYGPy)49cy-p266k3L)y)<98I|c?@-BAV0IZ4w4hN;kP=hh- zo&z$+NCF_IT{Z{APOIq>v?Yob%K@T;f5B2bKirqxOx|l-_N!j*)b4Q~ z{nE?DKWqQ&@4Z~mGDGiM{||e)|6pHoayu7wzH-1PWKXItgRc7PAM$d4*OyFL|4h00 zan{B{>6BB_w3m)aeG+S8&Be5t4BXRi`4ikm~mXA(bzPTjC~hLp_TjiPOe zi(L^qd(o$Fz1*3CKE-COmwWR4Wtxtq8g|TS%pI-_eRw;MJ`Q*FFCp}gqw}hHoYWF9=Nb7D#tfa~cG%4aQiqn!`XKLM^gDU<opMR;EV)x&WTWYI+AP-X2u~+N)-?SY^2I^nV?gSMn>?0Yzec#RGYw6T(E;mJz9_mWhhINksx#E+Y!9Ni(UcqnSu+QFhBo7d}yILRcoK(jv&TDpj3~ zR0I=8>($lXM5m3|(lgTx!J@oL2x?I-MC>Xoi$@H~3AwkhzEB{y7b+r!nGI6NPY(JN z7N^eaS4fkHNR^@?8<%(p>k6@61=`X}W!WesHWXwXjvm=sgrf**YekwsO31+4DThauIt;ffp2FL5t1xY1D|99zB?KdVpj?lDY-Aasf|LWf&B2LC_aHiINXSeM z*21)W#bARME>Wk|Qn5UWLl9N=L>lC-CD@=!P}rdIKB`bR2{;fL!!S=9%%M%JFv14p z!omIlZ=s^d1j`qbifAlCgtkYDdFkr*7U4h($@4BKGa*$nVF^#zSBG&nWOBUYECb78 zL_BXkW^aS_RpI#}qAD5duNHPUR@wMVyX81!EYb>VukwIg2yv=g4p~Ycp09&Y_4<|q zfkjegyfHmS*2U6ANuwM?Owmkg$X9KCb z)f@lFKlt5u(V5j=Nr&@0dOH9Y73z> z7XCDl3M$qv@vYo;)KtIZVM6-Ok(9iryDj=B#n}-2H5g#gw_{lqORa7uEL%Q0E(m zaJS;-PE?`yt$n>yiJ2+Q>Z0Dly&Gaip*FRpAUCGRj6 zXWne$KQWN{Jpt=pbwhFYE*5volNH1j#>JtN?|gB7>WaY`A72`LenvbpPpGq?vE0be z^ogD2XMM*TFPasf{bHNtj{~Xun`!>{O~tpu`p-#ECb69sGbuv;XB9wG0{f*lBJ*3BswgPFU@5VStd$}c~AO}8t+iMsR zHIR9%4G?IcARR$8f)oU|9HD7yuQaPGb%q)X646kT8C>-=F+yr1^&x0M+|u4iEZ1fy zD>gD%jTj_#nMPJX%35TNu;Eu~d3q^b`YC;bgBm#L;2?vR3hJj`IRgDc6NIP+q$yv! zz#cqCT^3pssi;cAFgEVxh@-12ig}brwW2s0z zF>XKq10q1zPTUFa8->J^(h*jx`8 zqq>`tW|!42A;RTl$?CFNnTUg;iyScrQ?fM^>yD(_3s6W(-cBealZGNJDpH&sf%z~5PiuTn8bEL|_ zT93jc!Z=^*phrUdXl+(4F(pW0L3M|sCLil-?kf`$M@zf<?{?AQgv!$b9aZ7&Bl{!9U^f`TAiw}7Ama?G$7l|nc`bu8A${ltrmM> z`so7}`Kn-Fth>siLPS(V3L*Nshb0ps;>@Zp^WXy9jC9`=eAJb4_l>Emb8f8{;<5GB z)gma`+M9{iLL4`;DqVVH02!DX|%y;7Z{2J+T zt0x?HY>)lLmCoETbN+huXIDC9>Bj5Qkl=}M;)4p-g; z%C@&xI=wR$H1kx+AHUMcUb`4bPp9%kl4oF!Q?jpY?cPJ4cOPd-k5=7Y+7lIM5j*dQ z%;NZnJa`7-{l~-1CwbfIK74XI%uW0x{|gfZke)QX#rjtoLa$g{GygQpfw58w&mb_; zYIW|Uy{Mwy_0N3@71fic7viryWBf>Ze!S9o^j5C#i?nN_F)^)5weC{`Vx&PjRS+NM|vk$3{R8Lw^LJ2e2>HOtM(5 z;fne4;uE zh44`nOUPr<0F0`alWi4V%32;}EG)A#_Hj4Pvr$xuh`xHVHVQAYHHIFiO=)9qNm3ic z_U3479-bbFdAJ!X3%xuXF-LQJpoL)TlU+47<*_(aDsI+zcOeePb8R^0YK>~-SbY)J zQA0Eq3I?jlM!8qC2&;|5N-TM71B|K^L*>y?qwjBz!J(_Ex2v$`xml8xGR)o@tCR^E ztKG{?d5!Ql%5YzMvSbz3l!qpGQ)QNRrQX_MUACo}rWQBkVMWen5_77ILuGmswcdmo z59_aU^>^b@Muee0S(QQzR0v_B$VZ7%0h*Ca6nH>|L@Jv+h8l24LX;lC=PMfWQK-o} zY6Qv-MQ5a#GDS5Fu0HnYP(8mQ8Xc-aE8|e8u4EztQjR5#L5}H`qit1o>Sk55!T~at zrV6jj<5%U`^;KbBZm6nQ0g{++LS}_yNkN#8BVJ;QN^8aSQVbYzc?8y4gjHscX2y7Z zrT`{s{Y|cwMPy$l78ijjJg|N_85crAs%w=Ad*wLvN01aTQ^MEH22x0gH`y*H%540U zHfB{7&V4droP_A85Y;Q3`R16iz}1&Rn@h=*U^F`ljf)f_Y}6RVa7U^w4=wS+)P<;_ zKAIGa+n8f2h;B9*62u@# zMg0x#|4xgv;6TQ&wn$C;>A!4|4m`Z{vli)F*&k|=n(xtP|5Mid2-(5@Kg60pVKFAY zX3gdb`@dt&6EG*8i+_|gyEV?%gj&ds4EoIM%n69LkjS!&jr^DAR}Pn&=N2}^zI(d3 zz0)tdtg~}!a@LSV5NOkNLHnx(qMx3E8gY;n>%CbaU2rIwCnnK??M;&QuyQN|UIkJ5O`eya!LdGRt61 z%~3`hUcZ2D^gpoXpN;93g^HBU$D-HWaouYhT<88}NbsMm`A63LXN&ZkYb~~H*&SZ< zje}9ayfuWgc0XjW&HwnYsu?P>eQi@q}FgRb- zjVd@+lz9S8pIX_(7YVQd6&Xts*jcQ-f#QC?Fj*R`VeeDC~@5;leCNXm2rzZQz^*E(G8R5Do50Q88jqKQlN+ zt7Yh5HQG{)MvHm<3ev~PxVFgkXcSrtEXLm$x)?J(v?&`+6&q(pD(VX{NjNdkg26^$ zWj3ZPva8MzWP4G~WzLc)V`(^65sQZfqA&m}i^Zz*Tw&tX(Ll&8;Uz~EAHjy|a6iWY z0}c*=sIkV`$CdE1s{n8W)@GBRU7r$5Ng|*m;_HzREkfLEg8X>KdYEttufs-MpF!eQ z1RU`SG1gc>#s%T+3c}Zw*QC%kTp9%iEDORzCCsthoH-l_Lj1;TJT%bQ)5W-6&QBJj zLRUMuE~S*>etrR2*0{eD#Lj_)AT+}oZHp9pJMg@%%pjrF7V)D*7-%o(-5|k2ntkoR z+~0DZ!9DT|K&Ycf4nsL%{^Ev7>uVYVGovxt(Y6FC<6@#IR&sKGI%rC5IvRiac*&0J*-SJ#^I^jvd=BLH{tZ!%+#_JIhRF#tZ?YnbR ze=JSXnoe+kwg>CUnf(D{{J6QphFvYEbugRn=jh>G>abf5t0fLBhoGKqBR-^*7lskh z|9lVXXMy2Q*YnTsLH!vRemyWui{^&sJv;I=aPrUhVD0$dEloU1icaK2&Cv1CnRGXY zouxbe?Q_?^XU?OQG7wo{XaffTgb$eKya6&0UtnAVJq7RXwQ20L(;fQ11O16c<+48R%4Mu2f(j`YUDz-Kdj zFq`nOIFf=!Ls?7l*r+rN&$h;EG6mtQa04@=gk^_m%L_LX49-93HQ=My!UBV1FL;A-MY8tX?UD%D@0G zwZXmw*Rf&JZICgjkUWT53c9_sHBpbXDR0F1%7p66O^U zDYA@-&K6;5Fp(KSLbVa%U{;ojLk$5P1oSM<`dW38WkrIEsVQ(x4Z-+MRH!dmnm|G; zkq}8VWufqe4|NI18aVGw^zqCnEOY}J9%wvRkHf@CDZ~34Tqz4w5{xU0P>3vWkh@x- z&~8*0yE>bZKuDk!0>$IuVhsIAuosr$O&H_Cib4TIy6!qxWft0{#0Zht%LO%H;|123 z34%GAVCDpx$A^EGO--Q})IFeA0NQvt@bvXbkw|EwPZlO%5av2-g9RcAYMpQ|+!+@( z=Ai)&0f2P!mS8n9QGkK7ua%jvi=7pRgv_sBjSvWus7G09=PS0#ihY)D2niA77UmgRt}S zb!vg@+6;ZI)f&{i8TG*A=ii7ddcWFnRKG|2WykRkQYP#VbsT?_GIx(rK0iqrfBgTT zlv$#Szm_ty35@HQs(W|ZCQ9vTwv#+&tcA!mXqIUvEyX%u-?*~GYv+< z<;y;LH}`Z|_oLI|4=C;=D@WFa;=bI1Tln&)tXyE3Wg;Y>lLzVD)0kEc4CP?ca_p+go*(EE{>) z%5%*v?`z&$FO9qB``>tV`_IVo>yhQ3t?tbGd1SGf+9$m}_xgV2uK(oK?cb6zU)~o_ zQtILJg2bo4y1(1$LDRwQd1EHMRV=?}f}>R|3i@s!ERbbjQUgEry(t9dI1o}ms6f*K zNCo_gm5ElRXe~<$>~=AO(F~{*04tDaK(2sd0f_<;37Q-LD-dcxw7j;zX0X~Ecna7Q z&YP?R!<`1i$%M#?RFDLYGSJ#GXP7%^2Pks1)E(`t^MNBB1`u!_l7=|N$J3*tJLy zijEq)K{*-ag;hu6@<`0FLfl;LUY!i{9evOe5VGpZyc)_$n5UFDVYn#?2Yactu(I44 zj%z0?5;fJ%O_F^HNET(*TC}RJ_sOy*)N&z&7Z5OTp$bM(K8|GR5+UdcCw&UKhyo!2 zbCXOr!UDm3Y%pcHh~#5lt{5mBwVVXi0U@Za(jAginI#TM1g0L4;|c_rDF^j)!dz`o zBST?nD%vi$^S2e667WA53OhGJx{x^9D(6FF0KEZ*28J@m#yA}KnNc_}8jw9sP6QAZ zc`BYBhGRSwQVe(+bG|l9rbm#F8qzmtqnSAeFS5oQ1H~ooIN)7~NEOK>+@pf10x+dE z4;`!*0>`m1BbALFaki8UERiFOw}?1TVVpbR!zUEBSY{FdVW-3cgM11jr?x6%jsfmq zt<7{`ZmObDNMz|DC_ol}jN%z%c6@E}a1H7UQHIQPo1IBL{}aU`owH;4KPr~5Z~Q{B82pzi78A*c zH;SeF?-Wan6B=*!H^pM+On+Lm|6f-u0g>NVY=*_;5y6QW@h%o?oxj)jc$}H)pN3_o zLAuF07CmTsYUyVdojFrF-#d_zm(dBHW#RCa+qp$Y8)-{V*UQ!&*K~D0If`g3ERRjl zU)PmxVw~Gmcz%_Vd(L(PIijfk=#2#Gjt3}~ot@V73ycqPMVpa5EgtLfG0RZYysBM zScF1^0juI~FRY2eYvs=FPPkI8y*mSgAUN>=p}@QdLJi#FDNjIQEaPs6l|*3xH{3`Z zL@S5}H$G-&id&juY<&!Thb)-@USV&fJ=n|Rpu17P7z9o~c^q1vLI88HvA`@1v5E|m zZ>5beu(7R94(*JtZCdO_ZSLlx#ca3EL6uu@ZAL$y1Y3*fsj9CLw?Vrd8SB5P*? zP)s!>7fUlAXXqe=nKotsNkGIvM+0Xv_>{(2qM@1uZ^DKOBOLQ{z#wJ7n5$YufS>_) z1Cc=wrcW(IW(*4Hsno^~`Wi?vpk2zH&7kyA+3I*j++8|SE z$pdM^HpHA9v8nztl?`pY{D9{))9_s6iL;3?OlMpEeN~4aXltoxp zBx+`eLoHQXAu{BU9ux*S4!95)qS{(sek7J&D^?VdJ`SW7-3$!W#9{t?f-({USAi?* z5UyXR75(y9@Fw~OoY%(WH7(J$igns*1_E_Pq&Bl?Lk(PO8tT)^lpzh2I51Gs#+(N2 zND9yj3{D}}{Nbi%!GY1g+SD{{{)eXKz{ApCXp{|qczHs3B(zJ6rI{Kca4jfJ6ei<^%Q1i>RKu5(N3$EX+c z+ulC1vLWMm^kDbThD$dyay}nvHvP{;n17E-*3n#5TaWWv~rBO{oG zzqMrV$1HQxMRc1=j9#a7-fA0s$8~l8=0BJ0ssDb--oKh<2L5Z7?A3-eWR8C+n!K%d z)NLgT`Ipx5!b}IC2`CdSIjx1Crf;DMO!Q%649sGHo4gS!TAos@wJ9){fuFKqQ-G?# z$q(EC7zdQ|Kt{lDBt_sLCxD?qa4E_kC_(|F0Br%g000F>6>%aIND4@f_Fw_8w0dWI(4fqUT5TH81pa3xeJ@dw(02u*a0;mN938)T`B|vaMW&pN; z-~c2AYzMF#05@P+fUto10D1z61BeM|6(BMIK0uIwcL9O%2BUz&0d@oK1o#EejfO0= z?x+^H0D^(I0k#9sPf7w2wLvRRz@q^48Emox-vcT|S-=PL0SW{rU!ZotbHKC(##;bB zfO=?$BML}K0$?@GC0HD-ok|2A)pa56_Hv_|$+G2iPp)1&(rb<@;E?`ywtU%&>V|@VS z09t}j1`-8i49FYsLm-5}Fabt^!V3x`&@+H(zzG3YN(e-O*8ouhJp(g1=r5|X^dZ%P zM}Yw%LH_J(=JW1Px8|ouRb~B*v{-KuuquVb=KBxM^~Yp zBaM4b>5@BXcDdWSr+bjh%}=98ph$VKD)1mR>cNlCv7H>O`eo~3=FNJ1RVJsMTk`}# zZcM^x^vPwurXjc)#nhV@e)P&PPDzS~1rvYAI^G|X!k_D9eq$Z)znT>O@2}&1Zxt+( zdH>#?{NTc0d5$go=QExE;5y!23uY&|!CA6}T(mtkYc|avl zRlrYu_;ds(0;mL>2pkA7ZGpKA%wOOH0GtAomp3>C<~472xBxC~&C( z7P!Ea2PQZWc0i-RkplcgTZzA3&hq*b6v7SyoB@UuQ18R{HVhG9<^r7pfC4}zKS~oX zn7qIw0(=Ubw4gI!Vv-z%fgAyE0-*z>iMulfU*q6PU~Pw{&J|#VgOkvZg97LPiva?q zKtupS0aOALnK!}(C`0pkEQ1ZWh15-=Ko6B6VFPzZnzKv6)QK)(PB>Hu!IIFR5b z;1&<;7O6-e0bBq`f$;}SY6hEJD}o8Aa=>E1%mqXVNExjPY4Fmj)JQRyj`T<&7!a^0 z0Br!9WJfCCoQLmukR3{}qZ@3XhJc9)q#K?Sl^3qnF_5Z&RDk0EegdHktOqy_@FT!_ z!KXki0#grY4Ip2DtQl%_1=9gJuD#9`CNjWtV0Zyi1N;ua6RusPs*wAeTbi-{zFiokXi7zqK5DG+PD42;`gxCSK-@ENc$P80?d z1=xTWWc1_0Z2l%twnS01p9D&;<^Mr}Qb!;ETA-{X1k8UFC?+F~>p%Hd1&YiKKX#4M5`h-@6QNI$B>XJb}$BKv5vGz$gbq3FH@` zEAR~r(;V@ z;ZCX@0E$vetwVtoD106!u)twh0M-KzYOp8z2nH-gKw!o0IBX^XNh-I*1-3XOAUM^P zWnM6^fx{DyP;e*!7GP7Ey%i3}HRKLIXAGK`d}|?`#ts!?2a1y0VvvgLQV=tHx%=B)}P1^8zrZrp$Sj zjdti$+vov#jjxXzvT+bSF!R#q-~{D# zfH|;(#mo!?d*W<}fqwyBR3Rh4%K$P0o&ymWXQM%u1VmBk5(2_wp*sp(1s34g8EW^& zM6JSLj0hU#H86R-P^I?u))dG!b%3h08U<1hBpm=&5QV^}z^)ZYK#+PstN>AgDD;Q( z&V0=1pO_Say(8)$P0Hg@SAM=(1w(p2_%Gb7GNI`qOKVb&u#|siQutRHT<5=;6lWT9 zXy6Z-l!+y;O-ftBYm@TPME4)tnRIL2wWp*mvfCc95k{Rklj}ZQ>X2O=w#vZcbvqN4 z51UoKw2gd{A07sqRW_T@V2)Gj=K8_4CNIUz8@69&O=oOr?JBD0G`TYF9=#Vg^}cqq ziYj_)cgca%pG>*f@pg{$)}-VdS@(pJ6uNyc$0JR}b0-EXzE_N46G|qshfpHOEaT&h zPP`u6?(f^IqJ1ps9Cfhc%V)KcVZn`7-bIvuvW|b|lStW2)xzUdq=C^MRp)@*8g^XwHj$Ef7 zbiVi7BE71!^V4cyibNap>j!f4PBSbe->F*4QrJh1pNjoPb9O4~k=H|T5O42KU1qRe zwIf3R1X(nDQ>*6KF7C{r^orT$2M!z8>b*Is~ZY-N3PqQ^4*W%c!In^wG2uupIMzMS%JUsiW$_Fd|Fd|9vm2K#X_d)v0q z)!A*|l`nes@?}6wj=>0>$R3T8)7$_jz0ce^k=ZS#e#b9o*~D#Rr9```)!%2fYhE-g z%uVL^-Ld+R(6f%d{h(}g*LD5N3Wdzwbq2=5_cSm2D)-LiO$PY5J&q23i*-~A>#F0d z2R~?vGxX0~Z4UQBBBEQFn)0fi@3Q|J-D4UnCy&N5aydCd z^Uc_IjP+Di9tX=hiv-$X-kLRQjERYf;WnmWclwnq`G7|Gp#Rp_0(M}1X0;Ba`|3?goc1&%apc$l|cwi%ZLX_>Ps6ZEl4ce=m}>bf`RGIm4PvN-67Y^0Amcjgj>7 zhbF^k)#eZ~861b!%2_S#U8`(upjTt~BHz61w0?0Q)S;zLkP?#E^3!ndsY6 zsWys$lB%*ug|!vgZD&_06T#x&);{Gb1ImKpyLc1XML|u9iYT1Qm&G;9ge`6{-JZO- zDk-cfj&T>VQ#;avGppLA#sQR#zA#fQZ7~!?7g2Tf&al2OrJc%3$dvU%wNfE^Jy=>yMIZ{9ATpG zad*nqm>UMZH6=4#wx1#vcy^Wa-oBdh-ny2Wi{~EQmVUU`WMQfKy|0qktFA2h+kV~t z>sG6gp;6hLD>i;NYVpU#3(HD+&ZH(zT~X^WmAxaavUg}?&-!Oi8qXyLnj0cmFWs;XZ-Ol%?#PX&);Xgk$|xI*Z_g ztKHC^;aIy*7 zV=e<%n}2N*a^B|cgO3Yev`wsBd+?_RAKzYd{%ODN8;jBq`1Zlaq9omWE7N-iC;Mzz zKH2g^S=rLOh$(LEK?Md`2Mk@;d^>ua-{(!)vFC4?-?Vhu@Wr~Wv(NX8U+&jt<=1fW zi!p~Rl8n_*nZsK%J)-Sn2T4W$Xc{y9k90onN$l%A5z<>( z)=ux0T-d2Ifc;MoKHgr?GRIK2ddaHY??e}Ub5-vpcWzqmfy()RJu)!B-CAXkQWAb^ z+U6Sz`AU#q)K?;>cMCdV#)K4p`~evi zIx~{-(Ys@I?ex9F{JcYV1Y3r^pMJ~LL_*B(qE77ap_@!P8MA2ps%u~M*|__9<>XY0 zSo(QdK><-g=^z4vAW}6TDpkP>hzf#=2pFU)C7b^@ z?|iclcA33Ta`;RRl3CCCt##dZ<*Hpg5ru3n5L2qmgldq$)Iw*h;65Dw(vp+c#0YVK zE%A6JCld2Lpv~p(JqrVjZE7b?%&QLJiB@5u$k6JBn$B9&7xag2HlWl7m;{xgQc^#i zoK_(|o)_CiYkqBhp!5?QsyAL`#Gu8(jqGtQPi4uP<%-SG_Ws6Ks3vb;Zi%0YZ!+8c zi=2F23$;ffo@uJ=q>-!K1OUo~D#T(JeC{AVpwi>;bx3(l zZjihv$27gfQ7o~A#Q>yJ_VeYcpUlIy7efuo6a2#kHsTF3LMK&B_x7J3ta@ZdPMl@d zYkt-;zd29%>7NsD&DCflGW_ukq$lh~WHT$1N>TIj-&!}U>3e~qdtv5mXKP34-6};k z6W>(s%R${Ae#RLsQ1jUB7+4{p%s;E4-?d-JG3CnO%hCWyLxQpcD}`#iNp{l_(00yk zls8*gq)PDeluKlitC2Q89j~<9N(=Del=A*L7SQvidU2Huy=o(!GN)|uezbw*LCE(` zZK=CHb2iQiA+P!qVoU7T}Rl}S(sU5Il01}k_d z-EyuJ#DS>(jIbAm(yDbo42=nuIBS}u2mdbLm(OwG>>AT8q!OHNsV#^LA8``Ty7U;I zWll!W1lT!Bo{RQqGCDvN1{{vQSIdXl*d;y-hQdIZrRR?#n=8xS z1*K*craH0-jzrAZOQx7jh~2+M0ZKgXK^;wAOuD=NedLv}67|d@Nf~Q5%<*(=QTLvh z;sQX5eoBUKL6o!j!^AlOj+emh9#$`L-B;Wfol48zXS<{(*xe+0a8^gi$|F00XXV{~Oq;H#sq-TWyY0x2(e?jEuP^Pi zp5ZX;ej1X}ki+PHcEy37c1JlaeQX!1vV;{kIIvn;dj8U`P~`N3qpHOhPm~X~_Ht&h ziJDwp65%4}t%g%$=ownat|%GPY$b8q-Dm!E9dH#=Fy#|8+dkwGffnj?p818&x;cO;zpcIE3^8!tx!IFdYZmaM2@yQGnR5ig%~_KL+`M3|fQ#MuazLF&IQUC;D$ zAI+_SjPL9RQ?_QV$^38JJ0B#;6lJ7zo1538kb6ipJZniJp0fk#hknFVk0xhuf#O1U^YpC$Js>h*Rm0Zzu0GjBa90Z@`Vt%&6ulf); zAB0k(0~81e`RzzjTl}FGr);Iy*UU2o>X(?Rf@0KJI8ngo=YWj}frJH+BHbBk2vjFR zTV{Bxh|Uap0@T9TM$n!H`i6Qiv=KbJ}46E@(p@6gDFNGz!n2dps^IhqLol_F@7u^Sb&bZJHs839d2U*fqG&E@#!dolA{2FCg}i0XSesWrA;H9;7HK(n2L&8l%&ppL5-NtnsQ^ zH(KBfx+tU2R=Espp9-=EyDzgxk{pp}<@}!)?5gl5howG+pn6G8)mhXjniIq@tb$Lq zmIpJ)l+6IdxIFV!R==ob2y1y1WnJZ~gCW`zz}sppsj}#J22njgiHYEsII2~ygI2EE zL78hguHPt6NP*YX!wu@7N3j7O3ztt?R|PN-kEybQOHhCuf_6XlLXf$l2OJvQ?2LE+~BMQP2aKNcJ(!E{O=6QeB~J z3YTcamNYN_R&}*gRT?KbK|?ud$#PUR+q9|*EDEll#n^x|5rYvm0Xd4=YX4p!7c`X_ z^%s42Yv&*FG&*HoEUVf05HMPdjK<>yVr_1erumIne*TapGnWX9(Np8EJBvB{u+v(k z!B1e$@=7MU{(Tk2UhmRB8;;ea;CR%HUH^g7V0{KZr(1S%Q)xAiXmW^UgN$*N7bbAW zC9}kX2eFTG3%TnB)8A53mY{)uMWP`=0##$E7P%%pDTuKWWUCDs-UbB6p%b51x6R!% zRz^BKJ;^^tDo(*%T+zlT`xmSCCjOyy8qsttB#;nigo0c_l}+Ak(W;_qmZ9^e&gTL2 zvz_whJX+=2k=#=t)qNk0vYT9Jw}bN$%OS1Xa~!X3qC3q&Z6xTwIOrvp`v3uq!3f%! zm?}&FACRD&GzjoxoBU#lc|1A_1<5_>8dX9HR^DdsYZqxxJ(x=62iE>YA&sXXs?XYG ztT@R0575tajVht6Hy^05aOU3BB{B9@2&>rhS{>)F)*IjKP-Bs-kmJf5>tI{z;LcXT z<%r?Wcbcn^{Sz9;#W|Tv0t$Q3&uee2WhDBK)OfF=d%8NU{4z1^*1kFZUrcmyQc+w$ zBz!EhW2JLzF`WgN@wf7-)rzL+IEJp)i7`~xv?LB{v7pD!8=|X(-aq(5_PfXVh$+&> zUq`v0nRg6x#pZj}@^!9tnSU>RVd+uSN5QoHp3HsZfrh0FSBv#OJ`WTGxr6kX zV$xgyxfV9!ssM@raCjvwq!J(||6t`W#!t$-C9;OO~1{jk;-j&}PL z04yOo5S`Fh1)jY8h3)CiVVcf?jOu%w^vC|hcq{~h+M(rv7y!}PNfI7~1;n9%b|xU^ zf0*ufPOfBo5DH>Ma6eZGr7MLPv_nB{&~awoYEIB_Mz2W^Di5b_QwZwmzJ~ULe4H5s zCQ2`BMKehGkZF*L(tYhB$50hi*A0wP8&sFTRI_s-zEaf)3)ieP;Vyb6s1zfHc1^vk zXHSAwVZi|;a23{>P1Mj%S9p`Cu1Em;V(u_dPCi%9f2;vSmvAgUq!}iPFUM3f0K=V; zk)z_sO$HYEIh2I)YYzlG7d3SClK^*|RQ=*WRWvZ?iyO>EcDLuT?g5Y~-jTa1SC9Q! zplGeVZx~G!9O5^ucI&PYiV2>Bjusr17zF9iuL1z@@av^N4oj?osKp$w{1&Km5E2+GOF!jo4@kp?U zHAs}zGq)0IPXo(qp?Bp)1Wc9nBoi4^rN7Xw)WY)yl8}5|j(1#rvxkzw*FDUfuTsz; z;@@%)lJy!a4<|ikLCiF26zazv#o32Va#%< zU5#h7#piv%+~a%60~~QhF)@??>Pi5#ATyu^mA4jn7*i-w_)-%MJ4HYU#5`jV40f<^ z6BxjWkKZ%Xg21(1ORY>h>;e+ z`7N_66+-IC5x95ntWxcI_mKTB?&K*0T$BKEg1w0ED0~)*I)%6&iec@Yl~J%Y1kC2V zWlnD~M)6nSJW$mK$PzNNB8Q`hHUp4Jb`?MmJL2DEMBHsb%Xam?&j|PMeDaiqf5H(t zsWaE|I^b(;z_06bc-Dq_wVWxFu1aPCb7cCvHw{`v{@*j^0(om748IycKMz<#xi(-P zc+EPx(L*Sq#@JJD0@mrr-Evpr?93D!lv` z7o;+f(2m$Rr8IZQbLx?@{_(v7tA| zjBRZ_I7TrE9POVx`#2|M7S2#Cv-+xXbZov&qR=Di6W~g9vDWeJX!Pe5p{U*iSQP)$ zTVDE0YE^yxzxtS`9`H9+xpPC<>#MZSe6z1!Z9OIVngz-qTVv6Jnaa6jWq)O|74z-# zW00TA>bPqz9cEDHr$~5dANBEN;+pIZQo6xw4T|Y#gT^k

UO$g;T>h@D}2T?&cr^ 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 F{y*$K94!C< literal 0 HcmV?d00001 diff --git a/sandbox/eventbus/lib/event_bus.dart b/sandbox/eventbus/lib/event_bus.dart new file mode 100644 index 0000000..e19ecc6 --- /dev/null +++ b/sandbox/eventbus/lib/event_bus.dart @@ -0,0 +1,3 @@ +library event_bus; + +export 'res/res.dart'; diff --git a/sandbox/eventbus/lib/res/app_event.dart b/sandbox/eventbus/lib/res/app_event.dart new file mode 100644 index 0000000..8182351 --- /dev/null +++ b/sandbox/eventbus/lib/res/app_event.dart @@ -0,0 +1,29 @@ +import 'package:clock/clock.dart'; +import 'package:equatable/equatable.dart'; + +/// The base class for all events +abstract class AppEvent extends Equatable { + /// Create the event + const AppEvent(); + + /// The event time + DateTime get timestamp => clock.now(); +} + +/// The event completion event +class EventCompletionEvent extends AppEvent { + /// Create the event + const EventCompletionEvent(this.event); + + /// The event that is completed + final AppEvent event; + + @override + List get props => [event]; +} + +/// The empty event +class EmptyEvent extends AppEvent { + @override + List get props => []; +} diff --git a/sandbox/eventbus/lib/res/event_bus.dart b/sandbox/eventbus/lib/res/event_bus.dart new file mode 100644 index 0000000..d23bb2c --- /dev/null +++ b/sandbox/eventbus/lib/res/event_bus.dart @@ -0,0 +1,212 @@ +import 'package:angel3_reactivex/subjects.dart'; +import 'package:logger/logger.dart'; + +import 'app_event.dart'; +import 'history_entry.dart'; +import 'subscription.dart'; + +/// The event bus interface +abstract class IEventBus { + /// Whether the event bus is busy + bool get isBusy; + + /// Whether the event bus is busy + Stream get isBusy$; + + /// The last event + AppEvent? get last; + + /// The last event + Stream get last$; + + /// The list of events that are in progress + Stream> get inProgress$; + + /// Subscribe `EventBus` on a specific type of event, and register responder to it. + Stream on(); + + /// Subscribe `EventBus` on a specific type of event, and register responder to it. + Stream whileInProgress(); + + /// Subscribe `EventBus` on a specific type of event, and register responder to it. + Subscription respond(Responder responder); + + /// The history of events + List get history; + + /// Fire a event + void fire(AppEvent event); + + /// Fire a event and wait for it to be completed + void watch(AppEvent event); + + /// Complete a event + void complete(AppEvent event, {AppEvent? nextEvent}); + + /// + bool isInProgress(); + + /// Reset the event bus + void reset(); + + /// Dispose the event bus + void dispose(); + + /// Clear the history + void clearHistory(); +} + +/// The event bus implementation +class EventBus implements IEventBus { + /// Create the event bus + EventBus({ + this.maxHistoryLength = 100, + this.map = const {}, + this.allowLogging = false, + }); + + final _logger = Logger(); + + /// The maximum length of history + final int maxHistoryLength; + + /// allow to log all events this when you call [fire] + /// the event will be in console log + final bool allowLogging; + + /// The map of events + final Map> map; + + @override + bool get isBusy => _inProgress.value.isNotEmpty; + @override + Stream get isBusy$ => _inProgress.map((event) => event.isNotEmpty); + + final _lastEventSubject = BehaviorSubject(); + @override + AppEvent? get last => _lastEventSubject.valueOrNull; + @override + Stream get last$ => _lastEventSubject.distinct(); + + final _inProgress = BehaviorSubject>.seeded([]); + List get _isInProgressEvents => _inProgress.value; + @override + Stream> get inProgress$ => _inProgress; + + @override + List get history => List.unmodifiable(_history); + final List _history = []; + + @override + void fire(AppEvent event) { + if (_history.length >= maxHistoryLength) { + _history.removeAt(0); + } + _history.add(EventBusHistoryEntry(event, event.timestamp)); + // 1. Fire the event + _lastEventSubject.add(event); + // 2. Map if needed + _map(event); + // 3. Reset stream + _lastEventSubject.add(EmptyEvent()); + if (allowLogging) { + _logger.d(' ⚡️ [${event.timestamp}] $event'); + } + } + + @override + void watch(AppEvent event) { + fire(event); + _inProgress.add([ + ..._isInProgressEvents, + event, + ]); + } + + @override + void complete(AppEvent event, {AppEvent? nextEvent}) { + // complete the event + if (_isInProgressEvents.any((e) => e == event)) { + final newArr = _isInProgressEvents.toList() + ..removeWhere((e) => e == event); + _inProgress.add(newArr); + fire(EventCompletionEvent(event)); + } + + // fire next event if any + if (nextEvent != null) { + fire(nextEvent); + } + } + + @override + bool isInProgress() { + return _isInProgressEvents.whereType().isNotEmpty; + } + + @override + Stream on() { + if (T == dynamic) { + return _lastEventSubject.stream as Stream; + } else { + return _lastEventSubject.stream.where((event) => event is T).cast(); + } + } + + /// Subscribe `EventBus` on a specific type of event, and register responder to it. + /// + /// When [T] is not given or given as `dynamic`, it listens to all events regardless of the type. + /// Returns [Subscription], which can be disposed to cancel all the subscription registered to itself. + @override + Subscription respond(Responder responder) => + Subscription(_lastEventSubject).respond(responder); + + @override + Stream whileInProgress() { + return _inProgress.map((events) { + return events.whereType().isNotEmpty; + }); + } + + void _map(AppEvent? event) { + if (event == null) { + return; + } + + final functions = map[event.runtimeType] ?? []; + if (functions.isEmpty) { + return; + } + + for (final func in functions) { + final newEvent = func(event); + if (newEvent.runtimeType == event.runtimeType) { + if (allowLogging) { + _logger.d( + ' 🟠 SKIP EVENT: ${newEvent.runtimeType} => ${event.runtimeType}', + ); + } + continue; + } + fire(newEvent); + } + } + + @override + void clearHistory() { + _history.clear(); + } + + @override + void reset() { + clearHistory(); + _inProgress.add([]); + _lastEventSubject.add(EmptyEvent()); + } + + @override + void dispose() { + _inProgress.close(); + _lastEventSubject.close(); + } +} diff --git a/sandbox/eventbus/lib/res/history_entry.dart b/sandbox/eventbus/lib/res/history_entry.dart new file mode 100644 index 0000000..65c7a11 --- /dev/null +++ b/sandbox/eventbus/lib/res/history_entry.dart @@ -0,0 +1,18 @@ +import 'package:equatable/equatable.dart'; + +import 'app_event.dart'; + +/// The history entry +class EventBusHistoryEntry extends Equatable { + /// The history entry + const EventBusHistoryEntry(this.event, this.timestamp); + + /// The event + final AppEvent event; + + /// The timestamp + final DateTime timestamp; + + @override + List get props => [event, timestamp]; +} diff --git a/sandbox/eventbus/lib/res/res.dart b/sandbox/eventbus/lib/res/res.dart new file mode 100644 index 0000000..c2e36e1 --- /dev/null +++ b/sandbox/eventbus/lib/res/res.dart @@ -0,0 +1,4 @@ +export 'app_event.dart'; +export 'event_bus.dart'; +export 'history_entry.dart'; +export 'subscription.dart'; diff --git a/sandbox/eventbus/lib/res/subscription.dart b/sandbox/eventbus/lib/res/subscription.dart new file mode 100644 index 0000000..74bbb41 --- /dev/null +++ b/sandbox/eventbus/lib/res/subscription.dart @@ -0,0 +1,78 @@ +import 'dart:async'; + +/// The function/method signature for the event handler +typedef Responder = void Function(T event); + +/// The class manages the subscription to event bus +class Subscription { + /// Create the subscription + /// + /// Should barely used directly, to subscribe to event bus, use `EventBus.respond`. + Subscription(this._stream); + + /// Returns an instance that indicates there is no subscription + factory Subscription.empty() => const _EmptySubscription(); + + final Stream _stream; + + /// Subscriptions that registered to event bus + final List subscriptions = []; + + Stream _cast() { + if (T == dynamic) { + return _stream as Stream; + } else { + return _stream.where((event) => event is T).cast(); + } + } + + /// Register a [responder] to event bus for the event type [T]. + /// If [T] is omitted or given as `dynamic`, it listens to all events that published on [EventBus]. + /// + /// Method call can be safely chained, and the order doesn't matter. + /// + /// ``` + /// eventBus + /// .respond(responderA) + /// .respond(responderB); + /// ``` + Subscription respond(Responder responder) { + subscriptions.add(_cast().listen(responder)); + return this; + } + + /// Cancel all the registered subscriptions. + /// After calling this method, all the events published won't be delivered to the cleared responders any more. + /// + /// No harm to call more than once. + void dispose() { + if (subscriptions.isEmpty) { + return; + } + for (final s in subscriptions) { + s.cancel(); + } + subscriptions.clear(); + } +} + +class _EmptySubscription implements Subscription { + const _EmptySubscription(); + static final List emptyList = + List.unmodifiable([]); + + @override + void dispose() {} + + @override + Subscription respond(responder) => throw Exception('Not supported'); + + @override + List get subscriptions => emptyList; + + @override + Stream _cast() => throw Exception('Not supported'); + + @override + Stream get _stream => throw Exception('Not supported'); +} diff --git a/sandbox/eventbus/pubspec.yaml b/sandbox/eventbus/pubspec.yaml new file mode 100644 index 0000000..bb71c80 --- /dev/null +++ b/sandbox/eventbus/pubspec.yaml @@ -0,0 +1,20 @@ +name: angel3_event_bus +description: Event Bus for Dart. +version: 0.6.2 +homepage: https://github.com/AndrewPiterov/event_bus_plus + +environment: + sdk: '>=2.17.1 <4.0.0' + +dependencies: + clock: ^1.1.0 + equatable: ^2.0.5 + logger: ^2.0.2+1 + angel3_reactivex: ^0.27.5 + +dev_dependencies: + flutter_lints: ^3.0.0 + given_when_then_unit_test: ^0.2.1 + shouldly: ^0.5.0+1 + test: ^1.22.0 + diff --git a/sandbox/eventbus/test/completion_test.dart b/sandbox/eventbus/test/completion_test.dart new file mode 100644 index 0000000..6105911 --- /dev/null +++ b/sandbox/eventbus/test/completion_test.dart @@ -0,0 +1,70 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'models.dart'; +import 'package:test/test.dart'; + +void main() { + late IEventBus bus; + + before(() { + bus = EventBus(); + }); + + test('emit Follower Events', () { + expect( + bus.on(), + emitsInOrder([ + const FollowAppEvent('username'), + EmptyEvent(), + const FollowAppEvent('username3'), + EmptyEvent(), + const FollowAppEvent('username2'), + EmptyEvent(), + ])); + + bus.fire(const FollowAppEvent('username')); + bus.fire(const FollowAppEvent('username3')); + bus.fire(const FollowAppEvent('username2')); + }); + + test('start watch but not complete', () { + expect( + bus.on(), + emitsInOrder([ + const FollowAppEvent('username'), + ])); + + bus.watch(const FollowAppEvent('username')); + }); + + test('start watch and complete', () { + const watchable = FollowAppEvent('username3'); + expect( + bus.on(), + emitsInOrder([ + watchable, + EmptyEvent(), + const EventCompletionEvent(watchable), + EmptyEvent(), + const FollowSuccessfullyEvent(watchable), + EmptyEvent(), + ])); + + bus.watch(watchable); + bus.complete(watchable, + nextEvent: const FollowSuccessfullyEvent(watchable)); + }); + + // test('emit Follower Events', () { + // final watchable = FollowAppEvent('username3', id: '3'); + // expect( + // _bus.on(), + // emitsInAnyOrder([ + // FollowAppEvent('username3', id: '3'), + // FollowSuccessfullyAppEvent(watchable), + // ])); + + // _bus.watch(watchable); + // _bus.complete(watchable, withh: FollowSuccessfullyAppEvent(watchable)); + // }); +} diff --git a/sandbox/eventbus/test/distinct_test.dart b/sandbox/eventbus/test/distinct_test.dart new file mode 100644 index 0000000..5aeaf9f --- /dev/null +++ b/sandbox/eventbus/test/distinct_test.dart @@ -0,0 +1,58 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +import 'models.dart'; + +void main() { + late IEventBus bus; + + before(() { + bus = EventBus(); + }); + + test('Call once', () { + expectLater( + bus.last$, + emitsInOrder([ + const SomeEvent(), + EmptyEvent(), + const SomeAnotherEvent(), + EmptyEvent(), + ])); + bus.fire(const SomeEvent()); + bus.fire(const SomeAnotherEvent()); + }); + + // test('Call twice', () { + // const event = SomeEvent(); + // expectLater( + // bus.last$, + // emitsInOrder([ + // const SomeEvent(), + // EmptyEvent(), + // const SomeAnotherEvent(), + // EmptyEvent(), + // ])); + // bus.fire(event); + // bus.fire(event); + // bus.fire(const SomeAnotherEvent()); + // }); + + // test('Call three times', () { + // const event = SomeEvent(); + // expectLater( + // bus.last$, + // emitsInOrder([ + // const SomeEvent(), + // EmptyEvent(), + // const SomeAnotherEvent(), + // EmptyEvent(), + // ])); + // bus.fire(event); + // bus.fire(event); + // bus.fire(event); + // bus.fire(const SomeAnotherEvent()); + // }); +} diff --git a/sandbox/eventbus/test/empty_event_test.dart b/sandbox/eventbus/test/empty_event_test.dart new file mode 100644 index 0000000..050505e --- /dev/null +++ b/sandbox/eventbus/test/empty_event_test.dart @@ -0,0 +1,20 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:test/test.dart'; +import 'models.dart'; + +void main() { + final IEventBus _bus = EventBus(); + + test('Should fire Empty event', () { + expect( + _bus.last$, + emitsInOrder( + [ + const SomeEvent(), + EmptyEvent(), + ], + ), + ); + _bus.fire(const SomeEvent()); + }, timeout: const Timeout(Duration(seconds: 1))); +} diff --git a/sandbox/eventbus/test/event_bus_test.dart b/sandbox/eventbus/test/event_bus_test.dart new file mode 100644 index 0000000..5d7a5b1 --- /dev/null +++ b/sandbox/eventbus/test/event_bus_test.dart @@ -0,0 +1,63 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:shouldly/shouldly.dart'; +import 'package:test/scaffolding.dart'; + +import 'models.dart'; + +void main() { + late IEventBus bus; + + before(() { + bus = EventBus(); + }); + + test('Empty event bus', () { + bus.isBusy.should.beFalse(); + }); + + when('start some event', () { + const event = FollowAppEvent('username'); + // const eventId = '1'; + + before(() { + bus.watch(event); + }); + + then('should be busy', () { + bus.isBusy.should.beTrue(); + }); + + then('should be in progress', () { + bus.isInProgress().should.beTrue(); + }); + + and('complete the event', () { + before(() { + bus.complete(event); + }); + + then('should not be busy', () { + bus.isBusy.should.beFalse(); + }); + + then('should not be in progress', () { + bus.isInProgress().should.not.beTrue(); + }); + }); + }); + + group('compare equality', () { + // test('compare two equal events - should not be equal', () { + // final event = FollowAppEvent('username'); + // final event2 = FollowAppEvent('username'); + // event.should.not.be(event2); + // }); + + test('compare two equal events - should be equal', () { + const event = FollowAppEvent('username'); + const event2 = FollowAppEvent('username'); + event.should.be(event2); + }); + }); +} diff --git a/sandbox/eventbus/test/history_test.dart b/sandbox/eventbus/test/history_test.dart new file mode 100644 index 0000000..9eaf709 --- /dev/null +++ b/sandbox/eventbus/test/history_test.dart @@ -0,0 +1,75 @@ +import 'package:clock/clock.dart'; +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:shouldly/shouldly.dart'; +import 'package:test/test.dart'; + +import 'models.dart'; + +void main() { + late IEventBus bus; + + before(() { + bus = EventBus(maxHistoryLength: 3); + }); + + test('Keep history', () { + final date = DateTime(2022, 9, 1); + withClock(Clock.fixed(date), () { + bus.fire(const SomeEvent()); + bus.fire(const SomeAnotherEvent()); + bus.fire(const FollowAppEvent('@username')); + + bus.history.should.be([ + EventBusHistoryEntry(const SomeEvent(), date), + EventBusHistoryEntry(const SomeAnotherEvent(), date), + EventBusHistoryEntry(const FollowAppEvent('@username'), date), + ]); + }); + }); + + test('Keep full history without debounce', () { + final date = DateTime(2022, 9, 1, 4, 59, 55); + withClock(Clock.fixed(date), () { + bus.fire(const SomeEvent()); + bus.fire(const SomeEvent()); + bus.fire(const SomeAnotherEvent()); + + bus.history.should.be([ + EventBusHistoryEntry(const SomeEvent(), date), + EventBusHistoryEntry(const SomeEvent(), date), + EventBusHistoryEntry(const SomeAnotherEvent(), date), + ]); + }); + }); + + test('Clear history', () { + bus.fire(const SomeEvent()); + bus.fire(const SomeAnotherEvent()); + + bus.clearHistory(); + + bus.history.should.beEmpty(); + }); + + group('History length', () { + test('Add more than max', () { + final date = DateTime(2022, 9, 1, 4, 59, 55); + + withClock(Clock.fixed(date), () { + bus.fire(const SomeEvent()); + bus.fire(const SomeAnotherEvent()); + bus.fire(const FollowAppEvent('@username')); + bus.fire(const NewCommentEvent('text')); + + bus.history.length.should.be(3); + + bus.history.should.be([ + EventBusHistoryEntry(const SomeAnotherEvent(), date), + EventBusHistoryEntry(const FollowAppEvent('@username'), date), + EventBusHistoryEntry(const NewCommentEvent('text'), date), + ]); + }); + }); + }); +} diff --git a/sandbox/eventbus/test/mapping/map_ignore_test.dart b/sandbox/eventbus/test/mapping/map_ignore_test.dart new file mode 100644 index 0000000..496aed7 --- /dev/null +++ b/sandbox/eventbus/test/mapping/map_ignore_test.dart @@ -0,0 +1,36 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:test/test.dart'; + +import '../models.dart'; + +void main() { + late IEventBus bus; + + before( + () { + bus = EventBus( + map: { + SomeEvent: [ + (e) => e, + (e) => const SomeAnotherEvent(), + ], + }, + ); + }, + ); + + test('does not emit the same event', () { + expect( + bus.last$, + emitsInOrder( + [ + const SomeEvent(), + const SomeAnotherEvent(), + EmptyEvent(), + ], + ), + ); + bus.fire(const SomeEvent()); + }, timeout: const Timeout(Duration(seconds: 1))); +} diff --git a/sandbox/eventbus/test/mapping/map_test.dart b/sandbox/eventbus/test/mapping/map_test.dart new file mode 100644 index 0000000..f83ef02 --- /dev/null +++ b/sandbox/eventbus/test/mapping/map_test.dart @@ -0,0 +1,34 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:test/test.dart'; + +import '../models.dart'; + +void main() { + late IEventBus bus; + + before( + () { + bus = EventBus( + map: { + SomeEvent: [ + (e) => const SomeAnotherEvent(), + ], + }, + ); + }, + ); + + test('emits another', () { + expect( + bus.last$, + emitsInOrder( + [ + const SomeEvent(), + const SomeAnotherEvent(), + ], + ), + ); + bus.fire(const SomeEvent()); + }, timeout: const Timeout(Duration(seconds: 1))); +} diff --git a/sandbox/eventbus/test/models.dart b/sandbox/eventbus/test/models.dart new file mode 100644 index 0000000..899c50f --- /dev/null +++ b/sandbox/eventbus/test/models.dart @@ -0,0 +1,42 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; + +class FollowAppEvent extends AppEvent { + const FollowAppEvent(this.username); + + final String username; + + @override + List get props => [username]; +} + +class FollowSuccessfullyEvent extends AppEvent { + const FollowSuccessfullyEvent(this.starting); + + final FollowAppEvent starting; + + @override + List get props => [starting]; +} + +class NewCommentEvent extends AppEvent { + const NewCommentEvent(this.text); + + final String text; + + @override + List get props => [text]; +} + +class SomeEvent extends AppEvent { + const SomeEvent(); + + @override + List get props => []; +} + +class SomeAnotherEvent extends AppEvent { + const SomeAnotherEvent(); + + @override + List get props => []; +} diff --git a/sandbox/eventbus/test/respond_test.dart b/sandbox/eventbus/test/respond_test.dart new file mode 100644 index 0000000..3c9b5cf --- /dev/null +++ b/sandbox/eventbus/test/respond_test.dart @@ -0,0 +1,74 @@ +// ignore_for_file: prefer_const_constructors + +import 'dart:async'; +import 'dart:developer'; + +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +import 'models.dart'; + +void main() { + late IEventBus bus; + + before(() { + bus = EventBus(); + }); + + test('emit Some Event', () { + final ctrl = StreamController(); + + final sub = bus.respond((event) { + log('new comment'); + ctrl.add(2); + }).respond((event) { + log('new follower'); + ctrl.add(1); + }); + + expect(ctrl.stream, emitsInOrder([1, 2])); + + bus.fire(FollowAppEvent('username')); + bus.fire(NewCommentEvent('comment #1')); + }); + + test('emit Some Events', () { + final ctrl = StreamController(); + + final sub = bus.respond((event) { + log('new comment'); + ctrl.add(2); + }).respond((event) { + log('new follower'); + ctrl.add(1); + }); + + expect(ctrl.stream, emitsInOrder([1, 2, 1])); + + bus.fire(FollowAppEvent('username')); + bus.fire(NewCommentEvent('comment #1')); + bus.fire(FollowAppEvent('username2')); + }); + + test('emit all Event', () { + final ctrl = StreamController(); + + final sub = bus.respond((event) { + log('new comment'); + ctrl.add(2); + }).respond((event) { + log('new follower'); + ctrl.add(1); + }).respond((event) { + log('event $event'); + ctrl.add(3); + }); + + expect(ctrl.stream, emitsInOrder([1, 3, 3, 2, 3, 3])); + + bus.fire(FollowAppEvent('username')); + bus.fire(NewCommentEvent('comment #1')); + }); +} diff --git a/sandbox/eventbus/test/streams_test.dart b/sandbox/eventbus/test/streams_test.dart new file mode 100644 index 0000000..1cec696 --- /dev/null +++ b/sandbox/eventbus/test/streams_test.dart @@ -0,0 +1,56 @@ +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:test/test.dart'; +import 'models.dart'; + +void main() { + late IEventBus bus; + + before(() { + bus = EventBus(); + }); + + test('description', () { + bus.inProgress$.map((List events) => + events.whereType().isNotEmpty); + }, skip: 'should skip'); + + test('emit Follower Event', () { + const id = 'id'; + expect(bus.on(), emitsInAnyOrder([const FollowAppEvent('username')])); + bus.fire(const FollowAppEvent('username')); + }); + + test('emit Follower Events', () { + expect( + bus.on(), + emitsInOrder([ + const FollowAppEvent('username'), + EmptyEvent(), + const FollowAppEvent('username3'), + EmptyEvent(), + const FollowAppEvent('username2'), + EmptyEvent(), + ])); + + bus.fire(const FollowAppEvent('username')); + bus.fire(const FollowAppEvent('username3')); + bus.fire(const FollowAppEvent('username2')); + }); + + test('emit New Comment Event', () { + expect( + bus.on(), + emitsInOrder([ + const NewCommentEvent('comment #1'), + const NewCommentEvent('comment #2'), + ])); + + bus.fire(const FollowAppEvent('username3')); + bus.fire(const FollowAppEvent('username3')); + bus.fire(const NewCommentEvent('comment #1')); + bus.fire(const FollowAppEvent('username3')); + bus.fire(const NewCommentEvent('comment #2')); + bus.fire(const FollowAppEvent('username3')); + }); +} diff --git a/sandbox/eventbus/test/timestamp_test.dart b/sandbox/eventbus/test/timestamp_test.dart new file mode 100644 index 0000000..a8dc0d0 --- /dev/null +++ b/sandbox/eventbus/test/timestamp_test.dart @@ -0,0 +1,36 @@ +import 'package:clock/clock.dart'; +import 'package:event_bus_plus/event_bus_plus.dart'; +import 'package:given_when_then_unit_test/given_when_then_unit_test.dart'; +import 'package:shouldly/shouldly.dart'; +import 'package:test/test.dart'; +import 'dart:developer' as dev; + +import 'models.dart'; + +void main() { + late IEventBus bus; + + before(() { + bus = EventBus(maxHistoryLength: 3); + }); + + test('right timestamp', () { + final date = DateTime(2022, 9, 1); + withClock(Clock.fixed(date), () { + bus.fire(const SomeEvent()); + bus.fire(const SomeAnotherEvent()); + bus.fire(const FollowAppEvent('@username')); + + for (final e in bus.history) { + e.timestamp.should.be(date); + dev.log(e.toString()); + } + + bus.history.should.be([ + EventBusHistoryEntry(const SomeEvent(), date), + EventBusHistoryEntry(const SomeAnotherEvent(), date), + EventBusHistoryEntry(const FollowAppEvent('@username'), date), + ]); + }); + }); +} diff --git a/sandbox/eventbus/tool/coverage.sh b/sandbox/eventbus/tool/coverage.sh new file mode 100755 index 0000000..5313d46 --- /dev/null +++ b/sandbox/eventbus/tool/coverage.sh @@ -0,0 +1,13 @@ +#!/bin/sh +cd .. +# Generate `coverage/lcov.info` file +flutter test --coverage +# Generate HTML report +# Note: on macOS you need to have lcov installed on your system (`brew install lcov`) to use this: +genhtml coverage/lcov.info -o coverage/html +# Open the report +open coverage/html/index.html + + + + diff --git a/sandbox/mqueue/.github/workflows/action.yaml b/sandbox/mqueue/.github/workflows/action.yaml new file mode 100644 index 0000000..b1c9c11 --- /dev/null +++ b/sandbox/mqueue/.github/workflows/action.yaml @@ -0,0 +1,43 @@ +name: build + +on: + push: + branches: + - master + - main + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: 📚 Git Checkout + uses: actions/checkout@v4 + + - name: 🎯 Setup Dart + uses: dart-lang/setup-dart@v1 + + - name: 📦 Install Dependencies + run: dart pub get + + - name: ✨ Check Formatting + run: dart format --line-length 80 --set-exit-if-changed . + + - name: 🕵️ Analyze + run: dart analyze --fatal-infos --fatal-warnings . + + - name: 🧪 Run Tests + run: | + dart pub global activate coverage 1.2.0 + dart test --coverage=coverage && dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info + + - name: 📊 Check Code Coverage + uses: VeryGoodOpenSource/very_good_coverage@v2 + with: + path: ./coverage/lcov.info + min_coverage: 100 + + - name: 📈 Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file diff --git a/sandbox/mqueue/.gitignore b/sandbox/mqueue/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/sandbox/mqueue/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/sandbox/mqueue/CHANGELOG.md b/sandbox/mqueue/CHANGELOG.md new file mode 100644 index 0000000..70c0899 --- /dev/null +++ b/sandbox/mqueue/CHANGELOG.md @@ -0,0 +1,19 @@ +## 1.0.0 + +- Initial version of the package. + +## 1.0.1 + +- Fix documentation. (Image path) +- Update package description. +- Fix linter rules. (Type matching) +- Update `example` files. +- Remove `mocktail` dependency. + +## 1.0.2 + + - Update documentation. + +## 1.1.0 + + - `Deprecate` the `Consumer` mixin in favor of `ConsumerMixin`. ([#1](https://github.com/N-Razzouk/dart_mq/issues/1)) diff --git a/sandbox/mqueue/LICENSE b/sandbox/mqueue/LICENSE new file mode 100644 index 0000000..0c5e429 --- /dev/null +++ b/sandbox/mqueue/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Naif Razzouk + +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. diff --git a/sandbox/mqueue/README.md b/sandbox/mqueue/README.md new file mode 100644 index 0000000..2563c78 --- /dev/null +++ b/sandbox/mqueue/README.md @@ -0,0 +1,165 @@ +# DartMQ: A Message Queue System for Dart and Flutter + + + +[![Pub](https://img.shields.io/pub/v/dart_mq.svg)](https://pub.dev/packages/dart_mq) +[![coverage](https://codecov.io/gh/N-Razzouk/dart_mq/graph/badge.svg)](https://app.codecov.io/gh/N-Razzouk/dart_mq) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + +DartMQ is a Dart package that provides message queue functionality for sending messages between different components in your Dart and Flutter applications. It offers a simple and efficient way to implement message queues, making it easier to build robust and scalable applications. + +## Table of Contents + +1. [Introduction](#introduction) +2. [Exchanges](#exchanges) +3. [Usage](#usage) +4. [Examples](#examples) +5. [Acknowledgment](#acknowledgment) + +### + +## Introduction + +In the development of complex applications, dependencies among components are almost inevitable. Often, different components within your application need to communicate with each other, leading to tight coupling between these elements. + +![Components](https://github.com/N-Razzouk/dart_mq/blob/master/assets/components.png?raw=true) + +### + +Message queues provide an effective means to decouple these components by enabling communication through messages. This decoupling strategy enhances the development of robust applications. + +![Components with MQ](https://github.com/N-Razzouk/dart_mq/blob/master/assets/components-mq.png?raw=true) + +### + +DartMQ employs the publish-subscribe pattern. **Producers** send messages, **Consumers** receive them, and **Queues** and **Exchanges** facilitate this communication. + +![Simple View](https://github.com/N-Razzouk/dart_mq/blob/master/assets/simple-view.png?raw=true) + +### + +Communication channels are called Exchanges. Exchanges receive messages from Producers, efficiently routing them to Queues for Consumer consumption. + +![Detailed View](https://github.com/N-Razzouk/dart_mq/blob/master/assets/detailed-view.png?raw=true) + +## Exchanges + +### DartMQ provides different types of Exchanges for different use cases. + +### + +- **Default Exchange**: Routes messages based on Queue names. + +![Default Exchange](https://github.com/N-Razzouk/dart_mq/blob/master/assets/default-exchange.png?raw=true) + +### + +- **Fanout Exchange**: Sends messages to all bound Queues. + +![Fanout Exchange](https://github.com/N-Razzouk/dart_mq/blob/master/assets/fanout-exchange.png?raw=true) + +### + +- **Direct Exchange**: Routes messages to Queues based on routing keys. + +![Direct Exchange](https://github.com/N-Razzouk/dart_mq/blob/master/assets/direct-exchange.png?raw=true) + +## Usage + +### Initialize an MQClient: + + + +```dart +import 'package:dart_mq/dart_mq.dart'; + +void main() { + // Initialize DartMQ + MQClient.initialize(); + + // Your application code here +} + +``` + +### Declare a Queue: + +```dart +MQClient.declareQueue('my_queue'); +``` + +> Note: Queues are idempotent, which means that if you declare a Queue multiple times, it will not create multiple Queues. Instead, it will return the existing Queue. + +### Create a Producer: + +```dart +class MyProducer with ProducerMixin { + void greet(String message) { + // Send a message to the queue + sendMessage( + routingKey: 'my_queue', + payload: message, + ); + } +} +``` + +> Note: `exchangeName` is optional. If you don't specify an exchange name, the message is sent to the default exchange. + +### Create a Consumer: + +```dart +class MyConsumer with ConsumerMixin { + void listenToQueue() { + // Subscribe to the queue and process incoming messages + subscribe( + queueId: 'my_queue', + callback: (message) { + // Handle incoming message + print('Received message: $message'); + }, + ) + } +} +``` + +### Putting it all together: + +```dart +void main() { + // Initialize DartMQ + MQClient.initialize(); + + // Declare a Queue + MQClient.declareQueue('my_queue'); + + // Create a Producer + final producer = MyProducer(); + + // Create a Consumer + final consumer = MyConsumer(); + + // Start listening + consumer.listenToQueue(); + + // Send a message + producer.greet('Hello World!'); + + // Your application code here + ... +} +``` + +## Examples + +- [Hello World](example/hello_world): A simple example that demonstrates how to send and receive messages using DartMQ. + +- [Message Filtering](example/message_filtering): An example that demonstrates how to multiple consumers can listen to the same queue and filter messages accordingly. + +- [Routing](example/routing): An example that demonstrates how to use Direct Exchanges to route messages to different queues based on the routing key. + +- [RPC (Remote Procedure Call)](example/rpc): An example that demonstrates how to send RPC requests and receive responses using DartMQ. + +## Acknowledgment + +- [RabbitMQ](https://www.rabbitmq.com/): This package is inspired by RabbitMQ, an open-source message-broker software that implements the Advanced Message Queuing Protocol (AMQP). diff --git a/sandbox/mqueue/analysis_options.yaml b/sandbox/mqueue/analysis_options.yaml new file mode 100644 index 0000000..662618b --- /dev/null +++ b/sandbox/mqueue/analysis_options.yaml @@ -0,0 +1,211 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +linter: + rules: + - prefer_const_constructors + - prefer_const_literals_to_create_immutables + - prefer_final_fields + - always_put_required_named_parameters_first + - avoid_init_to_null + - lines_longer_than_80_chars + - use_function_type_syntax_for_parameters + - avoid_relative_lib_imports + - avoid_shadowing_type_parameters + - avoid_equals_and_hash_code_on_mutable_classes + - unnecessary_brace_in_string_interps + - always_declare_return_types + - always_use_package_imports + - annotate_overrides + - avoid_bool_literals_in_conditional_expressions + - avoid_catching_errors + - avoid_double_and_int_checks + - avoid_dynamic_calls + - avoid_empty_else + - avoid_escaping_inner_quotes + - avoid_field_initializers_in_const_classes + - avoid_final_parameters + - avoid_function_literals_in_foreach_calls + - avoid_js_rounded_ints + - avoid_multiple_declarations_per_line + - avoid_null_checks_in_equality_operators + - avoid_positional_boolean_parameters + - avoid_print + - avoid_private_typedef_functions + - avoid_redundant_argument_values + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + - avoid_returning_null_for_void + - avoid_returning_this + - avoid_setters_without_getters + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_type_to_string + - avoid_types_as_parameter_names + - avoid_unnecessary_containers + - avoid_unused_constructor_parameters + - avoid_void_async + - avoid_web_libraries_in_flutter + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + - cascade_invocations + - cast_nullable_to_non_nullable + - collection_methods_unrelated_type + - combinators_ordering + - comment_references + - conditional_uri_does_not_exist + - constant_identifier_names + - control_flow_in_finally + - curly_braces_in_flow_control_structures + - dangling_library_doc_comments + - depend_on_referenced_packages + - deprecated_consistency + - directives_ordering + - empty_catches + - empty_constructor_bodies + - empty_statements + - eol_at_end_of_file + - exhaustive_cases + - file_names + - flutter_style_todos + - hash_and_equals + - implementation_imports + - implicit_call_tearoffs + - implicit_reopen + - invalid_case_patterns + - join_return_with_assignment + - leading_newlines_in_multiline_strings + - library_annotations + - library_names + - library_prefixes + - library_private_types_in_public_api + - literal_only_boolean_expressions + - missing_whitespace_between_adjacent_strings + - no_adjacent_strings_in_list + - no_default_cases + - no_duplicate_case_values + - no_leading_underscores_for_library_prefixes + - no_leading_underscores_for_local_identifiers + - no_logic_in_create_state + - no_runtimeType_toString + - non_constant_identifier_names + - noop_primitive_operations + - null_check_on_nullable_type_parameter + - null_closures + - omit_local_variable_types + - one_member_abstracts + - only_throw_errors + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + - parameter_assignments + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + - prefer_asserts_with_message + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_constructors_over_static_methods + - prefer_contains + - prefer_final_in_for_each + - prefer_final_locals + - prefer_for_elements_to_map_fromIterable + - prefer_function_declarations_over_variables + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + - prefer_int_literals + - prefer_interpolation_to_compose_strings + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + - prefer_null_aware_method_calls + - prefer_null_aware_operators + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + - provide_deprecation_message + - public_member_api_docs + - recursive_getters + - require_trailing_commas + - secure_pubspec_urls + - sized_box_for_whitespace + - sized_box_shrink_expand + - slash_for_doc_comments + - sort_child_properties_last + - sort_constructors_first + - sort_pub_dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + - tighten_type_of_initializing_formals + - type_annotate_public_apis + - type_init_formals + - unawaited_futures + - unnecessary_await_in_return + - unnecessary_breaks + - unnecessary_const + - unnecessary_constructor_name + - unnecessary_getters_setters + - unnecessary_lambdas + - unnecessary_late + - unnecessary_library_directive + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_checks + - unnecessary_null_in_if_null_operators + - unnecessary_nullable_for_final_variable_declarations + - unnecessary_overrides + - unnecessary_parenthesis + - unnecessary_raw_strings + - unnecessary_statements + - unnecessary_string_escapes + - unnecessary_string_interpolations + - unnecessary_this + - unnecessary_to_list_in_spreads + - unrelated_type_equality_checks + - use_build_context_synchronously + - use_colored_box + - use_enums + - use_full_hex_values_for_flutter_colors + - use_if_null_to_convert_nulls_to_bools + - use_is_even_rather_than_modulo + - use_key_in_widget_constructors + - use_late_for_private_fields_and_variables + - use_named_constants + - use_raw_strings + - use_rethrow_when_possible + - use_setters_to_change_properties + - use_string_buffers + - use_string_in_part_of_directives + - use_super_parameters + - use_test_throws_matchers + - use_to_and_as_if_applicable + - valid_regexps + - void_checks + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/sandbox/mqueue/assets/components-mq.png b/sandbox/mqueue/assets/components-mq.png new file mode 100644 index 0000000000000000000000000000000000000000..c0bf8458db1eca272316fec07d39592eaae9ea4d GIT binary patch literal 94259 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

G#gfD{lep_6lsC`;ik*cPE(s+MU~d+I$^YW@<@E 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 literal 0 HcmV?d00001 diff --git a/sandbox/mqueue/assets/components.png b/sandbox/mqueue/assets/components.png new file mode 100644 index 0000000000000000000000000000000000000000..bfced0ab57949867639198a96363f32bddcfa536 GIT binary patch literal 30338 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 us0|D1!3KEhENOwt_bT1EG|W&# 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 literal 0 HcmV?d00001 diff --git a/sandbox/mqueue/assets/detailed-view.png b/sandbox/mqueue/assets/detailed-view.png new file mode 100644 index 0000000000000000000000000000000000000000..2ce7eee66245a2f02d25e6d36fc062f5975a4c9d GIT binary patch literal 138254 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 literal 0 HcmV?d00001 diff --git a/sandbox/mqueue/assets/direct-exchange.png b/sandbox/mqueue/assets/direct-exchange.png new file mode 100644 index 0000000000000000000000000000000000000000..f519dce78ce0b46567f997c5269436a4a94a9ea2 GIT binary patch literal 42545 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

;2iY&&*OHj2Y*uv8YP>TwVNP!F|O8q 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 S@KgZ}cqz+k$d$=j2K*mBg?*y{ literal 0 HcmV?d00001 diff --git a/sandbox/mqueue/assets/fanout-exchange.png b/sandbox/mqueue/assets/fanout-exchange.png new file mode 100644 index 0000000000000000000000000000000000000000..823a250264b00b16ed712b510c3019df29037343 GIT binary patch literal 26191 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 literal 0 HcmV?d00001 diff --git a/sandbox/mqueue/assets/simple-view.png b/sandbox/mqueue/assets/simple-view.png new file mode 100644 index 0000000000000000000000000000000000000000..b24e6b8b30222b1817ebf75e8fc8be7a7e7a4bcd GIT binary patch literal 36356 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 Fe*jrDWa0n- literal 0 HcmV?d00001 diff --git a/sandbox/mqueue/example/main.dart b/sandbox/mqueue/example/main.dart new file mode 100644 index 0000000..83f3e03 --- /dev/null +++ b/sandbox/mqueue/example/main.dart @@ -0,0 +1,16 @@ +import 'package:angel3_mq/mq.dart'; + +import 'receiver.dart'; +import 'sender.dart'; + +void main() async { + MQClient.initialize(); + + final sender = Sender(); + + final receiver = Receiver()..listenToGreeting(); + + await sender.sendGreeting(greeting: 'Hello, World!'); + + receiver.stopListening(); +} diff --git a/sandbox/mqueue/example/message_filtering/main.dart b/sandbox/mqueue/example/message_filtering/main.dart new file mode 100644 index 0000000..c5945a7 --- /dev/null +++ b/sandbox/mqueue/example/message_filtering/main.dart @@ -0,0 +1,27 @@ +import 'package:angel3_mq/mq.dart'; + +import 'task_manager.dart'; +import 'worker_one.dart'; +import 'worker_two.dart'; + +void main() async { + MQClient.initialize(); + + final workerOne = WorkerOne(); + + final workerTwo = WorkerTwo(); + + final taskManager = TaskManager(); + + workerOne.startListening(); + + workerTwo.startListening(); + + taskManager + ..sendTask(task: 'Hello..') + ..sendTask(task: 'Hello...') + ..sendTask(task: 'Hello....') + ..sendTask(task: 'Hello.') + ..sendTask(task: 'Hello.......') + ..sendTask(task: 'Hello..'); +} diff --git a/sandbox/mqueue/example/message_filtering/task_manager.dart b/sandbox/mqueue/example/message_filtering/task_manager.dart new file mode 100644 index 0000000..9c6aee9 --- /dev/null +++ b/sandbox/mqueue/example/message_filtering/task_manager.dart @@ -0,0 +1,12 @@ +import 'package:angel3_mq/mq.dart'; + +final class TaskManager with ProducerMixin { + TaskManager() { + MQClient.instance.declareQueue('task_queue'); + } + + void sendTask({required String task}) => sendMessage( + payload: task, + routingKey: 'task_queue', + ); +} diff --git a/sandbox/mqueue/example/message_filtering/worker_one.dart b/sandbox/mqueue/example/message_filtering/worker_one.dart new file mode 100644 index 0000000..788c6bb --- /dev/null +++ b/sandbox/mqueue/example/message_filtering/worker_one.dart @@ -0,0 +1,22 @@ +import 'dart:developer'; + +import 'package:angel3_mq/mq.dart'; + +final class WorkerOne with ConsumerMixin { + WorkerOne() { + MQClient.instance.declareQueue('task_queue'); + } + + void startListening() => subscribe( + queueId: 'task_queue', + filter: (Object messagePayload) => messagePayload + .toString() + .split('') + .where((String char) => char == '.') + .length + .isEven, + callback: (Message message) { + log('WorkerOne reacting to ${message.payload}'); + }, + ); +} diff --git a/sandbox/mqueue/example/message_filtering/worker_two.dart b/sandbox/mqueue/example/message_filtering/worker_two.dart new file mode 100644 index 0000000..a4cbd98 --- /dev/null +++ b/sandbox/mqueue/example/message_filtering/worker_two.dart @@ -0,0 +1,24 @@ +import 'dart:developer'; + +import 'package:angel3_mq/mq.dart'; + +final class WorkerTwo with ConsumerMixin { + WorkerTwo() { + MQClient.instance.declareQueue('task_queue'); + } + + void startListening() => subscribe( + queueId: 'task_queue', + filter: (Object messagePayload) => + messagePayload + .toString() + .split('') + .where((String char) => char == '.') + .length % + 2 != + 0, + callback: (Message message) { + log('WorkerTwo reacting to ${message.payload}'); + }, + ); +} diff --git a/sandbox/mqueue/example/receiver.dart b/sandbox/mqueue/example/receiver.dart new file mode 100644 index 0000000..8b929a8 --- /dev/null +++ b/sandbox/mqueue/example/receiver.dart @@ -0,0 +1,18 @@ +import 'dart:developer'; + +import 'package:angel3_mq/mq.dart'; + +final class Receiver with ConsumerMixin { + Receiver() { + MQClient.instance.declareQueue('hello'); + } + + void listenToGreeting() => subscribe( + queueId: 'hello', + callback: (Message message) { + log('Received: ${message.payload}'); + }, + ); + + void stopListening() => unsubscribe(queueId: 'hello'); +} diff --git a/sandbox/mqueue/example/routing/debug_logger.dart b/sandbox/mqueue/example/routing/debug_logger.dart new file mode 100644 index 0000000..e45bece --- /dev/null +++ b/sandbox/mqueue/example/routing/debug_logger.dart @@ -0,0 +1,39 @@ +import 'dart:developer'; + +import 'package:angel3_mq/mq.dart'; + +final class DebugLogger with ConsumerMixin { + DebugLogger() { + MQClient.instance.declareExchange( + exchangeName: 'logs', + exchangeType: ExchangeType.direct, + ); + _queueName = MQClient.instance.declareQueue('debug'); + } + + late final String _queueName; + + void startListening() { + MQClient.instance.bindQueue( + queueId: _queueName, + exchangeName: 'logs', + bindingKey: 'info', + ); + MQClient.instance.bindQueue( + queueId: _queueName, + exchangeName: 'logs', + bindingKey: 'warning', + ); + MQClient.instance.bindQueue( + queueId: _queueName, + exchangeName: 'logs', + bindingKey: 'error', + ); + subscribe( + queueId: _queueName, + callback: (Message message) { + log('Debug Logger recieved: ${message.payload}'); + }, + ); + } +} diff --git a/sandbox/mqueue/example/routing/logger.dart b/sandbox/mqueue/example/routing/logger.dart new file mode 100644 index 0000000..98f6e8c --- /dev/null +++ b/sandbox/mqueue/example/routing/logger.dart @@ -0,0 +1,21 @@ +import 'package:angel3_mq/mq.dart'; + +final class Logger with ProducerMixin { + Logger() { + MQClient.instance.declareExchange( + exchangeName: 'logs', + exchangeType: ExchangeType.direct, + ); + } + + Future log({ + required String level, + required String message, + }) async { + sendMessage( + payload: message, + exchangeName: 'logs', + routingKey: level, + ); + } +} diff --git a/sandbox/mqueue/example/routing/main.dart b/sandbox/mqueue/example/routing/main.dart new file mode 100644 index 0000000..4136032 --- /dev/null +++ b/sandbox/mqueue/example/routing/main.dart @@ -0,0 +1,30 @@ +import 'package:angel3_mq/mq.dart'; + +import 'debug_logger.dart'; +import 'logger.dart'; +import 'production_logger.dart'; + +void main() async { + MQClient.initialize(); + + DebugLogger().startListening(); + + ProductionLogger().startListening(); + + final logger = Logger(); + + await logger.log( + level: 'info', + message: 'This is an info message', + ); + + await logger.log( + level: 'warning', + message: 'This is a warning message', + ); + + await logger.log( + level: 'error', + message: 'This is an error message', + ); +} diff --git a/sandbox/mqueue/example/routing/production_logger.dart b/sandbox/mqueue/example/routing/production_logger.dart new file mode 100644 index 0000000..e7c345a --- /dev/null +++ b/sandbox/mqueue/example/routing/production_logger.dart @@ -0,0 +1,29 @@ +import 'dart:developer'; + +import 'package:angel3_mq/mq.dart'; + +final class ProductionLogger with ConsumerMixin { + ProductionLogger() { + MQClient.instance.declareExchange( + exchangeName: 'logs', + exchangeType: ExchangeType.direct, + ); + _queueName = MQClient.instance.declareQueue('production'); + } + + late final String _queueName; + + void startListening() { + MQClient.instance.bindQueue( + queueId: _queueName, + exchangeName: 'logs', + bindingKey: 'error', + ); + subscribe( + queueId: _queueName, + callback: (Message message) { + log('Production Logger recieved: ${message.payload}'); + }, + ); + } +} diff --git a/sandbox/mqueue/example/rpc/main.dart b/sandbox/mqueue/example/rpc/main.dart new file mode 100644 index 0000000..ba05996 --- /dev/null +++ b/sandbox/mqueue/example/rpc/main.dart @@ -0,0 +1,19 @@ +import 'package:angel3_mq/mq.dart'; + +import 'service_one.dart'; +import 'service_two.dart'; + +void main() { + MQClient.initialize(); + + MQClient.instance.declareExchange( + exchangeName: 'ServiceRPC', + exchangeType: ExchangeType.direct, + ); + + final serviceOne = ServiceOne(); + + ServiceTwo().startListening(); + + serviceOne.requestFoo(); +} diff --git a/sandbox/mqueue/example/rpc/service_one.dart b/sandbox/mqueue/example/rpc/service_one.dart new file mode 100644 index 0000000..a2d4f97 --- /dev/null +++ b/sandbox/mqueue/example/rpc/service_one.dart @@ -0,0 +1,19 @@ +import 'dart:developer'; + +import 'package:angel3_mq/mq.dart'; + +class ServiceOne with ProducerMixin { + Future requestFoo() async { + final res = await sendRPCMessage( + exchangeName: 'ServiceRPC', + routingKey: 'rpcBinding', + processId: 'foo', + args: {}, + ); + _handleFuture(res); + } + + void _handleFuture(String data) { + log('Service One received: $data\n'); + } +} diff --git a/sandbox/mqueue/example/rpc/service_two.dart b/sandbox/mqueue/example/rpc/service_two.dart new file mode 100644 index 0000000..20e4ba2 --- /dev/null +++ b/sandbox/mqueue/example/rpc/service_two.dart @@ -0,0 +1,46 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:angel3_mq/mq.dart'; + +class ServiceTwo with ConsumerMixin { + ServiceTwo() { + MQClient.instance.declareExchange( + exchangeName: 'ServiceRPC', + exchangeType: ExchangeType.direct, + ); + _queueName = MQClient.instance.declareQueue('two'); + } + + late final String _queueName; + + Future startListening() async { + MQClient.instance.bindQueue( + queueId: _queueName, + exchangeName: 'ServiceRPC', + bindingKey: 'rpcBinding', + ); + subscribe( + queueId: _queueName, + callback: (Message message) async { + log('Service Two got message $message\n'); + if (message.headers['type'] == 'RPC') { + switch (message.headers['processId']) { + case 'foo': + final data = await foo(); + final Completer completer = + message.headers['completer'] ?? (throw Exception()); + completer.complete(data); + default: + } + } + }, + ); + } + + Future foo() async { + // log('Service Two bar\n'); + await Future.delayed(const Duration(seconds: 2)); + return 'Hello, world!'; + } +} diff --git a/sandbox/mqueue/example/sender.dart b/sandbox/mqueue/example/sender.dart new file mode 100644 index 0000000..6d9b842 --- /dev/null +++ b/sandbox/mqueue/example/sender.dart @@ -0,0 +1,12 @@ +import 'package:angel3_mq/mq.dart'; + +final class Sender with ProducerMixin { + Sender() { + MQClient.instance.declareQueue('hello'); + } + + Future sendGreeting({required String greeting}) async => sendMessage( + routingKey: 'hello', + payload: greeting, + ); +} diff --git a/sandbox/mqueue/lib/mq.dart b/sandbox/mqueue/lib/mq.dart new file mode 100644 index 0000000..e3736c8 --- /dev/null +++ b/sandbox/mqueue/lib/mq.dart @@ -0,0 +1,11 @@ +/// Library definition. +library angel3_mq; + +/// Export files. +export 'src/consumer/consumer.dart'; +export 'src/consumer/consumer.mixin.dart'; +export 'src/core/constants/enums.dart'; +export 'src/message/message.dart'; +export 'src/mq/mq.dart'; +export 'src/producer/producer.dart'; +export 'src/producer/producer.mixin.dart'; diff --git a/sandbox/mqueue/lib/src/binding/binding.dart b/sandbox/mqueue/lib/src/binding/binding.dart new file mode 100644 index 0000000..c93d94a --- /dev/null +++ b/sandbox/mqueue/lib/src/binding/binding.dart @@ -0,0 +1,75 @@ +import 'package:angel3_mq/src/binding/binding.interface.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; + +/// A class representing a binding between a topic and its associated queues. +/// +/// The `Binding` class implements the [BindingInterface] interface and is +/// responsible for managing the association between a topic and its associated +/// queues. It allows the addition and removal of queues to the binding and the +/// publication of messages to all associated queues. +/// +/// Example: +/// ```dart +/// final binding = Binding('my_binding'); +/// final queue1 = Queue('queue_1'); +/// final queue2 = Queue('queue_2'); +/// +/// // Add queues to the binding. +/// binding.addQueue(queue1); +/// binding.addQueue(queue2); +/// +/// // Publish a message to all associated queues. +/// final message = Message( +/// headers: {'contentType': 'json', 'sender': 'Alice'}, +/// payload: {'text': 'Hello, World!'}, +/// timestamp: '2023-09-07T12:00:002', +/// ); +/// binding.publishMessage(message); +/// +/// // Check if the binding has associated queues. +/// final hasQueues = binding.hasQueues(); // Returns true +/// ``` +final class Binding implements BindingInterface { + /// Creates a new binding with the specified [id]. + /// + /// The [id] parameter represents the unique identifier for the binding. + Binding(this.id); + + /// The unique identifier for the binding. + final String id; + + /// A list of associated queues. + final List _queues = []; + + @override + bool hasQueues() => _queues.isNotEmpty; + + @override + void addQueue(Queue queue) => _queues.add(queue); + + @override + void removeQueue(String queueId) => _queues.removeWhere( + (Queue queue) => queue.id == queueId && queue.hasListeners() + ? throw QueueHasSubscribersException(queueId) + : queue.id == queueId, + ); + + @override + void publishMessage(Message message) { + for (final queue in _queues) { + queue.enqueue(message); + } + } + + @override + void clear() { + for (final queue in _queues) { + if (queue.hasListeners()) { + throw QueueHasSubscribersException(queue.id); + } + } + _queues.clear(); + } +} diff --git a/sandbox/mqueue/lib/src/binding/binding.interface.dart b/sandbox/mqueue/lib/src/binding/binding.interface.dart new file mode 100644 index 0000000..18fd762 --- /dev/null +++ b/sandbox/mqueue/lib/src/binding/binding.interface.dart @@ -0,0 +1,44 @@ +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; + +/// An abstract interface class defining the contract for managing bindings. +/// +/// The `BindingInterface` abstract interface class defines a contract for +/// classes that are responsible for managing bindings between topics and +/// queues. Implementing classes must provide functionality for adding and +/// removing queues from the binding, publishing messages to the associated +/// queues, and checking if the binding has queues. +/// +/// Example: +/// ```dart +/// class MyBinding implements BindingInterface { +/// // Custom implementation of the binding interface methods. +/// } +/// ``` +abstract interface class BindingInterface { + /// Checks if the binding has associated queues. + /// + /// Returns `true` if the binding has one or more associated queues; + /// otherwise, `false`. + bool hasQueues(); + + /// Adds a queue to the binding. + /// + /// The [queue] parameter represents the queue to be associated with the + /// binding. + void addQueue(Queue queue); + + /// Removes a queue from the binding based on its ID. + /// + /// The [queueId] parameter represents the ID of the queue to be removed. + void removeQueue(String queueId); + + /// Publishes a message to all associated queues in the binding. + /// + /// The [message] parameter represents the message to be published to the + /// queues. + void publishMessage(Message message); + + /// Removes all queues from the binding. + void clear(); +} diff --git a/sandbox/mqueue/lib/src/consumer/consumer.dart b/sandbox/mqueue/lib/src/consumer/consumer.dart new file mode 100644 index 0000000..8d42065 --- /dev/null +++ b/sandbox/mqueue/lib/src/consumer/consumer.dart @@ -0,0 +1,95 @@ +import 'dart:async'; + +import 'package:angel3_mq/src/consumer/consumer.interface.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/core/registrar/simple_registrar.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/mq/mq.dart'; + +/// A mixin implementing the `ConsumerInterface` for message consumption. +/// +/// The `Consumer` mixin provides a concrete implementation of the +/// `ConsumerInterface`for message consumption. It allows classes to easily +/// consume messages from specific queues by subscribing to them, handling +/// received messages, and managing subscriptions. +/// +/// Example: +/// ```dart +/// class MyMessageConsumer with Consumer { +/// // Custom implementation of the message consumer. +/// } +/// ``` +@Deprecated('Please use `ConsumerMixin` instead. ' + 'This will be removed in v2.0.0') +mixin Consumer implements ConsumerInterface { + /// A registry of active message subscriptions. + final Registrar> _subscriptions = + Registrar>(); + + @override + Message? getLatestMessage(String queueId) => + MQClient.instance.getLatestMessage(queueId); + + @override + void subscribe({ + required String queueId, + required Function(Message) callback, + bool Function(Object)? filter, + }) { + try { + final messageStream = MQClient.instance.fetchQueue(queueId); + + final sub = filter != null + ? messageStream.listen((Message message) { + if (filter(message.payload)) { + callback(message); + } + }) + : messageStream.listen(callback); + + _subscriptions.register(queueId, sub); + } on IdAlreadyRegisteredException catch (_) { + throw ConsumerAlreadySubscribedException( + consumer: runtimeType.toString(), + queue: queueId, + ); + } + } + + @override + void unsubscribe({required String queueId}) { + _subscriptions.get(queueId).cancel(); + _subscriptions.unregister(queueId); + } + + @override + void pauseSubscription(String queueId) => _subscriptions.get(queueId).pause(); + + @override + void resumeSubscription(String queueId) => + _subscriptions.get(queueId).resume(); + + @override + void updateSubscription({ + required String queueId, + required Function(Message) callback, + bool Function(Object)? filter, + }) { + _subscriptions.get(queueId).cancel(); + _subscriptions.unregister(queueId); + subscribe( + queueId: queueId, + callback: callback, + filter: filter, + ); + } + + @override + void clearSubscriptions() { + for (final StreamSubscription sub in _subscriptions.getAll()) { + sub.cancel(); + } + + _subscriptions.clear(); + } +} diff --git a/sandbox/mqueue/lib/src/consumer/consumer.interface.dart b/sandbox/mqueue/lib/src/consumer/consumer.interface.dart new file mode 100644 index 0000000..6890099 --- /dev/null +++ b/sandbox/mqueue/lib/src/consumer/consumer.interface.dart @@ -0,0 +1,74 @@ +import 'package:angel3_mq/src/message/message.dart'; + +/// An abstract interface class defining the contract for a message consumer. +/// +/// The `ConsumerInterface` abstract interface class defines a contract for +/// classes that implement a message consumer. Implementing classes must +/// provide methods for subscribing and unsubscribing from queues, pausing and +/// resuming subscriptions, updating subscriptions, retrieving the +/// latest message from a queue, and clearing all subscriptions. +/// +/// Example: +/// ```dart +/// class MyConsumer implements ConsumerInterface { +/// // Custom implementation of the message consumer. +/// } +/// ``` +abstract interface class ConsumerInterface { + /// Subscribes to a queue to receive messages. + /// + /// The [queueId] parameter represents the ID of the queue to subscribe to. + /// The [callback] parameter is a function that will be invoked for each + /// received message. + /// The [filter] parameter is an optional function that can be used to filter + /// messages based on custom criteria. + void subscribe({ + required String queueId, + required Function(Message) callback, + bool Function(Object)? filter, + }); + + /// Unsubscribes from a previously subscribed queue. + /// + /// The [queueId] parameter represents the ID of the queue to unsubscribe + /// from. + void unsubscribe({required String queueId}); + + /// Pauses message subscription for a specified queue. + /// + /// The [queueId] parameter represents the ID of the queue to pause the + /// subscription. + void pauseSubscription(String queueId); + + /// Resumes a paused subscription for a specified queue. + /// + /// The [queueId] parameter represents the ID of the queue to resume the + /// subscription. + void resumeSubscription(String queueId); + + /// Updates an existing subscription with a new callback and/or filter. + /// + /// The [queueId] parameter represents the ID of the queue to update the + /// subscription. + /// The [callback] parameter is a new function that will be invoked for each + /// received message. + /// The [filter] parameter is an optional new filter function for message + /// filtering. + void updateSubscription({ + required String queueId, + required Function(Message) callback, + bool Function(Object)? filter, + }); + + /// Retrieves the latest message from a queue. + /// + /// The [queueId] parameter represents the ID of the queue to fetch the latest + /// message from. + /// + /// Returns the latest message from the specified queue or `null` if the queue + /// is empty. + Message? getLatestMessage(String queueId); + + /// Clears all active subscriptions, unsubscribing from all queues. + void clearSubscriptions(); +} diff --git a/sandbox/mqueue/lib/src/consumer/consumer.mixin.dart b/sandbox/mqueue/lib/src/consumer/consumer.mixin.dart new file mode 100644 index 0000000..b3bc347 --- /dev/null +++ b/sandbox/mqueue/lib/src/consumer/consumer.mixin.dart @@ -0,0 +1,92 @@ +import 'dart:async'; + +import 'package:angel3_mq/src/consumer/consumer.interface.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/core/registrar/simple_registrar.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/mq/mq.dart'; + +/// A mixin implementing the `ConsumerInterface` for message consumption. +/// +/// The `ConsumerMixin` mixin provides a concrete implementation of the +/// `ConsumerInterface`for message consumption. It allows classes to easily +/// consume messages from specific queues by subscribing to them, handling +/// received messages, and managing subscriptions. +/// +/// Example: +/// ```dart +/// class MyMessageConsumer with ConsumerMixin { +/// // Custom implementation of the message consumer. +/// } +/// ``` +mixin ConsumerMixin implements ConsumerInterface { + /// A registry of active message subscriptions. + final Registrar> _subscriptions = + Registrar>(); + + @override + Message? getLatestMessage(String queueId) => + MQClient.instance.getLatestMessage(queueId); + + @override + void subscribe({ + required String queueId, + required Function(Message) callback, + bool Function(Object)? filter, + }) { + try { + final messageStream = MQClient.instance.fetchQueue(queueId); + + final sub = filter != null + ? messageStream.listen((Message message) { + if (filter(message.payload)) { + callback(message); + } + }) + : messageStream.listen(callback); + + _subscriptions.register(queueId, sub); + } on IdAlreadyRegisteredException catch (_) { + throw ConsumerAlreadySubscribedException( + consumer: runtimeType.toString(), + queue: queueId, + ); + } + } + + @override + void unsubscribe({required String queueId}) => _subscriptions + ..get(queueId).cancel() + ..unregister(queueId); + + @override + void pauseSubscription(String queueId) => _subscriptions.get(queueId).pause(); + + @override + void resumeSubscription(String queueId) => + _subscriptions.get(queueId).resume(); + + @override + void updateSubscription({ + required String queueId, + required Function(Message) callback, + bool Function(Object)? filter, + }) { + _subscriptions.get(queueId).cancel(); + _subscriptions.unregister(queueId); + subscribe( + queueId: queueId, + callback: callback, + filter: filter, + ); + } + + @override + void clearSubscriptions() { + for (final StreamSubscription sub in _subscriptions.getAll()) { + sub.cancel(); + } + + _subscriptions.clear(); + } +} diff --git a/sandbox/mqueue/lib/src/core/constants/enums.dart b/sandbox/mqueue/lib/src/core/constants/enums.dart new file mode 100644 index 0000000..582d02c --- /dev/null +++ b/sandbox/mqueue/lib/src/core/constants/enums.dart @@ -0,0 +1,22 @@ +/// An enumeration representing different types of message exchanges. +/// +/// The [ExchangeType] enum defines various types of message exchanges that are +/// commonly used in messaging systems. Each type represents a specific behavior +/// for distributing messages to multiple queues or consumers. +/// +/// - `direct`: A direct exchange routes messages to queues based on a specified +/// routing key. +/// - `base`: The default exchange (unnamed) routes messages to queues using +/// their names. +/// - `fanout`: A fanout exchange routes messages to all connected queues, +/// ignoring routing keys. +enum ExchangeType { + /// Represents a direct message exchange. + direct, + + /// Represents the default exchange (unnamed). + base, + + /// Represents a fanout message exchange. + fanout, +} diff --git a/sandbox/mqueue/lib/src/core/constants/error_strings.dart b/sandbox/mqueue/lib/src/core/constants/error_strings.dart new file mode 100644 index 0000000..0ea4dc5 --- /dev/null +++ b/sandbox/mqueue/lib/src/core/constants/error_strings.dart @@ -0,0 +1,99 @@ +/// A utility class providing exception-related error messages. +/// +/// The `ExceptionStrings` class defines static methods that generate error +/// messages for various exception scenarios. These messages can be used to +/// provide descriptive error information in exception handling and debugging. +class ExceptionStrings { + /// Generates an error message when MQClient is not initialized. + /// + /// This message is used when attempting to use the MQClient before it has + /// been properly initialized using the `MQClient.initialize()` method. + static String mqClientNotInitialized() => + 'MQClient is not initialized. Please make sure to call ' + 'MQClient.initialize() first.'; + + /// Generates an error message for a Queue that is not registered. + /// + /// The [queueId] parameter represents the name of the unregistered queue. + static String queueNotRegistered(String queueId) => + 'Queue: $queueId is not registered.'; + + /// Generates an error message for a queue with active subscribers. + /// + /// The [queueId] parameter represents the ID of the queue with active + /// subscribers. + static String queueHasSubscribers(String queueId) => + 'Queue: $queueId has subscribers.'; + + /// Generates an error message for a queue with no name. + /// + /// This message is used when the name of the queue is not provided and is + /// null. + static String queueIdNull() => "Queue name can't be null."; + + /// Generates an error message for a required routing key. + /// + /// This message is used when a routing key is required for a specific + /// operation but is not provided. + static String routingKeyRequired() => 'Routing key is required.'; + + /// Generates an error message for a non-existent binding key. + /// + /// The [bindingKey] parameter represents the non-existent binding key. + static String bindingKeyNotFound(String bindingKey) => + 'The binding key "$bindingKey" was not found.'; + + /// Generates an error message for a missing binding key. + /// + /// This message is used when a binding operation expects a binding key to + static String bindingKeyRequired() => 'Binding key is required.'; + + /// Generates an error message for an exchange that is not registered. + /// + /// The [exchangeName] parameter represents the name of the unregistered + /// exchange. + static String exchangeNotRegistered(String exchangeName) => + 'Exchange: $exchangeName is not registered.'; + + /// Generates an error message for invalid exchange type. + static String invalidExchangeType() => 'Exchange type is invalid.'; + + /// Generates an error message for a consumer that is not subscribed to a + /// queue. + /// + /// The [consumerId] parameter represents the ID of the consumer. + /// The [queue] parameter represents the name of the queue. + static String consumerNotSubscribed(String consumerId, String queue) => + 'The consumer "$consumerId" is not subscribed to the queue "$queue".'; + + /// Generates an error message for a consumer that is already subscribed to + /// a queue. + /// + /// The [consumerId] parameter represents the ID of the consumer. + /// The [queue] parameter represents the name of the queue. + static String consumerAlreadySubscribed(String consumerId, String queue) => + 'The consumer "$consumerId" is already subscribed to the queue "$queue".'; + + /// Generates an error message for a consumer that is not registered. + /// + /// The [consumerId] parameter represents the ID of the consumer. + static String consumerNotRegistered(String consumerId) => + 'The consumer "$consumerId" is not registered.'; + + /// Generates an error message for a consumer that has active subscriptions. + /// + /// The [consumerId] parameter represents the ID of the consumer. + static String consumerHasSubscriptions(String consumerId) => + 'The consumer "$consumerId" has active subscriptions.'; + + /// Generates an error message for an ID that is already registered. + /// + /// The [id] parameter represents the ID that is already registered. + static String idAlreadyRegistered(String id) => + 'Id "$id" already registered.'; + + /// Generates an error message for an ID that is not registered. + /// + /// The [id] parameter represents the ID that is not registered. + static String idNotRegistered(String id) => 'Id "$id" not registered.'; +} diff --git a/sandbox/mqueue/lib/src/core/exceptions/binding_exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/binding_exceptions.dart new file mode 100644 index 0000000..898f5f1 --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/binding_exceptions.dart @@ -0,0 +1,42 @@ +import 'package:angel3_mq/src/core/constants/error_strings.dart'; + +/// The [BindingException] class represents a base exception related to +/// bindings. +/// +/// It is used to handle exceptions that may occur when working with bindings, +/// such as when a binding key is not found or when a binding key is required +/// but not provided. +/// +/// Subclasses of [BindingException] can provide more specific information about +/// the nature of the exception. +abstract base class BindingException implements Exception { + /// Creates a new [BindingException] with the specified error [message]. + BindingException(this.message); + + /// The error message associated with the exception. + final String message; + + @override + String toString() => '$runtimeType: $message'; +} + +/// The [BindingKeyNotFoundException] class represents an exception that occurs +/// when a binding key is not found. +/// +/// This exception is thrown when attempting to access a binding key that does +/// not exist in the context of bindings. +final class BindingKeyNotFoundException extends BindingException { + /// Creates a new [BindingKeyNotFoundException] instance. + BindingKeyNotFoundException(String key) + : super(ExceptionStrings.bindingKeyNotFound(key)); +} + +/// The [BindingKeyRequiredException] class represents an exception that occurs +/// when a binding key is required but not provided. +/// +/// This exception is thrown when a binding operation expects a binding key to +/// be provided, but it is missing or empty. +final class BindingKeyRequiredException extends BindingException { + /// Creates a new [BindingKeyRequiredException] instance. + BindingKeyRequiredException() : super(ExceptionStrings.bindingKeyRequired()); +} diff --git a/sandbox/mqueue/lib/src/core/exceptions/consumer_exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/consumer_exceptions.dart new file mode 100644 index 0000000..9cd76cc --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/consumer_exceptions.dart @@ -0,0 +1,73 @@ +import 'package:angel3_mq/src/core/constants/error_strings.dart'; + +/// The [ConsumerException] class represents a base exception related to +/// consumers. +/// +/// It is used to handle exceptions that may occur when working with consumers, +/// such as when a consumer is not registered, is already subscribed to a queue, +/// is not subscribed to a queue when expected, or has active subscriptions. +/// +/// Subclasses of [ConsumerException] can provide more specific information +/// about the nature of the exception. +abstract base class ConsumerException implements Exception { + /// Creates a new [ConsumerException] with the specified error [message]. + ConsumerException(this.message); + + /// The error message associated with the exception. + final String message; + + @override + String toString() => '$runtimeType: $message'; +} + +/// The [ConsumerNotRegisteredException] class represents an exception that +/// occurs when a consumer is not registered. +/// +/// This exception is thrown when attempting to perform operations on a consumer +/// that has not been registered. +final class ConsumerNotRegisteredException extends ConsumerException { + /// Creates a new [ConsumerNotRegisteredException] instance with the + /// specified [consumer]. + ConsumerNotRegisteredException(String consumer) + : super(ExceptionStrings.consumerNotRegistered(consumer)); +} + +/// The [ConsumerAlreadySubscribedException] class represents an exception that +/// occurs when a consumer is already subscribed to a queue. +/// +/// This exception is thrown when attempting to subscribe a consumer to a queue +/// that it is already subscribed to. +final class ConsumerAlreadySubscribedException extends ConsumerException { + /// Creates a new [ConsumerAlreadySubscribedException] instance with the + /// specified [queue]. + ConsumerAlreadySubscribedException({ + required String consumer, + required String queue, + }) : super(ExceptionStrings.consumerAlreadySubscribed(consumer, queue)); +} + +/// The [ConsumerNotSubscribedException] class represents an exception that +/// occurs when a consumer is not subscribed to a queue when expected. +/// +/// This exception is thrown when an operation expects a consumer to be +/// subscribed to a queue, but the consumer is not. +final class ConsumerNotSubscribedException extends ConsumerException { + /// Creates a new [ConsumerNotSubscribedException] instance with the + /// specified [queue]. + ConsumerNotSubscribedException({ + required String consumer, + required String queue, + }) : super(ExceptionStrings.consumerNotSubscribed(consumer, queue)); +} + +/// The [ConsumerHasSubscriptionsException] class represents an exception that +/// occurs when a consumer has active subscriptions. +/// +/// This exception is thrown when an operation expects a consumer to have no +/// active subscriptions, but the consumer has active subscriptions. +final class ConsumerHasSubscriptionsException extends ConsumerException { + /// Creates a new [ConsumerHasSubscriptionsException] instance with the + /// specified [consumer]. + ConsumerHasSubscriptionsException(String consumer) + : super(ExceptionStrings.consumerHasSubscriptions(consumer)); +} diff --git a/sandbox/mqueue/lib/src/core/exceptions/exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/exceptions.dart new file mode 100644 index 0000000..77c94ba --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/exceptions.dart @@ -0,0 +1,7 @@ +export 'binding_exceptions.dart'; +export 'consumer_exceptions.dart'; +export 'exchange_exceptions.dart'; +export 'mq_client_exceptions.dart'; +export 'queue_exceptions.dart'; +export 'registrar_exceptions.dart'; +export 'routing_key_exceptions.dart'; diff --git a/sandbox/mqueue/lib/src/core/exceptions/exchange_exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/exchange_exceptions.dart new file mode 100644 index 0000000..eb9336f --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/exchange_exceptions.dart @@ -0,0 +1,44 @@ +import 'package:angel3_mq/src/core/constants/error_strings.dart'; + +/// The [ExchangeException] class represents a base exception related to +/// exchanges. +/// +/// It is used to handle exceptions that may occur when working with exchanges, +/// such as when an exchange is not registered or when an invalid exchange type +/// is encountered. +/// +/// Subclasses of [ExchangeException] can provide more specific information +/// about the nature of the exception. +abstract base class ExchangeException implements Exception { + /// Creates a new [ExchangeException] with the specified error [message]. + ExchangeException(this.message); + + /// The error message associated with the exception. + final String message; + + @override + String toString() => '$runtimeType: $message'; +} + +/// The [ExchangeNotRegisteredException] class represents an exception that +/// occurs when an exchange is not registered. +/// +/// This exception is thrown when attempting to perform operations on an +/// exchange that has not been registered. +final class ExchangeNotRegisteredException extends ExchangeException { + /// Creates a new [ExchangeNotRegisteredException] instance with the + /// specified [exchangeName]. + ExchangeNotRegisteredException(String exchangeName) + : super(ExceptionStrings.exchangeNotRegistered(exchangeName)); +} + +/// The [InvalidExchangeTypeException] class represents an exception that occurs +/// when an invalid exchange type is encountered. +/// +/// This exception is thrown when an operation encounters an exchange type that +/// is not recognized or supported. +final class InvalidExchangeTypeException extends ExchangeException { + /// Creates a new [InvalidExchangeTypeException] instance. + InvalidExchangeTypeException() + : super(ExceptionStrings.invalidExchangeType()); +} diff --git a/sandbox/mqueue/lib/src/core/exceptions/mq_client_exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/mq_client_exceptions.dart new file mode 100644 index 0000000..bc2c819 --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/mq_client_exceptions.dart @@ -0,0 +1,31 @@ +import 'package:angel3_mq/src/core/constants/error_strings.dart'; + +/// The [MQClientException] class represents a base exception related to the +/// MQClient. +/// +/// It is used to handle exceptions that may occur when working with the +/// MQClient, such as when the MQClient is not initialized. +/// +/// Subclasses of [MQClientException] can provide more specific information +/// about the nature of the exception. +abstract base class MQClientException implements Exception { + /// Creates a new [MQClientException] with the specified error [message]. + MQClientException(this.message); + + /// The error message associated with the exception. + final String message; + + @override + String toString() => '$runtimeType: $message'; +} + +/// The [MQClientNotInitializedException] class represents an exception that +/// occurs when the MQClient is not initialized. +/// +/// This exception is thrown when attempting to use the MQClient before it has +/// been properly initialized using the `MQClient.initialize()` method. +final class MQClientNotInitializedException extends MQClientException { + /// Creates a new [MQClientNotInitializedException] instance. + MQClientNotInitializedException() + : super(ExceptionStrings.mqClientNotInitialized()); +} diff --git a/sandbox/mqueue/lib/src/core/exceptions/queue_exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/queue_exceptions.dart new file mode 100644 index 0000000..5a2947d --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/queue_exceptions.dart @@ -0,0 +1,54 @@ +import 'package:angel3_mq/src/core/constants/error_strings.dart'; + +/// The [QueueException] class represents a base exception related to queues. +/// +/// It is used to handle exceptions that may occur when working with queues, +/// such as when a queue is not registered or when there are subscribers to a +/// queue. +/// +/// Subclasses of [QueueException] can provide more specific information about +/// the nature of the exception. +abstract class QueueException implements Exception { + /// Creates a new [QueueException] with the specified error [message]. + QueueException(this.message); + + /// The error message associated with the exception. + final String message; + + @override + String toString() => '$runtimeType: $message'; +} + +/// The [QueueNotRegisteredException] class represents an exception that occurs +/// when a queue with a specific ID is not registered. +/// +/// This exception is thrown when attempting to perform an operation on an +/// unregistered queue. +final class QueueNotRegisteredException extends QueueException { + /// Creates a new [QueueNotRegisteredException] instance with the specified + /// [queueId]. + QueueNotRegisteredException(String queueId) + : super(ExceptionStrings.queueNotRegistered(queueId)); +} + +/// The [QueueHasSubscribersException] class represents an exception that occurs +/// when there are active subscribers to a queue. +/// +/// This exception is thrown when attempting to delete a queue that still has +/// subscribers listening to it. +final class QueueHasSubscribersException extends QueueException { + /// Creates a new [QueueHasSubscribersException] instance with the specified + /// [queueId]. + QueueHasSubscribersException(String queueId) + : super(ExceptionStrings.queueHasSubscribers(queueId)); +} + +/// The [QueueIdNullException] class represents an exception that occurs when +/// attempting to create a queue with a null name. +/// +/// This exception is thrown when the name of the queue is not provided and is +/// null. +final class QueueIdNullException extends QueueException { + /// Creates a new [QueueIdNullException] instance. + QueueIdNullException() : super(ExceptionStrings.queueIdNull()); +} diff --git a/sandbox/mqueue/lib/src/core/exceptions/registrar_exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/registrar_exceptions.dart new file mode 100644 index 0000000..c5ef09b --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/registrar_exceptions.dart @@ -0,0 +1,43 @@ +import 'package:angel3_mq/src/core/constants/error_strings.dart'; + +/// The [RegistrarException] class represents a base exception related to +/// registrar operations. +/// +/// It is used to handle exceptions that may occur when working with registrar +/// objects, which are responsible for managing and registering items. +/// +/// Subclasses of [RegistrarException] can provide more specific information +/// about the nature of the exception. +abstract class RegistrarException implements Exception { + /// Creates a new [RegistrarException] with the specified error [message]. + RegistrarException(this.message); + + /// The error message associated with the exception. + final String message; + + @override + String toString() => '$runtimeType: $message'; +} + +/// The [IdAlreadyRegisteredException] class represents an exception that occurs +/// when attempting to register an ID that is already registered in a registrar. +/// +/// This exception is thrown when a duplicate ID is detected during the +/// registration process. +final class IdAlreadyRegisteredException extends RegistrarException { + /// Creates a new [IdAlreadyRegisteredException] instance with the specified + /// [id]. + IdAlreadyRegisteredException(String id) + : super(ExceptionStrings.idAlreadyRegistered(id)); +} + +/// The [IdNotRegisteredException] class represents an exception that occurs +/// when attempting to access an ID that is not registered in a registrar. +/// +/// This exception is thrown when an operation is performed on an unregistered +/// ID. +final class IdNotRegisteredException extends RegistrarException { + /// Creates a new [IdNotRegisteredException] instance with the specified [id]. + IdNotRegisteredException(String id) + : super(ExceptionStrings.idNotRegistered(id)); +} diff --git a/sandbox/mqueue/lib/src/core/exceptions/routing_key_exceptions.dart b/sandbox/mqueue/lib/src/core/exceptions/routing_key_exceptions.dart new file mode 100644 index 0000000..407b2f0 --- /dev/null +++ b/sandbox/mqueue/lib/src/core/exceptions/routing_key_exceptions.dart @@ -0,0 +1,30 @@ +import 'package:angel3_mq/src/core/constants/error_strings.dart'; + +/// The [RoutingKeyException] class represents a base exception related to +/// routing key operations. +/// +/// It is used to handle exceptions that may occur when working with routing +/// keys, which are used for message routing in message broker systems. +/// +/// Subclasses of [RoutingKeyException] can provide more specific information +/// about the nature of the exception. +abstract class RoutingKeyException implements Exception { + /// Creates a new [RoutingKeyException] with the specified error [message]. + RoutingKeyException(this.message); + + /// The error message associated with the exception. + final String message; + + @override + String toString() => '$runtimeType: $message'; +} + +/// The [RoutingKeyRequiredException] class represents an exception that occurs +/// when a routing key is required for a specific operation but is not provided. +/// +/// This exception is thrown when an operation expects a routing key to be +/// provided, but it is missing. +final class RoutingKeyRequiredException extends RoutingKeyException { + /// Creates a new [RoutingKeyRequiredException] instance. + RoutingKeyRequiredException() : super(ExceptionStrings.routingKeyRequired()); +} diff --git a/sandbox/mqueue/lib/src/core/registrar/simple_registrar.dart b/sandbox/mqueue/lib/src/core/registrar/simple_registrar.dart new file mode 100644 index 0000000..472d4c0 --- /dev/null +++ b/sandbox/mqueue/lib/src/core/registrar/simple_registrar.dart @@ -0,0 +1,100 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; + +/// A generic registrar for managing and storing objects by their unique +/// identifiers. +/// +/// The [Registrar] class allows you to register, get, unregister, and manage +/// objects associated with unique identifiers (IDs). It provides a way to store +/// and access objects in a key-value fashion. +/// +/// Example: +/// ```dart +/// final registrar = Registrar(); +/// +/// // Register objects with unique IDs. +/// registrar.register('user_1', 'Alice'); +/// registrar.register('user_2', 'Bob'); +/// +/// // Get an object by its ID. +/// final user1 = registrar.get('user_1'); // Returns 'Alice' +/// +/// // Check if an object with a specific ID exists. +/// final hasUser2 = registrar.has('user_2'); // Returns true +/// +/// // Unregister an object by its ID. +/// registrar.unregister('user_1'); +/// +/// // Check the number of registered objects. +/// final count = registrar.count; // Returns 1 +/// ``` +final class Registrar { + /// A map to store objects with their associated IDs. + final Map _registry = {}; + + /// Registers an object with a unique ID. + /// + /// The [id] parameter represents the unique identifier for the object. + /// The [value] parameter represents the object to be registered. + /// + /// If an object with the same ID already exists, an + /// [IdAlreadyRegisteredException] is thrown. + void register(String id, T value) { + if (_registry.containsKey(id)) { + throw IdAlreadyRegisteredException(id); + } + _registry[id] = value; + } + + /// Gets an object by its unique ID. + /// + /// The [id] parameter represents the unique identifier of the object to + /// retrieve. + /// + /// If no object with the specified ID is found, an [IdNotRegisteredException] + /// is thrown. + T get(String id) { + if (!_registry.containsKey(id)) { + throw IdNotRegisteredException(id); + } + return _registry[id]!; + } + + /// Retrieves a list of all registered objects. + List getAll() => _registry.values.toList(); + + /// Unregisters an object by its unique ID. + /// + /// The [id] parameter represents the unique identifier of the object to + /// unregister. + /// + /// If no object with the specified ID is found, an [IdNotRegisteredException] + /// is thrown. + void unregister(String id) { + if (!_registry.containsKey(id)) { + throw IdNotRegisteredException(id); + } + _registry.remove(id); + } + + /// Clears the registrar, removing all registered objects. + void clear() => _registry.clear(); + + /// Checks if an object with a specific ID is registered. + /// + /// The [id] parameter represents the unique identifier to check. + /// + /// Returns `true` if an object with the specified ID is registered; + /// otherwise, `false`. + bool has(String id) => _registry.containsKey(id); + + /// Returns the count of registered objects. + int get count => _registry.length; + + @override + String toString() { + return ''' +Registrar( +\t${_registry.entries.map((e) => '${e.key}: ${e.value}').join(',\n\t')} + )'''; + } +} diff --git a/sandbox/mqueue/lib/src/exchange/default_exchange.dart b/sandbox/mqueue/lib/src/exchange/default_exchange.dart new file mode 100644 index 0000000..4c20164 --- /dev/null +++ b/sandbox/mqueue/lib/src/exchange/default_exchange.dart @@ -0,0 +1,86 @@ +import 'package:angel3_mq/src/binding/binding.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/exchange/exchange.base.dart'; +import 'package:angel3_mq/src/exchange/exchange_interface.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; + +/// A class representing the default message exchange for message routing. +/// +/// The `DefaultExchange` class is a specific implementation of the +/// `BaseExchange` abstract base class, representing the default exchange. +/// It provides functionality for binding queues, forwarding messages based on +/// routing keys, and preventing unbinding from the default exchange. +/// +/// Example: +/// ```dart +/// final defaultExchange = DefaultExchange('default_exchange'); +/// +/// // Bind a queue to the default exchange. +/// final queue = Queue('my_queue'); +/// defaultExchange.bindQueue(queue: queue, bindingKey: 'my_routing_key'); +/// +/// // Forward a message to the default exchange using a routing key. +/// final message = Message( +/// headers: {'contentType': 'json', 'sender': 'Alice'}, +/// payload: {'text': 'Hello, World!'}, +/// timestamp: '2023-09-07T12:00:002', +/// ); +/// defaultExchange.forwardMessage(message, routingKey: 'my_routing_key'); +/// ``` +final class DefaultExchange extends BaseExchange implements ExchangeInterface { + /// Creates a new instance of the default exchange with the specified [id]. + /// + /// The [id] parameter represents the unique identifier for the default + /// exchange. + DefaultExchange(super.id); + + @override + void bindQueue({ + required Queue queue, + required String bindingKey, + }) => + (bindings.has(bindingKey) + ? bindings.get(bindingKey) + : _registerAndGetBinding(bindingKey)) + ..addQueue(queue); + + Binding _registerAndGetBinding(String bindingKey) { + bindings.register(bindingKey, Binding(bindingKey)); + return bindings.get(bindingKey); + } + + @override + void unbindQueue({ + required String queueId, + required String bindingKey, + }) { + (bindings.has(bindingKey) + ? bindings.get(bindingKey) + : throw BindingKeyNotFoundException(bindingKey)) + .removeQueue(queueId); + + if (!bindings.get(bindingKey).hasQueues()) { + bindings.unregister(bindingKey); + } + } + + @override + void forwardMessage({ + required Message message, + String? routingKey, + }) => + (bindings.has( + routingKey ?? (throw RoutingKeyRequiredException()), + ) + ? bindings.get(routingKey) + : throw BindingKeyNotFoundException(routingKey)) + .publishMessage(message); + + @override + void deleteQueue(String queueId) { + for (final binding in bindings.getAll()) { + binding.removeQueue(queueId); + } + } +} diff --git a/sandbox/mqueue/lib/src/exchange/direct_exchange.dart b/sandbox/mqueue/lib/src/exchange/direct_exchange.dart new file mode 100644 index 0000000..2560f29 --- /dev/null +++ b/sandbox/mqueue/lib/src/exchange/direct_exchange.dart @@ -0,0 +1,89 @@ +import 'package:angel3_mq/src/binding/binding.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/exchange/exchange.base.dart'; +import 'package:angel3_mq/src/exchange/exchange_interface.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; + +/// A class representing a direct message exchange for message routing. +/// +/// The `DirectExchange` class is a specific implementation of the +/// `BaseExchange` abstract base class, representing a direct exchange. A +/// direct exchange routes messages to queues based on matching routing keys. +/// It provides functionality for binding queues, forwarding messages based on +/// routing keys, and unbinding queues from the direct exchange. +/// +/// Example: +/// ```dart +/// final directExchange = DirectExchange('my_direct_exchange'); +/// +/// // Bind queues to the direct exchange with different routing keys. +/// final queue1 = Queue('queue_1'); +/// final queue2 = Queue('queue_2'); +/// directExchange.bindQueue(queue: queue1, bindingKey: 'routing_key_1'); +/// directExchange.bindQueue(queue: queue2, bindingKey: 'routing_key_2'); +/// +/// // Forward a message with a matching routing key to the appropriate queue. +/// final message = Message( +/// headers: {'contentType': 'json', 'sender': 'Alice'}, +/// payload: {'text': 'Hello, World!'}, +/// timestamp: '2023-09-07T12:00:002', +/// ); +/// directExchange.forwardMessage(message, routingKey: 'routing_key_1'); +/// ``` +final class DirectExchange extends BaseExchange implements ExchangeInterface { + /// Creates a new instance of the direct exchange with the specified [id]. + /// + /// The [id] parameter represents the unique identifier for the direct + /// exchange. + DirectExchange(super.id); + + @override + void bindQueue({ + required Queue queue, + required String bindingKey, + }) => + (bindings.has(bindingKey) + ? bindings.get(bindingKey) + : _registerAndGetBinding(bindingKey)) + .addQueue(queue); + + Binding _registerAndGetBinding(String bindingKey) { + bindings.register(bindingKey, Binding(bindingKey)); + return bindings.get(bindingKey); + } + + @override + void unbindQueue({ + required String queueId, + required String bindingKey, + }) { + (bindings.has(bindingKey) + ? bindings.get(bindingKey) + : throw BindingKeyNotFoundException(bindingKey)) + .removeQueue(queueId); + + if (!bindings.get(bindingKey).hasQueues()) { + bindings.unregister(bindingKey); + } + } + + @override + void forwardMessage({ + required Message message, + String? routingKey, + }) => + (bindings.has( + routingKey ?? (throw RoutingKeyRequiredException()), + ) + ? bindings.get(routingKey) + : throw BindingKeyNotFoundException(routingKey)) + .publishMessage(message); + + @override + void deleteQueue(String queueId) { + for (final binding in bindings.getAll()) { + binding.removeQueue(queueId); + } + } +} diff --git a/sandbox/mqueue/lib/src/exchange/exchange.base.dart b/sandbox/mqueue/lib/src/exchange/exchange.base.dart new file mode 100644 index 0000000..18e8184 --- /dev/null +++ b/sandbox/mqueue/lib/src/exchange/exchange.base.dart @@ -0,0 +1,27 @@ +import 'package:angel3_mq/src/binding/binding.dart'; +import 'package:angel3_mq/src/core/registrar/simple_registrar.dart'; +import 'package:angel3_mq/src/exchange/exchange_interface.dart'; + +/// An abstract base class representing an exchange for message routing. +/// +/// The `BaseExchange` abstract base class defines the core functionality of a +/// message exchange for routing messages to specific queues or bindings. +/// +/// Example: +/// ```dart +/// class MyExchange extends BaseExchange { +/// // Custom implementation of the exchange. +/// } +/// ``` +abstract base class BaseExchange implements ExchangeInterface { + /// Creates a new exchange with the specified [id]. + /// + /// The [id] parameter represents the unique identifier for the exchange. + BaseExchange(this.id); + + /// The unique identifier for the exchange. + final String id; + + /// A registrar for managing bindings associated with the exchange. + Registrar bindings = Registrar(); +} diff --git a/sandbox/mqueue/lib/src/exchange/exchange_interface.dart b/sandbox/mqueue/lib/src/exchange/exchange_interface.dart new file mode 100644 index 0000000..638ca72 --- /dev/null +++ b/sandbox/mqueue/lib/src/exchange/exchange_interface.dart @@ -0,0 +1,51 @@ +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; + +/// An abstract interface class defining the contract for managing exchanges. +/// +/// The `ExchangeInterface` defines a contract for classes that are responsible +/// for managing exchanges. Implementing classes must provide functionality for +/// binding queues to the exchange, unbinding queues from the exchange, +/// forwarding messages to queues or bindings, and removing queues from all +/// associated bindings. +/// +/// Example: +/// ```dart +/// class MyExchange implements ExchangeInterface { +/// // Custom implementation of the exchange. +/// } +/// ``` +abstract interface class ExchangeInterface { + /// Binds a queue to the exchange with a specific binding key. + /// + /// The [queue] parameter represents the queue to be bound to the exchange. + /// The [bindingKey] parameter represents the binding key for the queue. + void bindQueue({ + required Queue queue, + required String bindingKey, + }); + + /// Unbinds a queue from the exchange based on its ID and binding key. + /// + /// The [queueId] parameter represents the ID of the queue to be unbound. + /// The [bindingKey] parameter represents the binding key for the queue. + void unbindQueue({ + required String queueId, + required String bindingKey, + }); + + /// Forwards a message to queues or bindings based on the routing key. + /// + /// The [message] parameter represents the message to be forwarded. + /// The [routingKey] parameter represents the optional routing key to + /// determine the destination queues or bindings. + void forwardMessage({ + required Message message, + String? routingKey, + }); + + /// Removes a queue from all associated bindings. + /// + /// The [queueId] parameter represents the ID of the queue to be removed. + void deleteQueue(String queueId); +} diff --git a/sandbox/mqueue/lib/src/exchange/fanout_exchange.dart b/sandbox/mqueue/lib/src/exchange/fanout_exchange.dart new file mode 100644 index 0000000..a7a225e --- /dev/null +++ b/sandbox/mqueue/lib/src/exchange/fanout_exchange.dart @@ -0,0 +1,70 @@ +import 'package:angel3_mq/src/binding/binding.dart'; +import 'package:angel3_mq/src/exchange/exchange.base.dart'; +import 'package:angel3_mq/src/exchange/exchange_interface.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; + +/// A class representing a fanout message exchange for message routing. +/// +/// The `FanoutExchange` class is a specific implementation of the +/// `BaseExchange` abstract base class, representing a fanout exchange. +/// A fanout exchange routes messages to all associated queues without +/// considering routing keys. It provides functionality for binding queues, +/// forwarding messages to all associated queues, and unbinding queues +/// from the fanout exchange. +/// +/// Example: +/// ```dart +/// final fanoutExchange = FanoutExchange('my_fanout_exchange'); +/// +/// // Bind multiple queues to the fanout exchange. +/// final queue1 = Queue('queue_1'); +/// final queue2 = Queue('queue_2'); +/// fanoutExchange.bindQueue(queue: queue1, bindingKey: 'binding_key_1'); +/// fanoutExchange.bindQueue(queue: queue2, bindingKey: 'binding_key_2'); +/// +/// // Forward a message to all associated queues in the fanout exchange. +/// final message = Message( +/// headers: {'contentType': 'json', 'sender': 'Alice'}, +/// payload: {'text': 'Hello, World!'}, +/// timestamp: '2023-09-07T12:00:002', +/// ); +/// fanoutExchange.forwardMessage(message); +/// ``` +final class FanoutExchange extends BaseExchange implements ExchangeInterface { + /// Creates a new instance of the fanout exchange with the specified [id]. + /// + /// The [id] parameter represents the unique identifier for the fanout + /// exchange. + FanoutExchange(super.id) { + bindings.register('', Binding('')); + } + + @override + void bindQueue({ + required Queue queue, + required String bindingKey, + }) => + bindings.get('').addQueue(queue); + + @override + void unbindQueue({ + required String queueId, + required String bindingKey, + }) => + bindings.get('').removeQueue(queueId); + + @override + void forwardMessage({ + required Message message, + String? routingKey, + }) => + bindings.get('').publishMessage(message); + + @override + void deleteQueue(String queueId) { + for (final binding in bindings.getAll()) { + binding.removeQueue(queueId); + } + } +} diff --git a/sandbox/mqueue/lib/src/message/message.base.dart b/sandbox/mqueue/lib/src/message/message.base.dart new file mode 100644 index 0000000..57e101d --- /dev/null +++ b/sandbox/mqueue/lib/src/message/message.base.dart @@ -0,0 +1,43 @@ +/// Represents a base message with headers, payload, and an optional timestamp. +/// +/// A [BaseMessage] is a fundamental unit of data used in various messaging +/// systems. It typically contains metadata in the form of headers, the actual +/// payload, and an optional timestamp indicating when the message was created. +/// +/// The `headers` property is a map that can contain additional information +/// about the message, such as content type, sender, or any custom metadata. +/// +/// The `payload` property stores the main content of the message. It can be +/// of any type, allowing flexibility in the data that can be transmitted. +/// +/// The `timestamp` property, if provided, represents the time when the message +/// was created. It is formatted as an ISO 8601 string. +abstract class BaseMessage { + /// Creates a new `BaseMessage` with the specified headers, payload, and + /// timestamp. + /// + /// The [headers] parameter is a map that can contain additional information + /// about the message. It is optional and defaults to an empty map if not + /// provided. + /// + /// The [payload] parameter represents the main content of the message and is + /// required. + /// + /// The [timestamp] parameter is an optional ISO 8601 formatted timestamp + /// indicating when the message was created. If not provided, it will be + /// `null`. + BaseMessage( + Map? headers, + this.payload, + this.timestamp, + ) : headers = headers ?? {}; + + /// A map containing headers or metadata associated with the message. + final Map headers; + + /// The main content of the message. + final Object payload; + + /// An optional timestamp indicating when the message was created. + final String? timestamp; +} diff --git a/sandbox/mqueue/lib/src/message/message.dart b/sandbox/mqueue/lib/src/message/message.dart new file mode 100644 index 0000000..053ab13 --- /dev/null +++ b/sandbox/mqueue/lib/src/message/message.dart @@ -0,0 +1,86 @@ +import 'package:angel3_mq/src/message/message.base.dart'; +import 'package:uuid/uuid.dart'; + +/// Represents a message with headers, payload, and an optional timestamp. +/// +/// A [Message] is a specific type of message that extends the [BaseMessage] +/// class. +/// +/// Example: +/// ```dart +/// final message = Message( +/// headers: {'contentType': 'json', 'sender': 'Alice'}, +/// payload: {'text': 'Hello, World!'}, +/// timestamp: '2023-09-07T12:00:002', +/// ); +/// ``` +class Message extends BaseMessage { + /// Creates a new [Message] with the specified headers, payload, timestamp, and id. + /// + /// The [headers] parameter is a map that can contain additional information + /// about the message. It is optional and defaults to an empty map if not + /// provided. + /// + /// The [payload] parameter represents the main content of the message and is + /// required. + /// + /// The [timestamp] parameter is an optional ISO 8601 formatted timestamp + /// indicating when the message was created. If not provided, the current + /// timestamp will be used. + /// + /// The [id] parameter is an optional unique identifier for the message. + /// If not provided, a new UUID will be generated. + /// + /// Example: + /// ```dart + /// final message = Message( + /// headers: {'contentType': 'json', 'sender': 'Alice'}, + /// payload: {'text': 'Hello, World!'}, + /// timestamp: '2023-09-07T12:00:002', + /// id: '123e4567-e89b-12d3-a456-426614174000', + /// ); + /// ``` + Message({ + required Object payload, + Map? headers, + String? timestamp, + String? id, + }) : id = id ?? Uuid().v4(), + super( + headers, + payload, + timestamp ?? DateTime.now().toUtc().toIso8601String(), + ); + + /// A unique identifier for the message. + final String id; + + /// Returns a human-readable string representation of the message. + /// + /// Example: + /// ```dart + /// final message = Message( + /// headers: {'contentType': 'json', 'sender': 'Alice'}, + /// payload: {'text': 'Hello, World!'}, + /// timestamp: '2023-09-07T12:00:002', + /// ); + /// + /// print(message.toString()); + /// // Output: + /// // Message{ + /// // headers: {contentType: json, sender: Alice}, + /// // payload: {text: Hello, World!}, + /// // timestamp: 2023-09-07T12:00:002, + /// // } + /// ``` + @override + String toString() { + return ''' +Message{ + id: $id, + headers: $headers, + payload: $payload, + timestamp: $timestamp, +}'''; + } +} diff --git a/sandbox/mqueue/lib/src/mq/mq.base.dart b/sandbox/mqueue/lib/src/mq/mq.base.dart new file mode 100644 index 0000000..2acafd7 --- /dev/null +++ b/sandbox/mqueue/lib/src/mq/mq.base.dart @@ -0,0 +1,14 @@ +/// An abstract base class representing a message queue client. +/// +/// The `BaseMQClient` abstract base class defines the core functionality and +/// contract for implementing message queue clients. It serves as a foundation +/// for creating client implementations that interact with message queues for +/// sending and receiving messages. +/// +/// Example: +/// ```dart +/// class MyMQClient extends BaseMQClient { +/// // Custom implementation of the message queue client. +/// } +/// ``` +abstract class BaseMQClient {} diff --git a/sandbox/mqueue/lib/src/mq/mq.dart b/sandbox/mqueue/lib/src/mq/mq.dart new file mode 100644 index 0000000..1f48e6b --- /dev/null +++ b/sandbox/mqueue/lib/src/mq/mq.dart @@ -0,0 +1,256 @@ +import 'package:angel3_mq/src/core/constants/enums.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/core/registrar/simple_registrar.dart'; +import 'package:angel3_mq/src/exchange/default_exchange.dart'; +import 'package:angel3_mq/src/exchange/direct_exchange.dart'; +import 'package:angel3_mq/src/exchange/exchange.base.dart'; +import 'package:angel3_mq/src/exchange/fanout_exchange.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/mq/mq.base.dart'; +import 'package:angel3_mq/src/mq/mq.interface.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; + +/// A class representing a message queue client with various messaging +/// functionalities. +/// +/// The `MQClient` class is an implementation of both the `BaseMQClient` class +/// and the `MQClientInterface` interface. It provides features for interacting +/// with message queues, including declaring and managing queues and exchanges, +/// sending and receiving messages, and binding/unbinding queues to/from exchanges. +/// +/// Example: +/// ```dart +/// // Initialize the message queue client. +/// MQClient.initialize(); +/// +/// // Declare a queue and an exchange. +/// final queueId = MQClient.instance.declareQueue(); +/// final exchangeName = 'my_direct_exchange'; +/// MQClient.instance.declareExchange( +/// exchangeName: exchangeName, +/// exchangeType: ExchangeType.direct, +/// ); +/// +/// // Bind the queue to the exchange. +/// MQClient.instance.bindQueue( +/// queueId: queueId, +/// exchangeName: exchangeName, +/// ); +/// +/// // Send a message to the exchange. +/// final message = Message( +/// headers: {'contentType': 'json', 'sender': 'Alice'}, +/// payload: {'text': 'Hello, World!'}, +/// timestamp: '2023-09-07T12:00:002', +/// ); +/// MQClient.instance.sendMessage( +/// exchangeName: exchangeName, +/// message: message, +/// routingKey: queueId, +/// ); +/// +/// // Fetch messages from the queue. +/// final messageStream = MQClient.instance.fetchQueue(queueId); +/// messageStream.listen((message) { +/// print('Received message: $message'); +/// }); +/// ``` +class MQClient extends BaseMQClient implements MQClientInterface { + /// Private constructor to create the `MQClient` instance. + MQClient._internal() { + _exchanges.register('', DefaultExchange('')); + } + + /// Initializes the `MQClient` and creates a singleton instance. + /// + /// This method should be called before using the `MQClient`. + factory MQClient.initialize() => _instance ??= MQClient._internal(); + + /// Singleton instance of the `MQClient`. + static MQClient? _instance; + + /// Gets the singleton instance of the `MQClient`. + /// + /// Throws a [MQClientNotInitializedException] if the client has not been + /// initialized. + static MQClient get instance => + _instance ?? (throw MQClientNotInitializedException()); + + final Registrar _exchanges = Registrar(); + final Registrar _queues = Registrar(); + + @override + String declareQueue(String queueId) { + try { + _queues.register(queueId, Queue(queueId)); + + _exchanges.get('').bindQueue( + queue: _queues.get(queueId), + bindingKey: queueId, + ); + + return queueId; + } on IdAlreadyRegisteredException catch (_) { + return queueId; + } + } + + @override + void deleteQueue(String queueId) { + try { + final queue = _queues.get(queueId); + + if (queue.hasListeners()) { + throw QueueHasSubscribersException(queueId); + } else { + _deleteQueue(queueId); + } + } on IdNotRegisteredException catch (_) { + throw QueueNotRegisteredException(queueId); + } + } + + void _deleteQueue(String queueId) { + _queues.get(queueId).dispose(); + _exchanges.getAll().forEach( + (BaseExchange exchange) => exchange.deleteQueue(queueId), + ); + _queues.unregister(queueId); + } + + @override + Stream fetchQueue(String queueId) => _fetchQueue(queueId).dataStream; + + Queue _fetchQueue(String queueId) { + try { + return _queues.get(queueId); + } on IdNotRegisteredException catch (_) { + throw QueueNotRegisteredException(queueId); + } + } + + @override + List listQueues() => _queues + .getAll() + .map( + (Queue queue) => queue.id, + ) + .toList(); + + void deleteMessage(String queueId, Message message) { + try { + final queue = _fetchQueue(queueId); + queue.removeMessage(message); + } on QueueNotRegisteredException { + // Queue doesn't exist, so we can't delete the message + // We might want to log this or handle it in some way + } + } + + @override + void sendMessage({ + required Message message, + String? exchangeName, + String? routingKey, + }) { + try { + _exchanges + .get(exchangeName ?? '') + .forwardMessage(routingKey: routingKey, message: message); + } on IdNotRegisteredException catch (_) { + throw ExchangeNotRegisteredException(exchangeName ?? ''); + } + } + + @override + Message? getLatestMessage(String queueId) => + _fetchQueue(queueId).latestMessage; + + @override + void bindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }) { + try { + final exchange = _exchanges.get(exchangeName); + switch (exchange) { + case DirectExchange _: + if (bindingKey == null) { + throw BindingKeyRequiredException(); + } + exchange.bindQueue( + queue: _fetchQueue(queueId), + bindingKey: bindingKey, + ); + case FanoutExchange _: + exchange.bindQueue( + queue: _fetchQueue(queueId), + bindingKey: '', + ); + default: + return; + } + } on IdNotRegisteredException catch (_) { + throw ExchangeNotRegisteredException(exchangeName); + } + } + + @override + void unbindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }) { + try { + final exchange = _exchanges.get(exchangeName); + if (exchange.runtimeType == DirectExchange && bindingKey == null) { + throw BindingKeyRequiredException(); + } + exchange.unbindQueue( + queueId: queueId, + bindingKey: bindingKey ?? '', + ); + } on IdNotRegisteredException catch (_) { + throw ExchangeNotRegisteredException(exchangeName); + } + } + + @override + void declareExchange({ + required String exchangeName, + required ExchangeType exchangeType, + }) { + try { + switch (exchangeType) { + case ExchangeType.direct: + _exchanges.register(exchangeName, DirectExchange(exchangeName)); + case ExchangeType.fanout: + _exchanges.register(exchangeName, FanoutExchange(exchangeName)); + case ExchangeType.base: + throw InvalidExchangeTypeException(); + } + } on IdAlreadyRegisteredException catch (_) { + return; + } + } + + @override + void deleteExchange(String exchangeName) { + try { + _exchanges.unregister(exchangeName); + } catch (_) { + return; + } + } + + @override + void close() { + _queues.getAll().forEach( + (Queue queue) => queue.dispose(), + ); + _queues.clear(); + _exchanges.clear(); + _instance = null; + } +} diff --git a/sandbox/mqueue/lib/src/mq/mq.interface.dart b/sandbox/mqueue/lib/src/mq/mq.interface.dart new file mode 100644 index 0000000..a1301c1 --- /dev/null +++ b/sandbox/mqueue/lib/src/mq/mq.interface.dart @@ -0,0 +1,115 @@ +import 'package:angel3_mq/src/core/constants/enums.dart'; +import 'package:angel3_mq/src/message/message.dart'; + +/// An abstract interface class defining the contract for a message queue +/// client. +/// +/// The `MQClientInterface` abstract interface class defines a contract for +/// classes that implement a message queue client. Implementing classes must +/// provide methods for fetching messages from a queue, sending messages to an +/// exchange, declaring queues and exchanges, deleting queues and exchanges, +/// binding and unbinding queues from exchanges, and more. +/// +/// Example: +/// ```dart +/// class MyMQClient implements MQClientInterface { +/// // Custom implementation of the message queue client. +/// } +/// ``` +abstract interface class MQClientInterface { + /// Declares a queue in the message queue system. + /// + /// The [queueId] parameter represents the optional ID for the queue. + /// + /// Returns the ID of the declared queue. + String declareQueue(String queueId); + + /// Deletes a queue from the message queue system. + /// + /// The [queueId] parameter represents the ID of the queue to be deleted. + void deleteQueue(String queueId); + + /// Fetches messages from a queue. + /// + /// The [queueId] parameter represents the ID of the queue to fetch messages + /// from. + /// + /// Returns a stream of messages from the specified queue. + Stream fetchQueue(String queueId); + + /// Retrieves the list of queues. + /// + /// Returns a list of queue IDs. + List listQueues(); + + /// Sends a message to an exchange for routing to queues. + /// + /// The [exchangeName] parameter represents the name of the exchange to send + /// the message to. + /// The [message] parameter represents the message to be sent. + /// The [routingKey] parameter represents the optional routing key for message + /// routing within the exchange. + void sendMessage({ + required Message message, + String? exchangeName, + String? routingKey, + }); + + /// Retrieves the latest message from a queue. + /// + /// The [queueId] parameter represents the ID of the queue to fetch the latest + /// message from. + /// + /// Returns the latest message from the specified queue or `null` if the queue + /// is empty. + Message? getLatestMessage(String queueId); + + /// Binds a queue to an exchange for message routing. + /// + /// The [queueId] parameter represents the ID of the queue to be bound. + /// The [exchangeName] parameter represents the name of the exchange to bind + /// to. + /// The [bindingKey] parameter represents the optional binding key for routing + /// messages to the queue within the exchange. + void bindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }); + + /// Unbinds a queue from an exchange to stop message routing. + /// + /// The [queueId] parameter represents the ID of the queue to be unbound. + /// The [exchangeName] parameter represents the name of the exchange to unbind + /// from. + /// The [bindingKey] parameter represents the optional binding key previously + /// used for binding. + void unbindQueue({ + required String queueId, + required String exchangeName, + String? bindingKey, + }); + + /// Declares an exchange in the message queue system. + /// + /// The [exchangeName] parameter represents the name of the exchange to be + /// declared. + /// The [exchangeType] parameter represents the type of exchange (e.g., + /// direct, fanout). + void declareExchange({ + required String exchangeName, + required ExchangeType exchangeType, + }); + + /// Deletes an exchange from the message queue system. + /// + /// The [exchangeName] parameter represents the name of the exchange to be + /// deleted. + void deleteExchange(String exchangeName); + + /// Closes the connection to the message queue system. + /// + /// This method should be called when the message queue client is no longer + /// needed. + void close(); +} diff --git a/sandbox/mqueue/lib/src/producer/producer.dart b/sandbox/mqueue/lib/src/producer/producer.dart new file mode 100644 index 0000000..2ec6bb5 --- /dev/null +++ b/sandbox/mqueue/lib/src/producer/producer.dart @@ -0,0 +1,91 @@ +import 'dart:async'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/mq/mq.dart'; +import 'package:angel3_mq/src/producer/producer.interface.dart'; + +/// A mixin implementing the `ProducerInterface` for message production. +/// +/// The `Producer` mixin provides a concrete implementation of the +/// `ProducerInterface` for message production. It allows classes to easily send +/// messages to exchanges, send RPC (Remote Procedure Call) messages, and set a +/// callback for handling push notifications. +/// +/// Example: +/// ```dart +/// class MyMessageProducer with Producer { +/// // Custom implementation of the message producer. +/// } +/// ``` +@Deprecated('Please use `ProducerMixin` instead. ' + 'This will be removed in v2.0.0') +mixin Producer implements ProducerInterface { + /// A callback function for handling push notifications (received messages). + Function(Message message)? _callback; + + @override + void sendMessage({ + required Object payload, + String? exchangeName, + Map? headers, + String? routingKey, + String? timestamp, + }) { + final newMessage = Message( + payload: payload, + headers: headers, + timestamp: timestamp, + ); + MQClient.instance.sendMessage( + exchangeName: exchangeName, + routingKey: routingKey, + message: newMessage, + ); + + _callback?.call(newMessage); + } + + @override + Future sendRPCMessage({ + required String processId, + required String exchangeName, + Map? args, + String? routingKey, + T Function(Object)? mapper, + String? timestamp, + }) async { + final Completer completer = + mapper == null ? Completer() : Completer(); + + final newMessage = Message( + payload: 'RPC', + headers: { + 'type': 'RPC', + 'processId': processId, + 'args': args, + 'completer': completer, + }, + timestamp: timestamp, + ); + + MQClient.instance.sendMessage( + exchangeName: exchangeName, + routingKey: routingKey, + message: newMessage, + ); + + if (mapper == null) { + _callback?.call(newMessage); + final res = await completer.future.then((value) => value); + return res; + } else { + _callback?.call(newMessage); + final rawData = await completer.future.then((value) => value); + final data = mapper(rawData); + return data; + } + } + + @override + void setPushCallback(Function(Message message) callback) => + _callback = callback; +} diff --git a/sandbox/mqueue/lib/src/producer/producer.interface.dart b/sandbox/mqueue/lib/src/producer/producer.interface.dart new file mode 100644 index 0000000..2fec00e --- /dev/null +++ b/sandbox/mqueue/lib/src/producer/producer.interface.dart @@ -0,0 +1,56 @@ +import 'package:angel3_mq/src/message/message.dart'; + +/// An abstract interface class defining the contract for a message producer. +/// +/// The `ProducerInterface` abstract interface class defines a contract for +/// classes that implement a message producer. Implementing classes must provide +/// methods for sending messages to exchanges, sending RPC (Remote Procedure +/// Call) messages, and setting a callback for push notifications. +/// +/// Example: +/// ```dart +/// class MyProducer implements ProducerInterface { +/// // Custom implementation of the message producer. +/// } +/// ``` +abstract interface class ProducerInterface { + /// Sends a message to an exchange. + /// + /// The [payload] parameter represents the message payload to send. + /// The [exchangeName] parameter is the name of the exchange to send the + /// message to. + /// The [headers] parameter is an optional map of headers for the message. + /// The [routingKey] parameter is an optional routing key for the message. + void sendMessage({ + required Object payload, + required String exchangeName, + Map? headers, + String? routingKey, + }); + + /// Sends an RPC (Remote Procedure Call) message and awaits a response. + /// + /// The [processId] parameter is a unique identifier for the RPC request. + /// The [args] parameter is an optional map of arguments for the RPC request. + /// The [exchangeName] parameter is the name of the exchange for RPC + /// communication. + /// The [routingKey] parameter is an optional routing key for the RPC message. + /// The [mapper] parameter is an optional function to map the response + /// payload. + /// + /// Returns a future that completes with the response payload. + Future sendRPCMessage({ + required String processId, + required String exchangeName, + Map? args, + String? routingKey, + T Function(Object)? mapper, + }); + + /// Sets a callback function to be called after every 'sendMessage` or + /// `sendRPCMessage`. + /// + /// The [callback] parameter is a function that will be invoked when a push + /// notification (message) is received. + void setPushCallback(Function(Message message) callback); +} diff --git a/sandbox/mqueue/lib/src/producer/producer.mixin.dart b/sandbox/mqueue/lib/src/producer/producer.mixin.dart new file mode 100644 index 0000000..5953fbb --- /dev/null +++ b/sandbox/mqueue/lib/src/producer/producer.mixin.dart @@ -0,0 +1,90 @@ +import 'dart:async'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/mq/mq.dart'; +import 'package:angel3_mq/src/producer/producer.interface.dart'; + +/// A mixin implementing the `ProducerInterface` for message production. +/// +/// The `ProducerMixin` mixin provides a concrete implementation of the +/// `ProducerInterface` for message production. It allows classes to easily send +/// messages to exchanges, send RPC (Remote Procedure Call) messages, and set a +/// callback for handling push notifications. +/// +/// Example: +/// ```dart +/// class MyMessageProducer with ProducerMixin { +/// // Custom implementation of the message producer. +/// } +/// ``` +mixin ProducerMixin implements ProducerInterface { + /// A callback function for handling push notifications (received messages). + Function(Message message)? _callback; + + @override + void sendMessage({ + required Object payload, + String? exchangeName, + Map? headers, + String? routingKey, + String? timestamp, + }) { + final newMessage = Message( + payload: payload, + headers: headers, + timestamp: timestamp, + ); + + MQClient.instance.sendMessage( + exchangeName: exchangeName, + routingKey: routingKey, + message: newMessage, + ); + + _callback?.call(newMessage); + } + + @override + Future sendRPCMessage({ + required String processId, + required String exchangeName, + Map? args, + String? routingKey, + T Function(Object)? mapper, + String? timestamp, + }) async { + final Completer completer = + mapper == null ? Completer() : Completer(); + + final newMessage = Message( + payload: 'RPC', + headers: { + 'type': 'RPC', + 'processId': processId, + 'args': args, + 'completer': completer, + }, + timestamp: timestamp, + ); + + MQClient.instance.sendMessage( + exchangeName: exchangeName, + routingKey: routingKey, + message: newMessage, + ); + + if (mapper == null) { + _callback?.call(newMessage); + final res = await completer.future.then((value) => value); + return res; + } else { + _callback?.call(newMessage); + final rawData = await completer.future.then((value) => value); + final data = mapper(rawData); + return data; + } + } + + @override + void setPushCallback(Function(Message message) callback) => + _callback = callback; +} diff --git a/sandbox/mqueue/lib/src/queue/data_stream.base.dart b/sandbox/mqueue/lib/src/queue/data_stream.base.dart new file mode 100644 index 0000000..5cb83f6 --- /dev/null +++ b/sandbox/mqueue/lib/src/queue/data_stream.base.dart @@ -0,0 +1,54 @@ +import 'dart:async'; + +import 'package:angel3_mq/src/message/message.dart'; + +/// An abstract base class for data streams that produce [Message] objects. +/// +/// The `BaseDataStream` class provides the foundation for creating data +/// streams that emit [Message] objects to their listeners. It includes a +/// [StreamController] to manage the stream of messages and methods to enqueue +/// messages and dispose of the stream when it's no longer needed. +/// +/// Example: +/// ```dart +/// class MyDataStream extends BaseDataStream { +/// // Custom methods and logic specific to your data stream can be added here. +/// } +/// ``` +abstract class BaseDataStream { + /// A [StreamController] for broadcasting [Message] objects to listeners. + final StreamController _data = StreamController.broadcast(); + + /// Returns a [Stream] of [Message] objects from this data stream. + Stream get dataStream => _data.stream; + + /// The latest [Message] enqueued in the data stream. + /// + /// This property keeps track of the most recently enqueued message. + Message? _latestMessage; + + /// Exposes the [_latestMessage] property. + /// + /// This getter returns the most recently enqueued message. + Message? get latestMessage => _latestMessage; + + /// Enqueues a [Message] to be emitted by the data stream. + /// + /// The [message] parameter represents the [Message] to enqueue, and it + /// becomes the latest message in the stream. + void enqueue(Message message) { + _latestMessage = message; + _data.add(message); + } + + /// Closes the data stream, freeing up resources. + /// + /// This method should be called when the data stream is no longer needed + /// to prevent resource leaks. + void dispose() => _data.close(); + + /// Checks if there are any active listeners on the data stream. + /// + /// Returns `true` if there are active listeners, and `false` otherwise. + bool hasListeners() => _data.hasListener; +} diff --git a/sandbox/mqueue/lib/src/queue/queue.dart b/sandbox/mqueue/lib/src/queue/queue.dart new file mode 100644 index 0000000..f03e00a --- /dev/null +++ b/sandbox/mqueue/lib/src/queue/queue.dart @@ -0,0 +1,60 @@ +import 'dart:async'; + +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_mq/src/queue/data_stream.base.dart'; +import 'package:equatable/equatable.dart'; + +/// A class representing a queue for message streaming. +/// +/// The `Queue` class extends the [BaseDataStream] class and adds an +/// identifier, making it suitable for managing and streaming messages in a +/// queue-like fashion. +/// +/// Example: +/// ```dart +/// final myQueue = Queue('my_queue_id'); +/// +/// // Enqueue a message to the queue. +/// final message = Message( +/// headers: {'contentType': 'json', 'sender': 'Alice'}, +/// payload: {'text': 'Hello, World!'}, +/// timestamp: '2023-09-07T12:00:002', +/// ); +/// myQueue.enqueue(message); +/// +/// // Check if the queue has active listeners. +/// final hasListeners = myQueue.hasListeners(); +/// ``` +class Queue extends BaseDataStream with EquatableMixin { + Queue(this.id); + final String id; + final StreamController _controller = + StreamController.broadcast(); + Message? _latestMessage; + + void addMessage(Message message) { + _latestMessage = message; + _controller.add(message); + } + + Stream get dataStream => _controller.stream; + + Message? get latestMessage => _latestMessage; + + bool hasListeners() => _controller.hasListener; + + void dispose() { + _controller.close(); + } + + // New method to remove a message + void removeMessage(Message message) { + if (_latestMessage == message) { + _latestMessage = null; + } + // Note: We can't remove past messages from the stream, + // but we can prevent this message from being processed again in the future. + } + + List get props => [id]; +} diff --git a/sandbox/mqueue/pubspec.yaml b/sandbox/mqueue/pubspec.yaml new file mode 100644 index 0000000..7985374 --- /dev/null +++ b/sandbox/mqueue/pubspec.yaml @@ -0,0 +1,18 @@ +name: angel3_mq +description: DartMQ is a message-queue system that facilitates communication between different components in the application. +repository: https://github.com/N-Razzouk/dart_mq +issue_tracker: https://github.com/N-Razzouk/dart_mq/issues +homepage: https://github.com/N-Razzouk/dart_mq +documentation: https://github.com/N-Razzouk/dart_mq +version: 1.1.0 + +environment: + sdk: ">=3.0.0 <4.0.0" + +dependencies: + equatable: ^2.0.5 + uuid: ^4.5.1 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.21.0 diff --git a/sandbox/mqueue/test/binding/binding_test.dart b/sandbox/mqueue/test/binding/binding_test.dart new file mode 100644 index 0000000..23d87c0 --- /dev/null +++ b/sandbox/mqueue/test/binding/binding_test.dart @@ -0,0 +1,97 @@ +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_mq/src/binding/binding.dart'; +import 'package:angel3_mq/src/core/exceptions/queue_exceptions.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; +import 'package:test/test.dart'; + +void main() { + late Binding binding; + late Queue queue1; + late Queue queue2; + + setUp(() { + binding = Binding('my_binding'); + queue1 = Queue('queue_1'); + queue2 = Queue('queue_2'); + }); + + test('addQueue adds a queue to the binding', () { + binding.addQueue(queue1); + expect(binding.hasQueues(), isTrue); + }); + + test('removeQueue removes a queue from the binding', () { + binding.addQueue(queue1); + expect(binding.hasQueues(), isTrue); + + binding.removeQueue('queue_1'); + expect(binding.hasQueues(), isFalse); + }); + + test( + 'removeQueue throws QueueHasSubscribersException if queue has ' + 'subscribers', () { + final sub = queue1.dataStream.listen((_) {}); + + binding.addQueue(queue1); + + expect( + () => binding.removeQueue('queue_1'), + throwsA(isA()), + ); + + sub.cancel(); + }); + + test('publishMessage publishes a message to all associated queues', () { + binding + ..addQueue(queue1) + ..addQueue(queue2); + + final message = Message( + headers: {'contentType': 'json', 'sender': 'Alice'}, + payload: {'text': 'Hello, World!'}, + timestamp: '2023-09-07T12:00:002', + ); + + binding.publishMessage(message); + + expect(queue1.latestMessage, equals(message)); + expect(queue2.latestMessage, equals(message)); + }); + + test('hasQueues returns true if the binding has associated queues', () { + expect(binding.hasQueues(), isFalse); + + binding.addQueue(queue1); + expect(binding.hasQueues(), isTrue); + }); + + test('clear clears all queues from the binding', () { + binding + ..addQueue(queue1) + ..addQueue(queue2); + + expect(binding.hasQueues(), isTrue); + + binding.clear(); + expect(binding.hasQueues(), isFalse); + }); + + test('clear throws QueueHasSubscribersException if a queue has subscribers', + () { + final sub = queue1.dataStream.listen((_) {}); + + binding + ..addQueue(queue1) + ..addQueue(queue2); + + expect(binding.hasQueues(), isTrue); + + expect(() => binding.clear(), throwsA(isA())); + + expect(binding.hasQueues(), isTrue); + + sub.cancel(); + }); +} diff --git a/sandbox/mqueue/test/consumer/consumer_test.dart b/sandbox/mqueue/test/consumer/consumer_test.dart new file mode 100644 index 0000000..f7fb078 --- /dev/null +++ b/sandbox/mqueue/test/consumer/consumer_test.dart @@ -0,0 +1,333 @@ +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +class MyMessageConsumer with ConsumerMixin { + // Custom implementation of the message consumer. +} + +void main() { + group('Consumer', () { + final consumer = MyMessageConsumer(); + setUpAll(() { + MQClient.initialize(); + + MQClient.instance.declareQueue('test-queue'); + }); + + test('subscribe should register a subscription and receive messages', + () async { + const queueId = 'test-queue'; + final message1 = Message(payload: 'Message 1'); + final message2 = Message(payload: 'Message 2'); + final callbackMessages = []; + + consumer.subscribe( + queueId: queueId, + callback: (message) { + callbackMessages.add(message); + }, + ); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message1, + routingKey: queueId, + ); + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + + // Ensure that the callback was called with the expected messages + expect(callbackMessages, contains(message1)); + expect(callbackMessages, contains(message2)); + }); + + test('unsubscribe should cancel a subscription', () async { + const queueId = 'test-queue'; + final message1 = Message(payload: 'Message 1'); + final message2 = Message(payload: 'Message 2'); + final callbackMessages = []; + + consumer + ..clearSubscriptions() + ..subscribe( + queueId: queueId, + callback: (message) { + callbackMessages.add(message); + }, + ); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message1, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + + // Unsubscribe and ensure that the callback is not called + consumer.unsubscribe(queueId: queueId); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + + expect(callbackMessages, contains(message1)); + expect(callbackMessages.length, equals(1)); + }); + + test('pauseSubscription should pause a subscription', () async { + const queueId = 'test-queue'; + final message1 = Message(payload: 'Message 1'); + final message2 = Message(payload: 'Message 2'); + final callbackMessages = []; + + consumer + ..clearSubscriptions() + ..subscribe( + queueId: queueId, + callback: (message) { + callbackMessages.add(message); + }, + ); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message1, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + + // Pause the subscription and ensure that the callback is not called + consumer.pauseSubscription(queueId); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + + expect(callbackMessages, contains(message1)); + expect(callbackMessages.length, equals(1)); + }); + + test('resumeSubscription should resume a paused subscription', () async { + const queueId = 'test-queue'; + final message1 = Message(payload: 'Message 1'); + final message2 = Message(payload: 'Message 2'); + final callbackMessages = []; + + consumer + ..clearSubscriptions() + ..subscribe( + queueId: queueId, + callback: (message) { + callbackMessages.add(message); + }, + ); + + // Publish a message to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message1, + routingKey: queueId, + ); + + // Pause and then resume the subscription and ensure that the callback is + // called. + consumer + ..pauseSubscription(queueId) + ..resumeSubscription(queueId); + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + + expect(callbackMessages, contains(message1)); + expect(callbackMessages, contains(message2)); + expect(callbackMessages.length, equals(2)); + }); + + test( + 'updateSubscription should update a subscription with a new callback ' + 'and filter', () async { + const queueId = 'test-queue'; + final message1 = Message(payload: 'Message 1'); + final message2 = Message(payload: 'Message 2'); + final message3 = Message(payload: 'Message 3'); + final callbackMessages = []; + + consumer + ..clearSubscriptions() + ..subscribe( + queueId: queueId, + callback: (message) { + callbackMessages.add(message); + }, + ); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message1, + routingKey: queueId, + ); + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + // Update the subscription with a new callback and filter + consumer.updateSubscription( + queueId: queueId, + callback: (message) { + if (message.payload == 'Message 2') { + callbackMessages.add(message); + } + }, + filter: (payload) => payload == 'Message 2', + ); + + // Publish another message to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message3, + routingKey: queueId, + ); + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + + // Ensure that the callback is only called with 'Message 2' + expect(callbackMessages, contains(message1)); + expect(callbackMessages, contains(message2)); + expect(callbackMessages.contains(message3), isFalse); + expect(callbackMessages.length, equals(3)); + }); + + test('clearSubscriptions should clear all subscriptions', () async { + const queueId = 'test-queue'; + final message1 = Message(payload: 'Message 1'); + final message2 = Message(payload: 'Message 2'); + final message3 = Message(payload: 'Message 3'); + final callbackMessages = []; + + consumer + ..clearSubscriptions() + ..subscribe( + queueId: queueId, + callback: (message) { + callbackMessages.add(message); + }, + ); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message1, + routingKey: queueId, + ); + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + // Update the subscription with a new callback and filter + consumer.clearSubscriptions(); + + // Publish another message to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message3, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + + // Ensure that the callback is only called on the first two messages. + expect(callbackMessages, contains(message1)); + expect(callbackMessages, contains(message2)); + expect(callbackMessages.contains(message3), isFalse); + expect(callbackMessages.length, equals(2)); + }); + + test('getLatestMessage should return the latest message from a queue', + () async { + const queueId = 'test-queue'; + final message1 = Message(payload: 'Message 1'); + final message2 = Message(payload: 'Message 2'); + final message3 = Message(payload: 'Message 3'); + + consumer + ..clearSubscriptions() + ..subscribe( + queueId: queueId, + callback: (_) {}, + ); + + // Publish messages to the queue + MQClient.instance.sendMessage( + exchangeName: '', + message: message1, + routingKey: queueId, + ); + MQClient.instance.sendMessage( + exchangeName: '', + message: message2, + routingKey: queueId, + ); + MQClient.instance.sendMessage( + exchangeName: '', + message: message3, + routingKey: queueId, + ); + + await Future.delayed(Duration.zero); + + // Get the latest message + final latestMessage = consumer.getLatestMessage(queueId); + + // Ensure that the latest message is 'Message 3' + expect(latestMessage, equals(message3)); + }); + + test( + 'subscribing to a queue that has already been subscribed to throws an ' + 'error.', () { + const queueId = 'test-queue'; + + consumer + ..clearSubscriptions() + ..subscribe(queueId: queueId, callback: (_) {}); + + expect( + () => consumer.subscribe(queueId: queueId, callback: (_) {}), + throwsA(isA()), + ); + }); + }); +} diff --git a/sandbox/mqueue/test/core/exceptions/binding_exceptions_test.dart b/sandbox/mqueue/test/core/exceptions/binding_exceptions_test.dart new file mode 100644 index 0000000..8d0e1bd --- /dev/null +++ b/sandbox/mqueue/test/core/exceptions/binding_exceptions_test.dart @@ -0,0 +1,24 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('BindingException', () { + test('BindingKeyNotFoundException', () { + final exception = BindingKeyNotFoundException('test-key'); + expect(exception.toString(), contains('BindingKeyNotFoundException')); + expect( + exception.toString(), + contains( + 'BindingKeyNotFoundException:' + ' The binding key "test-key" was not found.', + ), + ); + }); + + test('BindingKeyRequiredException', () { + final exception = BindingKeyRequiredException(); + expect(exception.toString(), contains('BindingKeyRequiredException')); + expect(exception.toString(), contains('Binding key is required')); + }); + }); +} diff --git a/sandbox/mqueue/test/core/exceptions/consumer_exceptions_test.dart b/sandbox/mqueue/test/core/exceptions/consumer_exceptions_test.dart new file mode 100644 index 0000000..0e302d2 --- /dev/null +++ b/sandbox/mqueue/test/core/exceptions/consumer_exceptions_test.dart @@ -0,0 +1,60 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('ConsumerException', () { + test('ConsumerNotRegisteredException', () { + final exception = ConsumerNotRegisteredException('Alice'); + expect(exception.toString(), contains('ConsumerNotRegisteredException')); + expect( + exception.toString(), + contains('ConsumerNotRegisteredException: The consumer "Alice" is not ' + 'registered.'), + ); + }); + + test('ConsumerAlreadySubscribedException', () { + final exception = ConsumerAlreadySubscribedException( + consumer: 'NewsConsumer', + queue: 'NewsQueue', + ); + expect( + exception.toString(), + contains('ConsumerAlreadySubscribedException'), + ); + expect( + exception.toString(), + contains( + 'ConsumerAlreadySubscribedException: The consumer "NewsConsumer" ' + 'is already subscribed to the queue "NewsQueue".'), + ); + }); + + test('ConsumerNotSubscribedException', () { + final exception = ConsumerNotSubscribedException( + consumer: 'WeatherConsumer', + queue: 'WeatherQueue', + ); + expect(exception.toString(), contains('ConsumerNotSubscribedException')); + expect( + exception.toString(), + contains( + 'ConsumerNotSubscribedException: The consumer "WeatherConsumer" ' + 'is not subscribed to the queue "WeatherQueue".'), + ); + }); + + test('ConsumerHasSubscriptionsException', () { + final exception = ConsumerHasSubscriptionsException('Bob'); + expect( + exception.toString(), + contains('ConsumerHasSubscriptionsException'), + ); + expect( + exception.toString(), + contains('ConsumerHasSubscriptionsException: The consumer "Bob" has ' + 'active subscriptions.'), + ); + }); + }); +} diff --git a/sandbox/mqueue/test/core/exceptions/exchange_exceptions_test.dart b/sandbox/mqueue/test/core/exceptions/exchange_exceptions_test.dart new file mode 100644 index 0000000..da20214 --- /dev/null +++ b/sandbox/mqueue/test/core/exceptions/exchange_exceptions_test.dart @@ -0,0 +1,21 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('ExchangeException', () { + test('ExchangeNotRegisteredException', () { + final exception = ExchangeNotRegisteredException('NewsExchange'); + expect(exception.toString(), contains('ExchangeNotRegisteredException')); + expect( + exception.toString(), + contains('Exchange: NewsExchange is not registered'), + ); + }); + + test('InvalidExchangeTypeException', () { + final exception = InvalidExchangeTypeException(); + expect(exception.toString(), contains('InvalidExchangeTypeException')); + expect(exception.toString(), contains('Exchange type is invalid.')); + }); + }); +} diff --git a/sandbox/mqueue/test/core/exceptions/mq_client_exceptions_test.dart b/sandbox/mqueue/test/core/exceptions/mq_client_exceptions_test.dart new file mode 100644 index 0000000..d38a122 --- /dev/null +++ b/sandbox/mqueue/test/core/exceptions/mq_client_exceptions_test.dart @@ -0,0 +1,17 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('MQClientException', () { + test('MQClientNotInitializedException', () { + final exception = MQClientNotInitializedException(); + expect(exception.toString(), contains('MQClientNotInitializedException')); + expect( + exception.toString(), + contains('MQClientNotInitializedException: MQClient is not ' + 'initialized. Please make sure to call MQClient.initialize() ' + 'first.'), + ); + }); + }); +} diff --git a/sandbox/mqueue/test/core/exceptions/queue_exceptions_test.dart b/sandbox/mqueue/test/core/exceptions/queue_exceptions_test.dart new file mode 100644 index 0000000..a0be43a --- /dev/null +++ b/sandbox/mqueue/test/core/exceptions/queue_exceptions_test.dart @@ -0,0 +1,30 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('QueueException', () { + test('QueueNotRegisteredException', () { + final exception = QueueNotRegisteredException('my_queue_id'); + expect(exception.toString(), contains('QueueNotRegisteredException')); + expect( + exception.toString(), + contains('Queue: my_queue_id is not registered'), + ); + }); + + test('QueueHasSubscribersException', () { + final exception = QueueHasSubscribersException('my_queue_id'); + expect(exception.toString(), contains('QueueHasSubscribersException')); + expect( + exception.toString(), + contains('Queue: my_queue_id has subscribers'), + ); + }); + + test('QueueIdNullException', () { + final exception = QueueIdNullException(); + expect(exception.toString(), contains('QueueIdNullException')); + expect(exception.toString(), contains("Queue name can't be null")); + }); + }); +} diff --git a/sandbox/mqueue/test/core/exceptions/registrar_exceptions_test.dart b/sandbox/mqueue/test/core/exceptions/registrar_exceptions_test.dart new file mode 100644 index 0000000..8f1d3f9 --- /dev/null +++ b/sandbox/mqueue/test/core/exceptions/registrar_exceptions_test.dart @@ -0,0 +1,25 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('RegistrarException', () { + test('IdAlreadyRegisteredException', () { + final exception = IdAlreadyRegisteredException('my_id'); + expect(exception.toString(), contains('IdAlreadyRegisteredException')); + expect( + exception.toString(), + contains('IdAlreadyRegisteredException: Id ' + '"my_id" already registered'), + ); + }); + + test('IdNotRegisteredException', () { + final exception = IdNotRegisteredException('my_id'); + expect(exception.toString(), contains('IdNotRegisteredException')); + expect( + exception.toString(), + contains('IdNotRegisteredException: Id "my_id" not registered.'), + ); + }); + }); +} diff --git a/sandbox/mqueue/test/core/exceptions/routing_key_exceptionss_test.dart b/sandbox/mqueue/test/core/exceptions/routing_key_exceptionss_test.dart new file mode 100644 index 0000000..de8f389 --- /dev/null +++ b/sandbox/mqueue/test/core/exceptions/routing_key_exceptionss_test.dart @@ -0,0 +1,12 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('RoutingKeyException', () { + test('RoutingKeyRequiredException', () { + final exception = RoutingKeyRequiredException(); + expect(exception.toString(), contains('RoutingKeyRequiredException')); + expect(exception.toString(), contains('Routing key is required')); + }); + }); +} diff --git a/sandbox/mqueue/test/core/registrar/simple_registrar_test.dart b/sandbox/mqueue/test/core/registrar/simple_registrar_test.dart new file mode 100644 index 0000000..975d699 --- /dev/null +++ b/sandbox/mqueue/test/core/registrar/simple_registrar_test.dart @@ -0,0 +1,105 @@ +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/core/registrar/simple_registrar.dart'; +import 'package:test/test.dart'; + +void main() { + late Registrar registrar; + + setUp(() { + registrar = Registrar(); + }); + + test('register and get objects', () { + registrar + ..register('user_1', 'Alice') + ..register('user_2', 'Bob'); + + expect(registrar.get('user_1'), equals('Alice')); + expect(registrar.get('user_2'), equals('Bob')); + }); + + test('register throws IdAlreadyRegisteredException for duplicate IDs', () { + registrar.register('user_1', 'Alice'); + expect( + () => registrar.register('user_1', 'Another Alice'), + throwsA(const TypeMatcher()), + ); + }); + + test('get throws IdNotRegisteredException for unknown IDs', () { + expect( + () => registrar.get('unknown_id'), + throwsA(const TypeMatcher()), + ); + }); + + test('getAll returns a list of all registered objects', () { + registrar + ..register('user_1', 'Alice') + ..register('user_2', 'Bob'); + + final allObjects = registrar.getAll(); + + expect(allObjects, contains('Alice')); + expect(allObjects, contains('Bob')); + }); + + test('unregister removes objects', () { + registrar + ..register('user_1', 'Alice') + ..register('user_2', 'Bob') + ..unregister('user_1'); + + expect( + () => registrar.get('user_1'), + throwsA(const TypeMatcher()), + ); + expect(registrar.get('user_2'), equals('Bob')); + }); + + test('unregister throws IdNotRegisteredException for unknown IDs', () { + expect( + () => registrar.unregister('unknown_id'), + throwsA(const TypeMatcher()), + ); + }); + + test('clear removes all registered objects', () { + registrar + ..register('user_1', 'Alice') + ..register('user_2', 'Bob') + ..clear(); + + expect(registrar.count, equals(0)); + }); + + test('has checks if an object is registered', () { + registrar.register('user_1', 'Alice'); + + expect(registrar.has('user_1'), isTrue); + expect(registrar.has('user_2'), isFalse); + }); + + test('count returns the number of registered objects', () { + registrar + ..register('user_1', 'Alice') + ..register('user_2', 'Bob'); + + expect(registrar.count, equals(2)); + }); + + test('toString returns a formatted string representation of the registrar', + () { + registrar + ..register('user_1', 'Alice') + ..register('user_2', 'Bob'); + + const expectedString = ''' +Registrar( +\tuser_1: Alice, +\tuser_2: Bob + )'''; + + expect(registrar.toString(), equals(expectedString)); + }); +} diff --git a/sandbox/mqueue/test/exchange/default_exchange_test.dart b/sandbox/mqueue/test/exchange/default_exchange_test.dart new file mode 100644 index 0000000..547f9e1 --- /dev/null +++ b/sandbox/mqueue/test/exchange/default_exchange_test.dart @@ -0,0 +1,79 @@ +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/exchange/default_exchange.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; +import 'package:test/test.dart'; + +void main() { + late DefaultExchange defaultExchange; + late Queue queue; + late Message message; + + setUp(() { + defaultExchange = DefaultExchange('default_exchange'); + queue = Queue('my_queue'); + message = Message( + headers: {'contentType': 'json', 'sender': 'Alice'}, + payload: {'text': 'Hello, World!'}, + timestamp: '2023-09-07T12:00:002', + ); + }); + + test('bindQueue binds a queue to the default exchange with a binding key', + () { + defaultExchange.bindQueue(queue: queue, bindingKey: 'my_routing_key'); + expect(defaultExchange.bindings.has('my_routing_key'), isTrue); + }); + + test( + 'unbindQueue throws an exception when attempting to unbind from the ' + 'default exchange', () { + expect( + () => defaultExchange.unbindQueue( + queueId: 'my_queue_id', + bindingKey: 'my_routing_key', + ), + throwsA(isA()), + ); + }); + + test('unbindQueue unbinds a queue from the default exchange', () { + defaultExchange + ..bindQueue(queue: queue, bindingKey: 'my_routing_key') + ..unbindQueue( + queueId: queue.id, + bindingKey: 'my_routing_key', + ); + expect(defaultExchange.bindings.has('my_routing_key'), isFalse); + }); + + test( + 'forwardMessage forwards a message to the default exchange using a ' + 'routing key', () { + defaultExchange + ..bindQueue(queue: queue, bindingKey: 'my_routing_key') + ..forwardMessage(message: message, routingKey: 'my_routing_key'); + expect(queue.latestMessage, equals(message)); + }); + + test( + 'forwardMessage throws BindingKeyNotFoundException when routing key is ' + 'not found', () { + expect( + () => defaultExchange.forwardMessage( + message: message, + routingKey: 'non_existent_routing_key', + ), + throwsA(isA()), + ); + }); + + test( + 'forwardMessage throws RoutingKeyRequiredException when routing key is ' + 'null', () { + expect( + () => defaultExchange.forwardMessage(message: message), + throwsA(isA()), + ); + }); +} diff --git a/sandbox/mqueue/test/exchange/direct_exchange_test.dart b/sandbox/mqueue/test/exchange/direct_exchange_test.dart new file mode 100644 index 0000000..0f0de29 --- /dev/null +++ b/sandbox/mqueue/test/exchange/direct_exchange_test.dart @@ -0,0 +1,88 @@ +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:angel3_mq/src/exchange/direct_exchange.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; +import 'package:test/test.dart'; + +void main() { + late DirectExchange directExchange; + late Queue queue1; + late Queue queue2; + late Message message; + + setUp(() { + directExchange = DirectExchange('my_direct_exchange'); + queue1 = Queue('queue_1'); + queue2 = Queue('queue_2'); + message = Message( + headers: {'contentType': 'json', 'sender': 'Alice'}, + payload: {'text': 'Hello, World!'}, + timestamp: '2023-09-07T12:00:002', + ); + }); + + test('bindQueue binds a queue to the direct exchange with a binding key', () { + directExchange.bindQueue(queue: queue1, bindingKey: 'routing_key_1'); + expect(directExchange.bindings.has('routing_key_1'), isTrue); + }); + + test( + 'bindQueue binds a queue to the direct exchange with a binding key that ' + 'already exists.', () { + directExchange + ..bindQueue(queue: queue1, bindingKey: 'routing_key_1') + ..bindQueue(queue: queue2, bindingKey: 'routing_key_1'); + expect(directExchange.bindings.has('routing_key_1'), isTrue); + }); + + test( + 'unbindQueue unbinds a queue from the direct exchange with a binding key', + () { + directExchange + ..bindQueue(queue: queue1, bindingKey: 'routing_key_1') + ..unbindQueue(queueId: queue1.id, bindingKey: 'routing_key_1'); + expect(directExchange.bindings.has('routing_key_1'), isFalse); + }); + + test( + 'forwardMessage forwards a message to the direct exchange using a ' + 'routing key', () { + directExchange + ..bindQueue(queue: queue1, bindingKey: 'routing_key_1') + ..forwardMessage(message: message, routingKey: 'routing_key_1'); + expect(queue1.latestMessage, equals(message)); + }); + + test( + 'forwardMessage throws BindingKeyNotFoundException when routing key is ' + 'not found', () { + expect( + () => directExchange.forwardMessage( + message: message, + routingKey: 'non_existent_routing_key', + ), + throwsA(isA()), + ); + }); + + test( + 'forwardMessage throws RoutingKeyRequiredException when routing key is ' + 'null', () { + expect( + () => directExchange.forwardMessage(message: message), + throwsA(isA()), + ); + }); + + test( + 'unbindQueue throws BindingKeyNotFoundException when attempting to ' + 'unbind with an invalid binding key', () { + expect( + () => directExchange.unbindQueue( + queueId: 'queue_id', + bindingKey: 'invalid_binding_key', + ), + throwsA(isA()), + ); + }); +} diff --git a/sandbox/mqueue/test/exchange/fanout_exchange_test.dart b/sandbox/mqueue/test/exchange/fanout_exchange_test.dart new file mode 100644 index 0000000..3332216 --- /dev/null +++ b/sandbox/mqueue/test/exchange/fanout_exchange_test.dart @@ -0,0 +1,69 @@ +import 'package:angel3_mq/src/exchange/fanout_exchange.dart'; +import 'package:angel3_mq/src/message/message.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; +import 'package:test/test.dart'; + +void main() { + group('FanoutExchange', () { + test('bindQueue should add a queue to the exchange', () { + final fanoutExchange = FanoutExchange('my_fanout_exchange'); + final queue1 = Queue('queue_1'); + final queue2 = Queue('queue_2'); + + fanoutExchange + ..bindQueue(queue: queue1, bindingKey: 'binding_key_1') + ..bindQueue(queue: queue2, bindingKey: 'binding_key_2'); + + expect(fanoutExchange.bindings.get('').hasQueues(), isTrue); + }); + + test('unbindQueue should remove a queue from the exchange', () { + final fanoutExchange = FanoutExchange('my_fanout_exchange'); + final queue1 = Queue('queue_1'); + final queue2 = Queue('queue_2'); + + fanoutExchange + ..bindQueue(queue: queue1, bindingKey: 'binding_key_1') + ..bindQueue(queue: queue2, bindingKey: 'binding_key_2') + ..unbindQueue(queueId: 'queue_1', bindingKey: 'binding_key_1') + ..unbindQueue(queueId: 'queue_2', bindingKey: 'binding_key_2'); + + expect(fanoutExchange.bindings.get('').hasQueues(), isFalse); + }); + + test('forwardMessage should forward a message to all associated queues', + () { + final fanoutExchange = FanoutExchange('my_fanout_exchange'); + final queue1 = Queue('queue_1'); + final queue2 = Queue('queue_2'); + + fanoutExchange + ..bindQueue(queue: queue1, bindingKey: 'binding_key_1') + ..bindQueue(queue: queue2, bindingKey: 'binding_key_2'); + + final message = Message( + headers: {'contentType': 'json', 'sender': 'Alice'}, + payload: {'text': 'Hello, World!'}, + timestamp: '2023-09-07T12:00:002', + ); + + fanoutExchange.forwardMessage(message: message); + + expect(queue1.latestMessage, equals(message)); + expect(queue2.latestMessage, equals(message)); + }); + + test('removeQueue removes a queue from all bindings', () { + final queue1 = Queue('queue_1'); + + final fanoutExchange = FanoutExchange('my_fanout_exchange') + ..bindQueue(queue: queue1, bindingKey: '') + ..unbindQueue( + queueId: queue1.id, + bindingKey: '', + ); + + expect(fanoutExchange.bindings.get('').hasQueues(), isFalse); + }); + }); +} diff --git a/sandbox/mqueue/test/message/message.base_test.dart b/sandbox/mqueue/test/message/message.base_test.dart new file mode 100644 index 0000000..86cc658 --- /dev/null +++ b/sandbox/mqueue/test/message/message.base_test.dart @@ -0,0 +1,59 @@ +import 'package:angel3_mq/mq.dart'; +import 'package:test/test.dart'; + +void main() { + group('BaseMessage', () { + test('Creating a BaseMessage', () { + // Arrange + final headers = {'content-type': 'text/plain'}; + const payload = 'Hello, World!'; + const timestamp = '2023-09-07T12:00:002'; + + // Act + final baseMessage = + Message(payload: payload, headers: headers, timestamp: timestamp); + + // Assert + expect(baseMessage.headers, equals(headers)); + expect(baseMessage.payload, equals(payload)); + expect(baseMessage.timestamp, equals(timestamp)); + }); + + test('Creating a BaseMessage without headers and timestamp', () { + // Arrange + const payload = 'Hello, World!'; + + // Act + final baseMessage = Message( + payload: payload, + ); + + // Assert + expect(baseMessage.headers, isEmpty); + expect(baseMessage.payload, equals(payload)); + expect(baseMessage.timestamp, isNotNull); + }); + + test('toString function.', () { + // Arrange + final headers = {'content-type': 'text/plain'}; + const payload = 'Hello, World!'; + const timestamp = '2023-09-07T12:00:002'; + + // Act + final baseMessage = + Message(payload: payload, headers: headers, timestamp: timestamp); + + // Assert + expect( + baseMessage.toString(), + equals(''' +Message{ + headers: $headers, + payload: $payload, + timestamp: $timestamp, + }'''), + ); + }); + }); +} diff --git a/sandbox/mqueue/test/mq/mq_test.dart b/sandbox/mqueue/test/mq/mq_test.dart new file mode 100644 index 0000000..0c81eea --- /dev/null +++ b/sandbox/mqueue/test/mq/mq_test.dart @@ -0,0 +1,342 @@ +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_mq/src/core/exceptions/exceptions.dart'; +import 'package:test/test.dart'; + +void main() { + group('Initialization', () { + test( + 'MQClient instance should throw MQClientNotInitializedException if ' + 'not initialized', () { + expect( + () => MQClient.instance, + throwsA(isA()), + ); + }); + + test('MQClient initialize should create a singleton instance', () { + MQClient.initialize(); + final initializedInstance = MQClient.instance; + expect(initializedInstance, isA()); + expect(MQClient.instance, equals(initializedInstance)); + }); + }); + + group('Queue Operations', () { + setUpAll(MQClient.initialize); + + test('listQueues should return a list of all registered queues', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + final queues = MQClient.instance.listQueues(); + expect(queues, isA>()); + expect(queues, contains(queueId)); + MQClient.instance.deleteQueue(queueId); + }); + test( + 'declareQueue should declare a new queue and bind it to the default ' + 'exchange', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + final queue = MQClient.instance.fetchQueue(queueId); + expect(queue, isNotNull); + MQClient.instance.deleteQueue(queueId); + }); + + test('declareQueue should declare a new queue with the specified name', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + final queue = MQClient.instance.fetchQueue(queueId); + expect(queue, isNotNull); + expect(MQClient.instance.fetchQueue(queueId), isA>()); + MQClient.instance.deleteQueue(queueId); + }); + + test( + "declareQueue should return name of queue even if it's already " + 'registered', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + + final queueId2 = MQClient.instance.declareQueue('test-queue'); + + expect(queueId, equals(queueId2)); + + MQClient.instance.deleteQueue(queueId); + }); + + test( + 'fetchQueue should throw QueueNotRegisteredException if the queue does ' + 'not exist.', () { + expect( + () => MQClient.instance.fetchQueue('test-queue'), + throwsA(isA()), + ); + }); + + test( + 'getLatestMessage should throw QueueNotRegisteredException if the ' + 'queue does not exist.', () { + expect( + () => MQClient.instance.getLatestMessage('test-queue'), + throwsA(isA()), + ); + }); + + test('deleteQueue should delete a queue', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + MQClient.instance.deleteQueue(queueId); + expect( + () => MQClient.instance.fetchQueue(queueId), + throwsA(isA()), + ); + }); + + test( + 'deleteQueue should throw QueueNotRegisteredException if the queue ' + 'does not exist.', () { + expect( + () => MQClient.instance.deleteQueue('test-queue'), + throwsA(isA()), + ); + }); + + test( + 'deleteQueue should throw QueueHasSubscribersException if there are ' + 'any consumers consuming that queue.', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + final queueStream = MQClient.instance.fetchQueue(queueId); + final sub = queueStream.listen((_) {}); + + expect( + () => MQClient.instance.deleteQueue(queueId), + throwsA(isA()), + ); + + sub.cancel(); + MQClient.instance.deleteQueue(queueId); + }); + }); + + group('Exchange Operations', () { + setUpAll(() => MQClient); + setUp(() { + MQClient.initialize(); + }); + test('declareExchange should declare a new exchange of the specified type', + () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.direct, + ); + + MQClient.instance.bindQueue( + queueId: queueId, + exchangeName: exchangeName, + bindingKey: 'test-binding', + ); + + MQClient.instance.sendMessage( + message: Message(payload: 'test'), + exchangeName: exchangeName, + routingKey: 'test-binding', + ); + + expect( + MQClient.instance.getLatestMessage(queueId)?.payload, + equals('test'), + ); + + MQClient.instance.deleteExchange(exchangeName); + MQClient.instance.deleteQueue(queueId); + }); + + test( + 'sendMessage to unregister exchange should throw ' + 'ExchangeNotRegisteredException', () { + const exchangeName = 'exchange'; + expect( + () => MQClient.instance.sendMessage( + message: Message(payload: 'test'), + exchangeName: exchangeName, + routingKey: 'test-binding', + ), + throwsA(isA()), + ); + }); + + test( + 'declareExchange should throw InvalidExchangeTypeException if the ' + 'exchange type is invalid', () { + const exchangeName = 'exchange'; + expect( + () => MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.base, + ), + throwsA(isA()), + ); + MQClient.instance.deleteExchange(exchangeName); + }); + + test('deleteExchange should delete an exchange', () { + const exchangeName = 'exchange'; + expect( + () => MQClient.instance.bindQueue( + queueId: 'test-queue', + exchangeName: exchangeName, + ), + throwsA(isA()), + ); + }); + + test('deleteExchange should do nothing if the exchange does not exist', () { + expect( + () => MQClient.instance.deleteExchange('nonexistent_exchange'), + returnsNormally, + ); + }); + + test('bindQueue should bind a queue to direct exchange', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.direct, + ); + MQClient.instance.bindQueue( + queueId: queueId, + exchangeName: exchangeName, + bindingKey: 'key', + ); + + MQClient.instance.deleteQueue(queueId); + MQClient.instance.deleteExchange(exchangeName); + }); + + test('bindQueue should bind a queue to fanout exchange', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.fanout, + ); + MQClient.instance.bindQueue(queueId: queueId, exchangeName: exchangeName); + + MQClient.instance.deleteQueue(queueId); + MQClient.instance.deleteExchange(exchangeName); + }); + + test( + 'bindQueue should throw BindingKeyRequiredException if bindingKey is ' + 'not provided for DirectExchange', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.direct, + ); + expect( + () => MQClient.instance.bindQueue( + queueId: queueId, + exchangeName: exchangeName, + ), + throwsA(isA()), + ); + + MQClient.instance.deleteQueue(queueId); + MQClient.instance.deleteExchange(exchangeName); + }); + + test('unbindQueue should unbind a queue from an exchange', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.direct, + ); + expect( + () => MQClient.instance.bindQueue( + queueId: queueId, + exchangeName: exchangeName, + bindingKey: 'test-binding-key', + ), + returnsNormally, + ); + MQClient.instance.unbindQueue( + queueId: queueId, + exchangeName: exchangeName, + bindingKey: 'test-binding-key', + ); + MQClient.instance.deleteQueue(queueId); + MQClient.instance.deleteExchange(exchangeName); + }); + + test( + 'unbindQueue should throw BindingKeyRequiredException if ' + 'bindingKey is not provided for DirectExchange', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.direct, + ); + expect( + () => MQClient.instance.unbindQueue( + queueId: queueId, + exchangeName: exchangeName, + ), + throwsA(isA()), + ); + + MQClient.instance.deleteQueue(queueId); + MQClient.instance.deleteExchange(exchangeName); + }); + test( + 'unbindQueue should not throw BindingKeyRequiredException if ' + 'bindingKey is not provided for FanoutExchange', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + MQClient.instance.declareExchange( + exchangeName: exchangeName, + exchangeType: ExchangeType.fanout, + ); + expect( + () => MQClient.instance + .unbindQueue(queueId: queueId, exchangeName: exchangeName), + returnsNormally, + ); + + MQClient.instance.deleteQueue(queueId); + MQClient.instance.deleteExchange(exchangeName); + }); + + test( + 'unbindQueue should throw ExchangeNotRegisteredException ' + 'if exchange does not exist', () { + final queueId = MQClient.instance.declareQueue('test-queue'); + const exchangeName = 'exchange'; + expect( + () => MQClient.instance.unbindQueue( + queueId: queueId, + exchangeName: exchangeName, + ), + throwsA(isA()), + ); + + MQClient.instance.deleteQueue(queueId); + }); + }); + + group('Close Operations.', () { + setUpAll(() => MQClient); + setUp(() { + MQClient.initialize(); + }); + test('close should close the MQClient', () { + MQClient.instance.declareQueue('test-queue'); + MQClient.instance.close(); + expect( + () => MQClient.instance, + throwsA(isA()), + ); + }); + }); +} diff --git a/sandbox/mqueue/test/producer/producer_test.dart b/sandbox/mqueue/test/producer/producer_test.dart new file mode 100644 index 0000000..1b3494c --- /dev/null +++ b/sandbox/mqueue/test/producer/producer_test.dart @@ -0,0 +1,111 @@ +import 'dart:async'; +import 'package:angel3_mq/mq.dart'; +import 'package:test/test.dart'; + +class MyMessageProducer with ProducerMixin { + // Custom implementation of the message producer. +} + +void main() { + group('Producer', () { + final producer = MyMessageProducer(); + + setUpAll(() { + MQClient.initialize(); + + MQClient.instance.declareQueue('test-queue'); + }); + + test( + 'sendMessage should send a message to an exchange and call the ' + 'callback', () { + final message = Message( + payload: 'Test Message', + timestamp: '2023-09-07T12:00:002', + ); + var callbackCalled = false; + producer + ..setPushCallback((message) { + callbackCalled = true; + }) + ..sendMessage( + payload: 'Test Message', + exchangeName: '', + routingKey: 'test-queue', + timestamp: '2023-09-07T12:00:002', + ); + + expect( + MQClient.instance.getLatestMessage('test-queue')?.headers, + equals(message.headers), + ); + expect( + MQClient.instance.getLatestMessage('test-queue')?.payload, + equals(message.payload), + ); + expect( + MQClient.instance.getLatestMessage('test-queue')?.timestamp, + equals(message.timestamp), + ); + expect(callbackCalled, isTrue); + }); + + test( + 'sendRPCMessage should send an RPC message to an exchange and call the ' + 'callback', () async { + var callbackCalled = false; + + producer.setPushCallback((message) { + callbackCalled = true; + }); + + final sub = MQClient.instance.fetchQueue('test-queue').listen((message) { + if (message.headers['type'] == 'RPC') { + (message.headers['completer'] as Completer).complete('Response'); + return; + } + }); + + final res = await producer.sendRPCMessage( + processId: 'foo', + args: {'key': 'value'}, + exchangeName: '', + routingKey: 'test-queue', + ); + + expect(callbackCalled, isTrue); + + expect(res, equals('Response')); + + await sub.cancel(); + }); + + test('sendRPCMessage with non-null mapper', () async { + var callbackCalled = false; + producer.setPushCallback((message) { + callbackCalled = true; + }); + + final sub = + MQClient.instance.fetchQueue('test-queue').listen((message) async { + if (message.headers['type'] == 'RPC') { + (message.headers['completer'] as Completer).complete('Response'); + return; + } + }); + + final response = await producer.sendRPCMessage( + processId: 'foo', + args: {'key': 'value'}, + exchangeName: '', + routingKey: 'test-queue', + mapper: (data) => '$data-new', + ); + + expect(callbackCalled, isTrue); + expect(response, equals('Response-new')); + + await sub.cancel(); + }); + }); +} diff --git a/sandbox/mqueue/test/queue/queue_test.dart b/sandbox/mqueue/test/queue/queue_test.dart new file mode 100644 index 0000000..0b80082 --- /dev/null +++ b/sandbox/mqueue/test/queue/queue_test.dart @@ -0,0 +1,98 @@ +import 'package:angel3_mq/mq.dart'; +import 'package:angel3_mq/src/queue/queue.dart'; +import 'package:test/test.dart'; + +void main() { + group('Queue', () { + test('Creating a Queue', () { + // Arrange + const queueId = 'my_queue_id'; + + // Act + final myQueue = Queue(queueId); + + // Assert + expect(myQueue.id, equals(queueId)); + expect(myQueue.latestMessage, isNull); + }); + + test('Get dataStream from Queue', () { + // Arrange + const queueId = 'my_queue_id'; + final myQueue = Queue(queueId); + + // Act + final dataStream = myQueue.dataStream; + + // Assert + expect(dataStream, isNotNull); + }); + + test('Enqueue and Check Has Listeners', () { + // Arrange + const queueId = 'my_queue_id'; + final myQueue = Queue(queueId); + final message = Message( + headers: {'contentType': 'json', 'sender': 'Alice'}, + payload: {'text': 'Hello, World!'}, + timestamp: '2023-09-07T12:00:002', + ); + + // Act + myQueue.enqueue(message); + final hasListeners = myQueue.hasListeners(); + + // Assert + expect(myQueue.id, equals(queueId)); + expect(myQueue.latestMessage, equals(message)); + expect(hasListeners, isFalse); // No listeners by default + }); + + test('Queue equality', () { + // Arrange + final queue1 = Queue('queue_id_1'); + final queue2 = Queue('queue_id_2'); + final queue3 = Queue('queue_id_1'); // Same ID as queue1 + + // Act & Assert + expect(queue1, equals(queue3)); // Should be equal based on ID + expect( + queue1, + isNot(equals(queue2)), + ); // Should not be equal due to different IDs + }); + + test('Queue hashCode', () { + // Arrange + final queue1 = Queue('queue_id_1'); + final queue2 = Queue('queue_id_2'); + final queue3 = Queue('queue_id_1'); // Same ID as queue1 + + // Act & Assert + expect(queue1.hashCode, equals(queue3.hashCode)); + expect(queue1.hashCode, isNot(equals(queue2.hashCode))); + }); + + test('Queue dispose', () { + // Arrange + const queueId = 'my_queue_id'; + final myQueue = Queue(queueId); + final message = Message( + headers: {'contentType': 'json', 'sender': 'Alice'}, + payload: {'text': 'Hello, World!'}, + timestamp: '2023-09-07T12:00:002', + ); + + // Act + myQueue + ..enqueue(message) + ..dispose(); + final hasListeners = myQueue.hasListeners(); + + // Assert + expect(myQueue.id, equals(queueId)); + expect(myQueue.latestMessage, equals(message)); + expect(hasListeners, isFalse); + }); + }); +} diff --git a/sandbox/reactivex/.gitignore b/sandbox/reactivex/.gitignore new file mode 100644 index 0000000..454fea2 --- /dev/null +++ b/sandbox/reactivex/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +coverage/ \ No newline at end of file diff --git a/sandbox/reactivex/CHANGELOG.md b/sandbox/reactivex/CHANGELOG.md new file mode 100644 index 0000000..9c6e7a0 --- /dev/null +++ b/sandbox/reactivex/CHANGELOG.md @@ -0,0 +1,775 @@ +# Changelog + +## [0.28.0] (2024-06-14) + +### New + +* ValueStream: + * Add `lastEventOrNull` getter to `ValueStream`, + which returns the last emitted event (either data/value or error event), or `null`. + * Add `isLastEventValue`, `isLastEventError` and `errorAndStackTraceOrNull` + extension getters to `ValueStream`, to check the kind of the last emitted event is data/value or error. + * Update documentation. + +* ReplayStream: + * Add `errorAndStackTraces` to `ReplayStream`, which returns a list of emitted `ErrorAndStackTrace`s. + +* Rename `Notification` and `Kind` to better reflect their purpose, + and to avoid confusion with [Flutter's Notification class](https://api.flutter.dev/flutter/widgets/Notification-class.html). + * Rename `Notification` to `StreamNotification` + * `Notification.onData` to `StreamNotification.data`. + * `Notification.onDone` to `StreamNotification.done`. + * `Notification.onError` to `StreamNotification.error`. + * Rename `Kind` to `NotificationKind` + * `Kind.onData` to `NotificationKind.data`. + * `Kind.onError` to `NotificationKind.error`. + * `Kind.onDone` to `NotificationKind.done`. + * Introduce `DataNotification`, `ErrorNotification` and `DoneNotification` as the subclasses of `StreamNotification`. + * Convert `isOnData`, `isOnError`, `isOnDone`, `requireData` to extension getters on `StreamNotification`, + they are now named `isData`, `isError`, `isDone` and `requireDataValue`. + * Add extensions on `StreamNotification`: `dataValueOrNull`, `requireErrorAndStackTrace`, `errorAndStackTraceOrNull` getters and `when` method. + +### Changed + +* Accept Dart SDK versions above 3.0. +* `switchMap`: when cancelling the previous inner subscription, + `switchMap` will pause the outer subscription and and wait for the inner subscription to be completely canceled. + It will then resume the outer subscription, and listen to the next inner Stream. + Any errors from canceling the previous inner subscription will now be forwarded to the resulting Stream. + +* **Breaking**: Rename `ForkJoinStream.combine2`..`combine9` to `ForkJoinStream.join2`..`join9`. +* **Breaking**: `Rx.using`/`UsingStream` + * Convert all _required positional_ parameters to _required named_ parameters. + * The `disposer` is now called after the future returned from `StreamSubscription.cancel` completes. + +### Documentation + +* Update and fix documentation. +* Fix README example (thanks to [@wurikiji](https://github.com/wurikiji)). +* Update Flutter example (thanks to [@hoangchungk53qx1](https://github.com/hoangchungk53qx1)). +* Replace deprecated "dart pub run" with "dart run" (thanks to [@tatsuyafujisaki](https://github.com/tatsuyafujisaki)). + +## [0.28.0-dev.2] (2024-03-30) + +Feedback on this change appreciated as this is a dev release before 0.28.0 stable! + +### Changed + +* **Breaking**: Rename `ForkJoinStream.combine2`..`combine9` to `ForkJoinStream.join2`..`join9`. +* **Breaking**: `Rx.using`/`UsingStream` + * Convert all _required positional_ parameters to _required named_ parameters. + * The `disposer` is now called after the future returned from `StreamSubscription.cancel` completes. + +## [0.28.0-dev.1] (2024-01-27) + +Feedback on this change appreciated as this is a dev release before 0.28.0 stable! + +### Changed + +* `switchMap`: when cancelling the previous inner subscription, + `switchMap` will pause the outer subscription and and wait for the inner subscription to be completely canceled. + It will then resume the outer subscription, and listen to the next inner Stream. + Any errors from canceling the previous inner subscription will now be forwarded to the resulting Stream. + +### Documentation + +* Replace deprecated "dart pub run" with "dart run" (thanks to [@tatsuyafujisaki](https://github.com/tatsuyafujisaki)). + +## [0.28.0-dev.0] (2023-07-26) + +Feedback on this change appreciated as this is a dev release before 0.28.0 stable! + +### New + +* ValueStream: + * Add `lastEventOrNull` getter to `ValueStream`, + which returns the last emitted event (either data/value or error event), or `null`. + * Add `isLastEventValue`, `isLastEventError` and `errorAndStackTraceOrNull` + extension getters to `ValueStream`, to check the kind of the last emitted event is data/value or error. + * Update documentation. + +* ReplayStream: + * Add `errorAndStackTraces` to `ReplayStream`, which returns a list of emitted `ErrorAndStackTrace`s. + +* Rename `Notification` and `Kind` to better reflect their purpose, + and to avoid confusion with [Flutter's Notification class](https://api.flutter.dev/flutter/widgets/Notification-class.html). + * Rename `Notification` to `StreamNotification` + * `Notification.onData` to `StreamNotification.data`. + * `Notification.onDone` to `StreamNotification.done`. + * `Notification.onError` to `StreamNotification.error`. + * Rename `Kind` to `NotificationKind` + * `Kind.onData` to `NotificationKind.data`. + * `Kind.onError` to `NotificationKind.error`. + * `Kind.onDone` to `NotificationKind.done`. + * Introduce `DataNotification`, `ErrorNotification` and `DoneNotification` as the subclasses of `StreamNotification`. + * Convert `isOnData`, `isOnError`, `isOnDone`, `requireData` to extension getters on `StreamNotification`, + they are now named `isData`, `isError`, `isDone` and `requireDataValue`. + * Add extensions on `StreamNotification`: `dataValueOrNull`, `requireErrorAndStackTrace`, `errorAndStackTraceOrNull` getters and `when` method. + +### Changed + +* Accept Dart SDK versions above 3.0. + +### Documentation + +* Update and fix documentation. +* Fix README example (thanks to [@wurikiji](https://github.com/wurikiji)). +* Update Flutter example (thanks to [@hoangchungk53qx1](https://github.com/hoangchungk53qx1)). + +## 0.27.7 (2022-11-16) + +### Fixed + +* `Subject` + * Only call `onAdd` and `onError` if the subject is not closed. + This ensures `BehaviorSubject` and `ReplaySubject` do not update their values after they have been closed. + + * `Subject.stream` now returns a **read-only** `Stream`. + Previously, `Subject.stream` was identical to the `Subject`, so we could add events to it, for example: `(subject.stream as Sink).add(event)`. + This behavior is now disallowed, and will throw a `TypeError` if attempted. Use `Subject.sink`/`Subject` itself for adding events. + + * Change return type of `ReplaySubject.stream` to `ReplayStream`. + * Internal refactoring of `Subject.addStream`. + +## 0.27.6 (2022-11-11) + +* `Rx.using`/`UsingStream`: `resourceFactory` can now return a `Future`. + This allows for asynchronous resource creation. + +* `Rx.range`/`RangeStream`: ensure `RangeStream` is only listened to once. + +## 0.27.5 (2022-07-16) + +### Bug fixes + +* Fix issue [#683](https://github.com/ReactiveX/rxdart/issues/683): Throws runtime type error when using extension + methods on a `Stream` but its type annotation is `Stream`, `R` is a subtype of `T` + (covariance issue with `StreamTransformer`). + ```Dart + Stream s1 = Stream.fromIterable([1, 2, 3]); + // throws "type 'SwitchMapStreamTransformer' is not a subtype of type 'StreamTransformer' of 'streamTransformer'" + s1.switchMap((v) => Stream.value(v)); + + Stream s2 = Stream.fromIterable([1, 2, 3]); + // throws "type 'SwitchMapStreamTransformer' is not a subtype of type 'StreamTransformer' of 'streamTransformer'" + s2.switchMap((v) => Stream.value(v)); + ``` + Extension methods were previously implemented via `stream.transform(streamTransformer)`, now + via `streamTransformer.bind(stream)` to avoid this issue. + +* Fix `concatEager`: `activeSubscription` should be changed to next subscription. + +### Code refactoring + +* Change return type of `pairwise` to `Stream>`. + +## 0.27.4 (2022-05-29) + +### Bug fixes + +* `withLatestFrom` should iterate over `Iterable` only once when the stream is listened to. +* Fix analyzer warnings when using `Dart 2.16.0`. + +### Features + +* Add `mapNotNull`/`MapNotNullStreamTransformer`. +* Add `whereNotNull`/`WhereNotNullStreamTransformer`. + +### Documentation + +* Fix grammar errors in code examples (thanks to [@fzyzcjy](https://github.com/fzyzcjy)). +* Update RxMarbles URL for `RaceStream` (thanks to [@Péter Ferenc Gyarmati](https://github.com/peter-gy)). + +## 0.27.3 (2021-11-21) + +### Bug fixes + +* `flatMap` now creates inner `Stream`s lazily. +* `combineLatest`, `concat`, `concatEager`, `forkJoin`, `merge`, `race`, `zip` iterate over `Iterable`s only once + when the stream is listened to. +* Disallow mixing `autoConnect`, `connect` and `refCount` together, only one of them should be used. + +### Features + +* Introduce `AbstractConnectableStream`, base class for the `ConnectableStream` implementations. +* Improve `CompositeSubscription` (thanks to [@BreX900](https://github.com/BreX900)) + * CompositeSubscription's `dispose`, `clear`, and `remove` methods now return a completion future. + * Fixed an issue where a stream not present in CompositeSubscription was canceled. + * Added the ability not to cancel the stream when it is removed from CompositeSubscription. + * CompositeSubscription implements `StreamSubscription`. + * `CompositeSubscription.add` will throw a `StateError` instead of a `String` if this composite was disposed. + +### Documentation + +* Fix `Connectable` examples. +* Update Web example to null safety. +* Fix `Flutter` example: `SearchResultItem.fromJson` type error (thanks to [@WenYeh](https://github.com/wayne900204)) + +### Code refactoring + +* Simplify `takeLast` implementation. +* Migrate from `pedantic` to `lints` and `flutter_lints`. +* Refactor `BehaviorSubject`, `ReplaySubject` implementations by using "`Sentinel object`"s instead of `ValueWrapper`s. + +## 0.27.2 (2021-09-03) + +### Bug fixes + +* `onErrorReturnWith` now does not drop the remaining data events after the first error. +* Disallow changing handlers of `ConnectableStreamSubscription`. + +### Features + +* Add `delayWhen` operator. +* Add optional parameter `maxConcurrent` to `flatMap`. +* `groupBy` + * Rename `GroupByStream` to `GroupedStream`. + * Add optional parameter `durationSelector`, which used to determine how long each group should exist. +* `ignoreElements` + * Remove `@deprecated` annotation (`ignoreElements` should not be marked as deprecated). + * Change return type to `Stream`. + +### Documentation + +* Update to `PublishSubject`'s docs (thanks to [@AlexanderJohr](https://github.com/AlexanderJohr)). + +### Code refactoring + +* Refactoring Stream Transformers, using `Stream.multi` internally. + +## 0.27.1 + +* Bugfix: `ForkJoinStream` throws `Null check operator used on a null value` when using nullable-type. +* Bugfix: `delay` operator + * Pause and resume properly. + * Cancel all timers after it has been cancelled. + +## 0.27.0 + * **BREAKING: ValueStream** + * Remove `ValueStreamExtensions`. + * `ValueStream.valueWrapper` becomes + - `value`. + - `valueOrNull`. + - `hasValue`. + * `ValueStream.errorAndStackTrace` becomes + - `error`. + - `errorOrNull`. + - `hasError`. + - `stackTrace`. + * Add `skipLast`/`SkipLastStreamTransformer` (thanks [@HannibalKcc](https://github.com/HannibalKcc)). + * Update `scan`: change `seed` to required param. + * Add `StackTrace` param to `recoveryFn` when using `OnErrorResumeStreamTransformer`/`onErrorResume`/`onErrorReturnWith`. + * Internal refactoring `ConnectableStream`. + +## 0.26.0 + * Stable, null-safe release. + * Add `takeLast` (thanks [@ThomasKliszowski](https://github.com/ThomasKliszowski)). + * Rework for `retry`/`retryWhen`: + * Removed `RetryError`. + * `retry`: emits all errors if retry fails. + * `retryWhen`: emits original error, and error from factory if they are not identical. + * `streamFactory` now accepts non-nullable `StackTrace` argument. + * Update `ValueStream.requireValue` and `ValueStream.requireError`: throws actual error or a `StateError`, + instead of throwing `"Null check operator used on a null value"` error. + +## 0.26.0-nullsafety.1 + * Breaking change: `ValueStream` + - Add `valueWrapper` to `ValueStream`. + - Change `value`, `hasValue`, `error` and `hasError` to extension getters. + * Fixed some API example documentation (thanks [@HannibalKcc](https://github.com/HannibalKcc)). + * `throttle`/`throttleTime` have been optimised for performance. + * Updated Flutter example to work with the latest Flutter stable. + +## 0.26.0-nullsafety.0 + * Migrate this package to null safety. + * Sdk constraints: `>=2.12.0-0 <3.0.0` based on beta release guidelines. + +## 0.25.0 + * Sync behavior when using `publishValueSeeded`. + * `ValueStream`, `ReplayStream`: exposes `stackTrace` along with the `error`: + * Change `ValueStream.error` to `ValueStream.errorAndStackTrace`. + * Change `ReplayStream.errors` to `ReplayStream.errorAndStackTraces`. + * Merge `Notification.error` and `Notification.stackTrace` into `Notification.errorAndStackTrace`. + * Bugfix: `debounce`/`debounceTime` unnecessarily kept too many elements in queue. + +## 0.25.0-beta3 + * Bugfix: `switchMap` doesn't close after the last inner Stream closes. + * Docs: updated URL for "Single-Subscription vs. Broadcast Streams" doc (thanks [Aman Gupta](https://github.com/Aman9026)). + * Add `FromCallableStream`/`Rx.fromCallable`: allows you to create a `Stream` from a callable function. + * Override `BehaviorSubject`'s built-in operators to correct replaying the latest value of `BehaviorSubject`. + * Bugfix: Source `StreamSubscription` doesn't cancel when cancelling `refCount`, `zip`, `merge`, `concat` StreamSubscription. + * Forward done event of upstream to `ConnectableStream`. + +## 0.25.0-beta2 + * Internal refactoring Stream Transformers. + * Fixed `RetryStream` example documentation. + * Error thrown from `DeferStream` factory will now be caught and converted to `Stream.error`. + * `doOnError` now have strong type signature: `Stream doOnError(void Function(Object, StackTrace) onError)`. + * Updated `ForkJoinStream`: + * When any Stream emits an error, listening still continues unless `cancelOnError: true` on the downstream. + * Pause and resume Streams properly. + * Added `UsingStream`. + * Updated `TimerStream`: Pause and resume Timer when pausing and resuming StreamSubscription. + +## 0.25.0-beta + * stream transformations on a ValueStream will also return a ValueStream, instead of + a standard broadcast Stream + * throttle can now be both leading and trailing + * better handling of empty Lists when using operators that accept a List as input + * error & hasError added to BehaviorSubject + * various docs updates + * note that this is a beta release, mainly because the behavior of transform has been adjusted (see first bullet) + if all goes well, we'll release a proper 0.25.0 release soon + +## 0.24.1 + * Fix for BehaviorSubject, no longer emits null when using addStream and expecting an Error as first event (thanks [yuvalr1](https://github.com/yuvalr1)) + * min/max have been optimised for performance + * Further refactors on our Transformers + +## 0.24.0 + * Fix throttle no longer outputting the current buffer onDone + * Adds endWith and endWithMany + * Fix when using pipe and an Error, Subjects would throw an Exception that couldn't be caught using onError + * Updates links for docs (thanks [@renefloor](https://github.com/renefloor)) + * Fix links to correct marbles diagram for debounceTime (thanks [@wheater](https://github.com/Wheater)) + * Fix flakiness of withLatestFrom test Streams + * Update to docs ([@wheater](https://github.com/Wheater)) + * Fix withLatestFrom not pause/resume/cancelling underlying Streams + * Support sync behavior for Subjects + * Add addTo extension for StreamSubscription, use it to easily add a subscription to a CompositeSubscription + * Fix mergeWith and zipWith will return a broadcast Stream, if the source Stream is also broadcast + * Fix concatWith will return a broadcast Stream, if the source Stream is also broadcast (thanks [@jarekb123](https://github.com/jarekb123)) + * Adds pauseAll, resumeAll, ... to CompositeSubscription + * Additionally, fixes some issues introduced with 0.24.0-dev.1 + +## 0.24.0-dev.1 + * Breaking: as of this release, we've refactored the way Stream transformers are set up. + Previous releases had some incorrect behavior when using certain operators, for example: + - startWith (startWithMany, startWithError) + would incorrectly replay the starting event(s) when using a + broadcast Stream at subscription time. + - doOnX was not always producing the expected results: + * doOnData did not output correct sequences on streams that were transformed + multiple times in sequence. + * doOnCancel now acts in the same manner onCancel works on + regular subscriptions, i.e. it will now be called when all + active subscriptions on a Stream are cancelled. + * doOnListen will now call the first time the Stream is + subscribed to, and will only call again after all subscribers + have cancelled, before a new subscription starts. + + To properly fix this up, a new way of transforming Streams was introduced. + Operators as of now use Stream.eventTransformed and we've refactored all + operators to implement Sink instead. + * Adds takeWileInclusive operator (thanks to [@hoc081098](https://github.com/hoc081098)) + + We encourage everyone to give the dev release(s) a spin and report back if + anything breaks. If needed, a guide will be written to help migrate from + the old behavior to the new behavior in certain common use cases. + + Keep in mind that we tend to stick as close as we can to how normal + Dart Streams work! + +## 0.23.1 + + * Fix API doc links in README + +## 0.23.0 + + * Extension Methods replace `Observable` class! + * Please upgrade existing code by using the rxdart_codemod package + * Remove the Observable class. With extensions, you no longer need to wrap Streams in a [Stream]! + * Convert all factories to static constructors to aid in discoverability of Stream classes + * Move all factories to an `Rx` class. + * Remove `Observable.just`, use `Stream.value` + * Remove `Observable.error`, use `Stream.error` + * Remove all tests that check base Stream methods + * Subjects and *Observable classes extend Stream instead of base Observable + * Rename *Observable to *Stream to reflect the fact they're just Streams. + * `ValueObservable` -> `ValueStream` + * `ReplayObservable` -> `ReplayStream` + * `ConnectableObservable` -> `ConnectableStream` + * `ValueConnectableObservable` -> `ValueConnectableStream` + * `ReplayConnectableObservable` -> `ReplayConnectableStream` + * All transformation methods removed from Observable class + * Transformation methods are now Extensions of the Stream class + * Any Stream can make use of the transformation methods provided by RxDart + * Observable class remains in place with factory methods to create different types of Streams + * Removed deprecated `ofType` method, use `whereType` instead + * Deprecated `concatMap`, use standard Stream `asyncExpand`. + * Removed `AsObservableFuture`, `MinFuture`, `MaxFuture`, and `WrappedFuture` + * This removes `asObservable` method in chains + * Use default `asStream` method from the base `Future` class instead. + * `min` and `max` now implemented directly on the Stream class + +## 0.23.0-dev.3 + + * Fix missing exports: + - `ValueStream` + - `ReplayStream` + - `ConnectableStream` + - `ValueConnectableStream` + - `ReplayConnectableStream` + +## 0.23.0-dev.2 + * Remove the Observable class. With extensions, you no longer need to wrap Streams in a [Stream]! + * Convert all factories to static constructors to aid in discoverability of Stream classes + * Move all factories to an `Rx` class. + * Remove `Observable.just`, use `Stream.value` + * Remove `Observable.error`, use `Stream.error` + * Remove all tests that check base Stream methods + * Subjects and *Observable classes extend Stream instead of base Observable + * Rename *Observable to *Stream to reflect the fact they're just Streams. + * `ValueObservable` -> `ValueStream` + * `ReplayObservable` -> `ReplayStream` + * `ConnectableObservable` -> `ConnectableStream` + * `ValueConnectableObservable` -> `ValueConnectableStream` + * `ReplayConnectableObservable` -> `ReplayConnectableStream` + +## 0.23.0-dev.1 + * Feedback on this change appreciated as this is a dev release before 0.23.0 stable! + * All transformation methods removed from Observable class + * Transformation methods are now Extensions of the Stream class + * Any Stream can make use of the transformation methods provided by RxDart + * Observable class remains in place with factory methods to create different types of Streams + * Removed deprecated `ofType` method, use `whereType` instead + * Deprecated `concatMap`, use standard Stream `asyncExpand`. + * Removed `AsObservableFuture`, `MinFuture`, `MaxFuture`, and `WrappedFuture` + * This removes `asObservable` method in chains + * Use default `asStream` method from the base `Future` class instead. + * `min` and `max` now implemented directly on the Stream class + +## 0.22.6 + * Bugfix: When listening multiple times to a`BehaviorSubject` that starts with an Error, + it emits duplicate events. + * Linter: public_member_api_docs is now used, we have added extra documentation + where required. + +## 0.22.5 + * Bugfix: DeferStream created Stream too early + * Bugfix: TimerStream created Timer too early + +## 0.22.4 + * Bugfix: switchMap controller no longer closes prematurely + +## 0.22.3 + * Bugfix: whereType failing in Flutter production builds only + +## 0.22.2 + * Bugfix: When using a seeded `BehaviorSubject` and adding an `Error`, + upon listening, the `BehaviorSubject` emits `null` instead of the last `Error`. + * Bugfix: calling cancel after a `switchMap` can cause a `NoSuchMethodError`. + * Updated Flutter example to match the latest Flutter release + * `Observable.withLatestFrom` is now expanded to accept 2 or more `Stream`s + thanks to Petrus Nguyễn Thái Học (@hoc081098)! + * Deprecates `ofType` in favor of `whereType`, drop `TypeToken`. + +## 0.22.1 + Fixes following issues: + * Erroneous behavior with scan and `BehaviorSubject`. + * Bug where `flatMap` would cancel inner subscriptions in `pause`/`resume`. + * Updates to make the current "pedantic" analyzer happy. + +## 0.22.0 + This version includes refactoring for the backpressure operators: + * Breaking Change: `debounce` is now split into `debounce` and `debounceTime`. + * Breaking Change: `sample` is now split into `sample` and `sampleTime`. + * Breaking Change: `throttle` is now split into `throttle` and `throttleTime`. + +## 0.21.0 + * Breaking Change: `BehaviorSubject` now has a separate factory constructor `seeded()` + This allows you to seed this Subject with a `null` value. + * Breaking Change: `BehaviorSubject` will now emit an `Error`, if the last event was also an `Error`. + Before, when an `Error` occurred before a `listen`, the subscriber would not be notified of that `Error`. + To refactor, simply change all occurences of `BehaviorSubject(seedValue: value)` to `BehaviorSubject.seeded(value)` + * Added the `groupBy` operator + * Bugix: `doOnCancel`: will now await the cancel result, if it is a `Future`. + * Removed: `bufferWithCount`, `windowWithCount`, `tween` + Please use `bufferCount` and `windowCount`, `tween` is removed, because it never was an official Rx spec. + * Updated Flutter example to work with the latest Flutter stable. + +## 0.20.0 + * Breaking Change: bufferCount had buggy behavior when using `startBufferEvery` (was `skip` previously) + If you were relying on bufferCount with `skip` greater than 1 before, then you may have noticed + erroneous behavior. + * Breaking Change: `repeat` is no longer an operator which simply repeats the last emitted event n-times, + instead this is now an Observable factory method which takes a StreamFactory and a count parameter. + This will cause each repeat cycle to create a fresh Observable sequence. + * `mapTo` is a new operator, which works just like `map`, but instead of taking a mapper Function, it takes + a single value where each event is mapped to. + * Bugfix: switchIfEmpty now correctly calls onDone + * combineLatest and zip can now take any amount of Streams: + * combineLatest2-9 & zip2-9 functionality unchanged, but now use a new path for construction. + * adds combineLatest and zipLatest which allows you to pass through an Iterable> and a combiner that takes a List when any source emits a change. + * adds combineLatestList / zipList which allows you to take in an Iterable> and emit a Observable> with the values. Just a convenience factory if all you want is the list! + * Constructors are provided by the Stream implementation directly + * Bugfix: Subjects that are transformed will now correctly return a new Observable where isBroadcast is true (was false before) + * Remove deprecated operators which were replaced long ago: `bufferWithCount`, `windowWithCount`, `amb`, `flatMapLatest` + +## 0.19.0 + + * Breaking Change: Subjects `onCancel` function now returns `void` instead of `Future` to properly comply with the `StreamController` signature. + * Bugfix: FlatMap operator properly calls onDone for all cases + * Connectable Observable: An observable that can be listened to multiple times, and does not begin emitting values until the `connect` method is called + * ValueObservable: A new interface that allows you to get the latest value emitted by an Observable. + * Implemented by BehaviorSubject + * Convert normal observables into ValueObservables via `publishValue` or `shareValue` + * ReplayObservable: A new interface that allows you to get the values emitted by an Observable. + * Implemented by ReplaySubject + * Convert normal observables into ReplayObservables via `publishReplay` or `shareReplay` + +## 0.18.1 + +* Add `retryWhen` operator. Thanks to Razvan Lung (@long1eu)! This can be used for custom retry logic. + +## 0.18.0 + +* Breaking Change: remove `retype` method, deprecated as part of Dart 2. +* Add `flatMapIterable` + +## 0.17.0 + +* Breaking Change: `stream` property on Observable is now private. + * Avoids API confusion + * Simplifies Subject implementation + * Require folks who are overriding the `stream` property to use a `super` constructor instead +* Adds proper onPause and onResume handling for `amb`/`race`, `combineLatest`, `concat`, `concat_eager`, `merge` and `zip` +* Add `switchLatest` operator +* Add errors and stacktraces to RetryError class +* Add `onErrorResume` and `onErrorRetryWith` operators. These allow folks to return a specific stream or value depending on the error that occurred. + +## 0.16.7 + +* Fix new buffer and window implementation for Flutter + Dart 2 +* Subject now implements the Observable interface + +## 0.16.6 + +* Rework for `buffer` and `window`, allow to schedule using a sampler +* added `buffer` +* added `bufferFuture` +* added `bufferTest` +* added `bufferTime` +* added `bufferWhen` +* added `window` +* added `windowFuture` +* added `windowTest` +* added `windowTime` +* added `windowWhen` +* added `onCount` sampler for `buffer` and `window` +* added `onFuture` sampler for `buffer` and `window` +* added `onTest` sampler for `buffer` and `window` +* added `onTime` sampler for `buffer` and `window` +* added `onStream` sampler for `buffer` and `window` + +## 0.16.5 + +* Renames `amb` to `race` +* Renames `flatMapLatest` to `switchMap` +* Renames `bufferWithCount` to `bufferCount` +* Renames `windowWithCount` to `windowCount` + +## 0.16.4 + +* Adds `bufferTime` transformer. +* Adds `windowTime` transformer. + +## 0.16.3 + +* Adds `delay` transformer. + +## 0.16.2 + +* Fix added events to `sink` are not processed correctly by `Subjects`. + +## 0.16.1 + +* Fix `dematerialize` method for Dart 2. + +## 0.16.0+2 + +* Add `value` to `BehaviorSubject`. Allows you to get the latest value emitted by the subject if it exists. +* Add `values` to `ReplayrSubject`. Allows you to get the values stored by the subject if any exists. + +## 0.16.0+1 + +* Update Changelog + +## 0.16.0 + +* **breaks backwards compatibility**, this release only works with Dart SDK >=2.0.0. +* Removed old `cast` in favour of the now native Stream cast method. +* Override `retype` to return an `Observable`. + +## 0.15.1 + +* Add `exhaustMap` map to inner observable, ignore other values until that observable completes. +* Improved code to be dartdevc compatible. +* Add upper SDK version limit in pubspec + +## 0.15.0 + +* Change `debounce` to emit the last item of the source stream as soon as the source stream completes. +* Ensure `debounce` does not keep open any addition async timers after it has been cancelled. + +## 0.14.0+1 + +* Change `DoStreamTransformer` to return a `Future` on cancel for api compatibility. + +## 0.14.0 + +* Add `PublishSubject` (thanks to @pauldemarco) +* Fix bug with `doOnX` operators where callbacks were fired too often + +## 0.13.1 + +* Fix error with FlatMapLatest where it was not properly cancelled in some scenarios +* Remove additional async methods on Stream handlers unless they're shown to solve a problem + +## 0.13.0 + +* Remove `call` operator / `StreamTransformer` entirely +* Important bug fix: Errors thrown within any Stream or Operator will now be properly sent to the `StreamSubscription`. +* Improve overall handling of errors throughout the library to ensure they're handled correctly + +## 0.12.0 + +* Added doOn* operators in place of `call`. +* Added `DoStreamTransformer` as a replacement for `CallStreamTransformer` +* Deprecated `call` and `CallStreamTransformer`. Please use the appropriate `doOnX` operator / transformer. +* Added `distinctUnique`. Emits items if they've never been emitted before. Same as to Rx#distinct. + +## 0.11.0 + +* !!!Breaking Api Change!!! + * Observable.groupBy has been removed in order to be compatible with the next version of the `Stream` class in Dart 1.24.0, which includes this method + +## 0.10.2 + +* BugFix: The new Subject implementation no longer causes infinite loops when used with ng2 async pipes. + +## 0.10.1 + +* Documentation fixes + +## 0.10.0 + +* Api Changes + * Observable + * Remove all deprecated methods, including: + * `observable` factory -- replaced by the constructor `new Observable()` + * `combineLatest` -- replaced by Strong-Mode versions `combineLatest2` - `combineLatest9` + * `zip` -- replaced by Strong-Mode versions `zip2` - `zip9` + * Support `asObservable` conversion from Future-returning methods. e.g. `new Observable.fromIterable([1, 2]).first.asObservable()` + * Max and Min now return a Future of the Max or Min value, rather than a stream of increasing or decreasing values. + * Add `cast` operator + * Remove `ConcatMapStreamTransformer` -- functionality is already supported by `asyncExpand`. Keep the `concatMap` method as an alias. + * Subjects + * BehaviourSubject has been renamed to BehaviorSubject + * The subjects have been rewritten and include far more testing + * In keeping with the Rx idea of Subjects, they are broadcast-only +* Documentation -- extensive documentation has been added to the library with explanations and examples for each Future, Stream & Transformer. + * Docs detailing the differences between RxDart and raw Observables. + +## 0.9.0 + +* Api Changes: + * Convert all StreamTransformer factories to proper classes + * Ensure these classes can be re-used multiple times + * Retry has moved from an operator to a constructor. This is to ensure the stream can be properly re-constructed every time in the correct way. + * Streams now properly enforce the single-subscription contract +* Include example Flutter app. To run it, please follow the instructions in the README. + +## 0.8.3+1 +* rename examples map to example + +## 0.8.3 +* added concatWith, zipWith, mergeWith, skipUntil +* cleanup of the examples folder +* cleanup of examples code +* added fibonacci example +* added search GitHub example + +## 0.8.2+1 +* moved repo into ReactiveX +* update readme badges accordingly + +## 0.8.2 +* added materialize/dematerialize +* added range (factory) +* added timer (factory) +* added timestamp +* added concatMap + +## 0.8.1 +* added never constructor +* added error constructor +* moved code coverage to [codecov.io](https://codecov.io/gh/frankpepermans/rxdart) + +## 0.8.0 +* BREAKING: tap is replaced by call(onData) +* added call, which can take any combination of the following event methods: +onCancel, onData, onDone, onError, onListen, onPause, onResume + +## 0.7.1+1 +* improved the README file + +## 0.7.1 +* added ignoreElements +* added onErrorResumeNext +* added onErrorReturn +* added switchIfEmpty +* added empty factory constructor + +## 0.7.0 +* BREAKING: rename combineXXXLatest and zipXXX to a numbered equivalent, +for example: combineThreeLatest becomes combineLatest3 +* internal refactoring, expose streams/stream transformers as a separate library + +## 0.6.3+4 +* changed ofType to use TypeToken + +## 0.6.3+3 +* added ofType + +## 0.6.3+2 +* added defaultIfEmpty + +## 0.6.3+1 +* changed concat, old concat is now concatEager, new concat behaves as expected + +## 0.6.3 +* Added withLatestFrom +* Added defer ctr +(both thanks to [brianegan](https://github.com/brianegan "GitHub link")) + +## 0.6.2 +* Added just (thanks to [brianegan](https://github.com/brianegan "GitHub link")) +* Added groupBy +* Added amb + +## 0.6.1 +* Added concat + +## 0.6.0 +* BREAKING: startWith now takes just one parameter instead of an Iterable. To add multiple starting events, please use startWithMany. +* Added BehaviourSubject and ReplaySubject. These implement StreamController. +* BehaviourSubject will notify the last added event upon listening. +* ReplaySubject will notify all past events upon listening. +* DEPRECATED: zip and combineLatest, use their strong-type-friendly alternatives instead (available as static methods on the Observable class, i.e. Observable.combineThreeLatest, Observable.zipFour, ...) + +## 0.5.1 + +* Added documentation (thanks to [dustinlessard-wf](https://github.com/dustinlessard-wf "GitHub link")) +* Fix tests breaking due to deprecation of expectAsync +* Fix tests to satisfy strong mode requirements + +## 0.5.0 + +* As of this version, rxdart depends on SDK v1.21.0, to support the newly added generic method type syntax + +[Unreleased]: https://github.com/ReactiveX/rxdart/compare/0.28.0...HEAD +[0.28.0]: https://github.com/ReactiveX/rxdart/releases/tag/0.28.0 +[0.28.0-dev.2]: https://github.com/ReactiveX/rxdart/releases/tag/0.28.0-dev.2 +[0.28.0-dev.1]: https://github.com/ReactiveX/rxdart/releases/tag/0.28.0-dev.1 +[0.28.0-dev.0]: https://github.com/ReactiveX/rxdart/releases/tag/0.28.0-dev.0 \ No newline at end of file diff --git a/sandbox/reactivex/LICENSE b/sandbox/reactivex/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/sandbox/reactivex/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sandbox/reactivex/README.md b/sandbox/reactivex/README.md new file mode 100644 index 0000000..4f6f0da --- /dev/null +++ b/sandbox/reactivex/README.md @@ -0,0 +1,277 @@ +# RxDart + +

+build +

+ +

+RxDart +

+ +[![Build Status](https://github.com/ReactiveX/rxdart/workflows/Dart%20CI/badge.svg)](https://github.com/ReactiveX/rxdart/actions) +[![codecov](https://codecov.io/gh/ReactiveX/rxdart/branch/master/graph/badge.svg)](https://codecov.io/gh/ReactiveX/rxdart) +[![Pub](https://img.shields.io/pub/v/rxdart.svg)](https://pub.dartlang.org/packages/rxdart) +[![Pub Version (including pre-releases)](https://img.shields.io/pub/v/rxdart?include_prereleases&color=%23A0147B)](https://pub.dartlang.org/packages/rxdart) +[![Gitter](https://img.shields.io/gitter/room/ReactiveX/rxdart.svg)](https://gitter.im/ReactiveX/rxdart) +[![Flutter website](https://img.shields.io/badge/flutter-website-deepskyblue.svg)](https://docs.flutter.dev/data-and-backend/state-mgmt/options#bloc--rx) +[![Build Flutter example](https://github.com/ReactiveX/rxdart/actions/workflows/flutter-example.yml/badge.svg)](https://github.com/ReactiveX/rxdart/actions/workflows/flutter-example.yml) +[![License](https://img.shields.io/github/license/ReactiveX/rxdart)](https://www.apache.org/licenses/LICENSE-2.0) +[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2FReactiveX%2Frxdart&count_bg=%23D71092&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://hits.seeyoufarm.com) + +## About + +RxDart extends the capabilities of Dart +[Streams](https://api.dart.dev/stable/dart-async/Stream-class.html) and +[StreamControllers](https://api.dart.dev/stable/dart-async/StreamController-class.html). + +Dart comes with a very decent +[Streams](https://api.dart.dev/stable/dart-async/Stream-class.html) API +out-of-the-box; rather than attempting to provide an alternative to this API, +RxDart adds functionality from the reactive extensions specification on top of +it. + +RxDart does not provide its Observable class as a replacement for Dart +Streams. Instead, it offers several additional Stream classes, operators +(extension methods on the Stream class), and Subjects. + +If you are familiar with Observables from other languages, please see [the Rx +Observables vs. Dart Streams comparison chart](#rx-observables-vs-dart-streams) +for notable distinctions between the two. + +## Upgrading from RxDart 0.22.x to 0.23.x + +RxDart 0.23.x moves away from the Observable class, utilizing Dart 2.6's new +extension methods instead. This requires several small refactors that can be +easily automated -- which is just what we've done! + +Please follow the instructions on the +[rxdart_codemod](https://pub.dev/packages/rxdart_codemod) package to +automatically upgrade your code to support RxDart 0.23.x. + +## How To Use RxDart + +### For Example: Reading the Konami Code + +```dart +import 'package:rxdart/rxdart.dart'; + +void main() { + const konamiKeyCodes = [ + KeyCode.UP, + KeyCode.UP, + KeyCode.DOWN, + KeyCode.DOWN, + KeyCode.LEFT, + KeyCode.RIGHT, + KeyCode.LEFT, + KeyCode.RIGHT, + KeyCode.B, + KeyCode.A, + ]; + + final result = querySelector('#result')!; + + document.onKeyUp + .map((event) => event.keyCode) + .bufferCount(10, 1) // An extension method provided by rxdart + .where((lastTenKeyCodes) => const IterableEquality().equals(lastTenKeyCodes, konamiKeyCodes)) + .listen((_) => result.innerHtml = 'KONAMI!'); +} +``` + +## API Overview + +RxDart adds functionality to Dart Streams in three ways: + + * [Stream Classes](#stream-classes) - create Streams with specific capabilities, such as combining or merging many Streams. + * [Extension Methods](#extension-methods) - transform a source Stream into a new Stream with different capabilities, such as throttling or buffering events. + * [Subjects](#subjects) - StreamControllers with additional powers + +### Stream Classes + +The Stream class provides different ways to create a Stream: `Stream.fromIterable` or `Stream.periodic`. RxDart provides additional Stream classes for a variety of tasks, such as combining or merging Streams! + +You can construct the Streams provided by RxDart in two ways. The following examples are equivalent in terms of functionality: + + - Instantiating the Stream class directly. + - Example: `final mergedStream = MergeStream([myFirstStream, mySecondStream]);` + - Using static factories from the Rx class, which are useful for discovering which types of Streams are provided by RxDart. Under the hood, these factories call the corresponding Stream constructor. + - Example: `final mergedStream = Rx.merge([myFirstStream, mySecondStream]);` + +#### List of Classes / Static Factories + +- [CombineLatestStream](https://pub.dev/documentation/rxdart/latest/rx/CombineLatestStream-class.html) (combine2, combine3... combine9) / [Rx.combineLatest2](https://pub.dev/documentation/rxdart/latest/rx/Rx/combineLatest2.html)...[Rx.combineLatest9](https://pub.dev/documentation/rxdart/latest/rx/Rx/combineLatest9.html) +- [ConcatStream](https://pub.dev/documentation/rxdart/latest/rx/ConcatStream-class.html) / [Rx.concat](https://pub.dev/documentation/rxdart/latest/rx/Rx/concat.html) +- [ConcatEagerStream](https://pub.dev/documentation/rxdart/latest/rx/ConcatEagerStream-class.html) / [Rx.concatEager](https://pub.dev/documentation/rxdart/latest/rx/Rx/concatEager.html) +- [DeferStream](https://pub.dev/documentation/rxdart/latest/rx/DeferStream-class.html) / [Rx.defer](https://pub.dev/documentation/rxdart/latest/rx/Rx/defer.html) +- [ForkJoinStream](https://pub.dev/documentation/rxdart/latest/rx/ForkJoinStream-class.html) (join2, join3... join9) / [Rx.forkJoin2](https://pub.dev/documentation/rxdart/latest/rx/Rx/forkJoin2.html)...[Rx.forkJoin9](https://pub.dev/documentation/rxdart/latest/rx/Rx/forkJoin9.html) +- [FromCallableStream](https://pub.dev/documentation/rxdart/latest/rx/FromCallableStream-class.html) / [Rx.fromCallable](https://pub.dev/documentation/rxdart/latest/rx/Rx/fromCallable.html) +- [MergeStream](https://pub.dev/documentation/rxdart/latest/rx/MergeStream-class.html) / [Rx.merge](https://pub.dev/documentation/rxdart/latest/rx/Rx/merge.html) +- [NeverStream](https://pub.dev/documentation/rxdart/latest/rx/NeverStream-class.html) / [Rx.never](https://pub.dev/documentation/rxdart/latest/rx/Rx/never.html) +- [RaceStream](https://pub.dev/documentation/rxdart/latest/rx/RaceStream-class.html) / [Rx.race](https://pub.dev/documentation/rxdart/latest/rx/Rx/race.html) +- [RangeStream](https://pub.dev/documentation/rxdart/latest/rx/RangeStream-class.html) / [Rx.range](https://pub.dev/documentation/rxdart/latest/rx/Rx/range.html) +- [RepeatStream](https://pub.dev/documentation/rxdart/latest/rx/RepeatStream-class.html) / [Rx.repeat](https://pub.dev/documentation/rxdart/latest/rx/Rx/repeat.html) +- [RetryStream](https://pub.dev/documentation/rxdart/latest/rx/RetryStream-class.html) / [Rx.retry](https://pub.dev/documentation/rxdart/latest/rx/Rx/retry.html) +- [RetryWhenStream](https://pub.dev/documentation/rxdart/latest/rx/RetryWhenStream-class.html) / [Rx.retryWhen](https://pub.dev/documentation/rxdart/latest/rx/Rx/retryWhen.html) +- [SequenceEqualStream](https://pub.dev/documentation/rxdart/latest/rx/SequenceEqualStream-class.html) / [Rx.sequenceEqual](https://pub.dev/documentation/rxdart/latest/rx/Rx/sequenceEqual.html) +- [SwitchLatestStream](https://pub.dev/documentation/rxdart/latest/rx/SwitchLatestStream-class.html) / [Rx.switchLatest](https://pub.dev/documentation/rxdart/latest/rx/Rx/switchLatest.html) +- [TimerStream](https://pub.dev/documentation/rxdart/latest/rx/TimerStream-class.html) / [Rx.timer](https://pub.dev/documentation/rxdart/latest/rx/Rx/timer.html) +- [UsingStream](https://pub.dev/documentation/rxdart/latest/rx/UsingStream-class.html) / [Rx.using](https://pub.dev/documentation/rxdart/latest/rx/Rx/using.html) +- [ZipStream](https://pub.dev/documentation/rxdart/latest/rx/ZipStream-class.html) (zip2, zip3, zip4, ..., zip9) / [Rx.zip](https://pub.dev/documentation/rxdart/latest/rx/Rx/zip2.html)...[Rx.zip9](https://pub.dev/documentation/rxdart/latest/rx/Rx/zip9.html) +- If you're looking for an [Interval](https://reactivex.io/documentation/operators/interval.html) equivalent, check out Dart's [Stream.periodic](https://api.dart.dev/stable/2.7.2/dart-async/Stream/Stream.periodic.html) for similar behavior. + +### Extension Methods + +The extension methods provided by RxDart can be used on any `Stream`. They convert a source Stream into a new Stream with additional capabilities, such as buffering or throttling events. + +#### Example + +```dart +Stream.fromIterable([1, 2, 3]) + .throttleTime(Duration(seconds: 1)) + .listen(print); // prints 1 +``` + +#### List of Extension Methods + +- [buffer](https://pub.dev/documentation/rxdart/latest/rx/BufferExtensions/buffer.html) +- [bufferCount](https://pub.dev/documentation/rxdart/latest/rx/BufferExtensions/bufferCount.html) +- [bufferTest](https://pub.dev/documentation/rxdart/latest/rx/BufferExtensions/bufferTest.html) +- [bufferTime](https://pub.dev/documentation/rxdart/latest/rx/BufferExtensions/bufferTime.html) +- [concatWith](https://pub.dev/documentation/rxdart/latest/rx/ConcatExtensions/concatWith.html) +- [debounce](https://pub.dev/documentation/rxdart/latest/rx/DebounceExtensions/debounce.html) +- [debounceTime](https://pub.dev/documentation/rxdart/latest/rx/DebounceExtensions/debounceTime.html) +- [defaultIfEmpty](https://pub.dev/documentation/rxdart/latest/rx/DefaultIfEmptyExtension/defaultIfEmpty.html) +- [delay](https://pub.dev/documentation/rxdart/latest/rx/DelayExtension/delay.html) +- [delayWhen](https://pub.dev/documentation/rxdart/latest/rx/DelayWhenExtension/delayWhen.html) +- [dematerialize](https://pub.dev/documentation/rxdart/latest/rx/DematerializeExtension/dematerialize.html) +- [distinctUnique](https://pub.dev/documentation/rxdart/latest/rx/DistinctUniqueExtension/distinctUnique.html) +- [doOnCancel](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnCancel.html) +- [doOnData](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnData.html) +- [doOnDone](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnDone.html) +- [doOnEach](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnEach.html) +- [doOnError](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnError.html) +- [doOnListen](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnListen.html) +- [doOnPause](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnPause.html) +- [doOnResume](https://pub.dev/documentation/rxdart/latest/rx/DoExtensions/doOnResume.html) +- [endWith](https://pub.dev/documentation/rxdart/latest/rx/EndWithExtension/endWith.html) +- [endWithMany](https://pub.dev/documentation/rxdart/latest/rx/EndWithManyExtension/endWithMany.html) +- [exhaustMap](https://pub.dev/documentation/rxdart/latest/rx/ExhaustMapExtension/exhaustMap.html) +- [flatMap](https://pub.dev/documentation/rxdart/latest/rx/FlatMapExtension/flatMap.html) +- [flatMapIterable](https://pub.dev/documentation/rxdart/latest/rx/FlatMapExtension/flatMapIterable.html) +- [groupBy](https://pub.dev/documentation/rxdart/latest/rx/GroupByExtension/groupBy.html) +- [interval](https://pub.dev/documentation/rxdart/latest/rx/IntervalExtension/interval.html) +- [mapNotNull](https://pub.dev/documentation/rxdart/latest/rx/MapNotNullExtension/mapNotNull.html) +- [mapTo](https://pub.dev/documentation/rxdart/latest/rx/MapToExtension/mapTo.html) +- [materialize](https://pub.dev/documentation/rxdart/latest/rx/MaterializeExtension/materialize.html) +- [max](https://pub.dev/documentation/rxdart/latest/rx/MaxExtension/max.html) +- [mergeWith](https://pub.dev/documentation/rxdart/latest/rx/MergeExtension/mergeWith.html) +- [min](https://pub.dev/documentation/rxdart/latest/rx/MinExtension/min.html) +- [onErrorResume](https://pub.dev/documentation/rxdart/latest/rx/OnErrorExtensions/onErrorResume.html) +- [onErrorResumeNext](https://pub.dev/documentation/rxdart/latest/rx/OnErrorExtensions/onErrorResumeNext.html) +- [onErrorReturn](https://pub.dev/documentation/rxdart/latest/rx/OnErrorExtensions/onErrorReturn.html) +- [onErrorReturnWith](https://pub.dev/documentation/rxdart/latest/rx/OnErrorExtensions/onErrorReturnWith.html) +- [pairwise](https://pub.dev/documentation/rxdart/latest/rx/PairwiseExtension/pairwise.html) +- [sample](https://pub.dev/documentation/rxdart/latest/rx/SampleExtensions/sample.html) +- [sampleTime](https://pub.dev/documentation/rxdart/latest/rx/SampleExtensions/sampleTime.html) +- [scan](https://pub.dev/documentation/rxdart/latest/rx/ScanExtension/scan.html) +- [skipLast](https://pub.dev/documentation/rxdart/latest/rx/SkipLastExtension/skipLast.html) +- [skipUntil](https://pub.dev/documentation/rxdart/latest/rx/SkipUntilExtension/skipUntil.html) +- [startWith](https://pub.dev/documentation/rxdart/latest/rx/StartWithExtension/startWith.html) +- [startWithMany](https://pub.dev/documentation/rxdart/latest/rx/StartWithManyExtension/startWithMany.html) +- [switchIfEmpty](https://pub.dev/documentation/rxdart/latest/rx/SwitchIfEmptyExtension/switchIfEmpty.html) +- [switchMap](https://pub.dev/documentation/rxdart/latest/rx/SwitchMapExtension/switchMap.html) +- [takeLast](https://pub.dev/documentation/rxdart/latest/rx/TakeLastExtension/takeLast.html) +- [takeUntil](https://pub.dev/documentation/rxdart/latest/rx/TakeUntilExtension/takeUntil.html) +- [takeWhileInclusive](https://pub.dev/documentation/rxdart/latest/rx/TakeWhileInclusiveExtension/takeWhileInclusive.html) +- [throttle](https://pub.dev/documentation/rxdart/latest/rx/ThrottleExtensions/throttle.html) +- [throttleTime](https://pub.dev/documentation/rxdart/latest/rx/ThrottleExtensions/throttleTime.html) +- [timeInterval](https://pub.dev/documentation/rxdart/latest/rx/TimeIntervalExtension/timeInterval.html) +- [timestamp](https://pub.dev/documentation/rxdart/latest/rx/TimeStampExtension/timestamp.html) +- [whereNotNull](https://pub.dev/documentation/rxdart/latest/rx/WhereNotNullExtension/whereNotNull.html) +- [whereType](https://pub.dev/documentation/rxdart/latest/rx/WhereTypeExtension/whereType.html) +- [window](https://pub.dev/documentation/rxdart/latest/rx/WindowExtensions/window.html) +- [windowCount](https://pub.dev/documentation/rxdart/latest/rx/WindowExtensions/windowCount.html) +- [windowTest](https://pub.dev/documentation/rxdart/latest/rx/WindowExtensions/windowTest.html) +- [windowTime](https://pub.dev/documentation/rxdart/latest/rx/WindowExtensions/windowTime.html) +- [withLatestFrom](https://pub.dev/documentation/rxdart/latest/rx/WithLatestFromExtensions.html) +- [zipWith](https://pub.dev/documentation/rxdart/latest/rx/ZipWithExtension/zipWith.html) + +### Subjects + +Dart provides the [StreamController](https://api.dart.dev/stable/dart-async/StreamController-class.html) class to create and manage a Stream. RxDart offers two additional StreamControllers with additional capabilities, known as Subjects: + +- [BehaviorSubject](https://pub.dev/documentation/rxdart/latest/rx/BehaviorSubject-class.html) - A broadcast StreamController that caches the latest added value or error. When a new listener subscribes to the Stream, the latest value or error will be emitted to the listener. Furthermore, you can synchronously read the last emitted value. +- [ReplaySubject](https://pub.dev/documentation/rxdart/latest/rx/ReplaySubject-class.html) - A broadcast StreamController that caches the added values. When a new listener subscribes to the Stream, the cached values will be emitted to the listener. + +## Rx Observables vs Dart Streams + +In many situations, Streams and Observables work the same way. However, if you're used to standard Rx Observables, some features of the Stream API may surprise you. We've included a table below to help folks understand the differences. + +Additional information about the following situations can be found by reading the [Rx class documentation](https://pub.dev/documentation/rxdart/latest/rx/Rx-class.html). + +| Situation | Rx Observables | Dart Streams | +| ------------- |------------- | ------------- | +| An error is raised | Observable Terminates with Error | Error is emitted and Stream continues | +| Cold Observables | Multiple subscribers can listen to the same cold Observable, and each subscription will receive a unique Stream of data | Single subscriber only | +| Hot Observables | Yes | Yes, known as Broadcast Streams | +| Is {Publish, Behavior, Replay}Subject hot? | Yes | Yes | +| Single/Maybe/Completable ? | Yes | Yes, uses [rxdart_ext Single](https://pub.dev/documentation/rxdart_ext/latest/rxdart_ext/Single-class.html) (`Completable == Single` and `Maybe == Single`) | +| Support back pressure| Yes | Yes | +| Can emit null? | Yes, except RxJava | Yes | +| Sync by default | Yes | No | +| Can pause/resume a subscription*? | No | Yes | + +## Examples + +Web and command-line examples can be found in the `example` folder. + +### Web Examples + +In order to run the web examples, please follow these steps: + + 1. Clone this repo and enter the directory `examples/web` + 2. Run `dart pub get` + 3. Run `dart pub global activate webdev` + 4. Run `webdev serve` + 5. Navigate to http://localhost:8080/ in your browser + +### Command Line Examples + +In order to run the command line example, please follow these steps: + + 1. Clone this repo and enter the directory + 2. Run `pub get` + 3. Run `dart examples/fibonacci/lib/example.dart 10` + +### Flutter Example + +#### Install Flutter + +To run the flutter example, you must have Flutter installed. For installation instructions, view the online +[documentation](https://flutter.io/). + +#### Run the app + + 1. Open up an Android Emulator, the iOS Simulator, or connect an appropriate mobile device for debugging. + 2. Open up a terminal + 3. `cd` into the `examples/flutter/github_search` directory + 4. Run `flutter doctor` to ensure you have all Flutter dependencies working. + 5. Run `flutter packages get` + 6. Run `flutter run` + +## Notable References + +- [Documentation on the Dart Stream class](https://api.dart.dev/stable/dart-async/Stream-class.html) +- [Tutorial on working with Streams in Dart](https://www.dartlang.org/tutorials/language/streams) +- [ReactiveX (Rx)](https://reactivex.io/) + +## Changelog + +Refer to the [Changelog](https://github.com/ReactiveX/rxdart/blob/master/packages/rxdart/CHANGELOG.md) to get all release notes. + +## Extensions + +Check out [rxdart_ext](https://pub.dev/packages/rxdart_ext), which provides many extension methods and classes built on top of RxDart. + + diff --git a/sandbox/reactivex/analysis_options.yaml b/sandbox/reactivex/analysis_options.yaml new file mode 100644 index 0000000..6f808f6 --- /dev/null +++ b/sandbox/reactivex/analysis_options.yaml @@ -0,0 +1,15 @@ +include: package:lints/recommended.yaml + +analyzer: + language: + strict-casts: true + strict-raw-types: true + strict-inference: true + +linter: + rules: + - public_member_api_docs + - always_declare_return_types # https://github.com/dart-lang/lints#migrating-from-packagepedantic + - prefer_single_quotes # https://github.com/dart-lang/lints#migrating-from-packagepedantic + - unawaited_futures # https://github.com/dart-lang/lints#migrating-from-packagepedantic + - unsafe_html # https://github.com/dart-lang/lints#migrating-from-packagepedantic diff --git a/sandbox/reactivex/lib/angel3_reactivex.dart b/sandbox/reactivex/lib/angel3_reactivex.dart new file mode 100644 index 0000000..2003c7a --- /dev/null +++ b/sandbox/reactivex/lib/angel3_reactivex.dart @@ -0,0 +1,7 @@ +library rx; + +export 'src/rx.dart'; +export 'streams.dart'; +export 'subjects.dart'; +export 'transformers.dart'; +export 'utils.dart'; diff --git a/sandbox/reactivex/lib/src/rx.dart b/sandbox/reactivex/lib/src/rx.dart new file mode 100644 index 0000000..113180e --- /dev/null +++ b/sandbox/reactivex/lib/src/rx.dart @@ -0,0 +1,1357 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; +import 'package:angel3_reactivex/streams.dart'; + +/// A utility class that provides static methods to create the various Streams +/// provided by angel3_reactivex. +/// +/// ### Example +/// +/// Rx.combineLatest([ +/// Stream.value('a'), +/// Stream.fromIterable(['b', 'c', 'd']) +/// ], (list) => list.join()) +/// .listen(print); // prints 'ab', 'ac', 'ad' +/// +/// ### Learning angel3_reactivex +/// +/// This library contains documentation and examples for each method. In +/// addition, more complex examples can be found in the +/// [angel3_reactivex github repo](https://github.com/ReactiveX/angel3_reactivex) demonstrating how +/// to use angel3_reactivex with web, command line, and Flutter applications. +/// +/// #### Additional Resources +/// +/// In addition to the angel3_reactivex documentation and examples, you can find many +/// more articles on Dart Streams that teach the fundamentals upon which +/// angel3_reactivex is built. +/// +/// - [Asynchronous Programming: Streams](https://www.dartlang.org/tutorials/language/streams) +/// - [Single-Subscription vs. Broadcast Streams](https://dart.dev/tutorials/language/streams#two-kinds-of-streams) +/// - [Creating Streams in Dart](https://www.dartlang.org/articles/libraries/creating-streams) +/// - [Testing Streams: Stream Matchers](https://pub.dartlang.org/packages/test#stream-matchers) +/// +/// ### Dart Streams vs Traditional Rx Observables +/// In ReactiveX, the Observable class is the heart of the ecosystem. +/// Observables represent data sources that emit 'items' or 'events' over time. +/// Dart already includes such a data source: Streams. +/// +/// In order to integrate fluently with the Dart ecosystem, Rx Dart does not +/// provide a [Stream] class, but rather adds functionality to Dart Streams. +/// This provides several advantages: +/// +/// - angel3_reactivex works with any API that expects a Dart Stream as an input. +/// - No need to implement or replace the many methods and properties from the core Stream API. +/// - Ability to create Streams with language-level syntax. +/// +/// Overall, we attempt to follow the ReactiveX spec as closely as we can, but +/// prioritize fitting in with the Dart ecosystem when a trade-off must be made. +/// Therefore, there are some important differences to note between Dart's +/// [Stream] class and standard Rx `Observable`. +/// +/// First, Cold Observables exist in Dart as normal Streams, but they are +/// single-subscription only. In other words, you can only listen a Stream +/// once, unless it is a hot (aka broadcast) Stream. If you attempt to listen to +/// a cold Stream twice, a StateError will be thrown. If you need to listen to a +/// stream multiple times, you can simply create a factory function that returns +/// a new instance of the stream. +/// +/// Second, many methods contained within, such as `first` and `last` do not +/// return a `Single` nor an `Observable`, but rather must return a Dart Future. +/// Luckily, Dart's `Future` class is conceptually similar to `Single`, and can +/// be easily converted back to a Stream using the `myFuture.asStream()` method +/// if needed. +/// +/// Third, Streams in Dart do not close by default when an error occurs. In Rx, +/// an Error causes the Observable to terminate unless it is intercepted by +/// an operator. Dart has mechanisms for creating streams that close when an +/// error occurs, but the majority of Streams do not exhibit this behavior. +/// +/// Fourth, Dart streams are asynchronous by default, whereas Observables are +/// synchronous by default, unless you schedule work on a different Scheduler. +/// You can create synchronous Streams with Dart, but please be aware the the +/// default is simply different. +/// +/// Finally, when using Dart Broadcast Streams (similar to Hot Observables), +/// please know that `onListen` will only be called the first time the +/// broadcast stream is listened to. +abstract class Rx { + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an item. + /// This is helpful when you need to combine a dynamic number of Streams. + /// + /// The Stream will not emit any lists of values until all of the source + /// streams have emitted at least one value. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items and without any calls to the combiner function. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest([ + /// Stream.value('a'), + /// Stream.fromIterable(['b', 'c', 'd']) + /// ], (list) => list.join()) + /// .listen(print); // prints 'ab', 'ac', 'ad' + static Stream combineLatest( + Iterable> streams, R Function(List values) combiner) => + CombineLatestStream(streams, combiner); + + /// Merges the given Streams into a single Stream that emits a List of the + /// values emitted by the source Stream. This is helpful when you need to + /// combine a dynamic number of Streams. + /// + /// The Stream will not emit any lists of values until all of the source + /// streams have emitted at least one value. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatestList([ + /// Stream.value(1), + /// Stream.fromIterable([0, 1, 2]), + /// ]) + /// .listen(print); // prints [1, 0], [1, 1], [1, 2] + static Stream> combineLatestList(Iterable> streams) => + CombineLatestStream.list(streams); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest2( + /// Stream.value(1), + /// Stream.fromIterable([0, 1, 2]), + /// (a, b) => a + b) + /// .listen(print); //prints 1, 2, 3 + static Stream combineLatest2(Stream streamA, Stream streamB, + T Function(A a, B b) combiner) => + CombineLatestStream.combine2(streamA, streamB, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest3( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.fromIterable(['c', 'c']), + /// (a, b, c) => a + b + c) + /// .listen(print); //prints 'abc', 'abc' + static Stream combineLatest3( + Stream streamA, + Stream streamB, + Stream streamC, + T Function(A a, B b, C c) combiner) => + CombineLatestStream.combine3(streamA, streamB, streamC, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest4( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.fromIterable(['d', 'd']), + /// (a, b, c, d) => a + b + c + d) + /// .listen(print); //prints 'abcd', 'abcd' + static Stream combineLatest4( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + T Function(A a, B b, C c, D d) combiner) => + CombineLatestStream.combine4( + streamA, streamB, streamC, streamD, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest5( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.fromIterable(['e', 'e']), + /// (a, b, c, d, e) => a + b + c + d + e) + /// .listen(print); //prints 'abcde', 'abcde' + static Stream combineLatest5( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + T Function(A a, B b, C c, D d, E e) combiner) => + CombineLatestStream.combine5( + streamA, streamB, streamC, streamD, streamE, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest6( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.fromIterable(['f', 'f']), + /// (a, b, c, d, e, f) => a + b + c + d + e + f) + /// .listen(print); //prints 'abcdef', 'abcdef' + static Stream combineLatest6( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + T Function(A a, B b, C c, D d, E e, F f) combiner) => + CombineLatestStream.combine6( + streamA, streamB, streamC, streamD, streamE, streamF, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest7( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.fromIterable(['g', 'g']), + /// (a, b, c, d, e, f, g) => a + b + c + d + e + f + g) + /// .listen(print); //prints 'abcdefg', 'abcdefg' + static Stream combineLatest7( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + T Function(A a, B b, C c, D d, E e, F f, G g) combiner) => + CombineLatestStream.combine7(streamA, streamB, streamC, streamD, streamE, + streamF, streamG, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest8( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.value('g'), + /// Stream.fromIterable(['h', 'h']), + /// (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h) + /// .listen(print); //prints 'abcdefgh', 'abcdefgh' + static Stream combineLatest8( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + T Function(A a, B b, C c, D d, E e, F f, G g, H h) combiner) => + CombineLatestStream.combine8( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + combiner, + ); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function whenever any of the stream sequences emits an + /// item. + /// + /// The Stream will not emit until all streams have emitted at least one + /// item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) + /// + /// ### Example + /// + /// Rx.combineLatest9( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.value('g'), + /// Stream.value('h'), + /// Stream.fromIterable(['i', 'i']), + /// (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i) + /// .listen(print); //prints 'abcdefghi', 'abcdefghi' + static Stream combineLatest9( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + Stream streamI, + T Function(A a, B b, C c, D d, E e, F f, G g, H h, I i) combiner) => + CombineLatestStream.combine9( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + streamI, + combiner, + ); + + /// Concatenates all of the specified stream sequences, as long as the + /// previous stream sequence terminated successfully. + /// + /// It does this by subscribing to each stream one by one, emitting all items + /// and completing before subscribing to the next stream. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#concat) + /// + /// ### Example + /// + /// Rx.concat([ + /// Stream.value(1), + /// Rx.timer(2, Duration(days: 1)), + /// Stream.value(3) + /// ]) + /// .listen(print); // prints 1, 2, 3 + static Stream concat(Iterable> streams) => + ConcatStream(streams); + + /// Concatenates all of the specified stream sequences, as long as the + /// previous stream sequence terminated successfully. + /// + /// In the case of concatEager, rather than subscribing to one stream after + /// the next, all streams are immediately subscribed to. The events are then + /// captured and emitted at the correct time, after the previous stream has + /// finished emitting items. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#concat) + /// + /// ### Example + /// + /// Rx.concatEager([ + /// Stream.value(1), + /// Rx.timer(2, Duration(days: 1)), + /// Stream.value(3) + /// ]) + /// .listen(print); // prints 1, 2, 3 + static Stream concatEager(Iterable> streams) => + ConcatEagerStream(streams); + + /// The defer factory waits until an observer subscribes to it, and then it + /// creates a [Stream] with the given factory function. + /// + /// In some circumstances, waiting until the last minute (that is, until + /// subscription time) to generate the Stream can ensure that this + /// Stream contains the freshest data. + /// + /// By default, DeferStreams are single-subscription. However, it's possible + /// to make them reusable. + /// + /// ### Example + /// + /// Rx.defer(() => Stream.value(1)) + /// .listen(print); //prints 1 + static Stream defer(Stream Function() streamFactory, + {bool reusable = false}) => + DeferStream(streamFactory, reusable: reusable); + + /// Creates a [Stream] where all last events of existing stream(s) are piped + /// through a sink-transformation. + /// + /// This operator is best used when you have a group of streams + /// and only care about the final emitted value of each. + /// One common use case for this is if you wish to issue multiple + /// requests on page load (or some other event) + /// and only want to take action when a response has been received for all. + /// + /// In this way it is similar to how you might use [Future.wait]. + /// + /// Be aware that if any of the inner streams supplied to forkJoin error + /// you will lose the value of any other streams that would or have already + /// completed if you do not catch the error correctly on the inner stream. + /// + /// If you are only concerned with all inner streams completing + /// successfully you can catch the error on the outside. + /// It's also worth noting that if you have an stream + /// that emits more than one item, and you are concerned with the previous + /// emissions forkJoin is not the correct choice. + /// + /// In these cases you may better off with an operator like combineLatest or zip. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items and without any calls to the combiner function. + /// + /// ### Example + /// + /// Rx.forkJoin([ + /// Stream.value('a'), + /// Stream.fromIterable(['b', 'c', 'd']) + /// ], (list) => list.join(', ')) + /// .listen(print); // prints 'a, d' + static Stream forkJoin( + Iterable> streams, R Function(List values) combiner) => + ForkJoinStream(streams, combiner); + + /// Merges the given Streams into a single Stream that emits a List of the + /// last values emitted by the source stream(s). This is helpful when you need to + /// forkJoin a dynamic number of Streams. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items. + /// + /// ### Example + /// + /// Rx.forkJoinList([ + /// Stream.value(1), + /// Stream.fromIterable([0, 1, 2]), + /// ]) + /// .listen(print); // prints [1, 2] + static Stream> forkJoinList(Iterable> streams) => + ForkJoinStream.list(streams); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin2( + /// Stream.value(1), + /// Stream.fromIterable([0, 1, 2]), + /// (a, b) => a + b) + /// .listen(print); //prints 3 + static Stream forkJoin2(Stream streamA, Stream streamB, + T Function(A a, B b) combiner) => + ForkJoinStream.join2(streamA, streamB, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin3( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.fromIterable(['c', 'd']), + /// (a, b, c) => a + b + c) + /// .listen(print); //prints 'abd' + static Stream forkJoin3(Stream streamA, Stream streamB, + Stream streamC, T Function(A a, B b, C c) combiner) => + ForkJoinStream.join3(streamA, streamB, streamC, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin4( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.fromIterable(['d', 'e']), + /// (a, b, c, d) => a + b + c + d) + /// .listen(print); //prints 'abce' + static Stream forkJoin4( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + T Function(A a, B b, C c, D d) combiner) => + ForkJoinStream.join4(streamA, streamB, streamC, streamD, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin5( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.fromIterable(['e', 'f']), + /// (a, b, c, d, e) => a + b + c + d + e) + /// .listen(print); //prints 'abcdf' + static Stream forkJoin5( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + T Function(A a, B b, C c, D d, E e) combiner) => + ForkJoinStream.join5( + streamA, streamB, streamC, streamD, streamE, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin6( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.fromIterable(['f', 'g']), + /// (a, b, c, d, e, f) => a + b + c + d + e + f) + /// .listen(print); //prints 'abcdeg' + static Stream forkJoin6( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + T Function(A a, B b, C c, D d, E e, F f) combiner) => + ForkJoinStream.join6( + streamA, streamB, streamC, streamD, streamE, streamF, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin7( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.fromIterable(['g', 'h']), + /// (a, b, c, d, e, f, g) => a + b + c + d + e + f + g) + /// .listen(print); //prints 'abcdefh' + static Stream forkJoin7( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + T Function(A a, B b, C c, D d, E e, F f, G g) combiner) => + ForkJoinStream.join7(streamA, streamB, streamC, streamD, streamE, streamF, + streamG, combiner); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin8( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.value('g'), + /// Stream.fromIterable(['h', 'i']), + /// (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h) + /// .listen(print); //prints 'abcdefgi' + static Stream forkJoin8( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + T Function(A a, B b, C c, D d, E e, F f, G g, H h) combiner) => + ForkJoinStream.join8( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + combiner, + ); + + /// Merges the given Streams into a single Stream sequence by using the + /// [combiner] function when all of the stream sequences emits their + /// last item. + /// + /// ### Example + /// + /// Rx.forkJoin9( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.value('g'), + /// Stream.value('h'), + /// Stream.fromIterable(['i', 'j']), + /// (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i) + /// .listen(print); //prints 'abcdefghj' + static Stream forkJoin9( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + Stream streamI, + T Function(A a, B b, C c, D d, E e, F f, G g, H h, I i) combiner) => + ForkJoinStream.join9( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + streamI, + combiner, + ); + + /// Returns a Stream that, when listening to it, calls a function you specify + /// and then emits the value returned from that function. + /// + /// If result from invoking [callable] function: + /// - Is a [Future]: when the future completes, this stream will fire one event, either + /// data or error, and then close with a done-event. + /// - Is a [T]: this stream emits a single data event and then completes with a done event. + /// + /// By default, a [FromCallableStream] is a single-subscription Stream. However, it's possible + /// to make them reusable. + /// This Stream is effectively equivalent to one created by + /// `(() async* { yield await callable() }())` or `(() async* { yield callable(); }())`. + /// + /// [ReactiveX doc](http://reactivex.io/documentation/operators/from.html) + /// + /// ### Example + /// + /// Rx.fromCallable(() => 'Value').listen(print); // prints Value + /// + /// Rx.fromCallable(() async { + /// await Future.delayed(const Duration(seconds: 1)); + /// return 'Value'; + /// }).listen(print); // prints Value + static Stream fromCallable(FutureOr Function() callable, + {bool reusable = false}) => + FromCallableStream(callable, reusable: reusable); + + /// Flattens the items emitted by the given [streams] into a single Stream + /// sequence. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#merge) + /// + /// ### Example + /// + /// Rx.merge([ + /// Rx.timer(1, Duration(days: 10)), + /// Stream.value(2) + /// ]) + /// .listen(print); // prints 2, 1 + static Stream merge(Iterable> streams) => + MergeStream(streams); + + /// Returns a non-terminating stream sequence, which can be used to denote + /// an infinite duration. + /// + /// The never operator is one with very specific and limited behavior. These + /// are useful for testing purposes, and sometimes also for combining with + /// other Streams or as parameters to operators that expect other + /// Streams as parameters. + /// + /// ### Example + /// + /// Rx.never().listen(print); // Neither prints nor terminates + static Stream never() => NeverStream(); + + /// Given two or more source [streams], emit all of the items from only + /// the first of these [streams] to emit an item or notification. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#amb) + /// + /// ### Example + /// + /// Rx.race([ + /// Rx.timer(1, Duration(days: 1)), + /// Rx.timer(2, Duration(days: 2)), + /// Rx.timer(3, Duration(seconds: 1)) + /// ]).listen(print); // prints 3 + static Stream race(Iterable> streams) => + RaceStream(streams); + + /// Returns a [Stream] that emits a sequence of Integers within a specified + /// range. + /// + /// ### Example + /// + /// Rx.range(1, 3).listen((i) => print(i)); // Prints 1, 2, 3 + /// + /// Rx.range(3, 1).listen((i) => print(i)); // Prints 3, 2, 1 + static Stream range(int startInclusive, int endInclusive) => + RangeStream(startInclusive, endInclusive); + + /// Creates a [Stream] that will recreate and re-listen to the source + /// Stream the specified number of times until the [Stream] terminates + /// successfully. + /// + /// If [count] is not specified, it repeats indefinitely. + /// + /// ### Example + /// + /// RepeatStream((int repeatCount) => + /// Stream.value('repeat index: $repeatCount'), 3) + /// .listen((i) => print(i)); // Prints 'repeat index: 0, repeat index: 1, repeat index: 2' + static Stream repeat(Stream Function(int repeatIndex) streamFactory, + [int? count]) => + RepeatStream(streamFactory, count); + + /// Creates a [Stream] that will recreate and re-listen to the source + /// Stream the specified number of times until the Stream terminates + /// successfully. + /// + /// If the retry count is not specified, it retries indefinitely. If the retry + /// count is met, but the Stream has not terminated successfully, all of the errors + /// and StackTraces that caused the failure will be emitted. + /// + /// ### Example + /// + /// Rx.retry(() => Stream.value(1)) + /// .listen((i) => print(i)); // Prints 1 + /// + /// Rx.retry( + /// () => Stream.value(1).concatWith([Stream.error(Error())]), + /// 1, + /// ).listen( + /// print, + /// onError: (Object e, StackTrace s) => print(e), + /// ); // Prints 1, 1, Instance of 'Error', Instance of 'Error' + static Stream retry(Stream Function() streamFactory, [int? count]) => + RetryStream(streamFactory, count); + + /// Creates a Stream that will recreate and re-listen to the source + /// Stream when the notifier emits a new value. If the source Stream + /// emits an error or it completes, the Stream terminates. + /// + /// If the [retryWhenFactory] throws an error or returns a Stream that emits an error, + /// original error will be emitted. And then, the error from [retryWhenFactory] will be emitted + /// if it is not identical with original error. + /// + /// ### Basic Example + /// + /// ```dart + /// Rx.retryWhen( + /// () => Stream.fromIterable([1]), + /// (Object error, StackTrace s) => throw error, + /// ).listen(print); // Prints 1 + /// ``` + /// + /// ### Periodic Example + /// + /// ```dart + /// Rx.retryWhen( + /// () => Stream.periodic(const Duration(seconds: 1), (int i) => i) + /// .map((int i) => i == 2 ? throw 'exception' : i), + /// (Object e, StackTrace s) => + /// Rx.timer(null, const Duration(milliseconds: 200)), + /// ).take(4).listen(print); // Prints 0, 1, 0, 1 + /// ``` + /// + /// ### Complex Example + /// + /// ```dart + /// var errorHappened = false; + /// Rx.retryWhen( + /// () => Stream.periodic(const Duration(seconds: 1), (i) => i).map((i) { + /// if (i == 3 && !errorHappened) { + /// throw 'We can take this. Please restart.'; + /// } else if (i == 4) { + /// throw 'It\'s enough.'; + /// } else { + /// return i; + /// } + /// }), + /// (e, s) { + /// errorHappened = true; + /// if (e == 'We can take this. Please restart.') { + /// return Stream.value('Ok. Here you go!'); + /// } else { + /// return Stream.error(e, s); + /// } + /// }, + /// ).listen(print, onError: print); // Prints 0, 1, 2, 0, 1, 2, 3, It's enough. + /// ``` + static Stream retryWhen( + Stream Function() streamFactory, + Stream Function(Object error, StackTrace stackTrace) retryWhenFactory, + ) => + RetryWhenStream(streamFactory, retryWhenFactory); + + /// Determine whether two Streams emit the same sequence of items. + /// You can provide an optional [equals] handler to determine equality. + /// + /// [Interactive marble diagram](https://rxmarbles.com/#sequenceEqual) + /// + /// ### Example + /// + /// Rx.sequenceEqual([ + /// Stream.fromIterable([1, 2, 3, 4, 5]), + /// Stream.fromIterable([1, 2, 3, 4, 5]) + /// ]) + /// .listen(print); // prints true + static Stream sequenceEqual( + Stream stream, + Stream other, { + bool Function(A a, B b)? equals, + bool Function(ErrorAndStackTrace, ErrorAndStackTrace)? errorEquals, + }) => + SequenceEqualStream( + stream, + other, + dataEquals: equals, + errorEquals: errorEquals, + ); + + /// Convert a Stream that emits Streams (aka a 'Higher Order Stream') into a + /// single Stream that emits the items emitted by the most-recently-emitted of + /// those Streams. + /// + /// This Stream will unsubscribe from the previously-emitted Stream when + /// a new Stream is emitted from the source Stream and subscribe to the new + /// Stream. + /// + /// ### Example + /// + /// ```dart + /// final switchLatestStream = SwitchLatestStream( + /// Stream.fromIterable(>[ + /// Rx.timer('A', Duration(seconds: 2)), + /// Rx.timer('B', Duration(seconds: 1)), + /// Stream.value('C'), + /// ]), + /// ); + /// + /// // Since the first two Streams do not emit data for 1-2 seconds, and the + /// // 3rd Stream will be emitted before that time, only data from the 3rd + /// // Stream will be emitted to the listener. + /// switchLatestStream.listen(print); // prints 'C' + /// ``` + static Stream switchLatest(Stream> streams) => + SwitchLatestStream(streams); + + /// Emits the given value after a specified amount of time. + /// + /// ### Example + /// + /// Rx.timer('hi', Duration(minutes: 1)) + /// .listen((i) => print(i)); // print 'hi' after 1 minute + static Stream timer(T value, Duration duration) => + TimerStream(value, duration); + + /// When listener listens to it, creates a resource object from resource factory function, + /// and creates a [Stream] from the given factory function and resource as argument. + /// Finally when the stream finishes emitting items or stream subscription + /// is cancelled (call [StreamSubscription.cancel] or `Stream.listen(cancelOnError: true)`), + /// call the disposer function on resource object. + /// + /// The [UsingStream] is a way you can instruct an Stream to create + /// a resource that exists only during the lifespan of the Stream + /// and is disposed of when the Stream terminates. + /// + /// [Marble diagram](http://reactivex.io/documentation/operators/images/using.c.png) + /// + /// ### Example + /// + /// Rx.using>( + /// resourceFactory: () => Queue.of([1, 2, 3]), + /// streamFactory: (r) => Stream.fromIterable(r), + /// disposer: (r) => r.clear(), + /// ).listen(print); // prints 1, 2, 3 + static Stream using({ + required FutureOr Function() resourceFactory, + required Stream Function(R) streamFactory, + required FutureOr Function(R) disposer, + }) => + UsingStream( + resourceFactory: resourceFactory, + streamFactory: streamFactory, + disposer: disposer, + ); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip2( + /// Stream.value('Hi '), + /// Stream.fromIterable(['Friend', 'Dropped']), + /// (a, b) => a + b) + /// .listen(print); // prints 'Hi Friend' + static Stream zip2( + Stream streamA, Stream streamB, T Function(A a, B b) zipper) => + ZipStream.zip2(streamA, streamB, zipper); + + /// Merges the iterable streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items and without any calls to the zipper function. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip( + /// [ + /// Stream.value('Hi '), + /// Stream.fromIterable(['Friend', 'Dropped']), + /// ], + /// (values) => values.first + values.last + /// ) + /// .listen(print); // prints 'Hi Friend' + static Stream zip( + Iterable> streams, R Function(List values) zipper) => + ZipStream(streams, zipper); + + /// Merges the iterable streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// If the provided streams is empty, the resulting sequence completes immediately + /// without emitting any items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zipList( + /// [ + /// Stream.value('Hi '), + /// Stream.fromIterable(['Friend', 'Dropped']), + /// ], + /// ) + /// .listen(print); // prints ['Hi ', 'Friend'] + static Stream> zipList(Iterable> streams) => + ZipStream.list(streams); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip3( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.fromIterable(['c', 'dropped']), + /// (a, b, c) => a + b + c) + /// .listen(print); //prints 'abc' + static Stream zip3(Stream streamA, Stream streamB, + Stream streamC, T Function(A a, B b, C c) zipper) => + ZipStream.zip3(streamA, streamB, streamC, zipper); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip4( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.fromIterable(['d', 'dropped']), + /// (a, b, c, d) => a + b + c + d) + /// .listen(print); //prints 'abcd' + static Stream zip4( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + T Function(A a, B b, C c, D d) zipper) => + ZipStream.zip4(streamA, streamB, streamC, streamD, zipper); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip5( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.fromIterable(['e', 'dropped']), + /// (a, b, c, d, e) => a + b + c + d + e) + /// .listen(print); //prints 'abcde' + static Stream zip5( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + T Function(A a, B b, C c, D d, E e) zipper) => + ZipStream.zip5(streamA, streamB, streamC, streamD, streamE, zipper); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip6( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.fromIterable(['f', 'dropped']), + /// (a, b, c, d, e, f) => a + b + c + d + e + f) + /// .listen(print); //prints 'abcdef' + static Stream zip6( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + T Function(A a, B b, C c, D d, E e, F f) zipper) => + ZipStream.zip6( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + zipper, + ); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip7( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.fromIterable(['g', 'dropped']), + /// (a, b, c, d, e, f, g) => a + b + c + d + e + f + g) + /// .listen(print); //prints 'abcdefg' + static Stream zip7( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + T Function(A a, B b, C c, D d, E e, F f, G g) zipper) => + ZipStream.zip7( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + zipper, + ); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip8( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.value('g'), + /// Stream.fromIterable(['h', 'dropped']), + /// (a, b, c, d, e, f, g, h) => a + b + c + d + e + f + g + h) + /// .listen(print); //prints 'abcdefgh' + static Stream zip8( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + T Function(A a, B b, C c, D d, E e, F f, G g, H h) zipper) => + ZipStream.zip8( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + zipper, + ); + + /// Merges the specified streams into one stream sequence using the given + /// zipper function whenever all of the stream sequences have produced + /// an element at a corresponding index. + /// + /// It applies this function in strict sequence, so the first item emitted by + /// the new Stream will be the result of the function applied to the first + /// item emitted by Stream #1 and the first item emitted by Stream #2; + /// the second item emitted by the new ZipStream will be the result of + /// the function applied to the second item emitted by Stream #1 and the + /// second item emitted by Stream #2; and so forth. It will only emit as + /// many items as the number of items emitted by the source Stream that + /// emits the fewest items. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#zip) + /// + /// ### Example + /// + /// Rx.zip9( + /// Stream.value('a'), + /// Stream.value('b'), + /// Stream.value('c'), + /// Stream.value('d'), + /// Stream.value('e'), + /// Stream.value('f'), + /// Stream.value('g'), + /// Stream.value('h'), + /// Stream.fromIterable(['i', 'dropped']), + /// (a, b, c, d, e, f, g, h, i) => a + b + c + d + e + f + g + h + i) + /// .listen(print); //prints 'abcdefghi' + static Stream zip9( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + Stream streamI, + T Function(A a, B b, C c, D d, E e, F f, G g, H h, I i) zipper) => + ZipStream.zip9( + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + streamI, + zipper, + ); +} diff --git a/sandbox/reactivex/lib/src/streams/combine_latest.dart b/sandbox/reactivex/lib/src/streams/combine_latest.dart new file mode 100644 index 0000000..9ed4331 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/combine_latest.dart @@ -0,0 +1,352 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +/// Merges the given Streams into one Stream sequence by using the +/// combiner function whenever any of the source stream sequences emits an +/// item. +/// +/// The Stream will not emit until all Streams have emitted at least one +/// item. +/// +/// If the provided streams is empty, the resulting sequence completes immediately +/// without emitting any items and without any calls to the combiner function. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#combineLatest) +/// +/// ### Basic Example +/// +/// This constructor takes in an `Iterable>` and outputs a +/// `Stream>` whenever any of the values change from the source +/// stream. This is useful with a dynamic number of source streams! +/// +/// CombineLatestStream.list([ +/// Stream.fromIterable(['a']), +/// Stream.fromIterable(['b']), +/// Stream.fromIterable(['C', 'D'])]) +/// .listen(print); //prints ['a', 'b', 'C'], ['a', 'b', 'D'] +/// +/// ### Example with combiner +/// +/// If you wish to combine the list of values into a new object before you +/// +/// CombineLatestStream( +/// [ +/// Stream.fromIterable(['a']), +/// Stream.fromIterable(['b']), +/// Stream.fromIterable(['C', 'D']) +/// ], +/// (values) => values.last +/// ) +/// .listen(print); //prints 'C', 'D' +/// +/// ### Example with a specific number of Streams +/// +/// If you wish to combine a specific number of Streams together with proper +/// types information for the value of each Stream, use the +/// [combine2] - [combine9] operators. +/// +/// CombineLatestStream.combine2( +/// Stream.fromIterable([1]), +/// Stream.fromIterable([2, 3]), +/// (a, b) => a + b, +/// ) +/// .listen(print); // prints 3, 4 +class CombineLatestStream extends StreamView { + /// Constructs a [Stream] that observes an [Iterable] of [Stream] + /// and builds a [List] containing all latest events emitted by the provided [Iterable] of [Stream]. + /// The [combiner] maps this [List] into a new event of type [R] + CombineLatestStream( + Iterable> streams, + R Function(List values) combiner, + ) : super(_buildController(streams, combiner).stream); + + /// Constructs a [CombineLatestStream] using a default combiner, which simply + /// yields a [List] of all latest events emitted by the provided [Iterable] of [Stream]. + static CombineLatestStream> list( + Iterable> streams, + ) => + CombineLatestStream>( + streams, + (List values) => values, + ); + + /// Constructs a [CombineLatestStream] from a pair of [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine2( + Stream streamOne, + Stream streamTwo, + R Function(A a, B b) combiner, + ) => + CombineLatestStream( + [streamOne, streamTwo], + (List values) => combiner(values[0] as A, values[1] as B), + ); + + /// Constructs a [CombineLatestStream] from 3 [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine3( + Stream streamA, + Stream streamB, + Stream streamC, + R Function(A a, B b, C c) combiner, + ) => + CombineLatestStream( + [streamA, streamB, streamC], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + ); + }, + ); + + /// Constructs a [CombineLatestStream] from 4 [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine4( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + R Function(A a, B b, C c, D d) combiner, + ) => + CombineLatestStream( + [streamA, streamB, streamC, streamD], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + ); + }, + ); + + /// Constructs a [CombineLatestStream] from 5 [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine5( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + R Function(A a, B b, C c, D d, E e) combiner, + ) => + CombineLatestStream( + [streamA, streamB, streamC, streamD, streamE], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + ); + }, + ); + + /// Constructs a [CombineLatestStream] from 6 [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine6( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + R Function(A a, B b, C c, D d, E e, F f) combiner, + ) => + CombineLatestStream( + [streamA, streamB, streamC, streamD, streamE, streamF], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + ); + }, + ); + + /// Constructs a [CombineLatestStream] from 7 [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine7( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + R Function(A a, B b, C c, D d, E e, F f, G g) combiner, + ) => + CombineLatestStream( + [streamA, streamB, streamC, streamD, streamE, streamF, streamG], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + ); + }, + ); + + /// Constructs a [CombineLatestStream] from 8 [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine8( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + R Function(A a, B b, C c, D d, E e, F f, G g, H h) combiner, + ) => + CombineLatestStream( + [ + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH + ], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + ); + }, + ); + + /// Constructs a [CombineLatestStream] from 9 [Stream]s + /// where [combiner] is used to create a new event of type [R], based on the + /// latest events emitted by the provided [Stream]s. + static CombineLatestStream combine9( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + Stream streamI, + R Function(A a, B b, C c, D d, E e, F f, G g, H h, I i) combiner, + ) => + CombineLatestStream( + [ + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + streamI + ], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + values[8] as I, + ); + }, + ); + + static StreamController _buildController( + Iterable> streams, + R Function(List values) combiner, + ) { + final controller = StreamController(sync: true); + late List> subscriptions; + List? values; + + controller.onListen = () { + var triggered = 0, completed = 0; + + void onDone() { + if (++completed == subscriptions.length) { + controller.close(); + } + } + + subscriptions = streams.mapIndexed((index, stream) { + var hasFirstEvent = false; + + return stream.listen( + (T value) { + if (values == null) { + return; + } + + values![index] = value; + + if (!hasFirstEvent) { + hasFirstEvent = true; + triggered++; + } + + if (triggered == subscriptions.length) { + final R combined; + try { + combined = combiner(List.unmodifiable(values!)); + } catch (e, s) { + controller.addError(e, s); + return; + } + controller.add(combined); + } + }, + onError: controller.addError, + onDone: onDone, + ); + }).toList(growable: false); + if (subscriptions.isEmpty) { + controller.close(); + } else { + values = List.filled(subscriptions.length, null); + } + }; + controller.onPause = () => subscriptions.pauseAll(); + controller.onResume = () => subscriptions.resumeAll(); + controller.onCancel = () { + values = null; + return subscriptions.cancelAll(); + }; + + return controller; + } +} diff --git a/sandbox/reactivex/lib/src/streams/concat.dart b/sandbox/reactivex/lib/src/streams/concat.dart new file mode 100644 index 0000000..a451e6a --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/concat.dart @@ -0,0 +1,75 @@ +import 'dart:async'; + +/// Concatenates all of the specified stream sequences, as long as the +/// previous stream sequence terminated successfully. +/// +/// It does this by subscribing to each stream one by one, emitting all items +/// and completing before subscribing to the next stream. +/// +/// If the provided streams is empty, the resulting sequence completes immediately +/// without emitting any items. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#concat) +/// +/// ### Example +/// +/// ConcatStream([ +/// Stream.fromIterable([1]), +/// TimerStream(2, Duration(days: 1)), +/// Stream.fromIterable([3]) +/// ]) +/// .listen(print); // prints 1, 2, 3 +class ConcatStream extends StreamView { + /// Constructs a [Stream] which emits all events from [streams]. + /// The [Iterable] is traversed upwards, meaning that the current first + /// [Stream] in the [Iterable] needs to complete, before events from the + /// next [Stream] will be subscribed to. + ConcatStream(Iterable> streams) + : super(_buildController(streams).stream); + + static StreamController _buildController(Iterable> streams) { + final controller = StreamController(sync: true); + StreamSubscription? subscription; + + controller.onListen = () { + final iterator = streams.iterator; + + void moveNext() { + if (!iterator.moveNext()) { + controller.close(); + return; + } + subscription?.cancel(); + subscription = iterator.current.listen(controller.add, + onError: controller.addError, onDone: moveNext); + } + + moveNext(); + }; + controller.onPause = () => subscription?.pause(); + controller.onResume = () => subscription?.resume(); + controller.onCancel = () => subscription?.cancel(); + + return controller; + } +} + +/// Extends the Stream class with the ability to concatenate one stream with +/// another. +extension ConcatExtensions on Stream { + /// Returns a Stream that emits all items from the current Stream, + /// then emits all items from the given streams, one after the next. + /// + /// ### Example + /// + /// TimerStream(1, Duration(seconds: 10)) + /// .concatWith([Stream.fromIterable([2])]) + /// .listen(print); // prints 1, 2 + Stream concatWith(Iterable> other) { + final concatStream = ConcatStream([this, ...other]); + + return isBroadcast + ? concatStream.asBroadcastStream(onCancel: (s) => s.cancel()) + : concatStream; + } +} diff --git a/sandbox/reactivex/lib/src/streams/concat_eager.dart b/sandbox/reactivex/lib/src/streams/concat_eager.dart new file mode 100644 index 0000000..17beddd --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/concat_eager.dart @@ -0,0 +1,88 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/streams/concat.dart'; +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +/// Concatenates all of the specified stream sequences, as long as the +/// previous stream sequence terminated successfully. +/// +/// In the case of concatEager, rather than subscribing to one stream after +/// the next, all streams are immediately subscribed to. The events are then +/// captured and emitted at the correct time, after the previous stream has +/// finished emitting items. +/// +/// If the provided streams is empty, the resulting sequence completes immediately +/// without emitting any items. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#concat) +/// +/// ### Example +/// +/// ConcatEagerStream([ +/// Stream.fromIterable([1]), +/// TimerStream(2, Duration(days: 1)), +/// Stream.fromIterable([3]) +/// ]) +/// .listen(print); // prints 1, 2, 3 +class ConcatEagerStream extends StreamView { + /// Constructs a [Stream] which emits all events from [streams]. + /// Unlike [ConcatStream], all [Stream]s inside [streams] are + /// immediately subscribed to and events captured at the correct time, + /// but emitted only after the previous [Stream] in [streams] is + /// successfully closed. + ConcatEagerStream(Iterable> streams) + : super(_buildController(streams).stream); + + static StreamController _buildController(Iterable> streams) { + final controller = StreamController(sync: true); + late List> subscriptions; + StreamSubscription? activeSubscription; + + controller.onListen = () { + final completeEvents = >[]; + + void Function() onDone(int index) { + return () { + if (index < subscriptions.length - 1) { + completeEvents[index].complete(); + activeSubscription = subscriptions[index + 1]; + } else if (index == subscriptions.length - 1) { + controller.close(); + } + }; + } + + StreamSubscription createSubscription(int index, Stream stream) { + final subscription = stream.listen(controller.add, + onError: controller.addError, onDone: onDone(index)); + + // pause all subscriptions, except the first, initially + if (index > 0) { + final completer = Completer.sync(); + completeEvents.add(completer); + subscription.pause(completer.future); + } + + return subscription; + } + + subscriptions = + streams.mapIndexed(createSubscription).toList(growable: false); + if (subscriptions.isEmpty) { + controller.close(); + } else { + // initially, the very first subscription is the active one + activeSubscription = subscriptions.first; + } + }; + controller.onPause = () => activeSubscription?.pause(); + controller.onResume = () => activeSubscription?.resume(); + controller.onCancel = () { + activeSubscription = null; + return subscriptions.cancelAll(); + }; + + return controller; + } +} diff --git a/sandbox/reactivex/lib/src/streams/connectable_stream.dart b/sandbox/reactivex/lib/src/streams/connectable_stream.dart new file mode 100644 index 0000000..bf4a5cb --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/connectable_stream.dart @@ -0,0 +1,516 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/streams/replay_stream.dart'; +import 'package:angel3_reactivex/src/streams/value_stream.dart'; +import 'package:angel3_reactivex/src/utils/notification.dart'; +import 'package:angel3_reactivex/subjects.dart'; + +/// A ConnectableStream resembles an ordinary Stream, except that it +/// can be listened to multiple times and does not begin emitting items when +/// it is listened to, but only when its [connect] method is called. +/// +/// This class can be used to broadcast a single-subscription Stream, and +/// can be used to wait for all intended Observers to [listen] to the +/// Stream before it begins emitting items. +abstract class ConnectableStream extends StreamView { + /// Constructs a [Stream] which only begins emitting events when + /// the [connect] method is called. + ConnectableStream(Stream stream) : super(stream); + + /// Returns a [Stream] that automatically connects (at most once) to this + /// ConnectableStream when the first Observer subscribes. + /// + /// To disconnect from the source Stream, provide a [connection] callback and + /// cancel the `subscription` at the appropriate time. + Stream autoConnect({ + void Function(StreamSubscription subscription) connection, + }); + + /// Instructs the [ConnectableStream] to begin emitting items from the + /// source Stream. To disconnect from the source stream, cancel the + /// subscription. + StreamSubscription connect(); + + /// Returns a [Stream] that stays connected to this ConnectableStream + /// as long as there is at least one subscription to this + /// ConnectableStream. + Stream refCount(); +} + +enum _ConnectableStreamUse { + autoConnect, + connect, + refCount, +} + +/// Base class for implementations of [ConnectableStream]. +/// [S] is type of the forwarding [Subject]. +/// [R] is return type of [autoConnect] and [refCount] (type constraint: `S extends R`). +abstract class AbstractConnectableStream, + R extends Stream> extends ConnectableStream { + final Stream _source; + final S _subject; + _ConnectableStreamUse? _use; + + /// Constructs a [AbstractConnectableStream] with a source [Stream] and the forwarding [Subject]. + AbstractConnectableStream( + Stream source, + S subject, + ) : assert(subject is R), + _source = source, + _subject = subject, + super(subject); + + late final _connection = ConnectableStreamSubscription( + _source.listen( + _subject.add, + onError: _subject.addError, + onDone: _subject.close, + ), + _subject, + ); + + bool _canReuse(_ConnectableStreamUse use) { + if (_use != null && _use != use) { + throw StateError( + 'Do not mix autoConnect, connect and refCount together, you should only use one of them!'); + } + + final canReuse = _use != null && _use == use; + _use = use; + return canReuse; + } + + @override + R autoConnect({ + void Function(StreamSubscription subscription)? connection, + }) { + if (_canReuse(_ConnectableStreamUse.autoConnect)) { + return _subject as R; + } + + _subject.onListen = () { + final subscription = _connection; + connection?.call(subscription); + }; + _subject.onCancel = null; + + return _subject as R; + } + + @override + StreamSubscription connect() { + if (_canReuse(_ConnectableStreamUse.connect)) { + return _connection; + } + + _subject.onListen = _subject.onCancel = null; + return _connection; + } + + @override + R refCount() { + if (_canReuse(_ConnectableStreamUse.refCount)) { + return _subject as R; + } + + StreamSubscription? subscription; + _subject.onListen = () => subscription = _connection; + _subject.onCancel = () => subscription?.cancel(); + + return _subject as R; + } +} + +/// A [ConnectableStream] that converts a single-subscription Stream into +/// a broadcast [Stream]. +class PublishConnectableStream + extends AbstractConnectableStream, Stream> { + /// Constructs a [Stream] which only begins emitting events when + /// the [connect] method is called, this [Stream] acts like a + /// [PublishSubject]. + PublishConnectableStream(Stream source, {bool sync = false}) + : super(source, PublishSubject(sync: sync)); +} + +/// A [ConnectableStream] that converts a single-subscription Stream into +/// a broadcast Stream that replays the latest value to any new listener, and +/// provides synchronous access to the latest emitted value. +class ValueConnectableStream + extends AbstractConnectableStream, ValueStream> + implements ValueStream { + /// Constructs a [Stream] which only begins emitting events when + /// the [connect] method is called, this [Stream] acts like a + /// [BehaviorSubject]. + ValueConnectableStream(Stream source, {bool sync = false}) + : super(source, BehaviorSubject(sync: sync)); + + /// Constructs a [Stream] which only begins emitting events when + /// the [connect] method is called, this [Stream] acts like a + /// [BehaviorSubject.seeded]. + ValueConnectableStream.seeded(Stream source, T seedValue, + {bool sync = false}) + : super(source, BehaviorSubject.seeded(seedValue, sync: sync)); + + @override + bool get hasValue => _subject.hasValue; + + @override + T get value => _subject.value; + + @override + T? get valueOrNull => _subject.valueOrNull; + + @override + Object get error => _subject.error; + + @override + Object? get errorOrNull => _subject.errorOrNull; + + @override + bool get hasError => _subject.hasError; + + @override + StackTrace? get stackTrace => _subject.stackTrace; + + @override + StreamNotification? get lastEventOrNull => _subject.lastEventOrNull; +} + +/// A [ConnectableStream] that converts a single-subscription Stream into +/// a broadcast Stream that replays emitted items to any new listener, and +/// provides synchronous access to the list of emitted values. +class ReplayConnectableStream + extends AbstractConnectableStream, ReplayStream> + implements ReplayStream { + /// Constructs a [Stream] which only begins emitting events when + /// the [connect] method is called, this [Stream] acts like a + /// [ReplaySubject]. + ReplayConnectableStream(Stream stream, {int? maxSize, bool sync = false}) + : super( + stream, + ReplaySubject(maxSize: maxSize, sync: sync), + ); + + @override + List get values => _subject.values; + + @override + List get errors => _subject.errors; + + @override + List get stackTraces => _subject.stackTraces; +} + +/// A special [StreamSubscription] that not only cancels the connection to +/// the source [Stream], but also closes down a subject that drives the Stream. +class ConnectableStreamSubscription extends StreamSubscription { + final StreamSubscription _source; + final Subject _subject; + + /// Constructs a special [StreamSubscription], which will close the provided subject + /// when [cancel] is called. + ConnectableStreamSubscription(this._source, this._subject); + + @override + Future cancel() => + _source.cancel().then((_) => _subject.close()); + + @override + Never asFuture([E? futureValue]) => _unsupportedError(); + + @override + bool get isPaused => _source.isPaused; + + @override + Never onData(void Function(T data)? handleData) => _unsupportedError(); + + @override + Never onDone(void Function()? handleDone) => _unsupportedError(); + + @override + Never onError(Function? handleError) => _unsupportedError(); + + @override + void pause([Future? resumeSignal]) => _source.pause(resumeSignal); + + @override + void resume() => _source.resume(); + + Never _unsupportedError() => throw UnsupportedError( + 'Cannot change handlers of ConnectableStreamSubscription.'); +} + +/// Extends the Stream class with the ability to transform a single-subscription +/// Stream into a ConnectableStream. +extension ConnectableStreamExtensions on Stream { + /// Convert the current Stream into a [ConnectableStream] that can be listened + /// to multiple times. It will not begin emitting items from the original + /// Stream until the `connect` method is invoked. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream. + /// + /// ### Example + /// + /// ``` + /// final source = Stream.fromIterable([1, 2, 3]); + /// final connectable = source.publish(); + /// + /// // Does not print anything at first + /// connectable.listen(print); + /// + /// // Start listening to the source Stream. Will cause the previous + /// // line to start printing 1, 2, 3 + /// final subscription = connectable.connect(); + /// await Future(() {}); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // Subject + /// subscription.cancel(); + /// ``` + PublishConnectableStream publish() => + PublishConnectableStream(this, sync: true); + + /// Convert the current Stream into a [ValueConnectableStream] + /// that can be listened to multiple times. It will not begin emitting items + /// from the original Stream until the `connect` method is invoked. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream that replays the latest emitted value to any new + /// listener. It also provides access to the latest value synchronously. + /// + /// ### Example + /// + /// ``` + /// final source = Stream.fromIterable([1, 2, 3]); + /// final connectable = source.publishValue(); + /// + /// // Does not print anything at first + /// connectable.listen(print); + /// + /// // Start listening to the source Stream. Will cause the previous + /// // line to start printing 1, 2, 3 + /// final subscription = connectable.connect(); + /// + /// // Late subscribers will receive the last emitted value + /// connectable.listen(print); // Prints 3 + /// await Future(() {}); + /// + /// // Can access the latest emitted value synchronously. Prints 3 + /// print(connectable.value); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // BehaviorSubject + /// subscription.cancel(); + /// ``` + ValueConnectableStream publishValue() => + ValueConnectableStream(this, sync: true); + + /// Convert the current Stream into a [ValueConnectableStream] + /// that can be listened to multiple times, providing an initial seeded value. + /// It will not begin emitting items from the original Stream + /// until the `connect` method is invoked. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream that replays the latest emitted value to any new + /// listener. It also provides access to the latest value synchronously. + /// + /// ### Example + /// + /// ``` + /// final source = Stream.fromIterable([1, 2, 3]); + /// final connectable = source.publishValueSeeded(0); + /// + /// // Does not print anything at first + /// connectable.listen(print); + /// + /// // Start listening to the source Stream. Will cause the previous + /// // line to start printing 0, 1, 2, 3 + /// final subscription = connectable.connect(); + /// + /// // Late subscribers will receive the last emitted value + /// connectable.listen(print); // Prints 3 + /// await Future(() {}); + /// + /// // Can access the latest emitted value synchronously. Prints 3 + /// print(connectable.value); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // BehaviorSubject + /// subscription.cancel(); + /// ``` + ValueConnectableStream publishValueSeeded(T seedValue) => + ValueConnectableStream.seeded(this, seedValue, sync: true); + + /// Convert the current Stream into a [ReplayConnectableStream] + /// that can be listened to multiple times. It will not begin emitting items + /// from the original Stream until the `connect` method is invoked. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream that replays a given number of items to any new + /// listener. It also provides access to the emitted values synchronously. + /// + /// ### Example + /// + /// ``` + /// final source = Stream.fromIterable([1, 2, 3]); + /// final connectable = source.publishReplay(); + /// + /// // Does not print anything at first + /// connectable.listen(print); + /// + /// // Start listening to the source Stream. Will cause the previous + /// // line to start printing 1, 2, 3 + /// final subscription = connectable.connect(); + /// + /// // Late subscribers will receive the emitted value, up to a specified + /// // maxSize + /// connectable.listen(print); // Prints 1, 2, 3 + /// await Future(() {}); + /// + /// // Can access a list of the emitted values synchronously. Prints [1, 2, 3] + /// print(connectable.values); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // ReplaySubject + /// subscription.cancel(); + /// ``` + ReplayConnectableStream publishReplay({int? maxSize}) => + ReplayConnectableStream(this, maxSize: maxSize, sync: true); + + /// Convert the current Stream into a new Stream that can be listened + /// to multiple times. It will automatically begin emitting items when first + /// listened to, and shut down when no listeners remain. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream. + /// + /// ### Example + /// + /// ``` + /// // Convert a single-subscription fromIterable stream into a broadcast + /// // stream + /// final stream = Stream.fromIterable([1, 2, 3]).share(); + /// + /// // Start listening to the source Stream. Will start printing 1, 2, 3 + /// final subscription = stream.listen(print); + /// await Future(() {}); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // PublishSubject + /// subscription.cancel(); + /// ``` + Stream share() => publish().refCount(); + + /// Convert the current Stream into a new [ValueStream] that can + /// be listened to multiple times. It will automatically begin emitting items + /// when first listened to, and shut down when no listeners remain. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream. It's also useful for providing sync access to the latest + /// emitted value. + /// + /// It will replay the latest emitted value to any new listener. + /// + /// ### Example + /// + /// ``` + /// // Convert a single-subscription fromIterable stream into a broadcast + /// // stream that will emit the latest value to any new listeners + /// final stream = Stream.fromIterable([1, 2, 3]).shareValue(); + /// + /// // Start listening to the source Stream. Will start printing 1, 2, 3 + /// final subscription = stream.listen(print); + /// await Future(() {}); + /// + /// // Synchronously print the latest value + /// print(stream.value); + /// + /// // Subscribe again later. This will print 3 because it receives the last + /// // emitted value. + /// final subscription2 = stream.listen(print); + /// await Future(() {}); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // BehaviorSubject by cancelling all subscriptions. + /// subscription.cancel(); + /// subscription2.cancel(); + /// ``` + ValueStream shareValue() => publishValue().refCount(); + + /// Convert the current Stream into a new [ValueStream] that can + /// be listened to multiple times, providing an initial value. + /// It will automatically begin emitting items when first listened to, + /// and shut down when no listeners remain. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream. It's also useful for providing sync access to the latest + /// emitted value. + /// + /// It will replay the latest emitted value to any new listener. + /// + /// ### Example + /// + /// ``` + /// // Convert a single-subscription fromIterable stream into a broadcast + /// // stream that will emit the latest value to any new listeners + /// final stream = Stream.fromIterable([1, 2, 3]).shareValueSeeded(0); + /// + /// // Start listening to the source Stream. Will start printing 0, 1, 2, 3 + /// final subscription = stream.listen(print); + /// + /// // Synchronously print the latest value + /// print(stream.value); + /// + /// // Subscribe again later. This will print 3 because it receives the last + /// // emitted value. + /// final subscription2 = stream.listen(print); + /// await Future(() {}); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // BehaviorSubject by cancelling all subscriptions. + /// subscription.cancel(); + /// subscription2.cancel(); + /// ``` + ValueStream shareValueSeeded(T seedValue) => + publishValueSeeded(seedValue).refCount(); + + /// Convert the current Stream into a new [ReplayStream] that can + /// be listened to multiple times. It will automatically begin emitting items + /// when first listened to, and shut down when no listeners remain. + /// + /// This is useful for converting a single-subscription stream into a + /// broadcast Stream. It's also useful for gaining access to the l + /// + /// It will replay the emitted values to any new listener, up to a given + /// [maxSize]. + /// + /// ### Example + /// + /// ``` + /// // Convert a single-subscription fromIterable stream into a broadcast + /// // stream that will emit the latest value to any new listeners + /// final stream = Stream.fromIterable([1, 2, 3]).shareReplay(); + /// + /// // Start listening to the source Stream. Will start printing 1, 2, 3 + /// final subscription = stream.listen(print); + /// await Future(() {}); + /// + /// // Synchronously print the emitted values up to a given maxSize + /// // Prints [1, 2, 3] + /// print(stream.values); + /// + /// // Subscribe again later. This will print 1, 2, 3 because it receives the + /// // last emitted value. + /// final subscription2 = stream.listen(print); + /// await Future(() {}); + /// + /// // Stop emitting items from the source stream and close the underlying + /// // ReplaySubject by cancelling all subscriptions. + /// subscription.cancel(); + /// subscription2.cancel(); + /// ``` + ReplayStream shareReplay({int? maxSize}) => + publishReplay(maxSize: maxSize).refCount(); +} diff --git a/sandbox/reactivex/lib/src/streams/defer.dart b/sandbox/reactivex/lib/src/streams/defer.dart new file mode 100644 index 0000000..25a8a12 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/defer.dart @@ -0,0 +1,57 @@ +import 'dart:async'; + +/// The defer factory waits until a listener subscribes to it, and then it +/// creates a Stream with the given factory function. +/// +/// In some circumstances, waiting until the last minute (that is, until +/// subscription time) to generate the Stream can ensure that listeners +/// receive the freshest data. +/// +/// By default, DeferStreams are single-subscription. However, it's possible +/// to make them reusable. +/// +/// ### Example +/// +/// DeferStream(() => Stream.value(1)).listen(print); //prints 1 +class DeferStream extends Stream { + final Stream Function() _factory; + final bool _isReusable; + + @override + bool get isBroadcast => _isReusable; + + /// Constructs a [Stream] lazily, at the moment of subscription, using + /// the [streamFactory] + DeferStream(Stream Function() streamFactory, {bool reusable = false}) + : _isReusable = reusable, + _factory = reusable + ? streamFactory + : (() { + Stream? stream; + return () => stream ??= streamFactory(); + }()); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + Stream stream; + + try { + stream = _factory(); + } catch (e, s) { + return Stream.error(e, s).listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } + + return stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} diff --git a/sandbox/reactivex/lib/src/streams/fork_join.dart b/sandbox/reactivex/lib/src/streams/fork_join.dart new file mode 100644 index 0000000..349909e --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/fork_join.dart @@ -0,0 +1,366 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +/// This operator is best used when you have a group of streams +/// and only care about the final emitted value of each. +/// One common use case for this is if you wish to issue multiple +/// requests on page load (or some other event) +/// and only want to take action when a response has been received for all. +/// +/// In this way it is similar to how you might use [Future.wait]. +/// +/// Be aware that if any of the inner streams supplied to forkJoin error +/// you will lose the value of any other streams that would or have already +/// completed if you do not catch the error correctly on the inner stream. +/// +/// If you are only concerned with all inner streams completing +/// successfully you can catch the error on the outside. +/// It's also worth noting that if you have an stream +/// that emits more than one item, and you are concerned with the previous +/// emissions forkJoin is not the correct choice. +/// +/// In these cases you may better off with an operator like combineLatest or zip. +/// +/// If the provided streams is empty, the resulting sequence completes immediately +/// without emitting any items and without any calls to the combiner function. +/// +/// ### Basic Example +/// +/// This constructor takes in an `Iterable>` and outputs a +/// `Stream>` whenever any of the values change from the source +/// stream. This is useful with a dynamic number of source streams! +/// +/// ForkJoinStream.list([ +/// Stream.fromIterable(['a']), +/// Stream.fromIterable(['b']), +/// Stream.fromIterable(['C', 'D']), +/// ]) +/// .listen(print); //prints ['a', 'b', 'D'] +/// +/// ### Example with combiner +/// +/// If you wish to combine the list of values into a new object before emitting, +/// you can provide the `combiner` function to the constructor. +/// +/// ForkJoinStream( +/// [ +/// Stream.fromIterable(['a']), +/// Stream.fromIterable(['b']), +/// Stream.fromIterable(['C', 'D']), +/// ], +/// (values) => values.last, +/// ) +/// .listen(print); //prints 'D' +/// +/// ### Example with a specific number of Streams +/// +/// If you wish to combine a specific number of Streams together with proper +/// types information for the value of each Stream, use the +/// [join2] - [join9] operators. +/// +/// ForkJoinStream.join2( +/// Stream.fromIterable([1]), +/// Stream.fromIterable([2, 3]), +/// (a, b) => a + b, +/// ) +/// .listen(print); // prints 4 +class ForkJoinStream extends StreamView { + /// Constructs a [Stream] that awaits the last values of the [Stream]s + /// in [streams], then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + ForkJoinStream( + Iterable> streams, + R Function(List values) combiner, + ) : super(_buildStream(streams, combiner)); + + /// Constructs a [Stream] that awaits the last values of the [Stream]s + /// in [streams] and then emits these values as a [List]. + /// After this event, the [Stream] closes. + static ForkJoinStream> list( + Iterable> streams, + ) => + ForkJoinStream>( + streams, + (values) => values, + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join2( + Stream streamOne, + Stream streamTwo, + R Function(A a, B b) combiner, + ) => + ForkJoinStream( + [streamOne, streamTwo], + (List values) => combiner(values[0] as A, values[1] as B), + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join3( + Stream streamA, + Stream streamB, + Stream streamC, + R Function(A a, B b, C c) combiner, + ) => + ForkJoinStream( + [streamA, streamB, streamC], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + ); + }, + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join4( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + R Function(A a, B b, C c, D d) combiner, + ) => + ForkJoinStream( + [streamA, streamB, streamC, streamD], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + ); + }, + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join5( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + R Function(A a, B b, C c, D d, E e) combiner, + ) => + ForkJoinStream( + [streamA, streamB, streamC, streamD, streamE], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + ); + }, + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join6( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + R Function(A a, B b, C c, D d, E e, F f) combiner, + ) => + ForkJoinStream( + [streamA, streamB, streamC, streamD, streamE, streamF], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + ); + }, + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join7( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + R Function(A a, B b, C c, D d, E e, F f, G g) combiner, + ) => + ForkJoinStream( + [streamA, streamB, streamC, streamD, streamE, streamF, streamG], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + ); + }, + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join8( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + R Function(A a, B b, C c, D d, E e, F f, G g, H h) combiner, + ) => + ForkJoinStream( + [ + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH + ], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + ); + }, + ); + + /// Constructs a [Stream] that awaits the last values the provided [Stream]s, + /// then calls the [combiner] to emit an event of type [R]. + /// After this event, the [Stream] closes. + static ForkJoinStream join9( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + Stream streamI, + R Function(A a, B b, C c, D d, E e, F f, G g, H h, I i) combiner, + ) => + ForkJoinStream( + [ + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + streamI + ], + (List values) { + return combiner( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + values[8] as I, + ); + }, + ); + + static Stream _buildStream( + Iterable> streams, + R Function(List values) combiner, + ) { + final controller = StreamController(sync: true); + late List> subscriptions; + List? values; + + controller.onListen = () { + var completed = 0; + + StreamSubscription listen(int i, Stream stream) { + var hasValue = false; + + return stream.listen( + (value) { + hasValue = true; + values?[i] = value; + }, + onError: controller.addError, + onDone: () { + if (!hasValue) { + controller.addError(StateError('No element')); + controller.close(); + return; + } + + if (values == null) { + return; + } + if (++completed == subscriptions.length) { + final R combined; + try { + combined = combiner(List.unmodifiable(values!)); + } catch (e, s) { + controller.addError(e, s); + controller.close(); + return; + } + + controller.add(combined); + controller.close(); + } + }, + ); + } + + subscriptions = streams.mapIndexed(listen).toList(growable: false); + if (subscriptions.isEmpty) { + controller.close(); + } else { + values = List.filled(subscriptions.length, null); + } + }; + controller.onPause = () => subscriptions.pauseAll(); + controller.onResume = () => subscriptions.resumeAll(); + controller.onCancel = () { + values = null; + return subscriptions.cancelAll(); + }; + + return controller.stream; + } +} diff --git a/sandbox/reactivex/lib/src/streams/from_callable.dart b/sandbox/reactivex/lib/src/streams/from_callable.dart new file mode 100644 index 0000000..ee4a6ba --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/from_callable.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +/// Returns a Stream that, when listening to it, calls a function you specify +/// and then emits the value returned from that function. +/// +/// If result from invoking [callable] function: +/// - Is a [Future]: when the future completes, this stream will fire one event, either +/// data or error, and then close with a done-event. +/// - Is a [T]: this stream emits a single data event and then completes with a done event. +/// +/// By default, a [FromCallableStream] is a single-subscription Stream. However, it's possible +/// to make them reusable. +/// This Stream is effectively equivalent to one created by +/// `(() async* { yield await callable() }())` or `(() async* { yield callable(); }())`. +/// +/// [ReactiveX doc](http://reactivex.io/documentation/operators/from.html) +/// +/// ### Example +/// +/// FromCallableStream(() => 'Value').listen(print); // prints Value +/// +/// FromCallableStream(() async { +/// await Future.delayed(const Duration(seconds: 1)); +/// return 'Value'; +/// }).listen(print); // prints Value +class FromCallableStream extends Stream { + Stream? _stream; + + /// A function will be called at subscription time. + final FutureOr Function() callable; + final bool _isReusable; + + /// Construct a Stream that, when listening to it, calls a function you specify + /// and then emits the value returned from that function. + /// [reusable] indicates whether this Stream can be listened to multiple times or not. + FromCallableStream(this.callable, {bool reusable = false}) + : _isReusable = reusable; + + @override + bool get isBroadcast => _isReusable; + + @override + StreamSubscription listen( + void Function(T event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) { + if (_isReusable || _stream == null) { + try { + final value = callable(); + + _stream = + value is Future ? Stream.fromFuture(value) : Stream.value(value); + } catch (e, s) { + _stream = Stream.error(e, s); + } + } + + return _stream!.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} diff --git a/sandbox/reactivex/lib/src/streams/merge.dart b/sandbox/reactivex/lib/src/streams/merge.dart new file mode 100644 index 0000000..2384052 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/merge.dart @@ -0,0 +1,74 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +/// Flattens the items emitted by the given streams into a single Stream +/// sequence. +/// +/// If the provided streams is empty, the resulting sequence completes immediately +/// without emitting any items. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#merge) +/// +/// ### Example +/// +/// MergeStream([ +/// TimerStream(1, Duration(days: 10)), +/// Stream.fromIterable([2]) +/// ]) +/// .listen(print); // prints 2, 1 +class MergeStream extends StreamView { + /// Constructs a [Stream] which flattens all events in [streams] and emits + /// them in a single sequence. + MergeStream(Iterable> streams) + : super(_buildController(streams).stream); + + static StreamController _buildController(Iterable> streams) { + final controller = StreamController(sync: true); + late List> subscriptions; + + controller.onListen = () { + var completed = 0; + + void onDone() { + if (++completed == subscriptions.length) { + controller.close(); + } + } + + subscriptions = streams + .map((s) => s.listen(controller.add, + onError: controller.addError, onDone: onDone)) + .toList(growable: false); + + if (subscriptions.isEmpty) { + controller.close(); + } + }; + controller.onPause = () => subscriptions.pauseAll(); + controller.onResume = () => subscriptions.resumeAll(); + controller.onCancel = () => subscriptions.cancelAll(); + + return controller; + } +} + +/// Extends the Stream class with the ability to merge one stream with another. +extension MergeExtension on Stream { + /// Combines the items emitted by multiple streams into a single stream of + /// items. The items are emitted in the order they are emitted by their + /// sources. + /// + /// ### Example + /// + /// TimerStream(1, Duration(seconds: 10)) + /// .mergeWith([Stream.fromIterable([2])]) + /// .listen(print); // prints 2, 1 + Stream mergeWith(Iterable> streams) { + final stream = MergeStream([this, ...streams]); + + return isBroadcast + ? stream.asBroadcastStream(onCancel: (s) => s.cancel()) + : stream; + } +} diff --git a/sandbox/reactivex/lib/src/streams/never.dart b/sandbox/reactivex/lib/src/streams/never.dart new file mode 100644 index 0000000..fc6b18b --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/never.dart @@ -0,0 +1,31 @@ +import 'dart:async'; + +/// Returns a non-terminating stream sequence, which can be used to denote +/// an infinite duration. +/// +/// The never operator is one with very specific and limited behavior. These +/// are useful for testing purposes, and sometimes also for combining with +/// other Streams or as parameters to operators that expect other +/// Streams as parameters. +/// +/// ### Example +/// +/// NeverStream().listen(print); // Neither prints nor terminates +class NeverStream extends Stream { + // ignore: close_sinks + final _controller = StreamController(); + + /// Constructs a [Stream] which never emits an event and simply remains + /// open until implicitly closed by the developer. + NeverStream(); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) => + _controller.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); +} diff --git a/sandbox/reactivex/lib/src/streams/race.dart b/sandbox/reactivex/lib/src/streams/race.dart new file mode 100644 index 0000000..98b6333 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/race.dart @@ -0,0 +1,70 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +/// Given two or more source streams, emit all of the items from only +/// the first of these streams to emit an item or notification. +/// +/// If the provided streams is empty, the resulting sequence completes immediately +/// without emitting any items. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#race) +/// +/// ### Example +/// +/// RaceStream([ +/// TimerStream(1, Duration(days: 1)), +/// TimerStream(2, Duration(days: 2)), +/// TimerStream(3, Duration(seconds: 3)) +/// ]).listen(print); // prints 3 +class RaceStream extends StreamView { + /// Constructs a [Stream] which emits all events from a single [Stream] + /// inside [streams]. The selected [Stream] is the first one which emits + /// an event. + /// After this event, all other [Stream]s in [streams] are discarded. + RaceStream(Iterable> streams) + : super(_buildController(streams).stream); + + static StreamController _buildController(Iterable> streams) { + final controller = StreamController(sync: true); + late List> subscriptions; + + controller.onListen = () { + void reduceToWinner(int winnerIndex) { + final winner = subscriptions.removeAt(winnerIndex); + + subscriptions.cancelAll()?.onError((e, s) { + if (!controller.isClosed && controller.hasListener) { + controller.addError(e, s); + } + }); + + subscriptions = [winner]; + } + + void Function(T value) doUpdate(int index) { + return (T value) { + if (subscriptions.length > 1) { + reduceToWinner(index); + } + controller.add(value); + }; + } + + subscriptions = streams + .mapIndexed((index, stream) => stream.listen(doUpdate(index), + onError: controller.addError, onDone: controller.close)) + .toList(); + + if (subscriptions.isEmpty) { + controller.close(); + } + }; + controller.onPause = () => subscriptions.pauseAll(); + controller.onResume = () => subscriptions.resumeAll(); + controller.onCancel = () => subscriptions.cancelAll(); + + return controller; + } +} diff --git a/sandbox/reactivex/lib/src/streams/range.dart b/sandbox/reactivex/lib/src/streams/range.dart new file mode 100644 index 0000000..83b4c1e --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/range.dart @@ -0,0 +1,41 @@ +import 'dart:async'; + +/// Returns a Stream that emits a sequence of Integers within a specified +/// range. +/// +/// ### Examples +/// +/// RangeStream(1, 3).listen((i) => print(i)); // Prints 1, 2, 3 +/// +/// RangeStream(3, 1).listen((i) => print(i)); // Prints 3, 2, 1 +class RangeStream extends Stream { + var _isListened = false; + final Stream _stream; + + /// Constructs a [Stream] which emits all integer values that exist + /// within the range between [startInclusive] and [endInclusive]. + RangeStream(int startInclusive, int endInclusive) + : _stream = _buildStream(startInclusive, endInclusive); + + @override + StreamSubscription listen(void Function(int event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + if (_isListened) { + throw StateError('Stream has already been listened to.'); + } + _isListened = true; + + return _stream.listen(onData, + onError: onError, onDone: onDone, cancelOnError: cancelOnError); + } + + static Stream _buildStream(int startInclusive, int endInclusive) { + final length = (endInclusive - startInclusive).abs() + 1; + + int nextValue(int index) => startInclusive > endInclusive + ? startInclusive - index + : startInclusive + index; + + return Stream.fromIterable(Iterable.generate(length, nextValue)); + } +} diff --git a/sandbox/reactivex/lib/src/streams/repeat.dart b/sandbox/reactivex/lib/src/streams/repeat.dart new file mode 100644 index 0000000..9f8f9c5 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/repeat.dart @@ -0,0 +1,78 @@ +import 'dart:async'; + +/// Creates a [Stream] that will recreate and re-listen to the source +/// Stream the specified number of times until the [Stream] terminates +/// successfully. +/// +/// If [count] is not specified, it repeats indefinitely. +/// +/// ### Example +/// +/// RepeatStream((int repeatCount) => +/// Stream.value('repeat index: $repeatCount'), 3) +/// .listen((i) => print(i)); // Prints 'repeat index: 0, repeat index: 1, repeat index: 2' +class RepeatStream extends Stream { + /// The factory method used at subscription time + final Stream Function(int) streamFactory; + + /// The amount of repeat attempts that will be made + /// If 0, then an indefinite amount of attempts will be made. + final int? count; + int _repeatStep = 0; + StreamController? _controller; + StreamSubscription? _subscription; + + /// Constructs a [Stream] that will recreate and re-listen to the source + /// [Stream] (created with the provided factory method). + /// The count parameter specifies number of times the repeat will take place, + /// until this [Stream] terminates successfully. + /// If the count parameter is not specified, then this [Stream] will repeat + /// indefinitely. + RepeatStream(this.streamFactory, [this.count]); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + _controller ??= StreamController( + sync: true, + onListen: _maybeRepeatNext, + onPause: () => _subscription?.pause(), + onResume: () => _subscription?.resume(), + onCancel: () => _subscription?.cancel()); + + return _controller!.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } + + void _repeatNext() { + void onDone() { + _subscription?.cancel(); + + _maybeRepeatNext(); + } + + final controller = _controller!; + try { + _subscription = streamFactory(_repeatStep++).listen( + controller.add, + onError: controller.addError, + onDone: onDone, + cancelOnError: false, + ); + } catch (e, s) { + controller.addError(e, s); + } + } + + void _maybeRepeatNext() { + if (_repeatStep == count) { + _controller!.close(); + } else { + _repeatNext(); + } + } +} diff --git a/sandbox/reactivex/lib/src/streams/replay_stream.dart b/sandbox/reactivex/lib/src/streams/replay_stream.dart new file mode 100644 index 0000000..a9d7957 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/replay_stream.dart @@ -0,0 +1,26 @@ +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; + +/// An [Stream] that provides synchronous access to the emitted values +abstract class ReplayStream implements Stream { + /// Synchronously get the values stored in Subject. May be empty. + List get values; + + /// Synchronously get the errors and stack traces stored in Subject. May be empty. + List get errors; + + /// Synchronously get the stack traces of errors stored in Subject. May be empty. + List get stackTraces; +} + +/// Extension method on [ReplayStream] to access the emitted [ErrorAndStackTrace]s. +extension ErrorAndStackTracesReplayStreamExtension on ReplayStream { + /// Returns the emitted [ErrorAndStackTrace]s. + /// May be empty. + List get errorAndStackTraces => + errors.zipWith( + stackTraces, + (e, s) => ErrorAndStackTrace(e, s), + growable: false, + ); +} diff --git a/sandbox/reactivex/lib/src/streams/retry.dart b/sandbox/reactivex/lib/src/streams/retry.dart new file mode 100644 index 0000000..f90cc97 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/retry.dart @@ -0,0 +1,89 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; + +/// Creates a [Stream] that will recreate and re-listen to the source +/// [Stream] the specified number of times until the [Stream] terminates +/// successfully. +/// +/// If the retry count is not specified, it retries indefinitely. If the retry +/// count is met, but the Stream has not terminated successfully, all of the errors +/// and StackTraces that caused the failure will be emitted. +/// +/// ### Example +/// +/// RetryStream(() => Stream.value(1)) +/// .listen((i) => print(i)); // Prints 1 +/// +/// RetryStream( +/// () => Stream.value(1).concatWith([Stream.error(Error())]), +/// 1, +/// ).listen( +/// print, +/// onError: (Object e, StackTrace s) => print(e), +/// ); // Prints 1, 1, Instance of 'Error', Instance of 'Error' +class RetryStream extends Stream { + /// The factory method used at subscription time + final Stream Function() streamFactory; + + /// The amount of retry attempts that will be made + /// If null, then an indefinite amount of attempts will be made. + final int? count; + + var _retryStep = 0; + final _errors = []; + late final StreamController _controller = StreamController( + sync: true, + onListen: _retry, + onPause: () => _subscription!.pause(), + onResume: () => _subscription!.resume(), + onCancel: () { + _errors.clear(); + return _subscription?.cancel(); + }, + ); + StreamSubscription? _subscription; + + /// Constructs a [Stream] that will recreate and re-listen to the source + /// [Stream] (created by the provided factory method) the specified number + /// of times until the [Stream] terminates successfully. + /// If [count] is not specified, it retries indefinitely. + RetryStream(this.streamFactory, [this.count]); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + return _controller.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } + + void _retry() { + void onError(Object e, StackTrace s) { + _subscription!.cancel(); + _subscription = null; + + _errors.add(ErrorAndStackTrace(e, s)); + + if (count == _retryStep) { + for (var e in [..._errors]) { + _controller.addError(e.error, e.stackTrace); + } + _controller.close(); + } else { + ++_retryStep; + _retry(); + } + } + + _subscription = streamFactory().listen( + _controller.add, + onError: onError, + onDone: _controller.close, + cancelOnError: false, + ); + } +} diff --git a/sandbox/reactivex/lib/src/streams/retry_when.dart b/sandbox/reactivex/lib/src/streams/retry_when.dart new file mode 100644 index 0000000..05e6073 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/retry_when.dart @@ -0,0 +1,142 @@ +import 'dart:async'; + +/// Creates a Stream that will recreate and re-listen to the source +/// Stream when the notifier emits a new value. If the source Stream +/// emits an error or it completes, the Stream terminates. +/// +/// If the [retryWhenFactory] throws an error or returns a Stream that emits an error, +/// original error will be emitted. And then, the error from [retryWhenFactory] will be emitted +/// if it is not identical with original error. +/// +/// ### Basic Example +/// +/// ```dart +/// RetryWhenStream( +/// () => Stream.fromIterable([1]), +/// (Object error, StackTrace s) => throw error, +/// ).listen(print); // Prints 1 +/// ``` +/// +/// ### Periodic Example +/// +/// ```dart +/// RetryWhenStream( +/// () => Stream.periodic(const Duration(seconds: 1), (int i) => i) +/// .map((int i) => i == 2 ? throw 'exception' : i), +/// (Object e, StackTrace s) => +/// Rx.timer(null, const Duration(milliseconds: 200)), +/// ).take(4).listen(print); // Prints 0, 1, 0, 1 +/// ``` +/// +/// ### Complex Example +/// +/// ```dart +/// var errorHappened = false; +/// RetryWhenStream( +/// () => Stream.periodic(const Duration(seconds: 1), (i) => i).map((i) { +/// if (i == 3 && !errorHappened) { +/// throw 'We can take this. Please restart.'; +/// } else if (i == 4) { +/// throw 'It\'s enough.'; +/// } else { +/// return i; +/// } +/// }), +/// (e, s) { +/// errorHappened = true; +/// if (e == 'We can take this. Please restart.') { +/// return Stream.value('Ok. Here you go!'); +/// } else { +/// return Stream.error(e, s); +/// } +/// }, +/// ).listen(print, onError: print); // Prints 0, 1, 2, 0, 1, 2, 3, It's enough. +/// ``` +class RetryWhenStream extends Stream { + /// The factory method used at subscription time + final Stream Function() streamFactory; + + /// The factory method used to create the [Stream] which triggers a re-listen + final Stream Function( + Object error, + StackTrace stackTrace, + ) retryWhenFactory; + + late final _controller = StreamController( + sync: true, + onListen: _retry, + onPause: () => _subscription!.pause(), + onResume: () => _subscription!.resume(), + onCancel: () => _subscription?.cancel(), + ); + StreamSubscription? _subscription; + + /// Constructs a [Stream] that will recreate and re-listen to the source + /// [Stream] (created by the provided factory method). + /// The retry will trigger whenever the [Stream] created by the retryWhen + /// factory emits and event. + RetryWhenStream(this.streamFactory, this.retryWhenFactory); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + return _controller.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } + + void _retry() { + void onError(Object originalError, StackTrace originalStacktrace) { + _cancelSubscription(); + + Stream retryStream; + try { + retryStream = retryWhenFactory(originalError, originalStacktrace); + } catch (e, s) { + return _addErrorAndClose(originalError, originalStacktrace, e, s); + } + + _subscription = retryStream.listen( + (_) { + _cancelSubscription(); + _retry(); + }, + onError: (Object e, StackTrace s) { + _cancelSubscription(); + _addErrorAndClose(originalError, originalStacktrace, e, s); + }, + cancelOnError: false, + ); + } + + _subscription = streamFactory().listen( + _controller.add, + onError: onError, + onDone: _controller.close, + cancelOnError: false, + ); + } + + void _addErrorAndClose( + Object originalError, + StackTrace originalStacktrace, + Object e, + StackTrace s, + ) { + if (identical(originalError, e)) { + _controller.addError(originalError, originalStacktrace); + } else { + _controller.addError(originalError, originalStacktrace); + _controller.addError(e, s); + } + _controller.close(); + } + + void _cancelSubscription() { + _subscription!.cancel(); + _subscription = null; + } +} diff --git a/sandbox/reactivex/lib/src/streams/sequence_equal.dart b/sandbox/reactivex/lib/src/streams/sequence_equal.dart new file mode 100644 index 0000000..5fd8d11 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/sequence_equal.dart @@ -0,0 +1,95 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/streams/zip.dart'; +import 'package:angel3_reactivex/src/transformers/materialize.dart'; +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; +import 'package:angel3_reactivex/src/utils/notification.dart'; + +/// Determine whether two Streams emit the same sequence of items. +/// You can provide an optional equals handler to determine equality. +/// +/// [Interactive marble diagram](https://rxmarbles.com/#sequenceEqual) +/// +/// ### Example +/// +/// SequenceEqualsStream([ +/// Stream.fromIterable([1, 2, 3, 4, 5]), +/// Stream.fromIterable([1, 2, 3, 4, 5]) +/// ]) +/// .listen(print); // prints true +class SequenceEqualStream extends Stream { + final StreamController _controller; + + /// Creates a [Stream] that emits true or false, depending on the + /// equality between the provided [Stream]s. + /// This single value is emitted when both provided [Stream]s are complete. + /// After this event, the [Stream] closes. + SequenceEqualStream( + Stream stream, + Stream other, { + bool Function(S s, T t)? dataEquals, + bool Function(ErrorAndStackTrace, ErrorAndStackTrace)? errorEquals, + }) : _controller = _buildController(stream, other, dataEquals, errorEquals); + + @override + StreamSubscription listen(void Function(bool event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) => + _controller.stream.listen(onData, + onError: onError, onDone: onDone, cancelOnError: cancelOnError); + + static StreamController _buildController( + Stream stream, + Stream other, + bool Function(S s, T t)? dataEquals, + bool Function(ErrorAndStackTrace, ErrorAndStackTrace)? errorEquals, + ) { + dataEquals = dataEquals ?? (s, t) => s == t; + errorEquals = errorEquals ?? (e1, e2) => e1 == e2; + + late StreamController controller; + late StreamSubscription subscription; + + controller = StreamController( + sync: true, + onListen: () { + void emitAndClose([bool value = true]) => controller + ..add(value) + ..close(); + + bool compare(StreamNotification s, StreamNotification t) { + if (s.kind != t.kind) { + return false; + } + + switch (s.kind) { + case NotificationKind.data: + return dataEquals!( + s.requireDataValue, + t.requireDataValue, + ); + case NotificationKind.done: + return true; + case NotificationKind.error: + return errorEquals!( + s.requireErrorAndStackTrace, + t.requireErrorAndStackTrace, + ); + } + } + + subscription = + ZipStream.zip2(stream.materialize(), other.materialize(), compare) + .where((isEqual) => !isEqual) + .listen( + emitAndClose, + onError: controller.addError, + onDone: emitAndClose, + ); + }, + onPause: () => subscription.pause(), + onResume: () => subscription.resume(), + onCancel: () => subscription.cancel()); + + return controller; + } +} diff --git a/sandbox/reactivex/lib/src/streams/switch_latest.dart b/sandbox/reactivex/lib/src/streams/switch_latest.dart new file mode 100644 index 0000000..87650ad --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/switch_latest.dart @@ -0,0 +1,99 @@ +import 'dart:async'; + +/// Convert a [Stream] that emits [Stream]s (aka a 'Higher Order Stream') into a +/// single [Stream] that emits the items emitted by the most-recently-emitted of +/// those [Stream]s. +/// +/// This stream will unsubscribe from the previously-emitted Stream when a new +/// Stream is emitted from the source Stream. +/// +/// ### Example +/// +/// ```dart +/// final switchLatestStream = SwitchLatestStream( +/// Stream.fromIterable(>[ +/// Rx.timer('A', Duration(seconds: 2)), +/// Rx.timer('B', Duration(seconds: 1)), +/// Stream.value('C'), +/// ]), +/// ); +/// +/// // Since the first two Streams do not emit data for 1-2 seconds, and the 3rd +/// // Stream will be emitted before that time, only data from the 3rd Stream +/// // will be emitted to the listener. +/// switchLatestStream.listen(print); // prints 'C' +/// ``` +class SwitchLatestStream extends Stream { + // ignore: close_sinks + final StreamController _controller; + + /// Constructs a [Stream] that emits [Stream]s (aka a 'Higher Order Stream") into a + /// single [Stream] that emits the items emitted by the most-recently-emitted of + /// those [Stream]s. + SwitchLatestStream(Stream> streams) + : _controller = _buildController(streams); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) => + _controller.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + + static StreamController _buildController(Stream> streams) { + late StreamController controller; + late StreamSubscription> subscription; + StreamSubscription? otherSubscription; + var leftClosed = false, rightClosed = false, hasMainEvent = false; + + controller = StreamController( + sync: true, + onListen: () { + void closeLeft() { + leftClosed = true; + + if (rightClosed || !hasMainEvent) controller.close(); + } + + void closeRight() { + rightClosed = true; + + if (leftClosed) controller.close(); + } + + subscription = streams.listen((stream) { + try { + otherSubscription?.cancel(); + + hasMainEvent = true; + + otherSubscription = stream.listen( + controller.add, + onError: controller.addError, + onDone: closeRight, + ); + } catch (e, s) { + controller.addError(e, s); + } + }, onError: controller.addError, onDone: closeLeft); + }, + onPause: () { + subscription.pause(); + otherSubscription?.pause(); + }, + onResume: () { + subscription.resume(); + otherSubscription?.resume(); + }, + onCancel: () async { + await subscription.cancel(); + + if (hasMainEvent) await otherSubscription?.cancel(); + }); + + return controller; + } +} diff --git a/sandbox/reactivex/lib/src/streams/timer.dart b/sandbox/reactivex/lib/src/streams/timer.dart new file mode 100644 index 0000000..c456b66 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/timer.dart @@ -0,0 +1,69 @@ +import 'dart:async'; + +/// Emits the given value after a specified amount of time. +/// +/// ### Example +/// +/// TimerStream('hi', Duration(minutes: 1)) +/// .listen((i) => print(i)); // print 'hi' after 1 minute +class TimerStream extends Stream { + final StreamController _controller; + + /// Constructs a [Stream] which emits [value] after the specified [Duration]. + TimerStream(T value, Duration duration) + : _controller = _buildController(value, duration); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + return _controller.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } + + static StreamController _buildController(T value, Duration duration) { + final watch = Stopwatch(); + Timer? timer; + late StreamController controller; + Duration? totalElapsed = Duration.zero; + + void onResume() { + // Already cancelled or is not paused. + if (totalElapsed == null || timer != null) return; + + totalElapsed = totalElapsed! + watch.elapsed; + watch.start(); + + timer = Timer(duration - totalElapsed!, () { + controller.add(value); + controller.close(); + }); + } + + controller = StreamController( + sync: true, + onListen: () { + watch.start(); + timer = Timer(duration, () { + controller.add(value); + controller.close(); + }); + }, + onPause: () { + timer?.cancel(); + timer = null; + watch.stop(); + }, + onResume: onResume, + onCancel: () { + timer?.cancel(); + timer = null; + totalElapsed = null; + }, + ); + return controller; + } +} diff --git a/sandbox/reactivex/lib/src/streams/using.dart b/sandbox/reactivex/lib/src/streams/using.dart new file mode 100644 index 0000000..1cbed85 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/using.dart @@ -0,0 +1,107 @@ +import 'dart:async'; + +/// When listener listens to it, creates a resource object from resource factory function, +/// and creates a [Stream] from the given factory function and resource as argument. +/// Finally when the stream finishes emitting items or stream subscription +/// is cancelled (call [StreamSubscription.cancel] or `Stream.listen(cancelOnError: true)`), +/// call the disposer function on resource object. +/// The disposer is called after the future returned from [StreamSubscription.cancel] completes. +/// +/// The [UsingStream] is a way you can instruct a Stream to create +/// a resource that exists only during the lifespan of the Stream +/// and is disposed of when the Stream terminates. +/// +/// [Marble diagram](http://reactivex.io/documentation/operators/images/using.c.png) +/// +/// ### Example +/// +/// UsingStream>( +/// resourceFactory: () => Queue.of([1, 2, 3]), +/// streamFactory: (r) => Stream.fromIterable(r), +/// disposer: (r) => r.clear(), +/// ).listen(print); // prints 1, 2, 3 +class UsingStream extends StreamView { + /// Construct a [UsingStream] that creates a resource object from [resourceFactory], + /// and then creates a [Stream] from [streamFactory] and resource as argument. + /// When the Stream terminates, call [disposer] on resource object. + UsingStream({ + required FutureOr Function() resourceFactory, + required Stream Function(R) streamFactory, + required FutureOr Function(R) disposer, + }) : super(_buildStream(resourceFactory, streamFactory, disposer)); + + static Stream _buildStream( + FutureOr Function() resourceFactory, + Stream Function(R) streamFactory, + FutureOr Function(R) disposer, + ) { + late StreamController controller; + var resourceCreated = false; + late R resource; + StreamSubscription? subscription; + + void useResource(R r) { + resource = r; + resourceCreated = true; + + Stream stream; + try { + stream = streamFactory(r); + } catch (e, s) { + controller.addError(e, s); + controller.close(); + return; + } + + subscription = stream.listen( + controller.add, + onError: controller.addError, + onDone: controller.close, + ); + } + + controller = StreamController( + sync: true, + onListen: () { + final FutureOr resourceOrFuture; + try { + resourceOrFuture = resourceFactory(); + } catch (e, s) { + controller.addError(e, s); + controller.close(); + return; + } + + if (resourceOrFuture is R) { + useResource(resourceOrFuture); + } else { + resourceOrFuture.then((r) { + // if the controller was cancelled before the resource is created, + // we should dispose the resource + if (!controller.hasListener) { + disposer(r); + } else { + useResource(r); + } + }).onError((e, s) { + controller.addError(e, s); + controller.close(); + }); + } + }, + onPause: () => subscription?.pause(), + onResume: () => subscription?.resume(), + onCancel: () { + final cancelFuture = subscription?.cancel(); + subscription = null; + + return cancelFuture == null + ? (resourceCreated ? disposer(resource) : null) + : cancelFuture + .then((_) => resourceCreated ? disposer(resource) : null); + }, + ); + + return controller.stream; + } +} diff --git a/sandbox/reactivex/lib/src/streams/value_stream.dart b/sandbox/reactivex/lib/src/streams/value_stream.dart new file mode 100644 index 0000000..2df9a86 --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/value_stream.dart @@ -0,0 +1,97 @@ +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; +import 'package:angel3_reactivex/src/utils/notification.dart'; + +/// A [Stream] that provides synchronous access to the last emitted value (aka. data event). +abstract class ValueStream implements Stream { + /// Returns the last emitted value, failing if there is no value. + /// See [hasValue] to determine whether [value] has already been set. + /// + /// Throws [ValueStreamError] if this Stream has no value. + /// + /// See also [valueOrNull]. + T get value; + + /// Returns the last emitted value, or `null` if value events haven't yet been emitted. + T? get valueOrNull; + + /// Returns `true` when [value] is available, + /// meaning this Stream has emitted at least one value. + bool get hasValue; + + /// Returns last emitted error, failing if there is no error. + /// See [hasError] to determine whether [error] has already been set. + /// + /// Throws [ValueStreamError] if this Stream has no error. + /// + /// See also [errorOrNull]. + Object get error; + + /// Returns the last emitted error, or `null` if error events haven't yet been emitted. + Object? get errorOrNull; + + /// Returns `true` when [error] is available, + /// meaning this Stream has emitted at least one error. + bool get hasError; + + /// Returns [StackTrace] of the last emitted error. + /// + /// If error events haven't yet been emitted, + /// or the last emitted error didn't have a stack trace, + /// the returned value is `null`. + StackTrace? get stackTrace; + + /// Returns the last emitted event (either data/value or error event). + /// `null` if no value or error events have been emitted yet. + StreamNotification? get lastEventOrNull; +} + +/// Extension methods on [ValueStream] related to [lastEventOrNull]. +extension LastEventValueStreamExtensions on ValueStream { + /// Returns `true` if the last emitted event is a data event (aka. a value event). + bool get isLastEventValue => lastEventOrNull?.isData ?? false; + + /// Returns `true` if the last emitted event is an error event. + bool get isLastEventError => lastEventOrNull?.isError ?? false; +} + +/// Extension method on [ValueStream] to access the last emitted [ErrorAndStackTrace]. +extension ErrorAndStackTraceValueStreamExtension on ValueStream { + /// Returns the last emitted [ErrorAndStackTrace], + /// or `null` if no error events have been emitted yet. + ErrorAndStackTrace? get errorAndStackTraceOrNull { + final error = errorOrNull; + return error == null ? null : ErrorAndStackTrace(error, stackTrace); + } +} + +enum _MissingCase { + value, + error, +} + +/// The error throw by [ValueStream.value] or [ValueStream.error]. +class ValueStreamError extends Error { + final _MissingCase _missingCase; + + ValueStreamError._(this._missingCase); + + /// Construct an [ValueStreamError] thrown by [ValueStream.value] when there is no value. + factory ValueStreamError.hasNoValue() => + ValueStreamError._(_MissingCase.value); + + /// Construct an [ValueStreamError] thrown by [ValueStream.error] when there is no error. + factory ValueStreamError.hasNoError() => + ValueStreamError._(_MissingCase.error); + + @override + String toString() { + switch (_missingCase) { + case _MissingCase.value: + return 'ValueStream has no value. You should check ValueStream.hasValue ' + 'before accessing ValueStream.value, or use ValueStream.valueOrNull instead.'; + case _MissingCase.error: + return 'ValueStream has no error. You should check ValueStream.hasError ' + 'before accessing ValueStream.error, or use ValueStream.errorOrNull instead.'; + } + } +} diff --git a/sandbox/reactivex/lib/src/streams/zip.dart b/sandbox/reactivex/lib/src/streams/zip.dart new file mode 100644 index 0000000..5caf6eb --- /dev/null +++ b/sandbox/reactivex/lib/src/streams/zip.dart @@ -0,0 +1,388 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +/// Merges the specified streams into one stream sequence using the given +/// zipper Function whenever all of the stream sequences have produced +/// an element at a corresponding index. +/// +/// It applies this function in strict sequence, so the first item emitted by +/// the new Stream will be the result of the function applied to the first +/// item emitted by Stream #1 and the first item emitted by Stream #2; +/// the second item emitted by the new ZipStream will be the result of +/// the function applied to the second item emitted by Stream #1 and the +/// second item emitted by Stream #2; and so forth. It will only emit as +/// many items as the number of items emitted by the source Stream that +/// emits the fewest items. +/// +/// If the provided streams is empty, the resulting sequence completes immediately +/// without emitting any items and without any calls to the zipper function. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#zip) +/// +/// ### Basic Example +/// +/// ZipStream( +/// [ +/// Stream.fromIterable(['A']), +/// Stream.fromIterable(['B']), +/// Stream.fromIterable(['C', 'D']), +/// ], +/// (values) => values.join(), +/// ).listen(print); // prints 'ABC' +/// +/// ### Example with a specific number of Streams +/// +/// If you wish to zip a specific number of Streams together with proper types +/// information for the value of each Stream, use the [zip2] - [zip9] operators. +/// +/// ZipStream.zip2( +/// Stream.fromIterable(['A']), +/// Stream.fromIterable(['B', 'C']), +/// (a, b) => a + b, +/// ) +/// .listen(print); // prints 'AB' +class ZipStream extends StreamView { + /// Constructs a [Stream] which merges the specified [streams] into a sequence using the given + /// [zipper] Function, whenever all of the [streams] have produced + /// an element at a corresponding index. + ZipStream( + Iterable> streams, + R Function(List values) zipper, + ) : super(_buildController(streams, zipper).stream); + + /// Constructs a [Stream] which merges the specified [streams] into a [List], + /// containing values that were produced by the [streams] at a corresponding index. + static ZipStream> list(Iterable> streams) { + return ZipStream>( + streams, + (List values) => values, + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip2( + Stream streamOne, + Stream streamTwo, + R Function(A a, B b) zipper, + ) { + return ZipStream( + [streamOne, streamTwo], + (List values) => zipper(values[0] as A, values[1] as B), + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip3( + Stream streamA, + Stream streamB, + Stream streamC, + R Function(A a, B b, C c) zipper, + ) { + return ZipStream( + [streamA, streamB, streamC], + (List values) { + return zipper( + values[0] as A, + values[1] as B, + values[2] as C, + ); + }, + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip4( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + R Function(A a, B b, C c, D d) zipper, + ) { + return ZipStream( + [streamA, streamB, streamC, streamD], + (List values) { + return zipper( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + ); + }, + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip5( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + R Function(A a, B b, C c, D d, E e) zipper, + ) { + return ZipStream( + [streamA, streamB, streamC, streamD, streamE], + (List values) { + return zipper( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + ); + }, + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip6( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + R Function(A a, B b, C c, D d, E e, F f) zipper, + ) { + return ZipStream( + [streamA, streamB, streamC, streamD, streamE, streamF], + (List values) { + return zipper( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + ); + }, + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip7( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + R Function(A a, B b, C c, D d, E e, F f, G g) zipper, + ) { + return ZipStream( + [streamA, streamB, streamC, streamD, streamE, streamF, streamG], + (List values) { + return zipper( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + ); + }, + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip8( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + R Function(A a, B b, C c, D d, E e, F f, G g, H h) zipper, + ) { + return ZipStream( + [streamA, streamB, streamC, streamD, streamE, streamF, streamG, streamH], + (List values) { + return zipper( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + ); + }, + ); + } + + /// Constructs a [Stream] which merges the specified [Stream]s into a sequence using the given + /// [zipper] Function, whenever all of the provided [Stream]s have produced + /// an element at a corresponding index. + static ZipStream zip9( + Stream streamA, + Stream streamB, + Stream streamC, + Stream streamD, + Stream streamE, + Stream streamF, + Stream streamG, + Stream streamH, + Stream streamI, + R Function(A a, B b, C c, D d, E e, F f, G g, H h, I i) zipper, + ) { + return ZipStream( + [ + streamA, + streamB, + streamC, + streamD, + streamE, + streamF, + streamG, + streamH, + streamI + ], + (List values) { + return zipper( + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + values[8] as I, + ); + }, + ); + } + + static StreamController _buildController( + Iterable> streams, + R Function(List values) zipper, + ) { + final controller = StreamController(sync: true); + late List> subscriptions; + var pendingSubscriptions = >[]; + + controller.onListen = () { + Completer? completeCurrent; + late final _Window window; + + // resets variables for the next zip window + void next() { + completeCurrent?.complete(null); + completeCurrent = Completer(); + + pendingSubscriptions = subscriptions.toList(); + } + + void Function(T value) doUpdate(int index) { + return (T value) { + window.onValue(index, value); + + if (window.isComplete) { + // all streams emitted for the current zip index + // dispatch event and reset for next + final R combined; + try { + combined = zipper(window.flush()); + } catch (e, s) { + controller.addError(e, s); + return; + } + controller.add(combined); + + // reset for next zip event + next(); + } else { + // other streams are still pending to get to the next + // zip event index. + // pause this subscription while we await the others + final subscription = subscriptions[index] + ..pause(completeCurrent!.future); + + pendingSubscriptions.remove(subscription); + } + }; + } + + subscriptions = streams + .mapIndexed((index, stream) => stream.listen(doUpdate(index), + onError: controller.addError, onDone: controller.close)) + .toList(growable: false); + if (subscriptions.isEmpty) { + controller.close(); + } else { + window = _Window(subscriptions.length); + next(); + } + }; + controller.onPause = () => pendingSubscriptions.pauseAll(); + controller.onResume = () => pendingSubscriptions.resumeAll(); + controller.onCancel = () => pendingSubscriptions.cancelAll(); + + return controller; + } +} + +/// A window keeps track of the values emitted by the different +/// zipped Streams. +class _Window { + final int size; + final List _values; + + int _valuesReceived = 0; + + bool get isComplete => _valuesReceived == size; + + _Window(this.size) : _values = List.filled(size, null); + + void onValue(int index, T value) { + _values[index] = value; + + _valuesReceived++; + } + + List flush() { + _valuesReceived = 0; + + return List.unmodifiable(_values); + } +} + +/// Extends the Stream class with the ability to zip one Stream with another. +extension ZipWithExtension on Stream { + /// Returns a Stream that combines the current stream together with another + /// stream using a given zipper function. + /// + /// ### Example + /// + /// Stream.fromIterable([1]) + /// .zipWith(Stream.fromIterable([2]), (one, two) => one + two) + /// .listen(print); // prints 3 + Stream zipWith(Stream other, R Function(T t, S s) zipper) { + final stream = ZipStream.zip2(this, other, zipper); + + return isBroadcast + ? stream.asBroadcastStream(onCancel: (s) => s.cancel()) + : stream; + } +} diff --git a/sandbox/reactivex/lib/src/subjects/behavior_subject.dart b/sandbox/reactivex/lib/src/subjects/behavior_subject.dart new file mode 100644 index 0000000..4a9f7d4 --- /dev/null +++ b/sandbox/reactivex/lib/src/subjects/behavior_subject.dart @@ -0,0 +1,275 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/rx.dart'; +import 'package:angel3_reactivex/src/streams/value_stream.dart'; +import 'package:angel3_reactivex/src/subjects/subject.dart'; +import 'package:angel3_reactivex/src/transformers/start_with.dart'; +import 'package:angel3_reactivex/src/transformers/start_with_error.dart'; +import 'package:angel3_reactivex/src/utils/empty.dart'; +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; +import 'package:angel3_reactivex/src/utils/notification.dart'; + +/// A special StreamController that captures the latest item that has been +/// added to the controller, and emits that as the first item to any new +/// listener. +/// +/// This subject allows sending data, error and done events to the listener. +/// The latest item that has been added to the subject will be sent to any +/// new listeners of the subject. After that, any new events will be +/// appropriately sent to the listeners. It is possible to provide a seed value +/// that will be emitted if no items have been added to the subject. +/// +/// BehaviorSubject is, by default, a broadcast (aka hot) controller, in order +/// to fulfill the Rx Subject contract. This means the Subject's `stream` can +/// be listened to multiple times. +/// +/// ### Example +/// +/// final subject = BehaviorSubject(); +/// +/// subject.add(1); +/// subject.add(2); +/// subject.add(3); +/// +/// subject.stream.listen(print); // prints 3 +/// subject.stream.listen(print); // prints 3 +/// subject.stream.listen(print); // prints 3 +/// +/// ### Example with seed value +/// +/// final subject = BehaviorSubject.seeded(1); +/// +/// subject.stream.listen(print); // prints 1 +/// subject.stream.listen(print); // prints 1 +/// subject.stream.listen(print); // prints 1 +class BehaviorSubject extends Subject implements ValueStream { + final _Wrapper _wrapper; + + BehaviorSubject._( + StreamController controller, + Stream stream, + this._wrapper, + ) : super(controller, stream); + + /// Constructs a [BehaviorSubject], optionally pass handlers for + /// [onListen], [onCancel] and a flag to handle events [sync]. + /// + /// See also [StreamController.broadcast] + factory BehaviorSubject({ + void Function()? onListen, + void Function()? onCancel, + bool sync = false, + }) { + // ignore: close_sinks + final controller = StreamController.broadcast( + onListen: onListen, + onCancel: onCancel, + sync: sync, + ); + + final wrapper = _Wrapper(); + + return BehaviorSubject._( + controller, + Rx.defer(_deferStream(wrapper, controller, sync), reusable: true), + wrapper); + } + + /// Constructs a [BehaviorSubject], optionally pass handlers for + /// [onListen], [onCancel] and a flag to handle events [sync]. + /// + /// [seedValue] becomes the current [value] and is emitted immediately. + /// + /// See also [StreamController.broadcast] + factory BehaviorSubject.seeded( + T seedValue, { + void Function()? onListen, + void Function()? onCancel, + bool sync = false, + }) { + // ignore: close_sinks + final controller = StreamController.broadcast( + onListen: onListen, + onCancel: onCancel, + sync: sync, + ); + + final wrapper = _Wrapper.seeded(seedValue); + + return BehaviorSubject._( + controller, + Rx.defer(_deferStream(wrapper, controller, sync), reusable: true), + wrapper, + ); + } + + static Stream Function() _deferStream( + _Wrapper wrapper, StreamController controller, bool sync) => + () { + final errorAndStackTrace = wrapper.errorAndStackTrace; + if (errorAndStackTrace != null && !wrapper.isValue) { + return controller.stream.transform( + StartWithErrorStreamTransformer( + errorAndStackTrace.error, + errorAndStackTrace.stackTrace, + ), + ); + } + + final value = wrapper.value; + if (isNotEmpty(value) && wrapper.isValue) { + return controller.stream + .transform(StartWithStreamTransformer(value as T)); + } + + return controller.stream; + }; + + @override + void onAdd(T event) => _wrapper.setValue(event); + + @override + void onAddError(Object error, [StackTrace? stackTrace]) => + _wrapper.setError(error, stackTrace); + + @override + ValueStream get stream => _BehaviorSubjectStream(this); + + @override + bool get hasValue => isNotEmpty(_wrapper.value); + + @override + T get value { + final value = _wrapper.value; + if (isNotEmpty(value)) { + return value as T; + } + throw ValueStreamError.hasNoValue(); + } + + @override + T? get valueOrNull => unbox(_wrapper.value); + + /// Set and emit the new value. + set value(T newValue) => add(newValue); + + @override + bool get hasError => _wrapper.errorAndStackTrace != null; + + @override + Object? get errorOrNull => _wrapper.errorAndStackTrace?.error; + + @override + Object get error { + final errorAndSt = _wrapper.errorAndStackTrace; + if (errorAndSt != null) { + return errorAndSt.error; + } + throw ValueStreamError.hasNoError(); + } + + @override + StackTrace? get stackTrace => _wrapper.errorAndStackTrace?.stackTrace; + + @override + StreamNotification? get lastEventOrNull { + // data event + if (_wrapper.isValue) { + return StreamNotification.data(_wrapper.value as T); + } + + // error event + final errorAndSt = _wrapper.errorAndStackTrace; + if (errorAndSt != null) { + return ErrorNotification(errorAndSt); + } + + // no event + return null; + } +} + +class _Wrapper { + var isValue = false; + var value = EMPTY; + ErrorAndStackTrace? errorAndStackTrace; + + /// Non-seeded constructor + _Wrapper() : isValue = false; + + _Wrapper.seeded(T v) { + setValue(v); + } + + void setValue(T event) { + value = event; + isValue = true; + } + + void setError(Object error, StackTrace? stackTrace) { + errorAndStackTrace = ErrorAndStackTrace(error, stackTrace); + isValue = false; + } +} + +class _BehaviorSubjectStream extends Stream implements ValueStream { + final BehaviorSubject _subject; + + _BehaviorSubjectStream(this._subject); + + @override + bool get isBroadcast => true; + + // Override == and hashCode so that new streams returned by the same + // subject are considered equal. + // The subject returns a new stream each time it's queried, + // but doesn't have to cache the result. + + @override + int get hashCode => _subject.hashCode ^ 0x35323532; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is _BehaviorSubjectStream && + identical(other._subject, _subject); + } + + @override + StreamSubscription listen( + void Function(T event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) => + _subject.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + + @override + Object get error => _subject.error; + + @override + Object? get errorOrNull => _subject.errorOrNull; + + @override + bool get hasError => _subject.hasError; + + @override + bool get hasValue => _subject.hasValue; + + @override + StackTrace? get stackTrace => _subject.stackTrace; + + @override + T get value => _subject.value; + + @override + T? get valueOrNull => _subject.valueOrNull; + + @override + StreamNotification? get lastEventOrNull => _subject.lastEventOrNull; +} diff --git a/sandbox/reactivex/lib/src/subjects/publish_subject.dart b/sandbox/reactivex/lib/src/subjects/publish_subject.dart new file mode 100644 index 0000000..35bbc6d --- /dev/null +++ b/sandbox/reactivex/lib/src/subjects/publish_subject.dart @@ -0,0 +1,51 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/subjects/subject.dart'; + +/// Exactly like a normal broadcast StreamController with one exception: +/// this class is both a Stream and Sink. +/// +/// This Subject allows sending data, error and done events to the listener. +/// +/// PublishSubject is, by default, a broadcast (aka hot) controller, in order +/// to fulfill the Rx Subject contract. This means the Subject's `stream` can +/// be listened to multiple times. +/// +/// ### Example +/// +/// final subject = PublishSubject(); +/// +/// // observer1 will receive all data and done events +/// subject.stream.listen(observer1); +/// subject.add(1); +/// subject.add(2); +/// +/// // observer2 will only receive 3 and done event +/// subject.stream.listen(observer2); +/// subject.add(3); +/// subject.close(); +class PublishSubject extends Subject { + PublishSubject._(StreamController controller, Stream stream) + : super(controller, stream); + + /// Constructs a [PublishSubject], optionally pass handlers for + /// [onListen], [onCancel] and a flag to handle events [sync]. + /// + /// See also [StreamController.broadcast] + factory PublishSubject( + {void Function()? onListen, + void Function()? onCancel, + bool sync = false}) { + // ignore: close_sinks + final controller = StreamController.broadcast( + onListen: onListen, + onCancel: onCancel, + sync: sync, + ); + + return PublishSubject._( + controller, + controller.stream, + ); + } +} diff --git a/sandbox/reactivex/lib/src/subjects/replay_subject.dart b/sandbox/reactivex/lib/src/subjects/replay_subject.dart new file mode 100644 index 0000000..5181a07 --- /dev/null +++ b/sandbox/reactivex/lib/src/subjects/replay_subject.dart @@ -0,0 +1,204 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:angel3_reactivex/src/rx.dart'; +import 'package:angel3_reactivex/src/streams/replay_stream.dart'; +import 'package:angel3_reactivex/src/subjects/subject.dart'; +import 'package:angel3_reactivex/src/transformers/start_with.dart'; +import 'package:angel3_reactivex/src/transformers/start_with_error.dart'; +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/empty.dart'; +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; + +/// A special StreamController that captures all of the items that have been +/// added to the controller, and emits those as the first items to any new +/// listener. +/// +/// This subject allows sending data, error and done events to the listener. +/// As items are added to the subject, the ReplaySubject will store them. +/// When the stream is listened to, those recorded items will be emitted to +/// the listener. After that, any new events will be appropriately sent to the +/// listeners. It is possible to cap the number of stored events by setting +/// a maxSize value. +/// +/// ReplaySubject is, by default, a broadcast (aka hot) controller, in order +/// to fulfill the Rx Subject contract. This means the Subject's `stream` can +/// be listened to multiple times. +/// +/// ### Example +/// +/// final subject = ReplaySubject(); +/// +/// subject.add(1); +/// subject.add(2); +/// subject.add(3); +/// +/// subject.stream.listen(print); // prints 1, 2, 3 +/// subject.stream.listen(print); // prints 1, 2, 3 +/// subject.stream.listen(print); // prints 1, 2, 3 +/// +/// ### Example with maxSize +/// +/// final subject = ReplaySubject(maxSize: 2); +/// +/// subject.add(1); +/// subject.add(2); +/// subject.add(3); +/// +/// subject.stream.listen(print); // prints 2, 3 +/// subject.stream.listen(print); // prints 2, 3 +/// subject.stream.listen(print); // prints 2, 3 +class ReplaySubject extends Subject implements ReplayStream { + final Queue<_Event> _queue; + final int? _maxSize; + + /// Constructs a [ReplaySubject], optionally pass handlers for + /// [onListen], [onCancel] and a flag to handle events [sync]. + /// + /// See also [StreamController.broadcast] + factory ReplaySubject({ + int? maxSize, + void Function()? onListen, + void Function()? onCancel, + bool sync = false, + }) { + // ignore: close_sinks + final controller = StreamController.broadcast( + onListen: onListen, + onCancel: onCancel, + sync: sync, + ); + + final queue = Queue<_Event>(); + + return ReplaySubject._( + controller, + Rx.defer( + () => queue.toList(growable: false).reversed.fold( + controller.stream, + (stream, event) { + final errorAndStackTrace = event.errorAndStackTrace; + + if (errorAndStackTrace != null) { + return stream.transform( + StartWithErrorStreamTransformer( + errorAndStackTrace.error, + errorAndStackTrace.stackTrace, + ), + ); + } else { + return stream + .transform(StartWithStreamTransformer(event.data as T)); + } + }, + ), + reusable: true, + ), + queue, + maxSize, + ); + } + + ReplaySubject._( + StreamController controller, + Stream stream, + this._queue, + this._maxSize, + ) : super(controller, stream); + + @override + void onAdd(T event) { + if (_queue.length == _maxSize) { + _queue.removeFirst(); + } + + _queue.add(_Event.data(event)); + } + + @override + void onAddError(Object error, [StackTrace? stackTrace]) { + if (_queue.length == _maxSize) { + _queue.removeFirst(); + } + + _queue.add(_Event.error(ErrorAndStackTrace(error, stackTrace))); + } + + @override + List get values => _queue + .where((event) => event.errorAndStackTrace == null) + .map((event) => event.data as T) + .toList(growable: false); + + @override + List get errors => _queue + .mapNotNull((event) => event.errorAndStackTrace?.error) + .toList(growable: false); + + @override + List get stackTraces => _queue + .mapNotNull((event) => event.errorAndStackTrace) + .map((errorAndStackTrace) => errorAndStackTrace.stackTrace) + .toList(growable: false); + + @override + ReplayStream get stream => _ReplaySubjectStream(this); +} + +class _Event { + final Object? data; + final ErrorAndStackTrace? errorAndStackTrace; + + _Event._({required this.data, required this.errorAndStackTrace}); + + factory _Event.data(T data) => _Event._(data: data, errorAndStackTrace: null); + + factory _Event.error(ErrorAndStackTrace e) => + _Event._(errorAndStackTrace: e, data: EMPTY); +} + +class _ReplaySubjectStream extends Stream implements ReplayStream { + final ReplaySubject _subject; + + _ReplaySubjectStream(this._subject); + + @override + bool get isBroadcast => true; + + @override + List get values => _subject.values; + + @override + List get errors => _subject.errors; + + @override + List get stackTraces => _subject.stackTraces; + + // Override == and hashCode so that new streams returned by the same + // subject are considered equal. + // The subject returns a new stream each time it's queried, + // but doesn't have to cache the result. + + @override + int get hashCode => _subject.hashCode ^ 0x35323532; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is _ReplaySubjectStream && identical(other._subject, _subject); + } + + @override + StreamSubscription listen( + void Function(T event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) => + _subject.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); +} diff --git a/sandbox/reactivex/lib/src/subjects/subject.dart b/sandbox/reactivex/lib/src/subjects/subject.dart new file mode 100644 index 0000000..746188d --- /dev/null +++ b/sandbox/reactivex/lib/src/subjects/subject.dart @@ -0,0 +1,231 @@ +import 'dart:async'; + +/// The base for all Subjects. If you'd like to create a new Subject, +/// extend from this class. +/// +/// It handles all of the nitty-gritty details that conform to the +/// StreamController spec and don't need to be repeated over and +/// over. +/// +/// Please see `PublishSubject` for the simplest example of how to +/// extend from this class, or `BehaviorSubject` for a slightly more +/// complex example. +abstract class Subject extends StreamView implements StreamController { + final StreamController _controller; + + bool _isAddingStreamItems = false; + + /// Constructs a [Subject] which wraps the provided [controller]. + /// This constructor is applicable only for classes that extend [Subject]. + /// + /// To guarantee the contract of a [Subject], the [controller] must be + /// a broadcast [StreamController] and the [stream] must also be a broadcast [Stream]. + Subject(StreamController controller, Stream stream) + : _controller = controller, + assert(stream.isBroadcast, 'Subject requires a broadcast stream'), + super(stream); + + @override + StreamSink get sink => _StreamSinkWrapper(this); + + @override + ControllerCallback? get onListen => _controller.onListen; + + @override + set onListen(void Function()? onListenHandler) { + _controller.onListen = onListenHandler; + } + + @override + Stream get stream => _SubjectStream(this); + + @override + ControllerCallback get onPause => + throw UnsupportedError('Subjects do not support pause callbacks'); + + @override + set onPause(void Function()? onPauseHandler) => + throw UnsupportedError('Subjects do not support pause callbacks'); + + @override + ControllerCallback get onResume => + throw UnsupportedError('Subjects do not support resume callbacks'); + + @override + set onResume(void Function()? onResumeHandler) => + throw UnsupportedError('Subjects do not support resume callbacks'); + + @override + ControllerCancelCallback? get onCancel => _controller.onCancel; + + @override + set onCancel(ControllerCancelCallback? onCancelHandler) { + _controller.onCancel = onCancelHandler; + } + + @override + bool get isClosed => _controller.isClosed; + + @override + bool get isPaused => _controller.isPaused; + + @override + bool get hasListener => _controller.hasListener; + + @override + Future get done => _controller.done; + + @override + void addError(Object error, [StackTrace? stackTrace]) { + if (_isAddingStreamItems) { + throw StateError( + 'You cannot add an error while items are being added from addStream'); + } + + _addError(error, stackTrace); + } + + void _addError(Object error, [StackTrace? stackTrace]) { + if (!_controller.isClosed) { + onAddError(error, stackTrace); + } + + // if the controller is closed, calling addError() will throw an StateError. + // that is expected behavior. + _controller.addError(error, stackTrace); + } + + /// An extension point for sub-classes. Perform any side-effect / state + /// management you need to here, rather than overriding the `add` method + /// directly. + void onAddError(Object error, [StackTrace? stackTrace]) {} + + @override + Future addStream(Stream source, {bool? cancelOnError}) { + if (_isAddingStreamItems) { + throw StateError( + 'You cannot add items while items are being added from addStream'); + } + _isAddingStreamItems = true; + + final completer = Completer(); + void complete() { + if (!completer.isCompleted) { + _isAddingStreamItems = false; + completer.complete(); + } + } + + source.listen( + _add, + onError: identical(cancelOnError, true) + ? (Object e, StackTrace s) { + _addError(e, s); + complete(); + } + : _addError, + onDone: complete, + cancelOnError: cancelOnError, + ); + + return completer.future; + } + + @override + void add(T event) { + if (_isAddingStreamItems) { + throw StateError( + 'You cannot add items while items are being added from addStream'); + } + + _add(event); + } + + void _add(T event) { + if (!_controller.isClosed) { + onAdd(event); + } + + // if the controller is closed, calling add() will throw an StateError. + // that is expected behavior. + _controller.add(event); + } + + /// An extension point for sub-classes. Perform any side-effect / state + /// management you need to here, rather than overriding the `add` method + /// directly. + void onAdd(T event) {} + + @override + Future close() { + if (_isAddingStreamItems) { + throw StateError( + 'You cannot close the subject while items are being added from addStream'); + } + + return _controller.close(); + } +} + +class _SubjectStream extends Stream { + final Subject _subject; + + _SubjectStream(this._subject); + + @override + bool get isBroadcast => true; + + // Override == and hashCode so that new streams returned by the same + // subject are considered equal. + // The subject returns a new stream each time it's queried, + // but doesn't have to cache the result. + + @override + int get hashCode => _subject.hashCode ^ 0x35323532; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is _SubjectStream && identical(other._subject, _subject); + } + + @override + StreamSubscription listen( + void Function(T event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) => + _subject.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); +} + +/// A class that exposes only the [StreamSink] interface of an object. +class _StreamSinkWrapper implements StreamSink { + final StreamController _target; + + _StreamSinkWrapper(this._target); + + @override + void add(T data) { + _target.add(data); + } + + @override + void addError(Object error, [StackTrace? stackTrace]) { + _target.addError(error, stackTrace); + } + + @override + Future close() => _target.close(); + + @override + Future addStream(Stream source) => _target.addStream(source); + + @override + Future get done => _target.done; +} diff --git a/sandbox/reactivex/lib/src/transformers/backpressure/backpressure.dart b/sandbox/reactivex/lib/src/transformers/backpressure/backpressure.dart new file mode 100644 index 0000000..c4a544c --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/backpressure/backpressure.dart @@ -0,0 +1,357 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +/// The strategy that is used to determine how and when a new window is created. +enum WindowStrategy { + /// cancels the open window (if any) and immediately opens a fresh one. + everyEvent, + + /// waits until the current open window completes, then when the + /// source [Stream] emits a next event, it opens a new window. + eventAfterLastWindow, + + /// opens a recurring window right after the very first event on + /// the source [Stream] is emitted. + firstEventOnly, + + /// does not open any windows, rather all events are buffered and emitted + /// whenever the handler triggers, after this trigger, the buffer is cleared. + onHandler +} + +class _BackpressureStreamSink extends ForwardingSink { + final WindowStrategy _strategy; + final Stream Function(S event)? _windowStreamFactory; + final T Function(S event)? _onWindowStart; + final T Function(List queue)? _onWindowEnd; + final int _startBufferEvery; + final bool Function(List queue)? _closeWindowWhen; + final bool _ignoreEmptyWindows; + final bool _dispatchOnClose; + final Queue queue = DoubleLinkedQueue(); + final int? maxLengthQueue; + var skip = 0; + var _hasData = false; + var _mainClosed = false; + StreamSubscription? _windowSubscription; + + _BackpressureStreamSink( + this._strategy, + this._windowStreamFactory, + this._onWindowStart, + this._onWindowEnd, + this._startBufferEvery, + this._closeWindowWhen, + this._ignoreEmptyWindows, + this._dispatchOnClose, + this.maxLengthQueue, + ); + + @override + void onData(S data) { + _hasData = true; + maybeCreateWindow(data, sink); + + if (skip == 0) { + queue.add(data); + + if (maxLengthQueue != null && queue.length > maxLengthQueue!) { + queue.removeFirstElements(queue.length - maxLengthQueue!); + } + } + + if (skip > 0) { + skip--; + } + + maybeCloseWindow(sink); + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + _mainClosed = true; + + if (_strategy == WindowStrategy.eventAfterLastWindow) { + return; + } + + // treat the final event as a Window that opens + // and immediately closes again + if (_dispatchOnClose && queue.isNotEmpty) { + resolveWindowStart(queue.last, sink); + } + + resolveWindowEnd(sink, true); + + queue.clear(); + + _windowSubscription?.cancel(); + sink.close(); + } + + @override + FutureOr onCancel() => _windowSubscription?.cancel(); + + @override + void onListen() {} + + @override + void onPause() => _windowSubscription?.pause(); + + @override + void onResume() => _windowSubscription?.resume(); + + void maybeCreateWindow(S event, EventSink sink) { + switch (_strategy) { + // for example throttle + case WindowStrategy.eventAfterLastWindow: + if (_windowSubscription != null) return; + + _windowSubscription = singleWindow(event, sink); + + resolveWindowStart(event, sink); + + break; + // for example scan + case WindowStrategy.firstEventOnly: + if (_windowSubscription != null) return; + + _windowSubscription = multiWindow(event, sink); + + resolveWindowStart(event, sink); + + break; + // for example debounce + case WindowStrategy.everyEvent: + _windowSubscription?.cancel(); + + _windowSubscription = singleWindow(event, sink); + + resolveWindowStart(event, sink); + + break; + case WindowStrategy.onHandler: + break; + } + } + + void maybeCloseWindow(EventSink sink) { + if (_closeWindowWhen != null && _closeWindowWhen!(unmodifiableQueue)) { + resolveWindowEnd(sink); + } + } + + StreamSubscription singleWindow(S event, EventSink sink) => + buildStream(event, sink).take(1).listen( + null, + onError: sink.addError, + onDone: () => resolveWindowEnd(sink, _mainClosed), + ); + + // opens a new Window which is kept open until the main Stream + // closes. + StreamSubscription multiWindow(S event, EventSink sink) => + buildStream(event, sink).listen( + (dynamic _) => resolveWindowEnd(sink), + onError: sink.addError, + onDone: () => resolveWindowEnd(sink), + ); + + Stream buildStream(S event, EventSink sink) { + Stream stream; + + _windowSubscription?.cancel(); + + stream = _windowStreamFactory!(event); + + return stream; + } + + void resolveWindowStart(S event, EventSink sink) { + if (_onWindowStart != null) { + sink.add(_onWindowStart!(event)); + } + } + + void resolveWindowEnd(EventSink sink, [bool isControllerClosing = false]) { + if (isControllerClosing && + _strategy == WindowStrategy.eventAfterLastWindow) { + if (_dispatchOnClose && + _hasData && + queue.length > 1 && + _onWindowEnd != null) { + sink.add(_onWindowEnd!(unmodifiableQueue)); + } + + queue.clear(); + _windowSubscription?.cancel(); + _windowSubscription = null; + + sink.close(); + return; + } + + if (isControllerClosing || + _strategy == WindowStrategy.eventAfterLastWindow || + _strategy == WindowStrategy.everyEvent) { + _windowSubscription?.cancel(); + _windowSubscription = null; + } + + if (isControllerClosing && !_dispatchOnClose) { + return; + } + + if (_hasData && (queue.isNotEmpty || !_ignoreEmptyWindows)) { + if (_onWindowEnd != null) { + sink.add(_onWindowEnd!(unmodifiableQueue)); + } + + // prepare the buffer for the next window. + // by default, this is just a cleared buffer + if (!isControllerClosing && _startBufferEvery > 0) { + skip = _startBufferEvery > queue.length + ? _startBufferEvery - queue.length + : 0; + + // ...unless startBufferEvery is provided. + // here we backtrack to the first event of the last buffer + // and count forward using startBufferEvery until we reach + // the next event. + // + // if the next event is found inside the current buffer, + // then this event and any later events in the buffer + // become the starting values of the next buffer. + // if the next event is not yet available, then a skip + // count is calculated. + // this count will skip the next Future n-events. + // when skip is reset to 0, then we start adding events + // again into the new buffer. + // + // example: + // startBufferEvery = 2 + // last buffer: [0, 1, 2, 3, 4] + // 0 is the first event, + // 2 is the n-th event + // new buffer starts with [2, 3, 4] + // + // example: + // startBufferEvery = 3 + // last buffer: [0, 1] + // 0 is the first event, + // the n-the event is not yet dispatched at this point + // skip becomes 1 + // event 2 is skipped, skip becomes 0 + // event 3 is now added to the buffer + if (_startBufferEvery < queue.length) { + queue.removeFirstElements(_startBufferEvery); + } else { + queue.clear(); + } + } else { + queue.clear(); + } + } + } + + List get unmodifiableQueue => List.unmodifiable(queue); +} + +/// A highly customizable [StreamTransformer] which can be configured +/// to serve any of the common rx backpressure operators. +/// +/// The [StreamTransformer] works by creating windows, during which it +/// buffers events to a [Queue]. +/// +/// The [StreamTransformer] works by creating windows, during which it +/// buffers events to a [Queue]. It uses a [WindowStrategy] to determine +/// how and when a new window is created. +/// +/// onWindowStart and onWindowEnd are handlers that fire when a window +/// opens and closes, right before emitting the transformed event. +/// +/// startBufferEvery allows to skip events coming from the source [Stream]. +/// +/// ignoreEmptyWindows can be set to true, to allow events to be emitted +/// at the end of a window, even if the current buffer is empty. +/// If the buffer is empty, then an empty [List] will be emitted. +/// If false, then nothing is emitted on an empty buffer. +/// +/// dispatchOnClose will cause the remaining values in the buffer to be +/// emitted when the source [Stream] closes. +/// When false, the remaining buffer is discarded on close. +class BackpressureStreamTransformer extends StreamTransformerBase { + /// Determines how the window is created + final WindowStrategy strategy; + + /// Factory method used to create the [Stream] which will be buffered + final Stream Function(S event)? windowStreamFactory; + + /// Handler which fires when the window opens + final T Function(S event)? onWindowStart; + + /// Handler which fires when the window closes + final T Function(List queue)? onWindowEnd; + + /// Maximum length of the buffer. + /// Specify this value to avoid running out of memory when adding too many events to the buffer. + /// If it's `null`, maximum length of the buffer is unlimited. + final int? maxLengthQueue; + + /// Used to skip an amount of events + final int startBufferEvery; + + /// Predicate which determines when the current window should close + final bool Function(List queue)? closeWindowWhen; + + /// Toggle to prevent, or allow windows that contain + /// no events to be dispatched + final bool ignoreEmptyWindows; + + /// Toggle to prevent, or allow the final set of events to be dispatched + /// when the source [Stream] closes + final bool dispatchOnClose; + + /// Constructs a [StreamTransformer] which buffers events emitted by the + /// [Stream] that is created by [windowStreamFactory]. + /// + /// Use the various optional parameters to precisely determine how and when + /// this buffer should be created. + /// + /// For more info on the parameters, see [BackpressureStreamTransformer], + /// or see the various back pressure [StreamTransformer]s for examples. + BackpressureStreamTransformer( + this.strategy, + this.windowStreamFactory, { + this.onWindowStart, + this.onWindowEnd, + this.startBufferEvery = 0, + this.closeWindowWhen, + this.ignoreEmptyWindows = true, + this.dispatchOnClose = true, + this.maxLengthQueue, + }); + + @override + Stream bind(Stream stream) => forwardStream( + stream, + () => _BackpressureStreamSink( + strategy, + windowStreamFactory, + onWindowStart, + onWindowEnd, + startBufferEvery, + closeWindowWhen, + ignoreEmptyWindows, + dispatchOnClose, + maxLengthQueue, + ), + ); +} diff --git a/sandbox/reactivex/lib/src/transformers/backpressure/buffer.dart b/sandbox/reactivex/lib/src/transformers/backpressure/buffer.dart new file mode 100644 index 0000000..1b6044b --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/backpressure/buffer.dart @@ -0,0 +1,149 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/transformers/backpressure/backpressure.dart'; + +/// Creates a [Stream] where each item is a [List] containing the items +/// from the source sequence. +/// +/// This [List] is emitted every time the window [Stream] +/// emits an event. +/// +/// ### Example +/// +/// Stream.periodic(const Duration(milliseconds: 100), (i) => i) +/// .buffer(Stream.periodic(const Duration(milliseconds: 160), (i) => i)) +/// .listen(print); // prints [0, 1] [2, 3] [4, 5] ... +class BufferStreamTransformer + extends BackpressureStreamTransformer> { + /// Constructs a [StreamTransformer] which buffers events into a [List] and + /// emits this [List] whenever [window] fires an event. + /// + /// The [List] is cleared upon every [window] event. + BufferStreamTransformer(Stream Function(T event) window) + : super(WindowStrategy.firstEventOnly, window, + onWindowEnd: (queue) => queue, ignoreEmptyWindows: false); +} + +/// Buffers a number of values from the source Stream by count then +/// emits the buffer and clears it, and starts a new buffer each +/// startBufferEvery values. If startBufferEvery is not provided, +/// then new buffers are started immediately at the start of the source +/// and when each buffer closes and is emitted. +/// +/// ### Example +/// count is the maximum size of the buffer emitted +/// +/// Rx.range(1, 4) +/// .bufferCount(2) +/// .listen(print); // prints [1, 2], [3, 4] done! +/// +/// ### Example +/// if startBufferEvery is 2, then a new buffer will be started +/// on every other value from the source. A new buffer is started at the +/// beginning of the source by default. +/// +/// Rx.range(1, 5) +/// .bufferCount(3, 2) +/// .listen(print); // prints [1, 2, 3], [3, 4, 5], [5] done! +class BufferCountStreamTransformer + extends BackpressureStreamTransformer> { + /// Constructs a [StreamTransformer] which buffers events into a [List] and + /// emits this [List] whenever its length is equal to [count]. + /// + /// A new buffer is created for every n-th event emitted + /// by the [Stream] that is being transformed, as specified by + /// the [startBufferEvery] parameter. + /// + /// If [startBufferEvery] is omitted or equals 0, then a new buffer is started whenever + /// the previous one reaches a length of [count]. + BufferCountStreamTransformer(int count, [int startBufferEvery = 0]) + : super(WindowStrategy.onHandler, null, + onWindowEnd: (queue) => queue, + startBufferEvery: startBufferEvery, + closeWindowWhen: (queue) => queue.length == count) { + if (count < 1) throw ArgumentError.value(count, 'count'); + if (startBufferEvery < 0) { + throw ArgumentError.value(startBufferEvery, 'startBufferEvery'); + } + } +} + +/// Creates a [Stream] where each item is a [List] containing the items +/// from the source sequence, batched whenever test passes. +/// +/// ### Example +/// +/// Stream.periodic(const Duration(milliseconds: 100), (int i) => i) +/// .bufferTest((i) => i % 2 == 0) +/// .listen(print); // prints [0], [1, 2] [3, 4] [5, 6] ... +class BufferTestStreamTransformer + extends BackpressureStreamTransformer> { + /// Constructs a [StreamTransformer] which buffers events into a [List] and + /// emits this [List] whenever the [test] Function yields true. + BufferTestStreamTransformer(bool Function(T value) test) + : super(WindowStrategy.onHandler, null, + onWindowEnd: (queue) => queue, + closeWindowWhen: (queue) => test(queue.last)); +} + +/// Extends the Stream class with the ability to buffer events in various ways +extension BufferExtensions on Stream { + /// Creates a Stream where each item is a [List] containing the items + /// from the source sequence. + /// + /// This [List] is emitted every time [window] emits an event. + /// + /// ### Example + /// + /// Stream.periodic(Duration(milliseconds: 100), (i) => i) + /// .buffer(Stream.periodic(Duration(milliseconds: 160), (i) => i)) + /// .listen(print); // prints [0, 1] [2, 3] [4, 5] ... + Stream> buffer(Stream window) => + BufferStreamTransformer((_) => window).bind(this); + + /// Buffers a number of values from the source Stream by [count] then + /// emits the buffer and clears it, and starts a new buffer each + /// [startBufferEvery] values. If [startBufferEvery] is not provided, + /// then new buffers are started immediately at the start of the source + /// and when each buffer closes and is emitted. + /// + /// ### Example + /// [count] is the maximum size of the buffer emitted + /// + /// RangeStream(1, 4) + /// .bufferCount(2) + /// .listen(print); // prints [1, 2], [3, 4] done! + /// + /// ### Example + /// if [startBufferEvery] is 2, then a new buffer will be started + /// on every other value from the source. A new buffer is started at the + /// beginning of the source by default. + /// + /// RangeStream(1, 5) + /// .bufferCount(3, 2) + /// .listen(print); // prints [1, 2, 3], [3, 4, 5], [5] done! + Stream> bufferCount(int count, [int startBufferEvery = 0]) => + BufferCountStreamTransformer(count, startBufferEvery).bind(this); + + /// Creates a Stream where each item is a [List] containing the items + /// from the source sequence, batched whenever test passes. + /// + /// ### Example + /// + /// Stream.periodic(Duration(milliseconds: 100), (int i) => i) + /// .bufferTest((i) => i % 2 == 0) + /// .listen(print); // prints [0], [1, 2] [3, 4] [5, 6] ... + Stream> bufferTest(bool Function(T event) onTestHandler) => + BufferTestStreamTransformer(onTestHandler).bind(this); + + /// Creates a Stream where each item is a [List] containing the items + /// from the source sequence, sampled on a time frame with [duration]. + /// + /// ### Example + /// + /// Stream.periodic(Duration(milliseconds: 100), (int i) => i) + /// .bufferTime(Duration(milliseconds: 220)) + /// .listen(print); // prints [0, 1] [2, 3] [4, 5] ... + Stream> bufferTime(Duration duration) => + buffer(Stream.periodic(duration)); +} diff --git a/sandbox/reactivex/lib/src/transformers/backpressure/debounce.dart b/sandbox/reactivex/lib/src/transformers/backpressure/debounce.dart new file mode 100644 index 0000000..b9e9a9e --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/backpressure/debounce.dart @@ -0,0 +1,85 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/streams/timer.dart'; +import 'package:angel3_reactivex/src/transformers/backpressure/backpressure.dart'; + +/// Transforms a [Stream] so that will only emit items from the source sequence +/// if a window has completed, without the source sequence emitting +/// another item. +/// +/// This window is created after the last debounced event was emitted. +/// You can use the value of the last debounced event to determine +/// the length of the next window. +/// +/// A window is open until the first window event emits. +/// +/// The debounce [StreamTransformer] filters out items emitted by the source +/// Stream that are rapidly followed by another emitted item. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#debounce) +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3, 4]) +/// .debounceTime(Duration(seconds: 1)) +/// .listen(print); // prints 4 +class DebounceStreamTransformer extends BackpressureStreamTransformer { + /// Constructs a [StreamTransformer] which will only emit items from the source sequence + /// if a window has completed, without the source sequence emitting. + /// + /// The [window] is reset whenever the [Stream] that is being transformed + /// emits an event. + DebounceStreamTransformer(Stream Function(T event) window) + : super( + WindowStrategy.everyEvent, + window, + onWindowEnd: (queue) => queue.last, + maxLengthQueue: 1, + ); +} + +/// Extends the Stream class with the ability to debounce events in various ways +extension DebounceExtensions on Stream { + /// Transforms a [Stream] so that will only emit items from the source sequence + /// if a [window] has completed, without the source sequence emitting + /// another item. + /// + /// This [window] is created after the last debounced event was emitted. + /// You can use the value of the last debounced event to determine + /// the length of the next [window]. + /// + /// A [window] is open until the first [window] event emits. + /// + /// debounce filters out items emitted by the source [Stream] + /// that are rapidly followed by another emitted item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#debounce) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3, 4]) + /// .debounce((_) => TimerStream(true, Duration(seconds: 1))) + /// .listen(print); // prints 4 + Stream debounce(Stream Function(T event) window) => + DebounceStreamTransformer(window).bind(this); + + /// Transforms a [Stream] so that will only emit items from the source + /// sequence whenever the time span defined by [duration] passes, without the + /// source sequence emitting another item. + /// + /// This time span start after the last debounced event was emitted. + /// + /// debounceTime filters out items emitted by the source [Stream] that are + /// rapidly followed by another emitted item. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#debounceTime) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3, 4]) + /// .debounceTime(Duration(seconds: 1)) + /// .listen(print); // prints 4 + Stream debounceTime(Duration duration) => + DebounceStreamTransformer((_) => TimerStream(null, duration)) + .bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/backpressure/pairwise.dart b/sandbox/reactivex/lib/src/transformers/backpressure/pairwise.dart new file mode 100644 index 0000000..fa2320e --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/backpressure/pairwise.dart @@ -0,0 +1,35 @@ +import 'package:angel3_reactivex/src/streams/never.dart'; +import 'package:angel3_reactivex/src/transformers/backpressure/backpressure.dart'; + +/// Emits the n-th and n-1th events as a pair. +/// The first event won't be emitted until the second one arrives. +/// +/// ### Example +/// +/// Rx.range(1, 4) +/// .pairwise() +/// .listen(print); // prints [1, 2], [2, 3], [3, 4] +class PairwiseStreamTransformer + extends BackpressureStreamTransformer> { + /// Constructs a [StreamTransformer] which buffers events into pairs as a [List]. + PairwiseStreamTransformer() + : super(WindowStrategy.firstEventOnly, (_) => NeverStream(), + onWindowEnd: (queue) => queue, + startBufferEvery: 1, + closeWindowWhen: (queue) => queue.length == 2, + dispatchOnClose: false); +} + +/// Extends the Stream class with the ability to emit the nth and n-1th events +/// as a pair +extension PairwiseExtension on Stream { + /// Emits the n-th and n-1th events as a pair. + /// The first event won't be emitted until the second one arrives. + /// + /// ### Example + /// + /// RangeStream(1, 4) + /// .pairwise() + /// .listen(print); // prints [1, 2], [2, 3], [3, 4] + Stream> pairwise() => PairwiseStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/backpressure/sample.dart b/sandbox/reactivex/lib/src/transformers/backpressure/sample.dart new file mode 100644 index 0000000..b2c5545 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/backpressure/sample.dart @@ -0,0 +1,50 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/transformers/backpressure/backpressure.dart'; + +/// A [StreamTransformer] that, when the specified window [Stream] emits +/// an item or completes, emits the most recently emitted item (if any) +/// emitted by the source [Stream] since the previous emission from +/// the sample [Stream]. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3]) +/// .transform(SampleStreamTransformer(TimerStream(1, const Duration(seconds: 1))) +/// .listen(print); // prints 3 +class SampleStreamTransformer extends BackpressureStreamTransformer { + /// Constructs a [StreamTransformer] that, when the specified [window] emits + /// an item or completes, emits the most recently emitted item (if any) + /// emitted by the source [Stream] since the previous emission from + /// the sample [Stream]. + SampleStreamTransformer(Stream Function(T event) window) + : super(WindowStrategy.firstEventOnly, window, + onWindowEnd: (queue) => queue.last); +} + +/// Extends the Stream class with the ability to sample events from the Stream +extension SampleExtensions on Stream { + /// Emits the most recently emitted item (if any) + /// emitted by the source [Stream] since the previous emission from + /// the [sampleStream]. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .sample(TimerStream(1, Duration(seconds: 1))) + /// .listen(print); // prints 3 + Stream sample(Stream sampleStream) => + SampleStreamTransformer((_) => sampleStream).bind(this); + + /// Emits the most recently emitted item (if any) emitted by the source + /// [Stream] since the previous emission within the recurring time span, + /// defined by [duration] + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .sampleTime(Duration(seconds: 1)) + /// .listen(print); // prints 3 + Stream sampleTime(Duration duration) => + sample(Stream.periodic(duration)); +} diff --git a/sandbox/reactivex/lib/src/transformers/backpressure/throttle.dart b/sandbox/reactivex/lib/src/transformers/backpressure/throttle.dart new file mode 100644 index 0000000..523c180 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/backpressure/throttle.dart @@ -0,0 +1,79 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/streams/timer.dart'; +import 'package:angel3_reactivex/src/transformers/backpressure/backpressure.dart'; + +/// A [StreamTransformer] that emits a value from the source [Stream], +/// then ignores subsequent source values while the window [Stream] is open, +/// then repeats this process. +/// +/// If leading is true, then the first item in each window is emitted. +/// If trailing is true, then the last item in each window is emitted. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3]) +/// .transform(ThrottleStreamTransformer((_) => TimerStream(true, const Duration(seconds: 1)))) +/// .listen(print); // prints 1 +class ThrottleStreamTransformer extends BackpressureStreamTransformer { + /// Construct a [StreamTransformer] that emits a value from the source [Stream], + /// then ignores subsequent source values while the window [Stream] is open, + /// then repeats this process. + /// + /// If [leading] is true, then the first item in each window is emitted. + /// If [trailing] is true, then the last item in each window is emitted. + ThrottleStreamTransformer( + Stream Function(T event) window, { + bool trailing = false, + bool leading = true, + }) : super( + WindowStrategy.eventAfterLastWindow, + window, + onWindowStart: leading ? (event) => event : null, + onWindowEnd: trailing ? (queue) => queue.last : null, + dispatchOnClose: trailing, + maxLengthQueue: trailing ? 2 : 0, + ); +} + +/// Extends the Stream class with the ability to throttle events in various ways +extension ThrottleExtensions on Stream { + /// Emits a value from the source [Stream], then ignores subsequent source values + /// while the window [Stream] is open, then repeats this process. + /// + /// If leading is true, then the first item in each window is emitted. + /// If trailing is true, then the last item in each window is emitted. + /// + /// You can use the value of the last throttled event to determine the length + /// of the next [window]. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .throttle((_) => TimerStream(true, Duration(seconds: 1))); + Stream throttle(Stream Function(T event) window, + {bool trailing = false, bool leading = true}) => + ThrottleStreamTransformer( + window, + trailing: trailing, + leading: leading, + ).bind(this); + + /// Emits a value from the source [Stream], then ignores subsequent source values + /// for a duration, then repeats this process. + /// + /// If leading is true, then the first item in each window is emitted. + /// If [trailing] is true, then the last item is emitted instead. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .throttleTime(Duration(seconds: 1)); + Stream throttleTime(Duration duration, + {bool trailing = false, bool leading = true}) => + ThrottleStreamTransformer( + (_) => TimerStream(true, duration), + trailing: trailing, + leading: leading, + ).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/backpressure/window.dart b/sandbox/reactivex/lib/src/transformers/backpressure/window.dart new file mode 100644 index 0000000..544a1b4 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/backpressure/window.dart @@ -0,0 +1,158 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/transformers/backpressure/backpressure.dart'; + +/// Creates a [Stream] where each item is a [Stream] containing the items +/// from the source sequence. +/// +/// This [List] is emitted every time the window [Stream] +/// emits an event. +/// +/// ### Example +/// +/// Stream.periodic(const Duration(milliseconds: 100), (i) => i) +/// .window(Stream.periodic(const Duration(milliseconds: 160), (i) => i)) +/// .asyncMap((stream) => stream.toList()) +/// .listen(print); // prints [0, 1] [2, 3] [4, 5] ... +class WindowStreamTransformer + extends BackpressureStreamTransformer> { + /// Constructs a [StreamTransformer] which buffers events into a [Stream] and + /// emits this [Stream] whenever [window] fires an event. + /// + /// The [Stream] is recreated and starts empty upon every [window] event. + WindowStreamTransformer(Stream Function(T event) window) + : super(WindowStrategy.firstEventOnly, window, + onWindowEnd: (queue) => Stream.fromIterable(queue), + ignoreEmptyWindows: false); +} + +/// Buffers a number of values from the source Stream by count then emits the +/// buffer as a [Stream] and clears it, and starts a new buffer each +/// startBufferEvery values. If startBufferEvery is not provided, then new +/// buffers are started immediately at the start of the source and when each +/// buffer closes and is emitted. +/// +/// ### Example +/// count is the maximum size of the buffer emitted +/// +/// Rx.range(1, 4) +/// .windowCount(2) +/// .asyncMap((stream) => stream.toList()) +/// .listen(print); // prints [1, 2], [3, 4] done! +/// +/// ### Example +/// if startBufferEvery is 2, then a new buffer will be started +/// on every other value from the source. A new buffer is started at the +/// beginning of the source by default. +/// +/// Rx.range(1, 5) +/// .bufferCount(3, 2) +/// .listen(print); // prints [1, 2, 3], [3, 4, 5], [5] done! +class WindowCountStreamTransformer + extends BackpressureStreamTransformer> { + /// Constructs a [StreamTransformer] which buffers events into a [Stream] and + /// emits this [Stream] whenever its length is equal to [count]. + /// + /// A new buffer is created for every n-th event emitted + /// by the [Stream] that is being transformed, as specified by + /// the [startBufferEvery] parameter. + /// + /// If [startBufferEvery] is omitted or equals 0, then a new buffer is started whenever + /// the previous one reaches a length of [count]. + WindowCountStreamTransformer(int count, [int startBufferEvery = 0]) + : super(WindowStrategy.onHandler, null, + onWindowEnd: (queue) => Stream.fromIterable(queue), + startBufferEvery: startBufferEvery, + closeWindowWhen: (queue) => queue.length == count) { + if (count < 1) throw ArgumentError.value(count, 'count'); + if (startBufferEvery < 0) { + throw ArgumentError.value(startBufferEvery, 'startBufferEvery'); + } + } +} + +/// Creates a [Stream] where each item is a [Stream] containing the items +/// from the source sequence, batched whenever test passes. +/// +/// ### Example +/// +/// Stream.periodic(const Duration(milliseconds: 100), (int i) => i) +/// .windowTest((i) => i % 2 == 0) +/// .asyncMap((stream) => stream.toList()) +/// .listen(print); // prints [0], [1, 2] [3, 4] [5, 6] ... +class WindowTestStreamTransformer + extends BackpressureStreamTransformer> { + /// Constructs a [StreamTransformer] which buffers events into a [Stream] and + /// emits this [Stream] whenever the [test] Function yields true. + WindowTestStreamTransformer(bool Function(T value) test) + : super(WindowStrategy.onHandler, null, + onWindowEnd: (queue) => Stream.fromIterable(queue), + closeWindowWhen: (queue) => test(queue.last)); +} + +/// Extends the Stream class with the ability to window +extension WindowExtensions on Stream { + /// Creates a Stream where each item is a [Stream] containing the items from + /// the source sequence. + /// + /// This [List] is emitted every time [window] emits an event. + /// + /// ### Example + /// + /// Stream.periodic(Duration(milliseconds: 100), (i) => i) + /// .window(Stream.periodic(Duration(milliseconds: 160), (i) => i)) + /// .asyncMap((stream) => stream.toList()) + /// .listen(print); // prints [0, 1] [2, 3] [4, 5] ... + Stream> window(Stream window) => + WindowStreamTransformer((_) => window).bind(this); + + /// Buffers a number of values from the source Stream by [count] then emits + /// the buffer as a [Stream] and clears it, and starts a new buffer each + /// [startBufferEvery] values. If [startBufferEvery] is not provided, then new + /// buffers are started immediately at the start of the source and when each + /// buffer closes and is emitted. + /// + /// ### Example + /// [count] is the maximum size of the buffer emitted + /// + /// RangeStream(1, 4) + /// .windowCount(2) + /// .asyncMap((stream) => stream.toList()) + /// .listen(print); // prints [1, 2], [3, 4] done! + /// + /// ### Example + /// if [startBufferEvery] is 2, then a new buffer will be started + /// on every other value from the source. A new buffer is started at the + /// beginning of the source by default. + /// + /// RangeStream(1, 5) + /// .bufferCount(3, 2) + /// .listen(print); // prints [1, 2, 3], [3, 4, 5], [5] done! + Stream> windowCount(int count, [int startBufferEvery = 0]) => + WindowCountStreamTransformer(count, startBufferEvery).bind(this); + + /// Creates a Stream where each item is a [Stream] containing the items from + /// the source sequence, batched whenever test passes. + /// + /// ### Example + /// + /// Stream.periodic(Duration(milliseconds: 100), (int i) => i) + /// .windowTest((i) => i % 2 == 0) + /// .asyncMap((stream) => stream.toList()) + /// .listen(print); // prints [0], [1, 2] [3, 4] [5, 6] ... + Stream> windowTest(bool Function(T event) onTestHandler) => + WindowTestStreamTransformer(onTestHandler).bind(this); + + /// Creates a Stream where each item is a [Stream] containing the items from + /// the source sequence, sampled on a time frame with [duration]. + /// + /// ### Example + /// + /// Stream.periodic(Duration(milliseconds: 100), (int i) => i) + /// .windowTime(Duration(milliseconds: 220)) + /// .doOnData((_) => print('next window')) + /// .flatMap((s) => s) + /// .listen(print); // prints next window 0, 1, next window 2, 3, ... + Stream> windowTime(Duration duration) => + window(Stream.periodic(duration)); +} diff --git a/sandbox/reactivex/lib/src/transformers/default_if_empty.dart b/sandbox/reactivex/lib/src/transformers/default_if_empty.dart new file mode 100644 index 0000000..fb9deed --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/default_if_empty.dart @@ -0,0 +1,60 @@ +import 'dart:async'; + +class _DefaultIfEmptyStreamSink implements EventSink { + final S _defaultValue; + final EventSink _outputSink; + bool _isEmpty = true; + + _DefaultIfEmptyStreamSink(this._outputSink, this._defaultValue); + + @override + void add(S data) { + _isEmpty = false; + _outputSink.add(data); + } + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() { + if (_isEmpty) { + _outputSink.add(_defaultValue); + } + + _outputSink.close(); + } +} + +/// Emit items from the source [Stream], or a single default item if the source +/// Stream emits nothing. +/// +/// ### Example +/// +/// Stream.empty() +/// .transform(DefaultIfEmptyStreamTransformer(10)) +/// .listen(print); // prints 10 +class DefaultIfEmptyStreamTransformer extends StreamTransformerBase { + /// The event that should be emitted if the source [Stream] is empty + final S defaultValue; + + /// Constructs a [StreamTransformer] which either emits from the source [Stream], + /// or just a [defaultValue] if the source [Stream] emits nothing. + DefaultIfEmptyStreamTransformer(this.defaultValue); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _DefaultIfEmptyStreamSink(sink, defaultValue)); +} + +/// +extension DefaultIfEmptyExtension on Stream { + /// Emit items from the source Stream, or a single default item if the source + /// Stream emits nothing. + /// + /// ### Example + /// + /// Stream.empty().defaultIfEmpty(10).listen(print); // prints 10 + Stream defaultIfEmpty(T defaultValue) => + DefaultIfEmptyStreamTransformer(defaultValue).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/delay.dart b/sandbox/reactivex/lib/src/transformers/delay.dart new file mode 100644 index 0000000..f2fd2b9 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/delay.dart @@ -0,0 +1,98 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:angel3_reactivex/src/rx.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +class _DelayStreamSink extends ForwardingSink { + final Duration _duration; + var _inputClosed = false; + final _subscriptions = Queue>(); + + _DelayStreamSink(this._duration); + + @override + void onData(S data) { + final subscription = Rx.timer(null, _duration).listen((_) { + _subscriptions.removeFirst(); + + sink.add(data); + + if (_inputClosed && _subscriptions.isEmpty) { + sink.close(); + } + }); + + _subscriptions.addLast(subscription); + } + + @override + void onError(Object error, StackTrace st) => sink.addError(error, st); + + @override + void onDone() { + _inputClosed = true; + + if (_subscriptions.isEmpty) { + sink.close(); + } + } + + @override + Future? onCancel() => _subscriptions.cancelAll(); + + @override + void onListen() {} + + @override + void onPause() => _subscriptions.pauseAll(); + + @override + void onResume() => _subscriptions.resumeAll(); +} + +/// The Delay operator modifies its source Stream by pausing for +/// a particular increment of time (that you specify) before emitting +/// each of the source Stream’s items. +/// This has the effect of shifting the entire sequence of items emitted +/// by the Stream forward in time by that specified increment. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#delay) +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3, 4]) +/// .delay(Duration(seconds: 1)) +/// .listen(print); // [after one second delay] prints 1, 2, 3, 4 immediately +class DelayStreamTransformer extends StreamTransformerBase { + /// The delay used to pause initial emission of events by + final Duration duration; + + /// Constructs a [StreamTransformer] which will first pause for [duration] of time, + /// before submitting events from the source [Stream]. + DelayStreamTransformer(this.duration); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _DelayStreamSink(duration)); +} + +/// Extends the Stream class with the ability to delay events being emitted +extension DelayExtension on Stream { + /// The Delay operator modifies its source Stream by pausing for a particular + /// increment of time (that you specify) before emitting each of the source + /// Stream’s items. This has the effect of shifting the entire sequence of + /// items emitted by the Stream forward in time by that specified increment. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#delay) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3, 4]) + /// .delay(Duration(seconds: 1)) + /// .listen(print); // [after one second delay] prints 1, 2, 3, 4 immediately + Stream delay(Duration duration) => + DelayStreamTransformer(duration).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/delay_when.dart b/sandbox/reactivex/lib/src/transformers/delay_when.dart new file mode 100644 index 0000000..5b80eb0 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/delay_when.dart @@ -0,0 +1,171 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; +import 'package:angel3_reactivex/src/utils/future.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +class _DelayWhenStreamSink extends ForwardingSink { + final Stream Function(T) itemDelaySelector; + final Stream? listenDelay; + + final subscriptions = >[]; + StreamSubscription? delaySubscription; + var closed = false; + + _DelayWhenStreamSink(this.itemDelaySelector, this.listenDelay); + + @override + void onData(T data) { + final subscription = + itemDelaySelector(data).take(1).listen(null, onError: sink.addError); + + subscription.onDone(() { + subscriptions.remove(subscription); + + sink.add(data); + if (subscriptions.isEmpty && closed) { + sink.close(); + } + }); + + subscriptions.add(subscription); + } + + @override + void onError(Object error, StackTrace st) => sink.addError(error, st); + + @override + void onDone() { + closed = true; + if (subscriptions.isEmpty) { + sink.close(); + } + } + + @override + Future? onCancel() { + final future = delaySubscription?.cancel(); + delaySubscription = null; + + if (subscriptions.isEmpty) { + return future; + } + + final futures = [ + for (final s in subscriptions) s.cancel(), + if (future != null) future, + ]; + subscriptions.clear(); + + return waitFuturesList(futures); + } + + @override + FutureOr onListen() { + if (listenDelay == null) { + return null; + } + + final completer = Completer.sync(); + delaySubscription = listenDelay!.take(1).listen( + null, + onError: (Object e, StackTrace s) { + delaySubscription?.cancel(); + delaySubscription = null; + completer.completeError(e, s); + }, + onDone: () { + delaySubscription?.cancel(); + delaySubscription = null; + completer.complete(null); + }, + ); + return completer.future; + } + + @override + void onPause() { + delaySubscription?.pause(); + subscriptions.pauseAll(); + } + + @override + void onResume() { + delaySubscription?.resume(); + subscriptions.resumeAll(); + } +} + +/// Delays the emission of items from the source [Stream] by a given time span +/// determined by the emissions of another [Stream]. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#delayWhen) +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3]) +/// .transform(DelayWhenStreamTransformer( +/// (i) => Rx.timer(null, Duration(seconds: i)))) +/// .listen(print); // [after 1s] prints 1 [after 1s] prints 2 [after 1s] prints 3 +/// +/// Stream.fromIterable([1, 2, 3]) +/// .transform( +/// DelayWhenStreamTransformer( +/// (i) => Rx.timer(null, Duration(seconds: i)), +/// listenDelay: Rx.timer(null, Duration(seconds: 2)), +/// ), +/// ) +/// .listen(print); // [after 3s] prints 1 [after 1s] prints 2 [after 1s] prints 3 +class DelayWhenStreamTransformer extends StreamTransformerBase { + /// A function used to determine delay time span for each data event. + final Stream Function(T value) itemDelaySelector; + + /// When [listenDelay] emits its first data or done event, the source Stream is listen to. + final Stream? listenDelay; + + /// Constructs a [StreamTransformer] which delays the emission of items + /// from the source [Stream] by a given time span determined by the emissions of another [Stream]. + DelayWhenStreamTransformer(this.itemDelaySelector, {this.listenDelay}); + + @override + Stream bind(Stream stream) => forwardStream( + stream, () => _DelayWhenStreamSink(itemDelaySelector, listenDelay)); +} + +/// Extends the Stream class with the ability to delay events being emitted. +extension DelayWhenExtension on Stream { + /// Delays the emission of items from the source [Stream] by a given time span + /// determined by the emissions of another [Stream]. + /// + /// When the source emits a data element, the `itemDelaySelector` function is called + /// with the data element as argument, and return a "duration" Stream. + /// The source element is emitted on the output Stream only when the "duration" Stream + /// emits a data or done event. + /// + /// Optionally, `delayWhen` takes a second argument `listenDelay`. When `listenDelay` + /// emits its first data or done event, the source Stream is listen to. + /// If `listenDelay` is not provided, `delayWhen` will listen to the source Stream + /// as soon as the output Stream is listen. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#delayWhen) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .delayWhen((i) => Rx.timer(null, Duration(seconds: i))) + /// .listen(print); // [after 1s] prints 1 [after 1s] prints 2 [after 1s] prints 3 + /// + /// Stream.fromIterable([1, 2, 3]) + /// .delayWhen( + /// (i) => Rx.timer(null, Duration(seconds: i)), + /// listenDelay: Rx.timer(null, Duration(seconds: 2)), + /// ) + /// .listen(print); // [after 3s] prints 1 [after 1s] prints 2 [after 1s] prints 3 + Stream delayWhen( + Stream Function(T value) itemDelaySelector, { + Stream? listenDelay, + }) => + DelayWhenStreamTransformer(itemDelaySelector, listenDelay: listenDelay) + .bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/dematerialize.dart b/sandbox/reactivex/lib/src/transformers/dematerialize.dart new file mode 100644 index 0000000..685b8ce --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/dematerialize.dart @@ -0,0 +1,81 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/notification.dart'; + +class _DematerializeStreamSink implements EventSink> { + final EventSink _outputSink; + + _DematerializeStreamSink(this._outputSink); + + @override + void add(StreamNotification data) => data.when( + data: _outputSink.add, + done: _outputSink.close, + error: _outputSink.addErrorAndStackTrace, + ); + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() => _outputSink.close(); +} + +/// Converts the onData, onDone, and onError [StreamNotification] objects from a +/// materialized stream into normal onData, onDone, and onError events. +/// +/// When a stream has been materialized, it emits onData, onDone, and onError +/// events as [StreamNotification] objects. Dematerialize simply reverses this by +/// transforming [StreamNotification] objects back to a normal stream of events. +/// +/// ### Example +/// +/// Stream> +/// .fromIterable([StreamNotification.data(1), StreamNotification.done()]) +/// .transform(DematerializeStreamTransformer()) +/// .listen(print); // Prints 1 +/// +/// ### Error example +/// +/// Stream> +/// .fromIterable([StreamNotification.error(Exception(), null)]) +/// .transform(DematerializeStreamTransformer()) +/// .listen(null, onError: (e, s) => print(e)); // Prints Exception +class DematerializeStreamTransformer + extends StreamTransformerBase, S> { + /// Constructs a [StreamTransformer] which converts the onData, onDone, and + /// onError [StreamNotification] objects from a materialized stream into normal + /// onData, onDone, and onError events. + DematerializeStreamTransformer(); + + @override + Stream bind(Stream> stream) => + Stream.eventTransformed(stream, (sink) => _DematerializeStreamSink(sink)); +} + +/// Converts the onData, onDone, and onError [StreamNotification]s from a +/// materialized stream into normal onData, onDone, and onError events. +extension DematerializeExtension on Stream> { + /// Converts the onData, onDone, and onError [StreamNotification] objects from a + /// materialized stream into normal onData, onDone, and onError events. + /// + /// When a stream has been materialized, it emits onData, onDone, and onError + /// events as [StreamNotification] objects. Dematerialize simply reverses this by + /// transforming [StreamNotification] objects back to a normal stream of events. + /// + /// ### Example + /// + /// Stream> + /// .fromIterable([StreamNotification.data(1), StreamNotification.done()]) + /// .dematerialize() + /// .listen(print); // Prints 1 + /// + /// ### Error example + /// + /// Stream> + /// .fromIterable([StreamNotification.error(Exception(), null)]) + /// .dematerialize() + /// .listen(null, onError: (e, s) => print(e)); // Prints Exception + Stream dematerialize() => DematerializeStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/distinct_unique.dart b/sandbox/reactivex/lib/src/transformers/distinct_unique.dart new file mode 100644 index 0000000..f3785df --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/distinct_unique.dart @@ -0,0 +1,92 @@ +import 'dart:async'; +import 'dart:collection'; + +class _DistinctUniqueStreamSink implements EventSink { + final EventSink _outputSink; + final HashSet _collection; + + _DistinctUniqueStreamSink(this._outputSink, + {bool Function(S e1, S e2)? equals, int Function(S e)? hashCodeMethod}) + : _collection = HashSet(equals: equals, hashCode: hashCodeMethod); + + @override + void add(S data) { + if (_collection.add(data)) { + _outputSink.add(data); + } + } + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() { + _collection.clear(); + _outputSink.close(); + } +} + +/// Create a [Stream] which implements a [HashSet] under the hood, using +/// the provided `equals` as equality. +/// +/// The [Stream] will only emit an event, if that event is not yet found +/// within the underlying [HashSet]. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 1, 2, 1, 2, 3, 2, 1]) +/// .listen((event) => print(event)); +/// +/// will emit: +/// 1, 2, 3 +/// +/// The provided `equals` must define a stable equivalence relation, and +/// `hashCode` must be consistent with `equals`. +/// +/// If `equals` or `hashCode` are omitted, the set uses the elements' intrinsic +/// `Object.==` and `Object.hashCode`. If you supply one of `equals` and +/// `hashCode`, you should generally also to supply the other. +class DistinctUniqueStreamTransformer extends StreamTransformerBase { + /// Optional method which determines equality between two events + final bool Function(S e1, S e2)? equals; + + /// Optional method which is used to create a hash from an event + final int Function(S e)? hashCodeMethod; + + /// Constructs a [StreamTransformer] which emits events from the source + /// [Stream] as if they were processed through a [HashSet]. + /// + /// See [HashSet] for a more detailed explanation. + DistinctUniqueStreamTransformer({this.equals, this.hashCodeMethod}); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, + (sink) => _DistinctUniqueStreamSink(sink, + equals: equals, hashCodeMethod: hashCodeMethod)); +} + +/// Extends the Stream class with the ability to skip items that have previously +/// been emitted. +extension DistinctUniqueExtension on Stream { + /// WARNING: More commonly known as distinct in other Rx implementations. + /// Creates a Stream where data events are skipped if they have already + /// been emitted before. + /// + /// Equality is determined by the provided equals and hashCode methods. + /// If these are omitted, the '==' operator and hashCode on the last provided + /// data element are used. + /// + /// The returned stream is a broadcast stream if this stream is. If a + /// broadcast stream is listened to more than once, each subscription will + /// individually perform the equals and hashCode tests. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#distinct) + Stream distinctUnique({ + bool Function(T e1, T e2)? equals, + int Function(T e)? hashCode, + }) => + DistinctUniqueStreamTransformer( + equals: equals, hashCodeMethod: hashCode) + .bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/do.dart b/sandbox/reactivex/lib/src/transformers/do.dart new file mode 100644 index 0000000..637505e --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/do.dart @@ -0,0 +1,305 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; +import 'package:angel3_reactivex/src/utils/notification.dart'; + +class _DoStreamSink extends ForwardingSink { + final FutureOr Function()? _onCancel; + final void Function(S event)? _onData; + final void Function()? _onDone; + final void Function(StreamNotification notification)? _onEach; + final void Function(Object, StackTrace)? _onError; + final void Function()? _onListen; + final void Function()? _onPause; + final void Function()? _onResume; + + _DoStreamSink( + this._onCancel, + this._onData, + this._onDone, + this._onEach, + this._onError, + this._onListen, + this._onPause, + this._onResume, + ); + + @override + void onData(S data) { + try { + _onData?.call(data); + } catch (e, s) { + sink.addError(e, s); + } + try { + _onEach?.call(StreamNotification.data(data)); + } catch (e, s) { + sink.addError(e, s); + } + sink.add(data); + } + + @override + void onError(Object e, StackTrace st) { + try { + _onError?.call(e, st); + } catch (e, s) { + sink.addError(e, s); + } + try { + _onEach?.call(StreamNotification.error(e, st)); + } catch (e, s) { + sink.addError(e, s); + } + sink.addError(e, st); + } + + @override + void onDone() { + try { + _onDone?.call(); + } catch (e, s) { + sink.addError(e, s); + } + try { + _onEach?.call(StreamNotification.done()); + } catch (e, s) { + sink.addError(e, s); + } + sink.close(); + } + + @override + FutureOr onCancel() => _onCancel?.call(); + + @override + void onListen() { + try { + _onListen?.call(); + } catch (e, s) { + sink.addError(e, s); + } + } + + @override + void onPause() { + try { + _onPause?.call(); + } catch (e, s) { + sink.addError(e, s); + } + } + + @override + void onResume() { + try { + _onResume?.call(); + } catch (e, s) { + sink.addError(e, s); + } + } +} + +/// Invokes the given callback at the corresponding point the the stream +/// lifecycle. For example, if you pass in an onDone callback, it will +/// be invoked when the stream finishes emitting items. +/// +/// This transformer can be used for debugging, logging, etc. by intercepting +/// the stream at different points to run arbitrary actions. +/// +/// It is possible to hook onto the following parts of the stream lifecycle: +/// +/// - onCancel +/// - onData +/// - onDone +/// - onError +/// - onListen +/// - onPause +/// - onResume +/// +/// In addition, the `onEach` argument is called at `onData`, `onDone`, and +/// `onError` with a [StreamNotification] passed in. The [StreamNotification] argument +/// contains the [NotificationKind] of event (OnData, OnDone, OnError), and the item or +/// error that was emitted. In the case of onDone, no data is emitted as part +/// of the [StreamNotification]. +/// +/// If no callbacks are passed in, a runtime error will be thrown in dev mode +/// in order to 'fail fast' and alert the developer that the transformer should +/// be used or safely removed. +/// +/// ### Example +/// +/// Stream.fromIterable([1]) +/// .transform(DoStreamTransformer( +/// onData: print, +/// onError: (e, s) => print('Oh no!'), +/// onDone: () => print('Done'))) +/// .listen(null); // Prints: 1, 'Done' +class DoStreamTransformer extends StreamTransformerBase { + /// fires when all subscriptions have cancelled. + final FutureOr Function()? onCancel; + + /// fires when data is emitted + final void Function(S event)? onData; + + /// fires on close + final void Function()? onDone; + + /// fires on data, close and error + final void Function(StreamNotification notification)? onEach; + + /// fires on errors + final void Function(Object, StackTrace)? onError; + + /// fires when a subscription first starts + final void Function()? onListen; + + /// fires when the subscription pauses + final void Function()? onPause; + + /// fires when the subscription resumes + final void Function()? onResume; + + /// Constructs a [StreamTransformer] which will trigger any of the provided + /// handlers as they occur. + DoStreamTransformer( + {this.onCancel, + this.onData, + this.onDone, + this.onEach, + this.onError, + this.onListen, + this.onPause, + this.onResume}) { + if (onCancel == null && + onData == null && + onDone == null && + onEach == null && + onError == null && + onListen == null && + onPause == null && + onResume == null) { + throw ArgumentError('Must provide at least one handler'); + } + } + + @override + Stream bind(Stream stream) => forwardStream( + stream, + () => _DoStreamSink( + onCancel, + onData, + onDone, + onEach, + onError, + onListen, + onPause, + onResume, + ), + true, + ); +} + +/// Extends the Stream class with the ability to execute a callback function +/// at different points in the Stream's lifecycle. +extension DoExtensions on Stream { + /// Invokes the given callback function when the stream subscription is + /// cancelled. Often called doOnUnsubscribe or doOnDispose in other + /// implementations. + /// + /// ### Example + /// + /// final subscription = TimerStream(1, Duration(minutes: 1)) + /// .doOnCancel(() => print('hi')) + /// .listen(null); + /// + /// subscription.cancel(); // prints 'hi' + Stream doOnCancel(FutureOr Function() onCancel) => + DoStreamTransformer(onCancel: onCancel).bind(this); + + /// Invokes the given callback function when the stream emits an item. In + /// other implementations, this is called doOnNext. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .doOnData(print) + /// .listen(null); // prints 1, 2, 3 + Stream doOnData(void Function(T event) onData) => + DoStreamTransformer(onData: onData).bind(this); + + /// Invokes the given callback function when the stream finishes emitting + /// items. In other implementations, this is called doOnComplete(d). + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .doOnDone(() => print('all set')) + /// .listen(null); // prints 'all set' + Stream doOnDone(void Function() onDone) => + DoStreamTransformer(onDone: onDone).bind(this); + + /// Invokes the given callback function when the stream emits data, emits + /// an error, or emits done. The callback receives a [StreamNotification] object. + /// + /// The [StreamNotification] object contains the [NotificationKind] of event (OnData, onDone, + /// or OnError), and the item or error that was emitted. In the case of + /// onDone, no data is emitted as part of the [StreamNotification]. + /// + /// ### Example + /// + /// Stream.fromIterable([1]) + /// .doOnEach(print) + /// .listen(null); // Prints DataNotification{value: 1}, DoneNotification{} + Stream doOnEach( + void Function(StreamNotification notification) onEach) => + DoStreamTransformer(onEach: onEach).bind(this); + + /// Invokes the given callback function when the stream emits an error. + /// + /// ### Example + /// + /// Stream.error(Exception()) + /// .doOnError((error, stacktrace) => print('oh no')) + /// .listen(null); // prints 'Oh no' + Stream doOnError(void Function(Object, StackTrace) onError) => + DoStreamTransformer(onError: onError).bind(this); + + /// Invokes the given callback function when the stream is first listened to. + /// + /// ### Example + /// + /// Stream.fromIterable([1]) + /// .doOnListen(() => print('Is someone there?')) + /// .listen(null); // prints 'Is someone there?' + Stream doOnListen(void Function() onListen) => + DoStreamTransformer(onListen: onListen).bind(this); + + /// Invokes the given callback function when the stream subscription is + /// paused. + /// + /// ### Example + /// + /// final subscription = Stream.fromIterable([1]) + /// .doOnPause(() => print('Gimme a minute please')) + /// .listen(null); + /// + /// subscription.pause(); // prints 'Gimme a minute please' + Stream doOnPause(void Function() onPause) => + DoStreamTransformer(onPause: onPause).bind(this); + + /// Invokes the given callback function when the stream subscription + /// resumes receiving items. + /// + /// ### Example + /// + /// final subscription = Stream.fromIterable([1]) + /// .doOnResume(() => print('Let's do this!')) + /// .listen(null); + /// + /// subscription.pause(); + /// subscription.resume(); 'Let's do this!' + Stream doOnResume(void Function() onResume) => + DoStreamTransformer(onResume: onResume).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/end_with.dart b/sandbox/reactivex/lib/src/transformers/end_with.dart new file mode 100644 index 0000000..c4f99ee --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/end_with.dart @@ -0,0 +1,52 @@ +import 'dart:async'; + +class _EndWithStreamSink implements EventSink { + final S _endValue; + final EventSink _outputSink; + + _EndWithStreamSink(this._outputSink, this._endValue); + + @override + void add(S data) => _outputSink.add(data); + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() { + _outputSink.add(_endValue); + _outputSink.close(); + } +} + +/// Appends a value to the source [Stream] before closing. +/// +/// ### Example +/// +/// Stream.fromIterable([2]) +/// .transform(EndWithStreamTransformer(1)) +/// .listen(print); // prints 2, 1 +class EndWithStreamTransformer extends StreamTransformerBase { + /// The ending event of this [Stream] + final S endValue; + + /// Constructs a [StreamTransformer] which appends the source [Stream] + /// with [endValue] just before it closes. + EndWithStreamTransformer(this.endValue); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _EndWithStreamSink(sink, endValue)); +} + +/// Extends the [Stream] class with the ability to emit the given value as the +/// final item before closing. +extension EndWithExtension on Stream { + /// Appends a value to the source [Stream] before closing. + /// + /// ### Example + /// + /// Stream.fromIterable([2]).endWith(1).listen(print); // prints 2, 1 + Stream endWith(T endValue) => + EndWithStreamTransformer(endValue).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/end_with_many.dart b/sandbox/reactivex/lib/src/transformers/end_with_many.dart new file mode 100644 index 0000000..050e456 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/end_with_many.dart @@ -0,0 +1,52 @@ +import 'dart:async'; + +class _EndWithManyStreamSink implements EventSink { + final Iterable _endValues; + final EventSink _outputSink; + + _EndWithManyStreamSink(this._outputSink, this._endValues); + + @override + void add(S data) => _outputSink.add(data); + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() { + _endValues.forEach(_outputSink.add); + _outputSink.close(); + } +} + +/// Appends a sequence of values to the source [Stream]. +/// +/// ### Example +/// +/// Stream.fromIterable([3]) +/// .transform(EndWithManyStreamTransformer([1, 2])) +/// .listen(print); // prints 3, 1, 2 +class EndWithManyStreamTransformer extends StreamTransformerBase { + /// The ending events of this [Stream] + final Iterable endValues; + + /// Constructs a [StreamTransformer] which appends the source [Stream] + /// with [endValues] before closing. + EndWithManyStreamTransformer(this.endValues); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _EndWithManyStreamSink(sink, endValues)); +} + +/// Extends the Stream class with the ability to emit the given value as the +/// final item before closing. +extension EndWithManyExtension on Stream { + /// Appends a sequence of values as final events to the source [Stream] before closing. + /// + /// ### Example + /// + /// Stream.fromIterable([2]).endWithMany([1, 0]).listen(print); // prints 2, 1, 0 + Stream endWithMany(Iterable endValues) => + EndWithManyStreamTransformer(endValues).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/exhaust_map.dart b/sandbox/reactivex/lib/src/transformers/exhaust_map.dart new file mode 100644 index 0000000..d9c9bac --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/exhaust_map.dart @@ -0,0 +1,113 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _ExhaustMapStreamSink extends ForwardingSink { + final Stream Function(S value) _mapper; + StreamSubscription? _mapperSubscription; + bool _inputClosed = false; + + _ExhaustMapStreamSink(this._mapper); + + @override + void onData(S data) { + if (_mapperSubscription != null) { + return; + } + + final Stream mappedStream; + try { + mappedStream = _mapper(data); + } catch (e, s) { + sink.addError(e, s); + return; + } + + _mapperSubscription = mappedStream.listen( + sink.add, + onError: sink.addError, + onDone: () { + _mapperSubscription = null; + + if (_inputClosed) { + sink.close(); + } + }, + ); + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + _inputClosed = true; + + _mapperSubscription ?? sink.close(); + } + + @override + FutureOr onCancel() => _mapperSubscription?.cancel(); + + @override + void onListen() {} + + @override + void onPause() => _mapperSubscription?.pause(); + + @override + void onResume() => _mapperSubscription?.resume(); +} + +/// Converts events from the source stream into a new Stream using a given +/// mapper. It ignores all items from the source stream until the new stream +/// completes. +/// +/// Useful when you have a noisy source Stream and only want to respond once +/// the previous async operation is finished. +/// +/// ### Example +/// // Emits 0, 1, 2 +/// Stream.periodic(Duration(milliseconds: 200), (i) => i).take(3) +/// .transform(ExhaustMapStreamTransformer( +/// // Emits the value it's given after 200ms +/// (i) => Rx.timer(i, Duration(milliseconds: 200)), +/// )) +/// .listen(print); // prints 0, 2 +class ExhaustMapStreamTransformer extends StreamTransformerBase { + /// Method which converts incoming events into a new [Stream] + final Stream Function(S value) mapper; + + /// Constructs a [StreamTransformer] which maps each event from the source [Stream] + /// using [mapper]. + /// + /// The mapped [Stream] will be be listened to and begin + /// emitting items, and any previously created mapper [Stream]s will stop emitting. + ExhaustMapStreamTransformer(this.mapper); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _ExhaustMapStreamSink(mapper)); +} + +/// Extends the Stream class with the ability to transform the Stream into +/// a new Stream. The new Stream emits items and ignores events from the source +/// Stream until the new Stream completes. +extension ExhaustMapExtension on Stream { + /// Converts items from the source stream into a Stream using a given + /// mapper. It ignores all items from the source stream until the new stream + /// completes. + /// + /// Useful when you have a noisy source Stream and only want to respond once + /// the previous async operation is finished. + /// + /// ### Example + /// + /// RangeStream(0, 2).interval(Duration(milliseconds: 50)) + /// .exhaustMap((i) => + /// TimerStream(i, Duration(milliseconds: 75))) + /// .listen(print); // prints 0, 2 + Stream exhaustMap(Stream Function(T value) mapper) => + ExhaustMapStreamTransformer(mapper).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/flat_map.dart b/sandbox/reactivex/lib/src/transformers/flat_map.dart new file mode 100644 index 0000000..c5dff2a --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/flat_map.dart @@ -0,0 +1,148 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +class _FlatMapStreamSink extends ForwardingSink { + final Stream Function(S value) _mapper; + final int? maxConcurrent; + + final List> _subscriptions = >[]; + final Queue queue = DoubleLinkedQueue(); + bool _inputClosed = false; + + _FlatMapStreamSink(this._mapper, this.maxConcurrent); + + @override + void onData(S data) { + if (maxConcurrent != null && _subscriptions.length >= maxConcurrent!) { + queue.addLast(data); + } else { + listenInner(data); + } + } + + void listenInner(S data) { + final Stream mappedStream; + try { + mappedStream = _mapper(data); + } catch (e, s) { + sink.addError(e, s); + return; + } + + final subscription = mappedStream.listen(sink.add, onError: sink.addError); + subscription.onDone(() { + _subscriptions.remove(subscription); + + if (queue.isNotEmpty) { + listenInner(queue.removeFirst()); + } else if (_inputClosed && _subscriptions.isEmpty) { + sink.close(); + } + }); + _subscriptions.add(subscription); + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + _inputClosed = true; + + if (_subscriptions.isEmpty) { + sink.close(); + } + } + + @override + Future? onCancel() { + queue.clear(); + return _subscriptions.cancelAll(); + } + + @override + void onListen() {} + + @override + void onPause() => _subscriptions.pauseAll(); + + @override + void onResume() => _subscriptions.resumeAll(); +} + +/// Converts each emitted item into a new Stream using the given mapper function, +/// while limiting the maximum number of concurrent subscriptions to these [Stream]s. +/// The newly created Stream will be listened to and begin emitting items downstream. +/// +/// The items emitted by each of the new Streams are emitted downstream in the +/// same order they arrive. In other words, the sequences are merged +/// together. +/// +/// ### Example +/// +/// Stream.fromIterable([4, 3, 2, 1]) +/// .transform(FlatMapStreamTransformer((i) => +/// Stream.fromFuture( +/// Future.delayed(Duration(minutes: i), () => i)) +/// .listen(print); // prints 1, 2, 3, 4 +class FlatMapStreamTransformer extends StreamTransformerBase { + /// Method which converts incoming events into a new [Stream] + final Stream Function(S value) mapper; + + /// Maximum number of inner [Stream] that may be listened to concurrently. + /// If it's `null`, it means unlimited. + final int? maxConcurrent; + + /// Constructs a [StreamTransformer] which emits events from the source [Stream] using the given [mapper]. + /// The mapped [Stream] will be listened to and begin emitting items downstream. + FlatMapStreamTransformer(this.mapper, {this.maxConcurrent}); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _FlatMapStreamSink(mapper, maxConcurrent)); +} + +/// Extends the Stream class with the ability to convert the source Stream into +/// a new Stream each time the source emits an item. +extension FlatMapExtension on Stream { + /// Converts each emitted item into a Stream using the given mapper function, + /// while limiting the maximum number of concurrent subscriptions to these [Stream]s. + /// The newly created Stream will be be listened to and begin emitting items downstream. + /// + /// The items emitted by each of the Streams are emitted downstream in the + /// same order they arrive. In other words, the sequences are merged + /// together. + /// + /// ### Example + /// + /// RangeStream(4, 1) + /// .flatMap((i) => TimerStream(i, Duration(minutes: i))) + /// .listen(print); // prints 1, 2, 3, 4 + Stream flatMap(Stream Function(T value) mapper, + {int? maxConcurrent}) => + FlatMapStreamTransformer(mapper, maxConcurrent: maxConcurrent) + .bind(this); + + /// Converts each item into a Stream. The Stream must return an + /// Iterable. Then, each item from the Iterable will be emitted one by one. + /// + /// Use case: you may have an API that returns a list of items, such as + /// a Stream>. However, you might want to operate on the individual items + /// rather than the list itself. This is the job of `flatMapIterable`. + /// + /// ### Example + /// + /// RangeStream(1, 4) + /// .flatMapIterable((i) => Stream.fromIterable([[i]])) + /// .listen(print); // prints 1, 2, 3, 4 + Stream flatMapIterable(Stream> Function(T value) mapper, + {int? maxConcurrent}) => + FlatMapStreamTransformer>(mapper, + maxConcurrent: maxConcurrent) + .bind(this) + .expand((Iterable iterable) => iterable); +} diff --git a/sandbox/reactivex/lib/src/transformers/group_by.dart b/sandbox/reactivex/lib/src/transformers/group_by.dart new file mode 100644 index 0000000..e2d2edb --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/group_by.dart @@ -0,0 +1,157 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; +import 'package:angel3_reactivex/src/utils/future.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +class _GroupByStreamSink extends ForwardingSink> { + final K Function(T event) grouper; + final Stream Function(GroupedStream)? duration; + + final groups = >{}; + Map>? subscriptions; + + _GroupByStreamSink(this.grouper, this.duration); + + void _closeAll() { + for (var c in groups.values) { + c.close(); + } + groups.clear(); + } + + StreamController _controllerBuilder(K key) { + final groupedController = StreamController.broadcast(sync: true); + final groupByStream = GroupedStream(key, groupedController.stream); + + if (duration != null) { + subscriptions?.remove(key)?.cancel(); + (subscriptions ??= {})[key] = duration!(groupByStream).take(1).listen( + null, + onDone: () { + subscriptions!.remove(key); + groups.remove(key)?.close(); + }, + onError: onError, + ); + } + + sink.add(groupByStream); + return groupedController; + } + + @override + void onData(T data) { + final K key; + try { + key = grouper(data); + } catch (e, s) { + sink.addError(e, s); + return; + } + + groups.putIfAbsent(key, () => _controllerBuilder(key)).add(data); + } + + @override + void onError(e, st) => sink.addError(e, st); + + @override + void onDone() { + _closeAll(); + sink.close(); + } + + @override + Future? onCancel() { + scheduleMicrotask(_closeAll); + + if (subscriptions?.isNotEmpty == true) { + final future = waitFuturesList([ + for (final s in subscriptions!.values) s.cancel(), + ]); + subscriptions?.clear(); + subscriptions = null; + return future; + } + return null; + } + + @override + FutureOr onListen() {} + + @override + void onPause() => subscriptions?.values.pauseAll(); + + @override + void onResume() => subscriptions?.values.resumeAll(); +} + +/// The GroupBy operator divides a [Stream] that emits items into +/// a [Stream] that emits [GroupedStream], +/// each one of which emits some subset of the items +/// from the original source [Stream]. +/// +/// [GroupedStream] acts like a regular [Stream], yet +/// adding a 'key' property, which receives its [Type] and value from +/// the [_grouper] Function. +/// +/// All items with the same key are emitted by the same [GroupedStream]. +class GroupByStreamTransformer + extends StreamTransformerBase> { + /// Method which converts incoming events into a new [GroupedStream] + final K Function(T event) grouper; + + /// A function that returns an [Stream] to determine how long each group should exist. + /// When the returned [Stream] emits its first data or done event, + /// the group will be closed and removed. + final Stream Function(GroupedStream grouped)? durationSelector; + + /// Constructs a [StreamTransformer] which groups events from the source + /// [Stream] and emits them as [GroupedStream]. + GroupByStreamTransformer(this.grouper, {this.durationSelector}); + + @override + Stream> bind(Stream stream) => forwardStream( + stream, () => _GroupByStreamSink(grouper, durationSelector)); +} + +/// The [Stream] used by [GroupByStreamTransformer], it contains events +/// that are grouped by a key value. +class GroupedStream extends StreamView { + /// The key is the category to which all events in this group belong to. + final K key; + + /// Constructs a [Stream] which only emits events that can be + /// categorized under [key]. + GroupedStream(this.key, Stream stream) : super(stream); + + @override + String toString() => 'GroupedStream{key: $key}'; +} + +/// Extends the Stream class with the ability to convert events into Streams +/// of events that are united by a key. +extension GroupByExtension on Stream { + /// The GroupBy operator divides a [Stream] that emits items into a [Stream] + /// that emits [GroupedStream], each one of which emits some subset of the + /// items from the original source [Stream]. + /// + /// [GroupedStream] acts like a regular [Stream], yet adding a 'key' property, + /// which receives its [Type] and value from the [grouper] Function. + /// + /// All items with the same key are emitted by the same [GroupedStream]. + /// + /// Optionally, `groupBy` takes a second argument [durationSelector]. + /// [durationSelector] is a function that returns an [Stream] to determine how long + /// each group should exist. When the returned [Stream] emits its first data or done event, + /// the group will be closed and removed. + Stream> groupBy( + K Function(T value) grouper, { + Stream Function(GroupedStream grouped)? durationSelector, + }) => + GroupByStreamTransformer(grouper, + durationSelector: durationSelector) + .bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/ignore_elements.dart b/sandbox/reactivex/lib/src/transformers/ignore_elements.dart new file mode 100644 index 0000000..a2f372b --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/ignore_elements.dart @@ -0,0 +1,61 @@ +import 'dart:async'; + +class _IgnoreElementsStreamSink implements EventSink { + final EventSink _outputSink; + + _IgnoreElementsStreamSink(this._outputSink); + + @override + void add(S data) {} + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() => _outputSink.close(); +} + +/// Creates a [Stream] where all emitted items are ignored, only the +/// error / completed notifications are passed +/// +/// [ReactiveX doc](http://reactivex.io/documentation/operators/ignoreelements.html) +/// [Interactive marble diagram](https://rxmarbles.com/#ignoreElements) +/// +/// ### Example +/// +/// MergeStream([ +/// Stream.fromIterable([1]), +/// ErrorStream(Exception()) +/// ]) +/// .transform(IgnoreElementsStreamTransformer()) +/// .listen(print, onError: print); // prints Exception +class IgnoreElementsStreamTransformer + extends StreamTransformerBase { + /// Constructs a [StreamTransformer] which simply ignores all events from + /// the source [Stream], except for error or completed events. + IgnoreElementsStreamTransformer(); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _IgnoreElementsStreamSink(sink)); +} + +/// Extends the Stream class with the ability to skip, or ignore, data events. +extension IgnoreElementsExtension on Stream { + /// Creates a Stream where all emitted items are ignored, only the error / + /// completed notifications are passed + /// + /// [ReactiveX doc](http://reactivex.io/documentation/operators/ignoreelements.html) + /// [Interactive marble diagram](https://rxmarbles.com/#ignoreElements) + /// + /// ### Example + /// + /// MergeStream([ + /// Stream.fromIterable([1]), + /// Stream.error(Exception()) + /// ]) + /// .ignoreElements() + /// .listen(print, onError: print); // prints Exception + Stream ignoreElements() => + IgnoreElementsStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/interval.dart b/sandbox/reactivex/lib/src/transformers/interval.dart new file mode 100644 index 0000000..4366760 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/interval.dart @@ -0,0 +1,91 @@ +import 'dart:async'; +import 'dart:collection'; + +class _IntervalStreamSink implements EventSink { + final Duration _duration; + final EventSink _outputSink; + final _queue = Queue(); + var _inputClosed = false; + var _openIntervals = 0; + + bool get noOpenIntervals => _openIntervals == 0; + + _IntervalStreamSink(this._outputSink, this._duration); + + @override + void add(S data) { + _queue.add(data); + + if (noOpenIntervals) { + _addNext(); + } + } + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() { + _inputClosed = true; + + if (noOpenIntervals) { + _outputSink.close(); + } + } + + void _addNext() { + if (_queue.isNotEmpty) { + _addDelayed(_queue.removeFirst()).whenComplete(_addNext); + } + } + + Future _addDelayed(S data) { + _openIntervals++; + + return Future.delayed(_duration, () => data) + .then(_outputSink.add) + .whenComplete(() { + _openIntervals--; + + if (_inputClosed && _queue.isEmpty) { + _outputSink.close(); + } + }); + } +} + +/// Creates a Stream that emits each item in the Stream after a given +/// duration. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3]) +/// .transform(IntervalStreamTransformer(Duration(seconds: 1))) +/// .listen((i) => print('$i sec')); // prints 1 sec, 2 sec, 3 sec +class IntervalStreamTransformer extends StreamTransformerBase { + /// The interval after which incoming events need to be emitted. + final Duration duration; + + /// Constructs a [StreamTransformer] which emits each item from the source [Stream], + /// after a given duration. + IntervalStreamTransformer(this.duration); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _IntervalStreamSink(sink, duration)); +} + +/// Extends the Stream class with the ability to emit each item after a given +/// duration. +extension IntervalExtension on Stream { + /// Creates a Stream that emits each item in the Stream after a given + /// duration. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .interval(Duration(seconds: 1)) + /// .listen((i) => print('$i sec'); // prints 1 sec, 2 sec, 3 sec + Stream interval(Duration duration) => + IntervalStreamTransformer(duration).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/map_not_null.dart b/sandbox/reactivex/lib/src/transformers/map_not_null.dart new file mode 100644 index 0000000..724d6ba --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/map_not_null.dart @@ -0,0 +1,75 @@ +import 'dart:async'; + +class _MapNotNullSink implements EventSink { + final R? Function(T) _transform; + final EventSink _outputSink; + + _MapNotNullSink(this._outputSink, this._transform); + + @override + void add(T event) { + final value = _transform(event); + if (value != null) { + _outputSink.add(value); + } + } + + @override + void addError(Object error, [StackTrace? stackTrace]) => + _outputSink.addError(error, stackTrace); + + @override + void close() => _outputSink.close(); +} + +/// Create a Stream containing only the non-`null` results +/// of applying the given [transform] function to each element of the Stream. +/// +/// ### Example +/// +/// Stream.fromIterable(['1', 'two', '3', 'four']) +/// .transform(MapNotNullStreamTransformer(int.tryParse)) +/// .listen(print); // prints 1, 3 +/// +/// // equivalent to: +/// +/// Stream.fromIterable(['1', 'two', '3', 'four']) +/// .map(int.tryParse) +/// .transform(WhereTypeStreamTransformer()) +/// .listen(print); // prints 1, 3 +class MapNotNullStreamTransformer + extends StreamTransformerBase { + /// A function that transforms each elements of the Stream. + final R? Function(T) transform; + + /// Constructs a [StreamTransformer] which emits non-`null` elements + /// of applying the given [transform] function to each element of the Stream. + const MapNotNullStreamTransformer(this.transform); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _MapNotNullSink(sink, transform)); +} + +/// Extends the Stream class with the ability to convert the source Stream +/// to a Stream containing only the non-`null` results +/// of applying the given [transform] function to each element of this Stream. +extension MapNotNullExtension on Stream { + /// Returns a Stream containing only the non-`null` results + /// of applying the given [transform] function to each element of this Stream. + /// + /// ### Example + /// + /// Stream.fromIterable(['1', 'two', '3', 'four']) + /// .mapNotNull(int.tryParse) + /// .listen(print); // prints 1, 3 + /// + /// // equivalent to: + /// + /// Stream.fromIterable(['1', 'two', '3', 'four']) + /// .map(int.tryParse) + /// .whereType() + /// .listen(print); // prints 1, 3 + Stream mapNotNull(R? Function(T) transform) => + MapNotNullStreamTransformer(transform).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/map_to.dart b/sandbox/reactivex/lib/src/transformers/map_to.dart new file mode 100644 index 0000000..d58d74a --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/map_to.dart @@ -0,0 +1,52 @@ +import 'dart:async'; + +class _MapToStreamSink implements EventSink { + final T _value; + final EventSink _outputSink; + + _MapToStreamSink(this._outputSink, this._value); + + @override + void add(S data) => _outputSink.add(_value); + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() => _outputSink.close(); +} + +/// Emits the given constant value on the output Stream every time the source +/// Stream emits a value. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3, 4]) +/// .mapTo(true) +/// .listen(print); // prints true, true, true, true +class MapToStreamTransformer extends StreamTransformerBase { + /// A constant [value] which will always be returned when using this transformer. + final T value; + + /// Constructs a [StreamTransformer] which always maps every event from + /// the source [Stream] to a constant [value]. + MapToStreamTransformer(this.value); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _MapToStreamSink(sink, value)); +} + +/// Extends the Stream class with the ability to convert each item to the same +/// value. +extension MapToExtension on Stream { + /// Emits the given constant value on the output Stream every time the source + /// Stream emits a value. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3, 4]) + /// .mapTo(true) + /// .listen(print); // prints true, true, true, true + Stream mapTo(T value) => MapToStreamTransformer(value).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/materialize.dart b/sandbox/reactivex/lib/src/transformers/materialize.dart new file mode 100644 index 0000000..e0f3d56 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/materialize.dart @@ -0,0 +1,68 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/notification.dart'; + +class _MaterializeStreamSink implements EventSink { + final EventSink> _outputSink; + + _MaterializeStreamSink(this._outputSink); + + @override + void add(S data) => _outputSink.add(StreamNotification.data(data)); + + @override + void addError(e, [st]) => _outputSink.add(StreamNotification.error(e, st)); + + @override + void close() { + _outputSink.add(StreamNotification.done()); + _outputSink.close(); + } +} + +/// Converts the onData, on Done, and onError events into [StreamNotification] +/// objects that are passed into the downstream onData listener. +/// +/// The [StreamNotification] object contains the [NotificationKind] of event (OnData, onDone, or +/// OnError), and the item or error that was emitted. In the case of onDone, +/// no data is emitted as part of the [StreamNotification]. +/// +/// ### Example +/// +/// Stream.fromIterable([1]) +/// .transform(MaterializeStreamTransformer()) +/// .listen(print); // Prints DataNotification{value: 1}, DoneNotification{} +class MaterializeStreamTransformer + extends StreamTransformerBase> { + /// Constructs a [StreamTransformer] which transforms the onData, on Done, + /// and onError events into [StreamNotification] objects. + MaterializeStreamTransformer(); + + @override + Stream> bind(Stream stream) => + Stream.eventTransformed( + stream, (sink) => _MaterializeStreamSink(sink)); +} + +/// Extends the Stream class with the ability to convert the onData, on Done, +/// and onError events into [StreamNotification]s that are passed into the +/// downstream onData listener. +extension MaterializeExtension on Stream { + /// Converts the onData, on Done, and onError events into [StreamNotification] + /// objects that are passed into the downstream onData listener. + /// + /// The [StreamNotification] object contains the [NotificationKind] of event (OnData, onDone, or + /// OnError), and the item or error that was emitted. In the case of onDone, + /// no data is emitted as part of the [StreamNotification]. + /// + /// Example: + /// Stream.fromIterable([1]) + /// .materialize() + /// .listen(print); // Prints DataNotification{value: 1}, DoneNotification{} + /// + /// Stream.error(Exception()) + /// .materialize() + /// .listen(print); // Prints ErrorNotification{error: Exception, stackTrace: }, DoneNotification{} + Stream> materialize() => + MaterializeStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/max.dart b/sandbox/reactivex/lib/src/transformers/max.dart new file mode 100644 index 0000000..ff66ae6 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/max.dart @@ -0,0 +1,25 @@ +import 'package:angel3_reactivex/src/utils/min_max.dart'; + +/// Extends the Stream class with the ability to transform into a Future +/// that completes with the largest item emitted by the Stream. +extension MaxExtension on Stream { + /// Converts a Stream into a Future that completes with the largest item + /// emitted by the Stream. + /// + /// This is similar to finding the max value in a list, but the values are + /// asynchronous. + /// + /// ### Example + /// + /// final max = await Stream.fromIterable([1, 2, 3]).max(); + /// + /// print(max); // prints 3 + /// + /// ### Example with custom [Comparator] + /// + /// final stream = Stream.fromIterable(['short', 'looooooong']); + /// final max = await stream.max((a, b) => a.length - b.length); + /// + /// print(max); // prints 'looooooong' + Future max([Comparator? comparator]) => minMax(this, false, comparator); +} diff --git a/sandbox/reactivex/lib/src/transformers/min.dart b/sandbox/reactivex/lib/src/transformers/min.dart new file mode 100644 index 0000000..41caec1 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/min.dart @@ -0,0 +1,27 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/min_max.dart'; + +/// Extends the Stream class with the ability to transform into a Future +/// that completes with the smallest item emitted by the Stream. +extension MinExtension on Stream { + /// Converts a Stream into a Future that completes with the smallest item + /// emitted by the Stream. + /// + /// This is similar to finding the min value in a list, but the values are + /// asynchronous! + /// + /// ### Example + /// + /// final min = await Stream.fromIterable([1, 2, 3]).min(); + /// + /// print(min); // prints 1 + /// + /// ### Example with custom [Comparator] + /// + /// final stream = Stream.fromIterable(['short', 'looooooong']); + /// final min = await stream.min((a, b) => a.length - b.length); + /// + /// print(min); // prints 'short' + Future min([Comparator? comparator]) => minMax(this, true, comparator); +} diff --git a/sandbox/reactivex/lib/src/transformers/on_error_resume.dart b/sandbox/reactivex/lib/src/transformers/on_error_resume.dart new file mode 100644 index 0000000..ad574b0 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/on_error_resume.dart @@ -0,0 +1,181 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +class _OnErrorResumeStreamSink extends ForwardingSink { + final Stream Function(Object error, StackTrace stackTrace) _recoveryFn; + final List> _recoverySubscriptions = []; + var closed = false; + + _OnErrorResumeStreamSink(this._recoveryFn); + + @override + void onData(S data) => sink.add(data); + + @override + void onError(Object e, StackTrace st) { + final Stream recoveryStream; + + try { + recoveryStream = _recoveryFn(e, st); + } catch (newError, newSt) { + sink.addError(newError, newSt); + return; + } + + final subscription = + recoveryStream.listen(sink.add, onError: sink.addError); + subscription.onDone(() { + _recoverySubscriptions.remove(subscription); + if (closed && _recoverySubscriptions.isEmpty) { + sink.close(); + } + }); + _recoverySubscriptions.add(subscription); + } + + @override + void onDone() { + closed = true; + if (_recoverySubscriptions.isEmpty) { + sink.close(); + } + } + + @override + Future? onCancel() => _recoverySubscriptions.cancelAll(); + + @override + void onListen() {} + + @override + void onPause() => _recoverySubscriptions.pauseAll(); + + @override + void onResume() => _recoverySubscriptions.resumeAll(); +} + +/// Intercepts error events and switches to a recovery stream created by the +/// provided recoveryFn Function. +/// +/// The OnErrorResumeStreamTransformer intercepts an onError notification from +/// the source Stream. Instead of passing the error through to any +/// listeners, it replaces it with another Stream of items created by the +/// recoveryFn. +/// +/// The recoveryFn receives the emitted error and returns a Stream. You can +/// perform logic in the recoveryFn to return different Streams based on the +/// type of error that was emitted. +/// +/// ### Example +/// +/// Stream.error(Exception()) +/// .onErrorResume((dynamic e) => +/// Stream.value(e is StateError ? 1 : 0) +/// .listen(print); // prints 0 +class OnErrorResumeStreamTransformer extends StreamTransformerBase { + /// Method which returns a [Stream], based from the error. + final Stream Function(Object error, StackTrace stackTrace) recoveryFn; + + /// Constructs a [StreamTransformer] which intercepts error events and + /// switches to a recovery [Stream] created by the provided [recoveryFn] Function. + OnErrorResumeStreamTransformer(this.recoveryFn); + + @override + Stream bind(Stream stream) => forwardStream( + stream, + () => _OnErrorResumeStreamSink(recoveryFn), + ); +} + +/// Extends the Stream class with the ability to recover from errors in various +/// ways +extension OnErrorExtensions on Stream { + /// Intercepts error events and switches to the given recovery stream in + /// that case + /// + /// The onErrorResumeNext operator intercepts an onError notification from + /// the source Stream. Instead of passing the error through to any + /// listeners, it replaces it with another Stream of items. + /// + /// If you need to perform logic based on the type of error that was emitted, + /// please consider using [onErrorResume]. + /// + /// ### Example + /// + /// ErrorStream(Exception()) + /// .onErrorResumeNext(Stream.fromIterable([1, 2, 3])) + /// .listen(print); // prints 1, 2, 3 + Stream onErrorResumeNext(Stream recoveryStream) => + OnErrorResumeStreamTransformer((_, __) => recoveryStream).bind(this); + + /// Intercepts error events and switches to a recovery stream created by the + /// provided [recoveryFn]. + /// + /// The onErrorResume operator intercepts an onError notification from + /// the source Stream. Instead of passing the error through to any + /// listeners, it replaces it with another Stream of items created by the + /// [recoveryFn]. + /// + /// The [recoveryFn] receives the emitted error and returns a Stream. You can + /// perform logic in the [recoveryFn] to return different Streams based on the + /// type of error that was emitted. + /// + /// If you do not need to perform logic based on the type of error that was + /// emitted, please consider using [onErrorResumeNext] or [onErrorReturn]. + /// + /// ### Example + /// + /// ErrorStream(Exception()) + /// .onErrorResume((e, st) => + /// Stream.fromIterable([e is StateError ? 1 : 0])) + /// .listen(print); // prints 0 + Stream onErrorResume( + Stream Function(Object error, StackTrace stackTrace) recoveryFn) => + OnErrorResumeStreamTransformer(recoveryFn).bind(this); + + /// Instructs a Stream to emit a particular item when it encounters an + /// error, and then terminate normally + /// + /// The onErrorReturn operator intercepts an onError notification from + /// the source Stream. Instead of passing it through to any observers, it + /// replaces it with a given item, and then terminates normally. + /// + /// If you need to perform logic based on the type of error that was emitted, + /// please consider using [onErrorReturnWith]. + /// + /// ### Example + /// + /// ErrorStream(Exception()) + /// .onErrorReturn(1) + /// .listen(print); // prints 1 + Stream onErrorReturn(T returnValue) => + OnErrorResumeStreamTransformer((_, __) => Stream.value(returnValue)) + .bind(this); + + /// Instructs a Stream to emit a particular item created by the + /// [returnFn] when it encounters an error, and then terminate normally. + /// + /// The onErrorReturnWith operator intercepts an onError notification from + /// the source Stream. Instead of passing it through to any observers, it + /// replaces it with a given item, and then terminates normally. + /// + /// The [returnFn] receives the emitted error and returns a value. You can + /// perform logic in the [returnFn] to return different value based on the + /// type of error that was emitted. + /// + /// If you do not need to perform logic based on the type of error that was + /// emitted, please consider using [onErrorReturn]. + /// + /// ### Example + /// + /// ErrorStream(Exception()) + /// .onErrorReturnWith((e, st) => e is Exception ? 1 : 0) + /// .listen(print); // prints 1 + Stream onErrorReturnWith( + T Function(Object error, StackTrace stackTrace) returnFn) => + OnErrorResumeStreamTransformer( + (e, st) => Stream.value(returnFn(e, st))).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/scan.dart b/sandbox/reactivex/lib/src/transformers/scan.dart new file mode 100644 index 0000000..a2d4e71 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/scan.dart @@ -0,0 +1,62 @@ +import 'dart:async'; + +class _ScanStreamSink implements EventSink { + final T Function(T accumulated, S value, int index) _accumulator; + final EventSink _outputSink; + T _acc; + var _index = 0; + + _ScanStreamSink(this._outputSink, this._accumulator, this._acc); + + @override + void add(S data) => + _outputSink.add(_acc = _accumulator(_acc, data, _index++)); + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() => _outputSink.close(); +} + +/// Applies an accumulator function over an stream sequence and returns +/// each intermediate result. The seed value is used as the initial +/// accumulator value. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3]) +/// .transform(ScanStreamTransformer((acc, curr, i) => acc + curr, 0)) +/// .listen(print); // prints 1, 3, 6 +class ScanStreamTransformer extends StreamTransformerBase { + /// Method which accumulates incoming event into a single, accumulated object + final T Function(T accumulated, S value, int index) accumulator; + + /// The initial value for the accumulated value in the [accumulator] + final T seed; + + /// Constructs a [ScanStreamTransformer] which applies an accumulator Function + /// over the source [Stream] and returns each intermediate result. + /// The seed value is used as the initial accumulator value. + ScanStreamTransformer(this.accumulator, this.seed); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _ScanStreamSink(sink, accumulator, seed)); +} + +/// Extends +extension ScanExtension on Stream { + /// Applies an accumulator function over a Stream sequence and returns each + /// intermediate result. The seed value is used as the initial + /// accumulator value. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3]) + /// .scan((acc, curr, i) => acc + curr, 0) + /// .listen(print); // prints 1, 3, 6 + Stream scan( + S Function(S accumulated, T value, int index) accumulator, S seed) => + ScanStreamTransformer(accumulator, seed).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/skip_last.dart b/sandbox/reactivex/lib/src/transformers/skip_last.dart new file mode 100644 index 0000000..1bbdfe6 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/skip_last.dart @@ -0,0 +1,79 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _SkipLastStreamSink extends ForwardingSink { + _SkipLastStreamSink(this.count); + + final int count; + final List queue = []; + + @override + void onData(T data) { + queue.add(data); + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + final limit = queue.length - count; + if (limit > 0) { + queue.sublist(0, limit).forEach(sink.add); + } + sink.close(); + } + + @override + FutureOr onCancel() { + queue.clear(); + } + + @override + void onListen() {} + + @override + void onPause() {} + + @override + void onResume() {} +} + +/// Skip the last [count] items emitted by the source [Stream] +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3, 4, 5]) +/// .transform(SkipLastStreamTransformer(3)) +/// .listen(print); // prints 1, 2 +class SkipLastStreamTransformer extends StreamTransformerBase { + /// Constructs a [StreamTransformer] which skip the last [count] items + /// emitted by the source [Stream] + SkipLastStreamTransformer(this.count) { + if (count < 0) throw ArgumentError.value(count, 'count'); + } + + /// The [count] of final items to skip. + final int count; + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _SkipLastStreamSink(count)); +} + +/// Extends the Stream class with the ability to skip the last [count] items +/// emitted by the source [Stream] +extension SkipLastExtension on Stream { + /// Starts emitting every items except last [count] items. + /// This causes items to be delayed. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3, 4, 5]) + /// .skipLast(3) + /// .listen(print); // prints 1, 2 + Stream skipLast(int count) => + SkipLastStreamTransformer(count).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/skip_until.dart b/sandbox/reactivex/lib/src/transformers/skip_until.dart new file mode 100644 index 0000000..accf206 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/skip_until.dart @@ -0,0 +1,82 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _SkipUntilStreamSink extends ForwardingSink { + final Stream _otherStream; + StreamSubscription? _otherSubscription; + var _canAdd = false; + + _SkipUntilStreamSink(this._otherStream); + + @override + void onData(S data) { + if (_canAdd) { + sink.add(data); + } + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + _otherSubscription?.cancel(); + sink.close(); + } + + @override + FutureOr onCancel() => _otherSubscription?.cancel(); + + @override + void onListen() => _otherSubscription = _otherStream + .take(1) + .listen(null, onError: sink.addError, onDone: () => _canAdd = true); + + @override + void onPause() => _otherSubscription?.pause(); + + @override + void onResume() => _otherSubscription?.resume(); +} + +/// Starts emitting events only after the given stream emits an event. +/// +/// ### Example +/// +/// MergeStream([ +/// Stream.value(1), +/// TimerStream(2, Duration(minutes: 2)) +/// ]) +/// .transform(SkipUntilStreamTransformer(TimerStream(1, Duration(minutes: 1)))) +/// .listen(print); // prints 2; +class SkipUntilStreamTransformer extends StreamTransformerBase { + /// The [Stream] which is required to emit first, before this [Stream] starts emitting + final Stream otherStream; + + /// Constructs a [StreamTransformer] which starts emitting events + /// only after [otherStream] emits an event. + SkipUntilStreamTransformer(this.otherStream); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _SkipUntilStreamSink(otherStream)); +} + +/// Extends the Stream class with the ability to skip events until another +/// Stream emits an item. +extension SkipUntilExtension on Stream { + /// Starts emitting items only after the given stream emits an item. + /// + /// ### Example + /// + /// MergeStream([ + /// Stream.fromIterable([1]), + /// TimerStream(2, Duration(minutes: 2)) + /// ]) + /// .skipUntil(TimerStream(true, Duration(minutes: 1))) + /// .listen(print); // prints 2; + Stream skipUntil(Stream otherStream) => + SkipUntilStreamTransformer(otherStream).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/start_with.dart b/sandbox/reactivex/lib/src/transformers/start_with.dart new file mode 100644 index 0000000..60e966c --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/start_with.dart @@ -0,0 +1,65 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _StartWithStreamSink extends ForwardingSink { + final S _startValue; + + _StartWithStreamSink(this._startValue); + + @override + void onData(S data) => sink.add(data); + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() => sink.close(); + + @override + FutureOr onCancel() {} + + @override + void onListen() { + sink.add(_startValue); + } + + @override + void onPause() {} + + @override + void onResume() {} +} + +/// Prepends a value to the source [Stream]. +/// +/// ### Example +/// +/// Stream.fromIterable([2]) +/// .transform(StartWithStreamTransformer(1)) +/// .listen(print); // prints 1, 2 +class StartWithStreamTransformer extends StreamTransformerBase { + /// The starting event of this [Stream] + final S startValue; + + /// Constructs a [StreamTransformer] which prepends the source [Stream] + /// with [startValue]. + StartWithStreamTransformer(this.startValue); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _StartWithStreamSink(startValue)); +} + +/// Extends the [Stream] class with the ability to emit the given value as the +/// first item. +extension StartWithExtension on Stream { + /// Prepends a value to the source [Stream]. + /// + /// ### Example + /// + /// Stream.fromIterable([2]).startWith(1).listen(print); // prints 1, 2 + Stream startWith(T startValue) => + StartWithStreamTransformer(startValue).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/start_with_error.dart b/sandbox/reactivex/lib/src/transformers/start_with_error.dart new file mode 100644 index 0000000..7a74a08 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/start_with_error.dart @@ -0,0 +1,57 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _StartWithErrorStreamSink extends ForwardingSink { + final Object _e; + final StackTrace? _st; + + _StartWithErrorStreamSink(this._e, this._st); + + @override + void onData(S data) => sink.add(data); + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() => sink.close(); + + @override + FutureOr onCancel() {} + + @override + void onListen() { + sink.addError(_e, _st); + } + + @override + void onPause() {} + + @override + void onResume() {} +} + +/// Prepends an error to the source [Stream]. +/// +/// ### Example +/// +/// Stream.fromIterable([2]) +/// .transform(StartWithErrorStreamTransformer('error')) +/// .listen(null, onError: (e) => print(e)); // prints 'error' +class StartWithErrorStreamTransformer extends StreamTransformerBase { + /// The starting error of this [Stream] + final Object error; + + /// The starting stackTrace of this [Stream] + final StackTrace? stackTrace; + + /// Constructs a [StreamTransformer] which starts with the provided [error] + /// and then outputs all events from the source [Stream]. + StartWithErrorStreamTransformer(this.error, [this.stackTrace]); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _StartWithErrorStreamSink(error, stackTrace)); +} diff --git a/sandbox/reactivex/lib/src/transformers/start_with_many.dart b/sandbox/reactivex/lib/src/transformers/start_with_many.dart new file mode 100644 index 0000000..7c8e401 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/start_with_many.dart @@ -0,0 +1,66 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _StartWithManyStreamSink extends ForwardingSink { + final Iterable _startValues; + + _StartWithManyStreamSink(this._startValues); + + @override + void onData(S data) => sink.add(data); + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() => sink.close(); + + @override + FutureOr onCancel() {} + + @override + void onListen() { + _startValues.forEach(sink.add); + } + + @override + void onPause() {} + + @override + void onResume() {} +} + +/// Prepends a sequence of values to the source [Stream]. +/// +/// ### Example +/// +/// Stream.fromIterable([3]) +/// .transform(StartWithManyStreamTransformer([1, 2])) +/// .listen(print); // prints 1, 2, 3 +class StartWithManyStreamTransformer extends StreamTransformerBase { + /// The starting events of this [Stream] + final Iterable startValues; + + /// Constructs a [StreamTransformer] which prepends the source [Stream] + /// with [startValues]. + StartWithManyStreamTransformer(this.startValues); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _StartWithManyStreamSink(startValues)); +} + +/// Extends the [Stream] class with the ability to emit the given values as the +/// first items. +extension StartWithManyExtension on Stream { + /// Prepends a sequence of values to the source [Stream]. + /// + /// ### Example + /// + /// Stream.fromIterable([3]).startWithMany([1, 2]) + /// .listen(print); // prints 1, 2, 3 + Stream startWithMany(List startValues) => + StartWithManyStreamTransformer(startValues).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/switch_if_empty.dart b/sandbox/reactivex/lib/src/transformers/switch_if_empty.dart new file mode 100644 index 0000000..aa5f779 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/switch_if_empty.dart @@ -0,0 +1,119 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _SwitchIfEmptyStreamSink extends ForwardingSink { + final Stream _fallbackStream; + + var _isEmpty = true; + StreamSubscription? _fallbackSubscription; + + _SwitchIfEmptyStreamSink(this._fallbackStream); + + @override + void onData(S data) { + _isEmpty = false; + sink.add(data); + } + + @override + void onError(Object error, StackTrace st) { + sink.addError(error, st); + } + + @override + void onDone() { + if (_isEmpty) { + _fallbackSubscription = _fallbackStream.listen( + sink.add, + onError: sink.addError, + onDone: sink.close, + ); + } else { + sink.close(); + } + } + + @override + FutureOr onCancel() => _fallbackSubscription?.cancel(); + + @override + void onListen() {} + + @override + void onPause() => _fallbackSubscription?.pause(); + + @override + void onResume() => _fallbackSubscription?.resume(); +} + +/// When the original stream emits no items, this operator subscribes to +/// the given fallback stream and emits items from that stream instead. +/// +/// This can be particularly useful when consuming data from multiple sources. +/// For example, when using the Repository Pattern. Assuming you have some +/// data you need to load, you might want to start with the fastest access +/// point and keep falling back to the slowest point. For example, first query +/// an in-memory database, then a database on the file system, then a network +/// call if the data isn't on the local machine. +/// +/// This can be achieved quite simply with switchIfEmpty! +/// +/// ### Example +/// +/// // Let's pretend we have some Data sources that complete without emitting +/// // any items if they don't contain the data we're looking for +/// Stream memory; +/// Stream disk; +/// Stream network; +/// +/// // Start with memory, fallback to disk, then fallback to network. +/// // Simple as that! +/// Stream getThatData = +/// memory.switchIfEmpty(disk).switchIfEmpty(network); +class SwitchIfEmptyStreamTransformer extends StreamTransformerBase { + /// The [Stream] which will be used as fallback, if the source [Stream] is empty. + final Stream fallbackStream; + + /// Constructs a [StreamTransformer] which, when the source [Stream] emits + /// no events, switches over to [fallbackStream]. + SwitchIfEmptyStreamTransformer(this.fallbackStream); + + @override + Stream bind(Stream stream) { + return forwardStream( + stream, () => _SwitchIfEmptyStreamSink(fallbackStream)); + } +} + +/// Extend the Stream class with the ability to return an alternative Stream +/// if the initial Stream completes with no items. +extension SwitchIfEmptyExtension on Stream { + /// When the original Stream emits no items, this operator subscribes to the + /// given fallback stream and emits items from that Stream instead. + /// + /// This can be particularly useful when consuming data from multiple sources. + /// For example, when using the Repository Pattern. Assuming you have some + /// data you need to load, you might want to start with the fastest access + /// point and keep falling back to the slowest point. For example, first query + /// an in-memory database, then a database on the file system, then a network + /// call if the data isn't on the local machine. + /// + /// This can be achieved quite simply with switchIfEmpty! + /// + /// ### Example + /// + /// // Let's pretend we have some Data sources that complete without + /// // emitting any items if they don't contain the data we're looking for + /// Stream memory; + /// Stream disk; + /// Stream network; + /// + /// // Start with memory, fallback to disk, then fallback to network. + /// // Simple as that! + /// Stream getThatData = + /// memory.switchIfEmpty(disk).switchIfEmpty(network); + Stream switchIfEmpty(Stream fallbackStream) => + SwitchIfEmptyStreamTransformer(fallbackStream).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/switch_map.dart b/sandbox/reactivex/lib/src/transformers/switch_map.dart new file mode 100644 index 0000000..63b63ae --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/switch_map.dart @@ -0,0 +1,155 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _SwitchMapStreamSink extends ForwardingSink { + final Stream Function(S value) _mapper; + StreamSubscription? _mapperSubscription; + bool _inputClosed = false; + bool _isCancelled = false; + + _SwitchMapStreamSink(this._mapper); + + @override + void onData(S data) { + final Stream mappedStream; + try { + mappedStream = _mapper(data); + } catch (e, s) { + sink.addError(e, s); + return; + } + + final mapperSubscription = _mapperSubscription; + + if (mapperSubscription == null) { + listenToInner(mappedStream); + return; + } + + _mapperSubscription = null; + pauseSubscription(); + mapperSubscription.cancel().onError((e, s) { + if (!_isCancelled) { + sink.addError(e, s); + } + }).whenComplete(() => resumeAndListenToInner(mappedStream)); + } + + void resumeAndListenToInner(Stream mappedStream) { + if (_isCancelled) { + return; + } + + resumeSubscription(); + listenToInner(mappedStream); + } + + void listenToInner(Stream mappedStream) { + assert(_mapperSubscription == null); + + _mapperSubscription = mappedStream.listen( + sink.add, + onError: sink.addError, + onDone: () { + _mapperSubscription = null; + + if (_inputClosed) { + sink.close(); + } + }, + ); + + // https://github.com/dart-lang/stream_transform/blob/9743578b0119de6a8badd30bb16ef15d79bd3b15/lib/src/switch.dart#L71-L74 + // If a pause happens during an _mapperSubscription.cancel, + // we still listen to the next stream when the cancel is done. + // Then we immediately pause it again here. + if (sink.isPaused) { + _mapperSubscription?.pause(); + } + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + _inputClosed = true; + + _mapperSubscription ?? sink.close(); + } + + @override + FutureOr onCancel() { + _isCancelled = true; + + return _mapperSubscription?.cancel(); + } + + @override + void onListen() {} + + @override + void onPause() => _mapperSubscription?.pause(); + + @override + void onResume() => _mapperSubscription?.resume(); +} + +/// Converts each emitted item into a new Stream using the given mapper +/// function. The newly created Stream will be be listened to and begin +/// emitting items, and any previously created Stream will stop emitting. +/// +/// The switchMap operator is similar to the flatMap and concatMap +/// methods, but it only emits items from the most recently created Stream. +/// +/// This can be useful when you only want the very latest state from +/// asynchronous APIs, for example. +/// +/// ### Example +/// +/// Stream.fromIterable([4, 3, 2, 1]) +/// .transform(SwitchMapStreamTransformer((i) => +/// Stream.fromFuture( +/// Future.delayed(Duration(minutes: i), () => i)) +/// .listen(print); // prints 1 +class SwitchMapStreamTransformer extends StreamTransformerBase { + /// Method which converts incoming events into a new [Stream] + final Stream Function(S value) mapper; + + /// Constructs a [StreamTransformer] which maps each event from the source [Stream] + /// using [mapper]. + /// + /// The mapped [Stream] will be be listened to and begin + /// emitting items, and any previously created mapper [Stream]s will stop emitting. + SwitchMapStreamTransformer(this.mapper); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _SwitchMapStreamSink(mapper)); +} + +/// Extends the Stream with the ability to convert one stream into a new Stream +/// whenever the source emits an item. Every time a new Stream is created, the +/// previous Stream is discarded. +extension SwitchMapExtension on Stream { + /// Converts each emitted item into a Stream using the given mapper function. + /// The newly created Stream will be be listened to and begin emitting items, + /// and any previously created Stream will stop emitting. + /// + /// The switchMap operator is similar to the flatMap and concatMap methods, + /// but it only emits items from the most recently created Stream. + /// + /// This can be useful when you only want the very latest state from + /// asynchronous APIs, for example. + /// + /// ### Example + /// + /// RangeStream(4, 1) + /// .switchMap((i) => + /// TimerStream(i, Duration(minutes: i))) + /// .listen(print); // prints 1 + Stream switchMap(Stream Function(T value) mapper) => + SwitchMapStreamTransformer(mapper).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/take_last.dart b/sandbox/reactivex/lib/src/transformers/take_last.dart new file mode 100644 index 0000000..56a11a7 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/take_last.dart @@ -0,0 +1,83 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _TakeLastStreamSink extends ForwardingSink { + _TakeLastStreamSink(this.count); + + final int count; + final Queue queue = DoubleLinkedQueue(); + + @override + void onData(T data) { + if (count > 0) { + queue.addLast(data); + if (queue.length > count) { + queue.removeFirst(); + } + } + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + if (queue.isNotEmpty) { + queue.toList(growable: false).forEach(sink.add); + } + sink.close(); + } + + @override + FutureOr onCancel() { + queue.clear(); + } + + @override + void onListen() {} + + @override + void onPause() {} + + @override + void onResume() {} +} + +/// Emits only the final [count] values emitted by the source [Stream]. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3, 4, 5]) +/// .transform(TakeLastStreamTransformer(3)) +/// .listen(print); // prints 3, 4, 5 +class TakeLastStreamTransformer extends StreamTransformerBase { + /// Constructs a [StreamTransformer] which emits only the final [count] + /// events from the source [Stream]. + TakeLastStreamTransformer(this.count) { + if (count < 0) throw ArgumentError.value(count, 'count'); + } + + /// The [count] of final items emitted when the stream completes. + final int count; + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _TakeLastStreamSink(count)); +} + +/// Extends the [Stream] class with the ability receive only the final [count] +/// events from the source [Stream]. +extension TakeLastExtension on Stream { + /// Emits only the final [count] values emitted by the source [Stream]. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3, 4, 5]) + /// .takeLast(3) + /// .listen(print); // prints 3, 4, 5 + Stream takeLast(int count) => + TakeLastStreamTransformer(count).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/take_until.dart b/sandbox/reactivex/lib/src/transformers/take_until.dart new file mode 100644 index 0000000..54fe0d6 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/take_until.dart @@ -0,0 +1,80 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _TakeUntilStreamSink extends ForwardingSink { + final Stream _otherStream; + StreamSubscription? _otherSubscription; + + _TakeUntilStreamSink(this._otherStream); + + @override + void onData(S data) => sink.add(data); + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() { + _otherSubscription?.cancel(); + sink.close(); + } + + @override + FutureOr onCancel() => _otherSubscription?.cancel(); + + @override + void onListen() => _otherSubscription = _otherStream + .take(1) + .listen(null, onError: sink.addError, onDone: sink.close); + + @override + void onPause() => _otherSubscription?.pause(); + + @override + void onResume() => _otherSubscription?.resume(); +} + +/// Returns the values from the source stream sequence until the other +/// stream sequence produces a value. +/// +/// ### Example +/// +/// MergeStream([ +/// Stream.fromIterable([1]), +/// TimerStream(2, Duration(minutes: 1)) +/// ]) +/// .transform(TakeUntilStreamTransformer( +/// TimerStream(3, Duration(seconds: 10)))) +/// .listen(print); // prints 1 +class TakeUntilStreamTransformer extends StreamTransformerBase { + /// The [Stream] which closes this [Stream] as soon as it emits an event. + final Stream otherStream; + + /// Constructs a [StreamTransformer] which emits events from the source [Stream], + /// until [otherStream] fires. + TakeUntilStreamTransformer(this.otherStream); + + @override + Stream bind(Stream stream) => + forwardStream(stream, () => _TakeUntilStreamSink(otherStream)); +} + +/// Extends the Stream class with the ability receive events from the source +/// Stream until another Stream produces a value. +extension TakeUntilExtension on Stream { + /// Returns the values from the source Stream sequence until the other Stream + /// sequence produces a value. + /// + /// ### Example + /// + /// MergeStream([ + /// Stream.fromIterable([1]), + /// TimerStream(2, Duration(minutes: 1)) + /// ]) + /// .takeUntil(TimerStream(3, Duration(seconds: 10))) + /// .listen(print); // prints 1 + Stream takeUntil(Stream otherStream) => + TakeUntilStreamTransformer(otherStream).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/take_while_inclusive.dart b/sandbox/reactivex/lib/src/transformers/take_while_inclusive.dart new file mode 100644 index 0000000..8471db1 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/take_while_inclusive.dart @@ -0,0 +1,74 @@ +import 'dart:async'; + +class _TakeWhileInclusiveStreamSink implements EventSink { + final bool Function(S) _test; + final EventSink _outputSink; + + _TakeWhileInclusiveStreamSink(this._outputSink, this._test); + + @override + void add(S data) { + bool satisfies; + + try { + satisfies = _test(data); + } catch (e, s) { + _outputSink.addError(e, s); + // The test didn't say true. Didn't say false either, but we stop anyway. + _outputSink.close(); + return; + } + + if (satisfies) { + _outputSink.add(data); + } else { + _outputSink.add(data); + _outputSink.close(); + } + } + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() => _outputSink.close(); +} + +/// Emits values emitted by the source Stream so long as each value +/// satisfies the given test. When the test is not satisfied by a value, it +/// will emit this value as a final event and then complete. +/// +/// ### Example +/// +/// Stream.fromIterable([2, 3, 4, 5, 6, 1, 2, 3]) +/// .transform(TakeWhileInclusiveStreamTransformer((i) => i < 4)) +/// .listen(print); // prints 2, 3, 4 +class TakeWhileInclusiveStreamTransformer + extends StreamTransformerBase { + /// Method used to test incoming events + final bool Function(S) test; + + /// Constructs a [StreamTransformer] which forwards data events while [test] + /// is successful, and includes last event that caused [test] to return false. + TakeWhileInclusiveStreamTransformer(this.test); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _TakeWhileInclusiveStreamSink(sink, test)); +} + +/// Extends the Stream class with the ability to take events while they pass +/// the condition given and include last event that doesn't pass the condition. +extension TakeWhileInclusiveExtension on Stream { + /// Emits values emitted by the source Stream so long as each value + /// satisfies the given test. When the test is not satisfied by a value, it + /// will emit this value as a final event and then complete. + /// + /// ### Example + /// + /// Stream.fromIterable([2, 3, 4, 5, 6, 1, 2, 3]) + /// .takeWhileInclusive((i) => i < 4) + /// .listen(print); // prints 2, 3, 4 + Stream takeWhileInclusive(bool Function(T) test) => + TakeWhileInclusiveStreamTransformer(test).bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/time_interval.dart b/sandbox/reactivex/lib/src/transformers/time_interval.dart new file mode 100644 index 0000000..b7e3c71 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/time_interval.dart @@ -0,0 +1,111 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; + +class _TimeIntervalStreamSink extends ForwardingSink> { + final _stopwatch = Stopwatch(); + + @override + void onData(S data) { + _stopwatch.stop(); + sink.add( + TimeInterval( + data, + Duration( + microseconds: _stopwatch.elapsedMicroseconds, + ), + ), + ); + _stopwatch + ..reset() + ..start(); + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() => sink.close(); + + @override + FutureOr onCancel() {} + + @override + void onListen() => _stopwatch.start(); + + @override + void onPause() {} + + @override + void onResume() {} +} + +/// Records the time interval between consecutive values in an stream +/// sequence. +/// +/// ### Example +/// +/// Stream.fromIterable([1]) +/// .transform(IntervalStreamTransformer(Duration(seconds: 1))) +/// .transform(TimeIntervalStreamTransformer()) +/// .listen(print); // prints TimeInterval{interval: 0:00:01, value: 1} +class TimeIntervalStreamTransformer + extends StreamTransformerBase> { + /// Constructs a [StreamTransformer] which emits events from the + /// source [Stream] as snapshots in the form of [TimeInterval]. + TimeIntervalStreamTransformer(); + + @override + Stream> bind(Stream stream) => + forwardStream(stream, () => _TimeIntervalStreamSink()); +} + +/// A class that represents a snapshot of the current value emitted by a +/// [Stream], at a specified interval. +class TimeInterval { + /// The interval at which this snapshot was taken + final Duration interval; + + /// The value at the moment of [interval] + final T value; + + /// Constructs a snapshot of a [Stream], containing the [Stream]'s event + /// at the specified [interval] as [value]. + TimeInterval(this.value, this.interval); + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + return other is TimeInterval && + interval == other.interval && + value == other.value; + } + + @override + int get hashCode { + return interval.hashCode ^ value.hashCode; + } + + @override + String toString() { + return 'TimeInterval{interval: $interval, value: $value}'; + } +} + +/// Extends the Stream class with the ability to record the time interval +/// between consecutive values in an stream +extension TimeIntervalExtension on Stream { + /// Records the time interval between consecutive values in a Stream sequence. + /// + /// ### Example + /// + /// Stream.fromIterable([1]) + /// .interval(Duration(seconds: 1)) + /// .timeInterval() + /// .listen(print); // prints TimeInterval{interval: 0:00:01, value: 1} + Stream> timeInterval() => + TimeIntervalStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/timestamp.dart b/sandbox/reactivex/lib/src/transformers/timestamp.dart new file mode 100644 index 0000000..0564402 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/timestamp.dart @@ -0,0 +1,87 @@ +import 'dart:async'; + +class _TimestampStreamSink implements EventSink { + final EventSink> _outputSink; + + _TimestampStreamSink(this._outputSink); + + @override + void add(S data) { + _outputSink.add(Timestamped(DateTime.now(), data)); + } + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() => _outputSink.close(); +} + +/// Wraps each item emitted by the source Stream in a [Timestamped] object +/// that includes the emitted item and the time when the item was emitted. +/// +/// Example +/// +/// Stream.fromIterable([1]) +/// .transform(TimestampStreamTransformer()) +/// .listen((i) => print(i)); // prints 'TimeStamp{timestamp: XXX, value: 1}'; +class TimestampStreamTransformer + extends StreamTransformerBase> { + /// Constructs a [StreamTransformer] which emits events from the + /// source [Stream] as snapshots in the form of [Timestamped]. + TimestampStreamTransformer(); + + @override + Stream> bind(Stream stream) => + Stream.eventTransformed(stream, (sink) => _TimestampStreamSink(sink)); +} + +/// A class that represents a snapshot of the current value emitted by a +/// [Stream], at a specified timestamp. +class Timestamped { + /// The value at the moment of the [timestamp] + final T value; + + /// The time at which this snapshot was taken + final DateTime timestamp; + + /// Constructs a snapshot of a [Stream], containing the [Stream]'s event + /// at the specified [timestamp] as [value]. + Timestamped(this.timestamp, this.value); + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + return other is Timestamped && + timestamp == other.timestamp && + value == other.value; + } + + @override + int get hashCode { + return timestamp.hashCode ^ value.hashCode; + } + + @override + String toString() { + return 'TimeStamp{timestamp: $timestamp, value: $value}'; + } +} + +/// Extends the Stream class with the ability to wrap each item emitted by the +/// source Stream in a [Timestamped] object that includes the emitted item and +/// the time when the item was emitted. +extension TimeStampExtension on Stream { + /// Wraps each item emitted by the source Stream in a [Timestamped] object + /// that includes the emitted item and the time when the item was emitted. + /// + /// Example + /// + /// Stream.fromIterable([1]) + /// .timestamp() + /// .listen((i) => print(i)); // prints 'TimeStamp{timestamp: XXX, value: 1}'; + Stream> timestamp() => + TimestampStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/where_not_null.dart b/sandbox/reactivex/lib/src/transformers/where_not_null.dart new file mode 100644 index 0000000..5fdcb4e --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/where_not_null.dart @@ -0,0 +1,65 @@ +import 'dart:async'; + +class _WhereNotNullStreamSink implements EventSink { + final EventSink _outputSink; + + _WhereNotNullStreamSink(this._outputSink); + + @override + void add(T? event) { + if (event != null) { + _outputSink.add(event); + } + } + + @override + void addError(Object error, [StackTrace? stackTrace]) => + _outputSink.addError(error, stackTrace); + + @override + void close() => _outputSink.close(); +} + +/// Create a Stream which emits all the non-`null` elements of the Stream, +/// in their original emission order. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2, 3, null, 4, null]) +/// .transform(WhereNotNullStreamTransformer()) +/// .listen(print); // prints 1, 2, 3, 4 +/// +/// // equivalent to: +/// +/// Stream.fromIterable([1, 2, 3, null, 4, null]) +/// .transform(WhereTypeStreamTransformer()) +/// .listen(print); // prints 1, 2, 3, 4 +class WhereNotNullStreamTransformer + extends StreamTransformerBase { + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _WhereNotNullStreamSink(sink)); +} + +/// Extends the Stream class with the ability to convert the source Stream +/// to a Stream which emits all the non-`null` elements +/// of this Stream, in their original emission order. +extension WhereNotNullExtension on Stream { + /// Returns a Stream which emits all the non-`null` elements + /// of this Stream, in their original emission order. + /// + /// For a `Stream`, this method is equivalent to `.whereType()`. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2, 3, null, 4, null]) + /// .whereNotNull() + /// .listen(print); // prints 1, 2, 3, 4 + /// + /// // equivalent to: + /// + /// Stream.fromIterable([1, 2, 3, null, 4, null]) + /// .whereType() + /// .listen(print); // prints 1, 2, 3, 4 + Stream whereNotNull() => WhereNotNullStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/where_type.dart b/sandbox/reactivex/lib/src/transformers/where_type.dart new file mode 100644 index 0000000..22a76a6 --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/where_type.dart @@ -0,0 +1,71 @@ +import 'dart:async'; + +class _WhereTypeStreamSink implements EventSink { + final EventSink _outputSink; + + _WhereTypeStreamSink(this._outputSink); + + @override + void add(S data) { + if (data is T) { + _outputSink.add(data); + } + } + + @override + void addError(e, [st]) => _outputSink.addError(e, st); + + @override + void close() => _outputSink.close(); +} + +/// This transformer is a shorthand for [Stream.where] followed by [Stream.cast]. +/// +/// Events that do not match [T] are filtered out, the resulting +/// [Stream] will be of Type [T]. +/// +/// ### Example +/// +/// Stream.fromIterable([1, 'two', 3, 'four']) +/// .whereType() +/// .listen(print); // prints 1, 3 +/// +/// // as opposed to: +/// +/// Stream.fromIterable([1, 'two', 3, 'four']) +/// .where((event) => event is int) +/// .cast() +/// .listen(print); // prints 1, 3 +/// +class WhereTypeStreamTransformer extends StreamTransformerBase { + /// Constructs a [StreamTransformer] which combines [Stream.where] followed by [Stream.cast]. + WhereTypeStreamTransformer(); + + @override + Stream bind(Stream stream) => Stream.eventTransformed( + stream, (sink) => _WhereTypeStreamSink(sink)); +} + +/// Extends the Stream class with the ability to filter down events to only +/// those of a specific type. +extension WhereTypeExtension on Stream { + /// This transformer is a shorthand for [Stream.where] followed by + /// [Stream.cast]. + /// + /// Events that do not match [T] are filtered out, the resulting [Stream] will + /// be of Type [T]. + /// + /// ### Example + /// + /// Stream.fromIterable([1, 'two', 3, 'four']) + /// .whereType() + /// .listen(print); // prints 1, 3 + /// + /// #### as opposed to: + /// + /// Stream.fromIterable([1, 'two', 3, 'four']) + /// .where((event) => event is int) + /// .cast() + /// .listen(print); // prints 1, 3 + Stream whereType() => WhereTypeStreamTransformer().bind(this); +} diff --git a/sandbox/reactivex/lib/src/transformers/with_latest_from.dart b/sandbox/reactivex/lib/src/transformers/with_latest_from.dart new file mode 100644 index 0000000..8e3013c --- /dev/null +++ b/sandbox/reactivex/lib/src/transformers/with_latest_from.dart @@ -0,0 +1,738 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/collection_extensions.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/forwarding_stream.dart'; +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +class _WithLatestFromStreamSink extends ForwardingSink { + final Iterable> _latestFromStreams; + final R Function(S t, List values) _combiner; + + bool _hasValues = false; + List? _latestValues; + late List> _subscriptions; + + _WithLatestFromStreamSink(this._latestFromStreams, this._combiner); + + @override + void onData(S data) { + if (_hasValues && _latestValues != null) { + final R combinedValue; + try { + combinedValue = _combiner(data, List.unmodifiable(_latestValues!)); + } catch (e, s) { + sink.addError(e, s); + return; + } + sink.add(combinedValue); + } + } + + @override + void onError(Object e, StackTrace st) => sink.addError(e, st); + + @override + void onDone() => sink.close(); + + @override + Future? onCancel() { + _latestValues = null; + return _subscriptions.cancelAll(); + } + + @override + void onListen() { + var count = 0; + + StreamSubscription mapper(int index, Stream stream) { + var hasValue = false; + + return stream.listen( + (value) { + if (!hasValue) { + hasValue = true; + if (++count == _subscriptions.length) { + _hasValues = true; + } + } + _latestValues![index] = value; + }, + onError: sink.addError, + ); + } + + _subscriptions = + _latestFromStreams.mapIndexed(mapper).toList(growable: false); + if (_subscriptions.isEmpty) { + _hasValues = true; + } + _latestValues = List.filled(_subscriptions.length, null); + } + + @override + void onPause() => _subscriptions.pauseAll(); + + @override + void onResume() => _subscriptions.resumeAll(); +} + +/// A StreamTransformer that emits when the source stream emits, combining +/// the latest values from the two streams using the provided function. +/// +/// If the latestFromStream has not emitted any values, this stream will not +/// emit either. +/// +/// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) +/// +/// ### Example +/// +/// Stream.fromIterable([1, 2]).transform( +/// WithLatestFromStreamTransformer( +/// Stream.fromIterable([2, 3]), (a, b) => a + b) +/// .listen(print); // prints 4 (due to the async nature of streams) +class WithLatestFromStreamTransformer + extends StreamTransformerBase { + /// A collection of [Stream]s of which the latest values will be combined. + final Iterable> latestFromStreams; + + /// The combiner Function + final R Function(S t, List values) combiner; + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from [latestFromStreams] using the provided function [fn]. + WithLatestFromStreamTransformer(this.latestFromStreams, this.combiner); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from [latestFromStreams] using a [List]. + static WithLatestFromStreamTransformer> withList( + Iterable> latestFromStreams, + ) { + return WithLatestFromStreamTransformer>( + latestFromStreams, + (s, values) => [s, ...values], + ); + } + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from [latestFromStream] using the provided function [fn]. + static WithLatestFromStreamTransformer with1( + Stream latestFromStream, + R Function(T t, S s) fn, + ) => + WithLatestFromStreamTransformer( + [latestFromStream], + (s, values) => fn(s, values[0]), + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer with2( + Stream latestFromStream1, + Stream latestFromStream2, + R Function(T t, A a, B b) fn, + ) => + WithLatestFromStreamTransformer( + [latestFromStream1, latestFromStream2], + (s, values) => fn(s, values[0] as A, values[1] as B), + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer with3( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + R Function(T t, A a, B b, C c) fn, + ) => + WithLatestFromStreamTransformer( + [ + latestFromStream1, + latestFromStream2, + latestFromStream3, + ], + (s, values) { + return fn( + s, + values[0] as A, + values[1] as B, + values[2] as C, + ); + }, + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer with4( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + R Function(T t, A a, B b, C c, D d) fn, + ) => + WithLatestFromStreamTransformer( + [ + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + ], + (s, values) { + return fn( + s, + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + ); + }, + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer + with5( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + R Function(T t, A a, B b, C c, D d, E e) fn, + ) => + WithLatestFromStreamTransformer( + [ + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + ], + (s, values) { + return fn( + s, + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + ); + }, + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer + with6( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + R Function(T t, A a, B b, C c, D d, E e, F f) fn, + ) => + WithLatestFromStreamTransformer( + [ + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + ], + (s, values) { + return fn( + s, + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + ); + }, + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer + with7( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + Stream latestFromStream7, + R Function(T t, A a, B b, C c, D d, E e, F f, G g) fn, + ) => + WithLatestFromStreamTransformer( + [ + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + latestFromStream7, + ], + (s, values) { + return fn( + s, + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + ); + }, + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer + with8( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + Stream latestFromStream7, + Stream latestFromStream8, + R Function(T t, A a, B b, C c, D d, E e, F f, G g, H h) fn, + ) => + WithLatestFromStreamTransformer( + [ + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + latestFromStream7, + latestFromStream8, + ], + (s, values) { + return fn( + s, + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + ); + }, + ); + + /// Constructs a [StreamTransformer] that emits when the source [Stream] emits, combining + /// the latest values from all [latestFromStream]s using the provided function [fn]. + static WithLatestFromStreamTransformer + with9( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + Stream latestFromStream7, + Stream latestFromStream8, + Stream latestFromStream9, + R Function(T t, A a, B b, C c, D d, E e, F f, G g, H h, I i) fn, + ) => + WithLatestFromStreamTransformer( + [ + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + latestFromStream7, + latestFromStream8, + latestFromStream9, + ], + (s, values) { + return fn( + s, + values[0] as A, + values[1] as B, + values[2] as C, + values[3] as D, + values[4] as E, + values[5] as F, + values[6] as G, + values[7] as H, + values[8] as I, + ); + }, + ); + + @override + Stream bind(Stream stream) => forwardStream( + stream, + () => _WithLatestFromStreamSink(latestFromStreams, combiner), + ); +} + +/// Extends the Stream class with the ability to merge the source Stream with +/// the last emitted item from another Stream. +extension WithLatestFromExtensions on Stream { + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the two streams using the provided function. + /// + /// If the latestFromStream has not emitted any values, this stream will not + /// emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]).withLatestFrom( + /// Stream.fromIterable([2, 3]), (a, b) => a + b) + /// .listen(print); // prints 4 (due to the async nature of streams) + Stream withLatestFrom( + Stream latestFromStream, R Function(T t, S s) fn) => + WithLatestFromStreamTransformer.with1(latestFromStream, fn) + .bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the streams into a list. This is helpful when you need + /// to combine a dynamic number of Streams. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// Stream.fromIterable([1, 2]).withLatestFromList( + /// [ + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// Stream.fromIterable([5, 6]), + /// Stream.fromIterable([6, 7]), + /// ], + /// ).listen(print); // print [2, 2, 3, 4, 5, 6] (due to the async nature of streams) + /// + Stream> withLatestFromList(Iterable> latestFromStreams) => + WithLatestFromStreamTransformer.withList(latestFromStreams).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the three streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom2( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// (int a, int b, int c) => a + b + c, + /// ) + /// .listen(print); // prints 7 (due to the async nature of streams) + Stream withLatestFrom2( + Stream latestFromStream1, + Stream latestFromStream2, + R Function(T t, A a, B b) fn, + ) => + WithLatestFromStreamTransformer.with2( + latestFromStream1, + latestFromStream2, + fn, + ).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the four streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom3( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// (int a, int b, int c, int d) => a + b + c + d, + /// ) + /// .listen(print); // prints 11 (due to the async nature of streams) + Stream withLatestFrom3( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + R Function(T t, A a, B b, C c) fn, + ) => + WithLatestFromStreamTransformer.with3( + latestFromStream1, + latestFromStream2, + latestFromStream3, + fn, + ).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the five streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom4( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// Stream.fromIterable([5, 6]), + /// (int a, int b, int c, int d, int e) => a + b + c + d + e, + /// ) + /// .listen(print); // prints 16 (due to the async nature of streams) + Stream withLatestFrom4( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + R Function(T t, A a, B b, C c, D d) fn, + ) => + WithLatestFromStreamTransformer.with4( + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + fn, + ).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the six streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom5( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// Stream.fromIterable([5, 6]), + /// Stream.fromIterable([6, 7]), + /// (int a, int b, int c, int d, int e, int f) => a + b + c + d + e + f, + /// ) + /// .listen(print); // prints 22 (due to the async nature of streams) + Stream withLatestFrom5( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + R Function(T t, A a, B b, C c, D d, E e) fn, + ) => + WithLatestFromStreamTransformer.with5( + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + fn, + ).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the seven streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom6( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// Stream.fromIterable([5, 6]), + /// Stream.fromIterable([6, 7]), + /// Stream.fromIterable([7, 8]), + /// (int a, int b, int c, int d, int e, int f, int g) => + /// a + b + c + d + e + f + g, + /// ) + /// .listen(print); // prints 29 (due to the async nature of streams) + Stream withLatestFrom6( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + R Function(T t, A a, B b, C c, D d, E e, F f) fn, + ) => + WithLatestFromStreamTransformer.with6( + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + fn, + ).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the eight streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom7( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// Stream.fromIterable([5, 6]), + /// Stream.fromIterable([6, 7]), + /// Stream.fromIterable([7, 8]), + /// Stream.fromIterable([8, 9]), + /// (int a, int b, int c, int d, int e, int f, int g, int h) => + /// a + b + c + d + e + f + g + h, + /// ) + /// .listen(print); // prints 37 (due to the async nature of streams) + Stream withLatestFrom7( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + Stream latestFromStream7, + R Function(T t, A a, B b, C c, D d, E e, F f, G g) fn, + ) => + WithLatestFromStreamTransformer.with7( + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + latestFromStream7, + fn, + ).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the nine streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom8( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// Stream.fromIterable([5, 6]), + /// Stream.fromIterable([6, 7]), + /// Stream.fromIterable([7, 8]), + /// Stream.fromIterable([8, 9]), + /// Stream.fromIterable([9, 10]), + /// (int a, int b, int c, int d, int e, int f, int g, int h, int i) => + /// a + b + c + d + e + f + g + h + i, + /// ) + /// .listen(print); // prints 46 (due to the async nature of streams) + Stream withLatestFrom8( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + Stream latestFromStream7, + Stream latestFromStream8, + R Function(T t, A a, B b, C c, D d, E e, F f, G g, H h) fn, + ) => + WithLatestFromStreamTransformer.with8( + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + latestFromStream7, + latestFromStream8, + fn, + ).bind(this); + + /// Creates a Stream that emits when the source stream emits, combining the + /// latest values from the ten streams using the provided function. + /// + /// If any of latestFromStreams has not emitted any values, this stream will + /// not emit either. + /// + /// [Interactive marble diagram](http://rxmarbles.com/#withLatestFrom) + /// + /// ### Example + /// + /// Stream.fromIterable([1, 2]) + /// .withLatestFrom9( + /// Stream.fromIterable([2, 3]), + /// Stream.fromIterable([3, 4]), + /// Stream.fromIterable([4, 5]), + /// Stream.fromIterable([5, 6]), + /// Stream.fromIterable([6, 7]), + /// Stream.fromIterable([7, 8]), + /// Stream.fromIterable([8, 9]), + /// Stream.fromIterable([9, 10]), + /// Stream.fromIterable([10, 11]), + /// (int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) => + /// a + b + c + d + e + f + g + h + i + j, + /// ) + /// .listen(print); // prints 46 (due to the async nature of streams) + Stream withLatestFrom9( + Stream latestFromStream1, + Stream latestFromStream2, + Stream latestFromStream3, + Stream latestFromStream4, + Stream latestFromStream5, + Stream latestFromStream6, + Stream latestFromStream7, + Stream latestFromStream8, + Stream latestFromStream9, + R Function(T t, A a, B b, C c, D d, E e, F f, G g, H h, I i) fn, + ) => + WithLatestFromStreamTransformer.with9( + latestFromStream1, + latestFromStream2, + latestFromStream3, + latestFromStream4, + latestFromStream5, + latestFromStream6, + latestFromStream7, + latestFromStream8, + latestFromStream9, + fn, + ).bind(this); +} diff --git a/sandbox/reactivex/lib/src/utils/collection_extensions.dart b/sandbox/reactivex/lib/src/utils/collection_extensions.dart new file mode 100644 index 0000000..a58f9ee --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/collection_extensions.dart @@ -0,0 +1,65 @@ +import 'dart:collection'; +import 'dart:math'; + +/// @internal +/// @nodoc +/// Provides extension methods on [List]. +extension ListExtensions on List { + /// @internal + /// Returns a list of values built from the elements of this list + /// and the other list with the same index + /// using the provided transform function applied to each pair of elements. + /// The returned list has length of the shortest list. + List zipWith( + List other, + R Function(T, S) transform, { + bool growable = true, + }) => + List.generate( + min(length, other.length), + (index) => transform(this[index], other[index]), + growable: growable, + ); +} + +/// @internal +/// Provides extension methods on [Iterable]. +extension IterableExtensions on Iterable { + /// @internal + /// The non-`null` results of calling [transform] on the elements of [this]. + /// + /// Returns a lazy iterable which calls [transform] + /// on the elements of this iterable in iteration order, + /// then emits only the non-`null` values. + /// + /// If [transform] throws, the iteration is terminated. + Iterable mapNotNull(R? Function(T) transform) sync* { + for (final e in this) { + final v = transform(e); + if (v != null) { + yield v; + } + } + } + + /// @internal + /// Maps each element and its index to a new value. + Iterable mapIndexed(R Function(int index, T element) transform) sync* { + var index = 0; + for (final e in this) { + yield transform(index++, e); + } + } +} + +/// @internal +/// Provides [removeFirstElements] extension method on [Queue]. +extension RemoveFirstElementsQueueExtension on Queue { + /// @internal + /// Removes the first [count] elements of this queue. + void removeFirstElements(int count) { + for (var i = 0; i < count; i++) { + removeFirst(); + } + } +} diff --git a/sandbox/reactivex/lib/src/utils/composite_subscription.dart b/sandbox/reactivex/lib/src/utils/composite_subscription.dart new file mode 100644 index 0000000..7745b8d --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/composite_subscription.dart @@ -0,0 +1,121 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/subscription.dart'; + +/// Acts as a container for multiple subscriptions that can be canceled at once +/// e.g. view subscriptions in Flutter that need to be canceled on view disposal +/// +/// Can be cleared or disposed. When disposed, cannot be used again. +/// ### Example +/// // init your subscriptions +/// composite.add(stream1.listen(listener1)) +/// ..add(stream2.listen(listener1)) +/// ..add(stream3.listen(listener1)); +/// +/// // clear them all at once +/// composite.clear(); +class CompositeSubscription implements StreamSubscription { + bool _isDisposed = false; + + final List> _subscriptionsList = []; + + /// Checks if this composite is disposed. If it is, the composite can't be used again + /// and will throw an error if you try to add more subscriptions to it. + bool get isDisposed => _isDisposed; + + /// Returns the total amount of currently added [StreamSubscription]s + int get length => _subscriptionsList.length; + + /// Checks if there currently are no [StreamSubscription]s added + bool get isEmpty => _subscriptionsList.isEmpty; + + /// Checks if there currently are [StreamSubscription]s added + bool get isNotEmpty => _subscriptionsList.isNotEmpty; + + /// Whether all managed [StreamSubscription]s are currently paused. + bool get allPaused => + _subscriptionsList.isNotEmpty && + _subscriptionsList.every((s) => s.isPaused); + + /// Adds new subscription to this composite. + /// + /// Throws an exception if this composite was disposed + StreamSubscription add(StreamSubscription subscription) { + if (isDisposed) { + throw StateError( + 'This $runtimeType was disposed, consider checking `isDisposed` or try to use new instance instead'); + } + _subscriptionsList.add(subscription); + return subscription; + } + + /// Remove the subscription from this composite and cancel it if it has been removed. + Future? remove( + StreamSubscription subscription, { + bool shouldCancel = true, + }) => + _subscriptionsList.remove(subscription) && shouldCancel + ? subscription.cancel() + : null; + + /// Cancels all subscriptions added to this composite. Clears subscriptions collection. + /// + /// This composite can be reused after calling this method. + Future? clear() { + final cancelAllDone = _subscriptionsList.cancelAll(); + _subscriptionsList.clear(); + return cancelAllDone; + } + + /// Cancels all subscriptions added to this composite. Disposes this. + /// + /// This composite can't be reused after calling this method. + Future? dispose() { + final clearDone = clear(); + _isDisposed = true; + return clearDone; + } + + /// Pauses all subscriptions added to this composite. + void pauseAll([Future? resumeSignal]) => + _subscriptionsList.pauseAll(resumeSignal); + + /// Resumes all subscriptions added to this composite. + void resumeAll() => _subscriptionsList.resumeAll(); + + // implements StreamSubscription + + @override + Future cancel() => dispose() ?? Future.value(null); + + @override + bool get isPaused => allPaused; + + @override + void pause([Future? resumeSignal]) => pauseAll(resumeSignal); + + @override + void resume() => resumeAll(); + + @override + Never asFuture([E? futureValue]) => _unsupportedError(); + + @override + Never onData(void Function(Never data)? handleData) => _unsupportedError(); + + @override + Never onDone(void Function()? handleDone) => _unsupportedError(); + + @override + Never onError(Function? handleError) => _unsupportedError(); + + Never _unsupportedError() => throw UnsupportedError( + 'Cannot change handlers of CompositeSubscription.'); +} + +/// Extends the [StreamSubscription] class with the ability to be added to [CompositeSubscription] container. +extension AddToCompositeSubscriptionExtension on StreamSubscription { + /// Adds this subscription to composite container for subscriptions. + void addTo(CompositeSubscription compositeSubscription) => + compositeSubscription.add(this); +} diff --git a/sandbox/reactivex/lib/src/utils/empty.dart b/sandbox/reactivex/lib/src/utils/empty.dart new file mode 100644 index 0000000..04a7766 --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/empty.dart @@ -0,0 +1,18 @@ +class _Empty { + const _Empty(); + + @override + String toString() => '<>'; +} + +/// @internal +/// Sentinel object used to represent a missing value (distinct from `null`). +const Object? EMPTY = _Empty(); // ignore: constant_identifier_names + +/// @internal +/// Returns `null` if [o] is [EMPTY], otherwise returns itself. +T? unbox(Object? o) => identical(o, EMPTY) ? null : o as T; + +/// @internal +/// Returns `true` if [o] is not [EMPTY]. +bool isNotEmpty(Object? o) => !identical(o, EMPTY); diff --git a/sandbox/reactivex/lib/src/utils/error_and_stacktrace.dart b/sandbox/reactivex/lib/src/utils/error_and_stacktrace.dart new file mode 100644 index 0000000..33a68c9 --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/error_and_stacktrace.dart @@ -0,0 +1,28 @@ +/// An Object which acts as a tuple containing both an error and the +/// corresponding stack trace. +class ErrorAndStackTrace { + /// A reference to the wrapped error object. + final Object error; + + /// A reference to the wrapped [StackTrace] + final StackTrace? stackTrace; + + /// Constructs an object containing both an [error] and the + /// corresponding [stackTrace]. + ErrorAndStackTrace(this.error, this.stackTrace); + + @override + String toString() => + 'ErrorAndStackTrace{error: $error, stackTrace: $stackTrace}'; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ErrorAndStackTrace && + runtimeType == other.runtimeType && + error == other.error && + stackTrace == other.stackTrace; + + @override + int get hashCode => error.hashCode ^ stackTrace.hashCode; +} diff --git a/sandbox/reactivex/lib/src/utils/forwarding_sink.dart b/sandbox/reactivex/lib/src/utils/forwarding_sink.dart new file mode 100644 index 0000000..65adbd0 --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/forwarding_sink.dart @@ -0,0 +1,82 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; + +/// A enhanced [EventSink] that allows to check if the sink is paused. +abstract class EnhancedEventSink implements EventSink { + /// Whether the subscription would need to buffer events. + bool get isPaused; +} + +/// A [Sink] that supports event hooks. +/// +/// This makes it suitable for certain rx transformers that need to +/// take action after onListen, onPause, onResume or onCancel. +/// +/// The [ForwardingSink] has been designed to handle asynchronous events from +/// [Stream]s. See, for example, [Stream.eventTransformed] which uses +/// `EventSink`s to transform events. +abstract class ForwardingSink { + EnhancedEventSink? _sink; + StreamSubscription? _subscription; + + /// The output sink. + /// @nonVirtual + /// @internal + EnhancedEventSink get sink => + _sink ?? (throw StateError('Must call setSink(sink) before accessing!')); + + /// Set the output sink. + /// @nonVirtual + /// @internal + void setSink(EnhancedEventSink sink) => _sink = sink; + + /// Set the upstream subscription + /// @nonVirtual + /// @internal + void setSubscription(StreamSubscription? subscription) => + _subscription = subscription; + + /// -------------------------------------------------------------------------- + + /// Pause the upstream subscription. + /// @nonVirtual + void pauseSubscription() => _subscription?.pause(); + + /// Resume the upstream subscription. + /// @nonVirtual + void resumeSubscription() => _subscription?.resume(); + + /// -------------------------------------------------------------------------- + + /// Handle data event + void onData(T data); + + /// Handle error event + void onError(Object error, StackTrace st); + + /// Handle close event + void onDone(); + + /// Fires when a listener subscribes on the underlying [Stream]. + /// Returns a [Future] to delay listening to source [Stream]. + FutureOr onListen(); + + /// Fires when a subscriber pauses. + void onPause(); + + /// Fires when a subscriber resumes after a pause. + void onResume(); + + /// Fires when a subscriber cancels. + FutureOr onCancel(); +} + +/// @internal +/// @nodoc +extension EventSinkExtension on EventSink { + /// @internal + /// @nodoc + void addErrorAndStackTrace(ErrorAndStackTrace errorAndSt) => + addError(errorAndSt.error, errorAndSt.stackTrace); +} diff --git a/sandbox/reactivex/lib/src/utils/forwarding_stream.dart b/sandbox/reactivex/lib/src/utils/forwarding_stream.dart new file mode 100644 index 0000000..9d414f4 --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/forwarding_stream.dart @@ -0,0 +1,165 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/forwarding_sink.dart'; +import 'package:angel3_reactivex/src/utils/future.dart'; + +/// @private +/// Helper method which forwards the events from an incoming [Stream] +/// to a new [StreamController]. +/// It captures events such as onListen, onPause, onResume and onCancel, +/// which can be used in pair with a [ForwardingSink] +Stream forwardStream( + Stream stream, + ForwardingSink Function() sinkFactory, [ + bool listenOnlyOnce = false, +]) { + return stream.isBroadcast + ? listenOnlyOnce + ? _forward(stream, sinkFactory) + : _forwardMulti(stream, sinkFactory) + : _forward(stream, sinkFactory); +} + +Stream _forwardMulti( + Stream stream, ForwardingSink Function() sinkFactory) { + return Stream.multi((controller) { + final sink = sinkFactory(); + sink.setSink(_MultiControllerSink(controller)); + + StreamSubscription? subscription; + var cancelled = false; + + void listenToUpstream([void _]) { + if (cancelled) { + return; + } + subscription = stream.listen( + sink.onData, + onError: sink.onError, + onDone: sink.onDone, + ); + sink.setSubscription(subscription); + } + + final futureOrVoid = sink.onListen(); + if (futureOrVoid is Future) { + futureOrVoid.then(listenToUpstream).onError((e, s) { + if (!cancelled && !controller.isClosed) { + controller.addError(e, s); + controller.close(); + } + }); + } else { + listenToUpstream(); + } + + controller.onCancel = () { + cancelled = true; + + final future = subscription?.cancel(); + subscription = null; + sink.setSubscription(null); + + return waitTwoFutures(future, sink.onCancel()); + }; + }, isBroadcast: true); +} + +Stream _forward( + Stream stream, + ForwardingSink Function() sinkFactory, +) { + final controller = stream.isBroadcast + ? StreamController.broadcast(sync: true) + : StreamController(sync: true); + + StreamSubscription? subscription; + var cancelled = false; + late final sink = sinkFactory(); + + controller.onListen = () { + void listenToUpstream([void _]) { + if (cancelled) { + return; + } + subscription = stream.listen( + sink.onData, + onError: sink.onError, + onDone: sink.onDone, + ); + sink.setSubscription(subscription); + + if (!stream.isBroadcast) { + controller.onPause = () { + subscription!.pause(); + sink.onPause(); + }; + controller.onResume = () { + subscription!.resume(); + sink.onResume(); + }; + } + } + + sink.setSink(_EnhancedEventSink(controller)); + final futureOrVoid = sink.onListen(); + if (futureOrVoid is Future) { + futureOrVoid.then(listenToUpstream).onError((e, s) { + if (!cancelled && !controller.isClosed) { + controller.addError(e, s); + controller.close(); + } + }); + } else { + listenToUpstream(); + } + }; + controller.onCancel = () { + cancelled = true; + + final future = subscription?.cancel(); + subscription = null; + sink.setSubscription(null); + + return waitTwoFutures(future, sink.onCancel()); + }; + return controller.stream; +} + +class _MultiControllerSink implements EventSink, EnhancedEventSink { + final MultiStreamController controller; + + _MultiControllerSink(this.controller); + + @override + void add(T event) => controller.addSync(event); + + @override + void addError(Object error, [StackTrace? stackTrace]) => + controller.addErrorSync(error, stackTrace); + + @override + void close() => controller.closeSync(); + + @override + bool get isPaused => controller.isPaused; +} + +class _EnhancedEventSink implements EnhancedEventSink { + final StreamController _controller; + + _EnhancedEventSink(this._controller); + + @override + void add(T event) => _controller.add(event); + + @override + void addError(Object error, [StackTrace? stackTrace]) => + _controller.addError(error, stackTrace); + + @override + void close() => _controller.close(); + + @override + bool get isPaused => _controller.isPaused; +} diff --git a/sandbox/reactivex/lib/src/utils/future.dart b/sandbox/reactivex/lib/src/utils/future.dart new file mode 100644 index 0000000..77e241f --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/future.dart @@ -0,0 +1,25 @@ +import 'dart:async'; + +/// @internal +/// An optimized version of [Future.wait]. +FutureOr waitTwoFutures(Future? f1, FutureOr f2) => f1 == null + ? f2 + : f2 is Future + ? Future.wait([f1, f2]).then(_ignore) + : f1; + +/// @internal +/// An optimized version of [Future.wait]. +Future? waitFuturesList(List> futures) { + switch (futures.length) { + case 0: + return null; + case 1: + return futures[0]; + default: + return Future.wait(futures).then(_ignore); + } +} + +/// Helper function to ignore future callback +void _ignore(Object? _) {} diff --git a/sandbox/reactivex/lib/src/utils/min_max.dart b/sandbox/reactivex/lib/src/utils/min_max.dart new file mode 100644 index 0000000..729d44c --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/min_max.dart @@ -0,0 +1,76 @@ +import 'dart:async'; + +/// @private +/// Helper method which find max value or min value in a stream +/// +/// When the stream is done, the returned future is completed with +/// the largest value or smallest value at that time. +/// +/// If the stream is empty, the returned future is completed with +/// an error. +/// If the stream emits an error, or the call to [comparator] throws, +/// the returned future is completed with that error, +/// and processing is stopped. +Future minMax(Stream stream, bool findMin, Comparator? comparator) { + var completer = Completer(); + var seenFirst = false; + + late StreamSubscription subscription; + late T accumulator; + late Comparator comparatorNotNull; + + Future cancelAndCompleteError(Object e, StackTrace st) async { + await subscription.cancel(); + + completer.completeError(e, st); + } + + void onData(T element) async { + if (seenFirst) { + try { + accumulator = findMin + ? (comparatorNotNull(element, accumulator) < 0 + ? element + : accumulator) + : (comparatorNotNull(element, accumulator) > 0 + ? element + : accumulator); + } catch (e, st) { + await cancelAndCompleteError(e, st); + } + return; + } + + accumulator = element; + seenFirst = true; + try { + comparatorNotNull = comparator ?? + () { + if (element is Comparable) { + return Comparable.compare as Comparator; + } else { + throw StateError( + 'Please provide a comparator for type $T, because it is not comparable'); + } + }(); + } catch (e, st) { + await cancelAndCompleteError(e, st); + } + } + + void onDone() { + if (seenFirst) { + completer.complete(accumulator); + } else { + completer.completeError(StateError('No element')); + } + } + + subscription = stream.listen( + onData, + onError: completer.completeError, + onDone: onDone, + cancelOnError: true, + ); + return completer.future; +} diff --git a/sandbox/reactivex/lib/src/utils/notification.dart b/sandbox/reactivex/lib/src/utils/notification.dart new file mode 100644 index 0000000..fec6172 --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/notification.dart @@ -0,0 +1,169 @@ +import 'package:angel3_reactivex/src/utils/error_and_stacktrace.dart'; + +/// The type of event used in [StreamNotification] +enum NotificationKind { + /// Specifies a data event + data, + + /// Specifies a done event + done, + + /// Specifies an error event + error +} + +/// A class that encapsulates the [NotificationKind] of event, value of the event in case of +/// onData, or the Error in the case of onError. + +/// A container object that wraps the [NotificationKind] of event (OnData, OnDone, OnError), +/// and the item or error that was emitted. In the case of onDone, no data is +/// emitted as part of the [StreamNotification]. +abstract class StreamNotification { + /// References the [NotificationKind] of this [StreamNotification] event. + final NotificationKind kind; + + const StreamNotification._(this.kind); + + /// Constructs a [StreamNotification] with [NotificationKind.data] and wraps a [value] + factory StreamNotification.data(T value) => DataNotification(value); + + /// Constructs a [StreamNotification] with [NotificationKind.done]. + const factory StreamNotification.done() = DoneNotification; + + /// Constructs a [StreamNotification] with [NotificationKind.error] and wraps an [error] and [stackTrace] + factory StreamNotification.error(Object error, [StackTrace? stackTrace]) => + ErrorNotification._internal(error, stackTrace); +} + +/// Provides extension methods on [StreamNotification]. +extension StreamNotificationExtensions on StreamNotification { + /// A test to determine if this [StreamNotification] wraps a data event. + bool get isData => kind == NotificationKind.data; + + /// A test to determine if this [StreamNotification] wraps a done event. + bool get isDone => kind == NotificationKind.done; + + /// A test to determine if this [StreamNotification] wraps an error event. + bool get isError => kind == NotificationKind.error; + + /// Returns data if [kind] is [NotificationKind.data], + /// otherwise throws a [TypeError] error. + /// See also [dataValueOrNull]. + T get requireDataValue => (this as DataNotification).value; + + /// Returns data if [kind] is [NotificationKind.data], + /// otherwise returns null. + T? get dataValueOrNull { + final self = this; + return self is DataNotification ? self.value : null; + } + + /// Returns error and stack trace if [kind] is [NotificationKind.error], + /// otherwise throws a [TypeError] error. + ErrorAndStackTrace get requireErrorAndStackTrace => + (this as ErrorNotification).errorAndStackTrace; + + /// Returns error and stack trace if [kind] is [NotificationKind.error], + /// otherwise returns null. + ErrorAndStackTrace? get errorAndStackTraceOrNull { + final self = this; + return self is ErrorNotification ? self.errorAndStackTrace : null; + } + + /// Invokes the appropriate function on the [StreamNotification] based on the [kind]. + @pragma('vm:prefer-inline') + @pragma('dart2js:prefer-inline') + R when({ + required R Function(T value) data, + required R Function() done, + required R Function(ErrorAndStackTrace) error, + }) { + final self = this; + if (self is DataNotification) { + return data(self.value); + } + + if (self is DoneNotification) { + return done(); + } + + if (self is ErrorNotification) { + return error(self.errorAndStackTrace); + } + + throw StateError('Unknown notification $self'); + } +} + +/// A notification representing a data event from a [Stream]. +class DataNotification extends StreamNotification { + /// The value of the data event. + final T value; + + /// Constructs a [DataNotification] with the provided [value]. + const DataNotification(this.value) : super._(NotificationKind.data); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is DataNotification && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; + + @override + String toString() => 'DataNotification{value: $value}'; +} + +/// A notification representing a done event from a [Stream]. +class DoneNotification extends StreamNotification { + /// Constructs a [DoneNotification]. + const DoneNotification() : super._(NotificationKind.done); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is DoneNotification && runtimeType == other.runtimeType; + + @override + int get hashCode => 0; + + @override + String toString() => 'DoneNotification{}'; +} + +/// A notification representing an error event from a [Stream]. +class ErrorNotification extends StreamNotification { + /// The wrapped error and stack trace, if applicable + final ErrorAndStackTrace errorAndStackTrace; + + /// The error of the error event. + Object get error => errorAndStackTrace.error; + + /// The stack trace of the error event, if available. + StackTrace? get stackTrace => errorAndStackTrace.stackTrace; + + /// Constructs an [ErrorNotification] with the provided [errorAndStackTrace]. + const ErrorNotification(this.errorAndStackTrace) + : super._(NotificationKind.error); + + /// Constructs an [ErrorNotification] with the provided [error] and [stackTrace]. + factory ErrorNotification._internal(Object error, StackTrace? stackTrace) => + ErrorNotification(ErrorAndStackTrace(error, stackTrace)); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ErrorNotification && + runtimeType == other.runtimeType && + errorAndStackTrace == other.errorAndStackTrace; + + @override + int get hashCode => errorAndStackTrace.hashCode; + + @override + String toString() => + 'ErrorNotification{error: $error, stackTrace: $stackTrace}'; +} diff --git a/sandbox/reactivex/lib/src/utils/subscription.dart b/sandbox/reactivex/lib/src/utils/subscription.dart new file mode 100644 index 0000000..d3500d9 --- /dev/null +++ b/sandbox/reactivex/lib/src/utils/subscription.dart @@ -0,0 +1,34 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/utils/future.dart'; + +/// @internal +/// Extensions for [Iterable] of [StreamSubscription]s. +extension StreamSubscriptionsIterableExtensions + on Iterable> { + /// @internal + /// Pause all subscriptions. + void pauseAll([Future? resumeSignal]) { + for (final s in this) { + s.pause(resumeSignal); + } + } + + /// @internal + /// Resume all subscriptions. + void resumeAll() { + for (final s in this) { + s.resume(); + } + } +} + +/// @internal +/// Extensions for [Iterable] of [StreamSubscription]s. +extension StreamSubscriptionsIterableExtension + on Iterable> { + /// @internal + /// Cancel all subscriptions. + Future? cancelAll() => + waitFuturesList([for (final s in this) s.cancel()]); +} diff --git a/sandbox/reactivex/lib/streams.dart b/sandbox/reactivex/lib/streams.dart new file mode 100644 index 0000000..79f57b3 --- /dev/null +++ b/sandbox/reactivex/lib/streams.dart @@ -0,0 +1,23 @@ +library rx_streams; + +export 'src/streams/combine_latest.dart'; +export 'src/streams/concat.dart'; +export 'src/streams/concat_eager.dart'; +export 'src/streams/connectable_stream.dart'; +export 'src/streams/defer.dart'; +export 'src/streams/fork_join.dart'; +export 'src/streams/from_callable.dart'; +export 'src/streams/merge.dart'; +export 'src/streams/never.dart'; +export 'src/streams/race.dart'; +export 'src/streams/range.dart'; +export 'src/streams/repeat.dart'; +export 'src/streams/replay_stream.dart'; +export 'src/streams/retry.dart'; +export 'src/streams/retry_when.dart'; +export 'src/streams/sequence_equal.dart'; +export 'src/streams/switch_latest.dart'; +export 'src/streams/timer.dart'; +export 'src/streams/using.dart'; +export 'src/streams/value_stream.dart'; +export 'src/streams/zip.dart'; diff --git a/sandbox/reactivex/lib/subjects.dart b/sandbox/reactivex/lib/subjects.dart new file mode 100644 index 0000000..77bc472 --- /dev/null +++ b/sandbox/reactivex/lib/subjects.dart @@ -0,0 +1,6 @@ +library rx_subjects; + +export 'src/subjects/behavior_subject.dart'; +export 'src/subjects/publish_subject.dart'; +export 'src/subjects/replay_subject.dart'; +export 'src/subjects/subject.dart'; diff --git a/sandbox/reactivex/lib/transformers.dart b/sandbox/reactivex/lib/transformers.dart new file mode 100644 index 0000000..e6ff971 --- /dev/null +++ b/sandbox/reactivex/lib/transformers.dart @@ -0,0 +1,42 @@ +library rx_transformers; + +export 'src/transformers/backpressure/buffer.dart'; +export 'src/transformers/backpressure/debounce.dart'; +export 'src/transformers/backpressure/pairwise.dart'; +export 'src/transformers/backpressure/sample.dart'; +export 'src/transformers/backpressure/throttle.dart'; +export 'src/transformers/backpressure/window.dart'; +export 'src/transformers/default_if_empty.dart'; +export 'src/transformers/delay.dart'; +export 'src/transformers/delay_when.dart'; +export 'src/transformers/dematerialize.dart'; +export 'src/transformers/distinct_unique.dart'; +export 'src/transformers/do.dart'; +export 'src/transformers/end_with.dart'; +export 'src/transformers/end_with_many.dart'; +export 'src/transformers/exhaust_map.dart'; +export 'src/transformers/flat_map.dart'; +export 'src/transformers/group_by.dart'; +export 'src/transformers/ignore_elements.dart'; +export 'src/transformers/interval.dart'; +export 'src/transformers/map_not_null.dart'; +export 'src/transformers/map_to.dart'; +export 'src/transformers/materialize.dart'; +export 'src/transformers/max.dart'; +export 'src/transformers/min.dart'; +export 'src/transformers/on_error_resume.dart'; +export 'src/transformers/scan.dart'; +export 'src/transformers/skip_last.dart'; +export 'src/transformers/skip_until.dart'; +export 'src/transformers/start_with.dart'; +export 'src/transformers/start_with_many.dart'; +export 'src/transformers/switch_if_empty.dart'; +export 'src/transformers/switch_map.dart'; +export 'src/transformers/take_last.dart'; +export 'src/transformers/take_until.dart'; +export 'src/transformers/take_while_inclusive.dart'; +export 'src/transformers/time_interval.dart'; +export 'src/transformers/timestamp.dart'; +export 'src/transformers/where_not_null.dart'; +export 'src/transformers/where_type.dart'; +export 'src/transformers/with_latest_from.dart'; diff --git a/sandbox/reactivex/lib/utils.dart b/sandbox/reactivex/lib/utils.dart new file mode 100644 index 0000000..5892516 --- /dev/null +++ b/sandbox/reactivex/lib/utils.dart @@ -0,0 +1,5 @@ +library rx_utils; + +export 'src/utils/composite_subscription.dart'; +export 'src/utils/error_and_stacktrace.dart'; +export 'src/utils/notification.dart'; diff --git a/sandbox/reactivex/pubspec.yaml b/sandbox/reactivex/pubspec.yaml new file mode 100644 index 0000000..e54c0bf --- /dev/null +++ b/sandbox/reactivex/pubspec.yaml @@ -0,0 +1,25 @@ +name: angel3_reactivex +version: 0.28.0 +description: > + angel3_reactivex is an implementation of the popular ReactiveX api for asynchronous + programming, leveraging the native Dart Streams api. +repository: https://github.com/ReactiveX/angel3_reactivex + +topics: + - angel3_reactivex + - reactive-programming + - streams + - observables + - rx + +environment: + sdk: '>=2.12.0 <4.0.0' + +dev_dependencies: + lints: ^1.0.1 + stack_trace: ^1.10.0 + test: ^1.17.12 + +screenshots: + - description: The angel3_reactivex package logo. + path: screenshots/logo.png diff --git a/sandbox/reactivex/screenshots/logo.png b/sandbox/reactivex/screenshots/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1ba0f821e5f05f48a09b5989fec38d80eee05aaa GIT binary patch literal 54748 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 literal 0 HcmV?d00001 diff --git a/sandbox/reactivex/test/rxdart_test.dart b/sandbox/reactivex/test/rxdart_test.dart new file mode 100644 index 0000000..ef41ddc --- /dev/null +++ b/sandbox/reactivex/test/rxdart_test.dart @@ -0,0 +1,187 @@ +library test.rx; + +import 'streams/combine_latest_test.dart' as combine_latest_test; +import 'streams/concat_eager_test.dart' as concat_eager_test; +import 'streams/concat_test.dart' as concat_test; +import 'streams/defer_test.dart' as defer_test; +import 'streams/fork_join_test.dart' as fork_join_test; +import 'streams/from_callable_test.dart' as from_callable_test; +import 'streams/merge_test.dart' as merge_test; +import 'streams/never_test.dart' as never_test; +import 'streams/publish_connectable_stream_test.dart' + as publish_connectable_stream_test; +import 'streams/race_test.dart' as race_test; +import 'streams/range_test.dart' as range_test; +import 'streams/repeat_test.dart' as repeat_test; +import 'streams/replay_connectable_stream_test.dart' + as replay_connectable_stream_test; +import 'streams/retry_test.dart' as retry_test; +import 'streams/retry_when_test.dart' as retry_when_test; +import 'streams/sequence_equals_test.dart' as sequence_equals_test; +import 'streams/switch_latest_test.dart' as switch_latest_test; +import 'streams/timer_test.dart' as timer_test; +import 'streams/using_test.dart' as using_test; +import 'streams/value_connectable_stream_test.dart' + as value_connectable_stream_test; +import 'streams/zip_test.dart' as zip_test; +import 'subject/behavior_subject_test.dart' as behaviour_subject_test; +import 'subject/publish_subject_test.dart' as publish_subject_test; +import 'subject/replay_subject_test.dart' as replay_subject_test; +import 'transformers/backpressure/buffer_count_test.dart' as buffer_count_test; +import 'transformers/backpressure/buffer_test.dart' as buffer_test; +import 'transformers/backpressure/buffer_test_test.dart' as buffer_test_test; +import 'transformers/backpressure/buffer_time_test.dart' as buffer_time_test; +import 'transformers/backpressure/debounce_test.dart' as debounce_test; +import 'transformers/backpressure/debounce_time_test.dart' + as debounce_time_test; +import 'transformers/backpressure/pairwise_test.dart' as pairwise_test; +import 'transformers/backpressure/sample_test.dart' as sample_test; +import 'transformers/backpressure/sample_time_test.dart' as sample_time_test; +import 'transformers/backpressure/throttle_test.dart' as throttle_test; +import 'transformers/backpressure/throttle_time_test.dart' + as throttle_time_test; +import 'transformers/backpressure/window_count_test.dart' as window_count_test; +import 'transformers/backpressure/window_test.dart' as window_test; +import 'transformers/backpressure/window_test_test.dart' as window_test_test; +import 'transformers/backpressure/window_time_test.dart' as window_time_test; +import 'transformers/concat_with_test.dart' as concat_with_test; +import 'transformers/default_if_empty_test.dart' as default_if_empty_test; +import 'transformers/delay_test.dart' as delay_test; +import 'transformers/delay_when_test.dart' as delay_when_test; +import 'transformers/dematerialize_test.dart' as dematerialize_test; +import 'transformers/distinct_test.dart' as distinct_test; +import 'transformers/distinct_unique_test.dart' as distinct_unique_test; +import 'transformers/do_test.dart' as do_test; +import 'transformers/end_with_many_test.dart' as end_with_many_test; +import 'transformers/end_with_test.dart' as end_with_test; +import 'transformers/exhaust_map_test.dart' as exhaust_map_test; +import 'transformers/flat_map_iterable_test.dart' as flat_map_iterable_test; +import 'transformers/flat_map_test.dart' as flat_map_test; +import 'transformers/group_by_test.dart' as group_by_test; +import 'transformers/ignore_elements_test.dart' as ignore_elements_test; +import 'transformers/interval_test.dart' as interval_test; +import 'transformers/join_test.dart' as join_test; +import 'transformers/map_not_null_test.dart' as map_not_null_test; +import 'transformers/map_to_test.dart' as map_to_test; +import 'transformers/materialize_test.dart' as materialize_test; +import 'transformers/merge_with_test.dart' as merge_with_test; +import 'transformers/on_error_return_test.dart' as on_error_resume_test; +import 'transformers/on_error_return_test.dart' as on_error_return_test; +import 'transformers/on_error_return_with_test.dart' + as on_error_return_with_test; +import 'transformers/scan_test.dart' as scan_test; +import 'transformers/skip_last_test.dart' as skip_last_test; +import 'transformers/skip_until_test.dart' as skip_until_test; +import 'transformers/start_with_many_test.dart' as start_with_many_test; +import 'transformers/start_with_test.dart' as start_with_test; +import 'transformers/switch_if_empty_test.dart' as switch_if_empty_test; +import 'transformers/switch_map_test.dart' as switch_map_test; +import 'transformers/take_last_test.dart' as take_last_test; +import 'transformers/take_until_test.dart' as take_until_test; +import 'transformers/take_while_inclusive_test.dart' + as take_while_inclusive_test; +import 'transformers/time_interval_test.dart' as time_interval_test; +import 'transformers/timeout_test.dart' as timeout_test; +import 'transformers/timestamp_test.dart' as timestamp_test; +import 'transformers/where_not_null_test.dart' as where_not_null_test; +import 'transformers/where_type_test.dart' as where_type_test; +import 'transformers/with_latest_from_test.dart' as with_latest_from_test; +import 'transformers/zip_with_test.dart' as zip_with_test; +import 'utils/composite_subscription_test.dart' as composite_subscription_test; +import 'utils/notification_test.dart' as notification_test; + +void main() { + // Streams + combine_latest_test.main(); + concat_eager_test.main(); + concat_test.main(); + defer_test.main(); + fork_join_test.main(); + from_callable_test.main(); + merge_test.main(); + never_test.main(); + range_test.main(); + race_test.main(); + repeat_test.main(); + retry_test.main(); + retry_when_test.main(); + sequence_equals_test.main(); + switch_latest_test.main(); + using_test.main(); + zip_test.main(); + + // StreamTransformers + concat_with_test.main(); + default_if_empty_test.main(); + delay_test.main(); + delay_when_test.main(); + dematerialize_test.main(); + distinct_test.main(); + distinct_unique_test.main(); + do_test.main(); + end_with_test.main(); + end_with_many_test.main(); + exhaust_map_test.main(); + flat_map_test.main(); + flat_map_iterable_test.main(); + group_by_test.main(); + ignore_elements_test.main(); + interval_test.main(); + join_test.main(); + map_not_null_test.main(); + map_to_test.main(); + materialize_test.main(); + merge_with_test.main(); + on_error_resume_test.main(); + on_error_return_test.main(); + on_error_return_with_test.main(); + scan_test.main(); + skip_last_test.main(); + skip_until_test.main(); + start_with_many_test.main(); + start_with_test.main(); + switch_if_empty_test.main(); + switch_map_test.main(); + take_last_test.main(); + take_until_test.main(); + take_while_inclusive_test.main(); + time_interval_test.main(); + timeout_test.main(); + timestamp_test.main(); + timer_test.main(); + where_not_null_test.main(); + where_type_test.main(); + with_latest_from_test.main(); + zip_with_test.main(); + + // Backpressure + buffer_test.main(); + buffer_count_test.main(); + buffer_test_test.main(); + buffer_time_test.main(); + debounce_test.main(); + debounce_time_test.main(); + pairwise_test.main(); + sample_test.main(); + sample_time_test.main(); + throttle_test.main(); + throttle_time_test.main(); + window_test.main(); + window_count_test.main(); + window_test_test.main(); + window_time_test.main(); + + // Subjects + behaviour_subject_test.main(); + publish_subject_test.main(); + replay_subject_test.main(); + + // Connectable Streams + value_connectable_stream_test.main(); + replay_connectable_stream_test.main(); + publish_connectable_stream_test.main(); + + // Utilities + composite_subscription_test.main(); + notification_test.main(); +} diff --git a/sandbox/reactivex/test/streams/combine_latest_test.dart b/sandbox/reactivex/test/streams/combine_latest_test.dart new file mode 100644 index 0000000..bd03e09 --- /dev/null +++ b/sandbox/reactivex/test/streams/combine_latest_test.dart @@ -0,0 +1,394 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +Stream get streamA => + Stream.periodic(const Duration(milliseconds: 1), (int count) => count) + .take(3); + +Stream get streamB => Stream.fromIterable(const [1, 2, 3, 4]); + +Stream get streamC { + final controller = StreamController() + ..add(true) + ..close(); + + return controller.stream; +} + +void main() { + test('Rx.combineLatestList', () async { + final combined = Rx.combineLatestList([ + Stream.fromIterable([1, 2, 3]), + Stream.value(2), + Stream.value(3), + ]); + + expect( + combined, + emitsInOrder([ + [1, 2, 3], + [2, 2, 3], + [3, 2, 3], + ]), + ); + }); + + test('Rx.combineLatestList.iterate.once', () async { + var iterationCount = 0; + + final combined = Rx.combineLatestList(() sync* { + ++iterationCount; + yield Stream.value(1); + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + combined, + emitsInOrder([ + [1, 2, 3], + emitsDone, + ]), + ); + expect(iterationCount, 1); + }); + + test('Rx.combineLatestList.empty', () async { + final combined = Rx.combineLatestList([]); + expect(combined, emitsDone); + }); + + test('Rx.combineLatest', () async { + final combined = Rx.combineLatest( + [ + Stream.fromIterable([1, 2, 3]), + Stream.value(2), + Stream.value(3), + ], + (values) => values.fold(0, (acc, val) => acc + val), + ); + + expect( + combined, + emitsInOrder([6, 7, 8]), + ); + }); + + test('Rx.combineLatest3', () async { + const expectedOutput = ['0 4 true', '1 4 true', '2 4 true']; + var count = 0; + + final stream = Rx.combineLatest3(streamA, streamB, streamC, + (int aValue, int bValue, bool cValue) { + return '$aValue $bValue $cValue'; + }); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result.compareTo(expectedOutput[count++]), 0); + }, count: 3)); + }); + + test('Rx.combineLatest3.single.subscription', () async { + final stream = Rx.combineLatest3(streamA, streamB, streamC, + (int aValue, int bValue, bool cValue) { + return '$aValue $bValue $cValue'; + }); + + stream.listen(null); + await expectLater(() => stream.listen((_) {}), throwsA(isStateError)); + }); + + test('Rx.combineLatest2', () async { + const expected = [ + [1, 2], + [2, 2] + ]; + var count = 0; + + var a = Stream.fromIterable(const [1, 2]), b = Stream.value(2); + + final stream = + Rx.combineLatest2(a, b, (int first, int second) => [first, second]); + + stream.listen(expectAsync1((result) { + expect(result, expected[count++]); + }, count: expected.length)); + }); + + test('Rx.combineLatest2.throws', () async { + var a = Stream.value(1), b = Stream.value(2); + + final stream = Rx.combineLatest2(a, b, (int first, int second) { + throw Exception(); + }); + + stream.listen(null, onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.combineLatest3', () async { + const expected = [1, '2', 3.0]; + + var a = Stream.value(1), + b = Stream.value('2'), + c = Stream.value(3.0); + + final stream = Rx.combineLatest3(a, b, c, + (int first, String second, double third) => [first, second, third]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.combineLatest4', () async { + const expected = [1, 2, 3, 4]; + + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4); + + final stream = Rx.combineLatest4( + a, + b, + c, + d, + (int first, int second, int third, int fourth) => + [first, second, third, fourth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.combineLatest5', () async { + const expected = [1, 2, 3, 4, 5]; + + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5); + + final stream = Rx.combineLatest5( + a, + b, + c, + d, + e, + (int first, int second, int third, int fourth, int fifth) => + [first, second, third, fourth, fifth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.combineLatest6', () async { + const expected = [1, 2, 3, 4, 5, 6]; + + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6); + + final stream = Rx.combineLatest6( + a, + b, + c, + d, + e, + f, + (int first, int second, int third, int fourth, int fifth, int sixth) => + [first, second, third, fourth, fifth, sixth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.combineLatest7', () async { + const expected = [1, 2, 3, 4, 5, 6, 7]; + + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7); + + final stream = Rx.combineLatest7( + a, + b, + c, + d, + e, + f, + g, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh) => + [first, second, third, fourth, fifth, sixth, seventh]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.combineLatest8', () async { + const expected = [1, 2, 3, 4, 5, 6, 7, 8]; + + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7), + h = Stream.value(8); + + final stream = Rx.combineLatest8( + a, + b, + c, + d, + e, + f, + g, + h, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh, int eighth) => + [first, second, third, fourth, fifth, sixth, seventh, eighth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.combineLatest9', () async { + const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7), + h = Stream.value(8), + i = Stream.value(9); + + final stream = Rx.combineLatest9( + a, + b, + c, + d, + e, + f, + g, + h, + i, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh, int eighth, int ninth) => + [ + first, + second, + third, + fourth, + fifth, + sixth, + seventh, + eighth, + ninth + ]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.combineLatest.asBroadcastStream', () async { + final stream = Rx.combineLatest3(streamA, streamB, streamC, + (int aValue, int bValue, bool cValue) { + return '$aValue $bValue $cValue'; + }).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.combineLatest.error.shouldThrowA', () async { + final streamWithError = Rx.combineLatest4(Stream.value(1), Stream.value(1), + Stream.value(1), Stream.error(Exception()), + (int aValue, int bValue, int cValue, dynamic _) { + return '$aValue $bValue $cValue $_'; + }); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.combineLatest.error.shouldThrowB', () async { + final streamWithError = + Rx.combineLatest3(Stream.value(1), Stream.value(1), Stream.value(1), + (int aValue, int bValue, int cValue) { + throw Exception('oh noes!'); + }); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + /*test('Rx.combineLatest.error.shouldThrowC', () { + expect( + () => Rx.combineLatest3(Stream.value(1), + Stream.just(1), Stream.value(1), null), + throwsArgumentError); + }); + + test('Rx.combineLatest.error.shouldThrowD', () { + expect(() => CombineLatestStream(null, null), throwsArgumentError); + }); + + test('Rx.combineLatest.error.shouldThrowE', () { + expect(() => CombineLatestStream(>[], null), + throwsArgumentError); + });*/ + + test('Rx.combineLatest.pause.resume', () async { + final first = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [1, 2, 3, 4][index]), + second = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [5, 6, 7, 8][index]), + last = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [9, 10, 11, 12][index]); + + late StreamSubscription> subscription; + // ignore: deprecated_member_use + subscription = Rx.combineLatest3( + first, second, last, (int a, int b, int c) => [a, b, c]) + .listen(expectAsync1((value) { + expect(value.elementAt(0), 1); + expect(value.elementAt(1), 5); + expect(value.elementAt(2), 9); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(Future.delayed(const Duration(milliseconds: 80))); + }); +} diff --git a/sandbox/reactivex/test/streams/concat_eager_test.dart b/sandbox/reactivex/test/streams/concat_eager_test.dart new file mode 100644 index 0000000..bb77624 --- /dev/null +++ b/sandbox/reactivex/test/streams/concat_eager_test.dart @@ -0,0 +1,185 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +List> _getStreams() { + var a = Stream.fromIterable(const [0, 1, 2]), + b = Stream.fromIterable(const [3, 4, 5]); + + return [a, b]; +} + +List> _getStreamsIncludingEmpty() { + var a = Stream.fromIterable(const [0, 1, 2]), + b = Stream.fromIterable(const [3, 4, 5]), + c = Stream.empty(); + + return [c, a, b]; +} + +void main() { + test('Rx.concatEager', () async { + const expectedOutput = [0, 1, 2, 3, 4, 5]; + var count = 0; + + final stream = Rx.concatEager(_getStreams()); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.concatEager.single', () async { + final stream = Rx.concatEager([ + Stream.fromIterable([1, 2, 3, 4, 5]) + ]); + + await expectLater(stream, emitsInOrder([1, 2, 3, 4, 5, emitsDone])); + }); + + test('Rx.concatEager.eagerlySubscription', () async { + var subscribed2 = false; + var subscribed3 = false; + + final stream = Rx.concatEager([ + Rx.timer(1, Duration(milliseconds: 100)).doOnDone( + expectAsync0(() => expect(subscribed2 && subscribed3, true))), + Rx.timer([2, 3, 4], Duration(milliseconds: 100)) + .exhaustMap((v) => Stream.fromIterable(v)) + .doOnListen(() => subscribed2 = true) + .doOnDone(expectAsync0(() => expect(subscribed3, true))), + Rx.timer(5, Duration(milliseconds: 100)) + .doOnListen(() => subscribed3 = true), + ]); + + await expectLater( + stream, + emitsInOrder([ + 1, + 2, + 3, + 4, + 5, + emitsDone, + ]), + ); + }); + + test('Rx.concatEager.single.subscription', () async { + final stream = Rx.concatEager(_getStreams()); + + stream.listen(null); + await expectLater(() => stream.listen((_) {}), throwsA(isStateError)); + }); + + test('Rx.concatEager.withEmptyStream', () async { + const expectedOutput = [0, 1, 2, 3, 4, 5]; + var count = 0; + + final stream = Rx.concatEager(_getStreamsIncludingEmpty()); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.concatEager.withBroadcastStreams', () async { + const expectedOutput = [1, 2, 3, 4, 99, 98, 97, 96, 999, 998, 997]; + final ctrlA = StreamController.broadcast(), + ctrlB = StreamController.broadcast(), + ctrlC = StreamController.broadcast(); + var x = 0, y = 100, z = 1000, count = 0; + + Timer.periodic(const Duration(milliseconds: 10), (_) { + ctrlA.add(++x); + ctrlB.add(--y); + + if (x <= 3) ctrlC.add(--z); + + if (x == 3) ctrlC.close(); + + if (x == 4) { + _.cancel(); + + ctrlA.close(); + ctrlB.close(); + } + }); + + final stream = Rx.concatEager([ctrlA.stream, ctrlB.stream, ctrlC.stream]); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.concatEager.asBroadcastStream', () async { + final stream = Rx.concatEager(_getStreams()).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.concatEager.error.shouldThrowA', () async { + final streamWithError = + Rx.concatEager(_getStreams()..add(Stream.error(Exception()))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.concatEager.pause.resume', () async { + final first = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [1, 2, 3, 4][index]), + second = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [5, 6, 7, 8][index]), + last = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [9, 10, 11, 12][index]); + + late StreamSubscription subscription; + // ignore: deprecated_member_use + subscription = + Rx.concatEager([first, second, last]).listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(Future.delayed(const Duration(milliseconds: 80))); + }); + + test('Rx.concatEager.empty', () { + expect(Rx.concatEager(const []), emitsDone); + }); + + test('Rx.concatEager.iterate.once', () async { + var iterationCount = 0; + + final stream = Rx.concatEager(() sync* { + ++iterationCount; + yield Stream.value(1); + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + stream, + emitsInOrder([ + 1, + 2, + 3, + emitsDone, + ]), + ); + expect(iterationCount, 1); + }); +} diff --git a/sandbox/reactivex/test/streams/concat_test.dart b/sandbox/reactivex/test/streams/concat_test.dart new file mode 100644 index 0000000..daacc24 --- /dev/null +++ b/sandbox/reactivex/test/streams/concat_test.dart @@ -0,0 +1,136 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +List> _getStreams() { + var a = Stream.fromIterable(const [0, 1, 2]), + b = Stream.fromIterable(const [3, 4, 5]); + + return [a, b]; +} + +List> _getStreamsIncludingEmpty() { + var a = Stream.fromIterable(const [0, 1, 2]), + b = Stream.fromIterable(const [3, 4, 5]), + c = Stream.empty(); + + return [c, a, b]; +} + +void main() { + test('Rx.concat', () async { + const expectedOutput = [0, 1, 2, 3, 4, 5]; + var count = 0; + + final stream = Rx.concat(_getStreams()); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.concatEager.single.subscription', () async { + final stream = Rx.concat(_getStreams()); + + stream.listen(null); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('Rx.concat.withEmptyStream', () async { + const expectedOutput = [0, 1, 2, 3, 4, 5]; + var count = 0; + + final stream = Rx.concat(_getStreamsIncludingEmpty()); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.concat.withBroadcastStreams', () async { + const expectedOutput = [1, 2, 3, 4]; + final ctrlA = StreamController.broadcast(), + ctrlB = StreamController.broadcast(), + ctrlC = StreamController.broadcast(); + var x = 0, y = 100, z = 1000, count = 0; + + Timer.periodic(const Duration(milliseconds: 1), (_) { + ctrlA.add(++x); + ctrlB.add(--y); + + if (x <= 3) ctrlC.add(--z); + + if (x == 3) ctrlC.close(); + + if (x == 4) { + _.cancel(); + + ctrlA.close(); + ctrlB.close(); + } + }); + + final stream = Rx.concat([ctrlA.stream, ctrlB.stream, ctrlC.stream]); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.concat.asBroadcastStream', () async { + final stream = Rx.concat(_getStreams()).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.concat.error.shouldThrowA', () async { + final streamWithError = + Rx.concat(_getStreams()..add(Stream.error(Exception()))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.concat.empty', () { + expect(Rx.concat(const []), emitsDone); + }); + + test('Rx.concat.single', () { + expect( + Rx.concat([Stream.value(1)]), + emitsInOrder([1, emitsDone]), + ); + }); + + test('Rx.concat.iterate.once', () async { + var iterationCount = 0; + + final stream = Rx.concat(() sync* { + ++iterationCount; + yield Stream.value(1); + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + stream, + emitsInOrder([ + 1, + 2, + 3, + emitsDone, + ]), + ); + expect(iterationCount, 1); + }); +} diff --git a/sandbox/reactivex/test/streams/defer_test.dart b/sandbox/reactivex/test/streams/defer_test.dart new file mode 100644 index 0000000..5ff00cc --- /dev/null +++ b/sandbox/reactivex/test/streams/defer_test.dart @@ -0,0 +1,128 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.defer', () async { + const value = 1; + + final stream = _getDeferStream(); + + stream.listen(expectAsync1((actual) { + expect(actual, value); + }, count: 1)); + }); + + test('Rx.defer.multiple.listeners', () async { + const value = 1; + + final stream = _getBroadcastDeferStream(); + + stream.listen(expectAsync1((actual) { + expect(actual, value); + }, count: 1)); + + stream.listen(expectAsync1((actual) { + expect(actual, value); + }, count: 1)); + }); + + test('Rx.defer.streamFactory.called', () async { + var count = 0; + + Stream streamFactory() { + ++count; + return Stream.value(1); + } + + var deferStream = DeferStream( + streamFactory, + reusable: false, + ); + + expect(count, 0); + + deferStream.listen( + expectAsync1((_) { + expect(count, 1); + }), + ); + }); + + test('Rx.defer.reusable', () async { + const value = 1; + + final stream = Rx.defer( + () => Stream.fromFuture( + Future.delayed( + Duration(seconds: 1), + () => value, + ), + ), + reusable: true, + ); + + stream.listen( + expectAsync1( + (actual) => expect(actual, value), + count: 1, + ), + ); + stream.listen( + expectAsync1( + (actual) => expect(actual, value), + count: 1, + ), + ); + }); + + test('Rx.defer.single.subscription', () async { + final stream = _getDeferStream(); + + try { + stream.listen(null); + stream.listen(null); + expect(true, false); + } catch (e) { + expect(e, isStateError); + } + }); + + test('Rx.defer.error.shouldThrow.A', () async { + final streamWithError = Rx.defer(() => _getErroneousStream()); + + streamWithError.listen(null, + onError: expectAsync1((Exception e) { + expect(e, isException); + }, count: 1)); + }); + + test('Rx.defer.error.shouldThrow.B', () { + final deferStream1 = Rx.defer(() => throw Exception()); + expect( + deferStream1, + emitsInOrder([emitsError(isException), emitsDone]), + ); + + final deferStream2 = Rx.defer(() => throw Exception(), reusable: true); + expect( + deferStream2, + emitsInOrder([emitsError(isException), emitsDone]), + ); + }); +} + +Stream _getDeferStream() => Rx.defer(() => Stream.value(1)); + +Stream _getBroadcastDeferStream() => + Rx.defer(() => Stream.value(1)).asBroadcastStream(); + +Stream _getErroneousStream() { + final controller = StreamController(); + + controller.addError(Exception()); + controller.close(); + + return controller.stream; +} diff --git a/sandbox/reactivex/test/streams/fork_join_test.dart b/sandbox/reactivex/test/streams/fork_join_test.dart new file mode 100644 index 0000000..5708581 --- /dev/null +++ b/sandbox/reactivex/test/streams/fork_join_test.dart @@ -0,0 +1,452 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +Stream get streamA => + Stream.periodic(const Duration(milliseconds: 1), (int count) => count) + .take(3); + +Stream get streamB => Stream.fromIterable(const [1, 2, 3, 4]); + +Stream get streamC { + final controller = StreamController() + ..add(true) + ..close(); + + return controller.stream; +} + +void main() { + test('Rx.forkJoinList', () async { + final combined = Rx.forkJoinList([ + Stream.fromIterable([1, 2, 3]), + Stream.value(2), + Stream.value(3), + ]); + + await expectLater( + combined, + emitsInOrder([ + [3, 2, 3], + emitsDone + ]), + ); + }); + + test('Rx.forkJoin.nullable', () { + expect( + ForkJoinStream.join2( + Stream.value(null), + Stream.value(1), + (a, b) => '$a $b', + ), + emitsInOrder([ + 'null 1', + emitsDone, + ]), + ); + }); + + test('Rx.forkJoin.iterate.once', () async { + var iterationCount = 0; + + final stream = Rx.forkJoinList(() sync* { + ++iterationCount; + yield Stream.value(1); + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + stream, + emitsInOrder([ + [1, 2, 3], + emitsDone, + ]), + ); + expect(iterationCount, 1); + }); + + test('Rx.forkJoin.empty', () { + expect(Rx.forkJoinList([]), emitsDone); + }); + + test('Rx.forkJoinList.singleStream', () async { + final combined = Rx.forkJoinList([ + Stream.fromIterable([1, 2, 3]) + ]); + + await expectLater( + combined, + emitsInOrder([ + [3], + emitsDone + ]), + ); + }); + + test('Rx.forkJoin', () async { + final combined = Rx.forkJoin( + [ + Stream.fromIterable([1, 2, 3]), + Stream.value(2), + Stream.value(3), + ], + (values) => values.fold(0, (acc, val) => acc + val), + ); + + await expectLater( + combined, + emitsInOrder([8, emitsDone]), + ); + }); + + test('Rx.forkJoin3', () async { + final stream = Rx.forkJoin3(streamA, streamB, streamC, + (int aValue, int bValue, bool cValue) => '$aValue $bValue $cValue'); + + await expectLater(stream, emitsInOrder(['2 4 true', emitsDone])); + }); + + test('Rx.forkJoin3.single.subscription', () async { + final stream = Rx.forkJoin3(streamA, streamB, streamC, + (int aValue, int bValue, bool cValue) => '$aValue $bValue $cValue'); + + await expectLater( + stream, + emitsInOrder(['2 4 true', emitsDone]), + ); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('Rx.forkJoin2', () async { + var a = Stream.fromIterable(const [1, 2]), b = Stream.value(2); + + final stream = + Rx.forkJoin2(a, b, (int first, int second) => [first, second]); + + await expectLater( + stream, + emitsInOrder([ + [2, 2], + emitsDone + ])); + }); + + test('Rx.forkJoin2.throws', () async { + var a = Stream.value(1), b = Stream.value(2); + + final stream = Rx.forkJoin2(a, b, (int first, int second) { + throw Exception(); + }); + + stream.listen(null, onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.forkJoin3', () async { + var a = Stream.value(1), + b = Stream.value('2'), + c = Stream.value(3.0); + + final stream = Rx.forkJoin3(a, b, c, + (int first, String second, double third) => [first, second, third]); + + await expectLater( + stream, + emitsInOrder([ + const [1, '2', 3.0], + emitsDone + ])); + }); + + test('Rx.forkJoin4', () async { + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4); + + final stream = Rx.forkJoin4( + a, + b, + c, + d, + (int first, int second, int third, int fourth) => + [first, second, third, fourth]); + + await expectLater( + stream, + emitsInOrder([ + const [1, 2, 3, 4], + emitsDone + ])); + }); + + test('Rx.forkJoin5', () async { + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5); + + final stream = Rx.forkJoin5( + a, + b, + c, + d, + e, + (int first, int second, int third, int fourth, int fifth) => + [first, second, third, fourth, fifth]); + + await expectLater( + stream, + emitsInOrder([ + const [1, 2, 3, 4, 5], + emitsDone + ])); + }); + + test('Rx.forkJoin6', () async { + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6); + + final stream = Rx.combineLatest6( + a, + b, + c, + d, + e, + f, + (int first, int second, int third, int fourth, int fifth, int sixth) => + [first, second, third, fourth, fifth, sixth]); + + await expectLater( + stream, + emitsInOrder([ + const [1, 2, 3, 4, 5, 6], + emitsDone + ])); + }); + + test('Rx.forkJoin7', () async { + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7); + + final stream = Rx.forkJoin7( + a, + b, + c, + d, + e, + f, + g, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh) => + [first, second, third, fourth, fifth, sixth, seventh]); + + await expectLater( + stream, + emitsInOrder([ + const [1, 2, 3, 4, 5, 6, 7], + emitsDone + ])); + }); + + test('Rx.forkJoin8', () async { + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7), + h = Stream.value(8); + + final stream = Rx.forkJoin8( + a, + b, + c, + d, + e, + f, + g, + h, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh, int eighth) => + [first, second, third, fourth, fifth, sixth, seventh, eighth]); + + await expectLater( + stream, + emitsInOrder([ + const [1, 2, 3, 4, 5, 6, 7, 8], + emitsDone + ])); + }); + + test('Rx.forkJoin9', () async { + var a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7), + h = Stream.value(8), + i = Stream.value(9); + + final stream = Rx.forkJoin9( + a, + b, + c, + d, + e, + f, + g, + h, + i, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh, int eighth, int ninth) => + [ + first, + second, + third, + fourth, + fifth, + sixth, + seventh, + eighth, + ninth + ]); + + await expectLater( + stream, + emitsInOrder([ + const [1, 2, 3, 4, 5, 6, 7, 8, 9], + emitsDone + ])); + }); + + test('Rx.forkJoin.asBroadcastStream', () async { + final stream = Rx.forkJoin3(streamA, streamB, streamC, + (int aValue, int bValue, bool cValue) => '$aValue $bValue $cValue') + .asBroadcastStream(); + +// listen twice on same stream + stream.listen(null); + stream.listen(null); +// code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.forkJoin.error.shouldThrowA', () async { + final streamWithError = Rx.forkJoin4( + Stream.value(1), + Stream.value(1), + Stream.value(1), + Stream.error(Exception()), + (int aValue, int bValue, int cValue, dynamic _) => + '$aValue $bValue $cValue $_'); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + }), cancelOnError: true); + }); + + test('Rx.forkJoin.error.shouldThrowB', () async { + final streamWithError = + Rx.forkJoin3(Stream.value(1), Stream.value(1), Stream.value(1), + (int aValue, int bValue, int cValue) { + throw Exception('oh noes!'); + }); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.forkJoin.pause.resume', () async { + final first = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [1, 2, 3, 4][index]).take(4), + second = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [5, 6, 7, 8][index]).take(4), + last = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [9, 10, 11, 12][index]).take(4); + + late StreamSubscription> subscription; + subscription = + Rx.forkJoin3(first, second, last, (int a, int b, int c) => [a, b, c]) + .listen(expectAsync1((value) { + expect(value.elementAt(0), 4); + expect(value.elementAt(1), 8); + expect(value.elementAt(2), 12); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(Future.delayed(const Duration(milliseconds: 80))); + }); + + test('Rx.forkJoin.completed', () async { + final stream = Rx.forkJoin2( + Stream.empty(), + Stream.value(1), + (int a, int b) => a + b, + ); + await expectLater( + stream, + emitsInOrder([emitsError(isStateError), emitsDone]), + ); + }); + + test('Rx.forkJoin.error.shouldThrowC', () async { + final stream = Rx.forkJoin2( + Stream.value(1), + Stream.error(Exception()).concatWith([ + Rx.timer( + 2, + const Duration(milliseconds: 100), + ) + ]), + (int a, int b) => a + b, + ); + await expectLater( + stream, + emitsInOrder([emitsError(isException), 3, emitsDone]), + ); + }); + + test('Rx.forkJoin.error.shouldThrowD', () async { + final stream = Rx.forkJoin2( + Stream.value(1), + Stream.error(Exception()).concatWith([ + Rx.timer( + 2, + const Duration(milliseconds: 100), + ) + ]), + (int a, int b) => a + b, + ); + + stream.listen( + expectAsync1((value) {}, count: 0), + onError: expectAsync2( + (Object e, StackTrace s) => expect(e, isException), + count: 1, + ), + cancelOnError: true, + ); + }); +} diff --git a/sandbox/reactivex/test/streams/from_callable_test.dart b/sandbox/reactivex/test/streams/from_callable_test.dart new file mode 100644 index 0000000..69b7dca --- /dev/null +++ b/sandbox/reactivex/test/streams/from_callable_test.dart @@ -0,0 +1,130 @@ +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.fromCallable.sync', () { + var called = false; + + var stream = Rx.fromCallable(() { + called = true; + return 2; + }); + + expect(called, false); + expectLater(stream, emitsInOrder([2, emitsDone])); + expect(called, true); + }); + + test('Rx.fromCallable.async', () { + var called = false; + + var stream = FromCallableStream(() async { + called = true; + await Future.delayed(const Duration(milliseconds: 10)); + return 2; + }); + + expect(called, false); + expectLater(stream, emitsInOrder([2, emitsDone])); + expect(called, true); + }); + + test('Rx.fromCallable.reusable', () { + var stream = Rx.fromCallable(() => 2, reusable: true); + expect(stream.isBroadcast, isTrue); + + stream.listen(null); + stream.listen(null); + + expect(true, true); + }); + + test('Rx.fromCallable.singleSubscription', () { + { + var stream = Rx.fromCallable(() => + Future.delayed(const Duration(milliseconds: 10), () => 'Value')); + + expect(stream.isBroadcast, isFalse); + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + } + + { + var stream = Rx.fromCallable(() => Future.error(Exception())); + + expect(stream.isBroadcast, isFalse); + stream.listen(null, onError: (Object e) {}); + expect( + () => stream.listen(null, onError: (Object e) {}), throwsStateError); + } + }); + + test('Rx.fromCallable.asBroadcastStream', () async { + final stream = Rx.fromCallable(() => 2).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.fromCallable.sync.shouldThrow', () { + var stream = Rx.fromCallable(() => throw Exception()); + + expectLater( + stream, + emitsInOrder([emitsError(isException), emitsDone]), + ); + }); + + test('Rx.fromCallable.async.shouldThrow', () { + { + var stream = Rx.fromCallable(() async => throw Exception()); + + expectLater( + stream, + emitsInOrder([emitsError(isException), emitsDone]), + ); + } + + { + var stream = Rx.fromCallable(() => Future.error(Exception())); + + expectLater( + stream, + emitsInOrder([emitsError(isException), emitsDone]), + ); + } + }); + + test('Rx.fromCallable.sync.pause.resume', () { + var stream = Rx.fromCallable(() => 'Value'); + + stream + .listen( + expectAsync1( + (v) => expect(v, 'Value'), + count: 1, + ), + ) + .pause(Future.delayed(const Duration(milliseconds: 50))); + }); + + test('Rx.fromCallable.async.pause.resume', () { + var stream = Rx.fromCallable(() async { + await Future.delayed(const Duration(milliseconds: 10)); + return 'Value'; + }); + + stream + .listen( + expectAsync1( + (v) => expect(v, 'Value'), + count: 1, + ), + ) + .pause(Future.delayed(const Duration(milliseconds: 50))); + }); +} diff --git a/sandbox/reactivex/test/streams/merge_test.dart b/sandbox/reactivex/test/streams/merge_test.dart new file mode 100644 index 0000000..b70975e --- /dev/null +++ b/sandbox/reactivex/test/streams/merge_test.dart @@ -0,0 +1,92 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +List> _getStreams() { + var a = Stream.periodic(const Duration(milliseconds: 1), (count) => count) + .take(3), + b = Stream.fromIterable(const [1, 2, 3, 4]); + + return [a, b]; +} + +void main() { + test('Rx.merge', () async { + final stream = Rx.merge(_getStreams()); + + await expectLater(stream, emitsInOrder(const [1, 2, 3, 4, 0, 1, 2])); + }); + + test('Rx.merge.iterate.once', () async { + var iterationCount = 0; + + final stream = Rx.merge(() sync* { + ++iterationCount; + yield Stream.value(1); + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + stream, + emitsInOrder([ + 1, + 2, + 3, + emitsDone, + ]), + ); + expect(iterationCount, 1); + }); + + test('Rx.merge.single.subscription', () async { + final stream = Rx.merge(_getStreams()); + + stream.listen(null); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('Rx.merge.asBroadcastStream', () async { + final stream = Rx.merge(_getStreams()).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.merge.error.shouldThrowA', () async { + final streamWithError = + Rx.merge(_getStreams()..add(Stream.error(Exception()))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.merge.pause.resume', () async { + final first = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [1, 2, 3, 4][index]), + second = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [5, 6, 7, 8][index]), + last = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [9, 10, 11, 12][index]); + + late StreamSubscription subscription; + // ignore: deprecated_member_use + subscription = Rx.merge([first, second, last]).listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(Future.delayed(const Duration(milliseconds: 80))); + }); + + test('Rx.merge.empty', () { + expect(Rx.merge(const []), emitsDone); + }); +} diff --git a/sandbox/reactivex/test/streams/never_test.dart b/sandbox/reactivex/test/streams/never_test.dart new file mode 100644 index 0000000..4254963 --- /dev/null +++ b/sandbox/reactivex/test/streams/never_test.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('NeverStream', () async { + var onDataCalled = false, onDoneCalled = false, onErrorCalled = false; + + final stream = NeverStream(); + + final subscription = stream.listen( + expectAsync1((_) { + onDataCalled = true; + }, count: 0), + onError: expectAsync2((Exception e, StackTrace s) { + onErrorCalled = false; + }, count: 0), + onDone: expectAsync0(() { + onDataCalled = true; + }, count: 0)); + + await Future.delayed(Duration(milliseconds: 10)); + + await subscription.cancel(); + + // We do not expect onData, onDone, nor onError to be called, as [never] + // streams emit no items or errors, and they do not terminate + await expectLater(onDataCalled, isFalse); + await expectLater(onDoneCalled, isFalse); + await expectLater(onErrorCalled, isFalse); + }); + + test('NeverStream.single.subscription', () async { + final stream = NeverStream(); + + stream.listen(null); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('Rx.never', () async { + var onDataCalled = false, onDoneCalled = false, onErrorCalled = false; + + final stream = Rx.never(); + + final subscription = stream.listen( + expectAsync1((_) { + onDataCalled = true; + }, count: 0), + onError: expectAsync2((Exception e, StackTrace s) { + onErrorCalled = false; + }, count: 0), + onDone: expectAsync0(() { + onDataCalled = true; + }, count: 0)); + + await Future.delayed(Duration(milliseconds: 10)); + + await subscription.cancel(); + + // We do not expect onData, onDone, nor onError to be called, as [never] + // streams emit no items or errors, and they do not terminate + await expectLater(onDataCalled, isFalse); + await expectLater(onDoneCalled, isFalse); + await expectLater(onErrorCalled, isFalse); + }); +} diff --git a/sandbox/reactivex/test/streams/publish_connectable_stream_test.dart b/sandbox/reactivex/test/streams/publish_connectable_stream_test.dart new file mode 100644 index 0000000..4e1e793 --- /dev/null +++ b/sandbox/reactivex/test/streams/publish_connectable_stream_test.dart @@ -0,0 +1,164 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +class MockStream extends Stream { + final Stream stream; + var listenCount = 0; + + MockStream(this.stream); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + ++listenCount; + return stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} + +void main() { + group('PublishConnectableStream', () { + test('should not emit before connecting', () { + final stream = MockStream(Stream.fromIterable(const [1, 2, 3])); + final connectableStream = PublishConnectableStream(stream); + + expect(stream.listenCount, 0); + connectableStream.connect(); + expect(stream.listenCount, 1); + }); + + test('should begin emitting items after connection', () { + final ConnectableStream stream = PublishConnectableStream( + Stream.fromIterable([1, 2, 3])); + + stream.connect(); + + expect(stream, emitsInOrder([1, 2, 3])); + }); + + test('stops emitting after the connection is cancelled', () async { + final ConnectableStream stream = + Stream.fromIterable([1, 2, 3]).publishValue(); + + stream.connect().cancel(); // ignore: unawaited_futures + + expect(stream, neverEmits(anything)); + }); + + test('multicasts a single-subscription stream', () async { + final stream = PublishConnectableStream( + Stream.fromIterable(const [1, 2, 3]), + ).autoConnect(); + + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + }); + + test('can multicast streams', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).publish(); + + stream.connect(); + + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + }); + + test('refcount automatically connects', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).share(); + + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + }); + + test('provide a function to autoconnect that stops listening', () async { + final stream = Stream.fromIterable(const [1, 2, 3]) + .publish() + .autoConnect(connection: (subscription) => subscription.cancel()); + + expect(await stream.isEmpty, true); + }); + + test('refCount cancels source subscription when no listeners remain', + () async { + var isCanceled = false; + + final controller = + StreamController(onCancel: () => isCanceled = true); + final stream = controller.stream.share(); + + StreamSubscription subscription; + subscription = stream.listen(null); + + await subscription.cancel(); + expect(isCanceled, true); + }); + + test('can close share() stream', () async { + final isCanceled = Completer(); + + final controller = StreamController(); + controller.stream + .share() + .doOnCancel(() => isCanceled.complete()) + .listen(null); + + controller.add(true); + await Future.delayed(Duration.zero); + await controller.close(); + + expect(isCanceled.future, completes); + }); + + test( + 'throws StateError when mixing autoConnect, connect and refCount together', + () { + PublishConnectableStream stream() => Stream.value(1).publish(); + + expect( + () => stream() + ..autoConnect() + ..connect(), + throwsStateError, + ); + expect( + () => stream() + ..autoConnect() + ..refCount(), + throwsStateError, + ); + expect( + () => stream() + ..connect() + ..refCount(), + throwsStateError, + ); + }); + + test('calling autoConnect() multiple times returns the same value', () { + final s = Stream.value(1).publish(); + expect(s.autoConnect(), same(s.autoConnect())); + expect(s.autoConnect(), same(s.autoConnect())); + }); + + test('calling connect() multiple times returns the same value', () { + final s = Stream.value(1).publish(); + expect(s.connect(), same(s.connect())); + expect(s.connect(), same(s.connect())); + }); + + test('calling refCount() multiple times returns the same value', () { + final s = Stream.value(1).publish(); + expect(s.refCount(), same(s.refCount())); + expect(s.refCount(), same(s.refCount())); + }); + }); +} diff --git a/sandbox/reactivex/test/streams/race_test.dart b/sandbox/reactivex/test/streams/race_test.dart new file mode 100644 index 0000000..ef932e4 --- /dev/null +++ b/sandbox/reactivex/test/streams/race_test.dart @@ -0,0 +1,136 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +Stream getDelayedStream(int delay, int value) async* { + final completer = Completer(); + + Timer(Duration(milliseconds: delay), () => completer.complete()); + + await completer.future; + + yield value; + yield value + 1; + yield value + 2; +} + +void main() { + test('Rx.race', () async { + final first = getDelayedStream(50, 1), + second = getDelayedStream(60, 2), + last = getDelayedStream(70, 3); + var expected = 1; + + Rx.race([first, second, last]).listen(expectAsync1((result) { + // test to see if the combined output matches + expect(result.compareTo(expected++), 0); + }, count: 3)); + }); + + test('Rx.race.iterate.once', () async { + var iterationCount = 0; + + final stream = Rx.race(() sync* { + ++iterationCount; + yield Stream.value(1); + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + stream, + emitsInOrder([1, emitsDone]), + ); + expect(iterationCount, 1); + }); + + test('Rx.race.single.subscription', () async { + final first = getDelayedStream(50, 1); + + final stream = Rx.race([first]); + + stream.listen(null); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('Rx.race.asBroadcastStream', () async { + final first = getDelayedStream(50, 1), + second = getDelayedStream(60, 2), + last = getDelayedStream(70, 3); + + final stream = Rx.race([first, second, last]).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.race.shouldThrowB', () async { + final stream = Rx.race([Stream.error(Exception('oh noes!'))]); + + // listen twice on same stream + stream.listen(null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException))); + }); + + test('Rx.race.pause.resume', () async { + final first = getDelayedStream(50, 1), + second = getDelayedStream(60, 2), + last = getDelayedStream(70, 3); + + late StreamSubscription subscription; + // ignore: deprecated_member_use + subscription = Rx.race([first, second, last]).listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(Future.delayed(const Duration(milliseconds: 80))); + }); + + test('Rx.race.empty', () { + expect(Rx.race(const []), emitsDone); + }); + + test('Rx.race.single', () { + expect( + Rx.race([Stream.value(1)]), + emitsInOrder([ + 1, + emitsDone, + ]), + ); + }); + + test('Rx.race.cancel.throws', () async { + Stream stream() { + final controller = StreamController(); + controller.onCancel = () async { + throw Exception('Exception when cancelling!'); + }; + + return Rx.race([ + controller.stream, + Rx.concat([ + Rx.timer(1, const Duration(milliseconds: 100)), + Rx.timer(2, const Duration(milliseconds: 100)), + ]), + ]); + } + + await expectLater( + stream(), + emitsInOrder([1, emitsError(isException), 2, emitsDone]), + ); + + await expectLater( + stream().take(1), + emitsInOrder([1, emitsDone]), + ); + }); +} diff --git a/sandbox/reactivex/test/streams/range_test.dart b/sandbox/reactivex/test/streams/range_test.dart new file mode 100644 index 0000000..e57739f --- /dev/null +++ b/sandbox/reactivex/test/streams/range_test.dart @@ -0,0 +1,52 @@ +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('RangeStream', () async { + final expected = const [1, 2, 3]; + var count = 0; + + final stream = RangeStream(1, 3); + + stream.listen(expectAsync1((actual) { + expect(actual, expected[count++]); + }, count: expected.length)); + }); + + test('RangeStream.single.subscription', () async { + final stream = RangeStream(1, 5); + + stream.listen(null); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('RangeStream.single', () async { + final stream = RangeStream(1, 1); + + stream.listen(expectAsync1((actual) { + expect(actual, 1); + }, count: 1)); + }); + + test('RangeStream.reverse', () async { + final expected = const [3, 2, 1]; + var count = 0; + + final stream = RangeStream(3, 1); + + stream.listen(expectAsync1((actual) { + expect(actual, expected[count++]); + }, count: expected.length)); + }); + + test('Rx.range', () async { + final expected = const [1, 2, 3]; + var count = 0; + + final stream = Rx.range(1, 3); + + stream.listen(expectAsync1((actual) { + expect(actual, expected[count++]); + }, count: expected.length)); + }); +} diff --git a/sandbox/reactivex/test/streams/repeat_test.dart b/sandbox/reactivex/test/streams/repeat_test.dart new file mode 100644 index 0000000..f16196f --- /dev/null +++ b/sandbox/reactivex/test/streams/repeat_test.dart @@ -0,0 +1,99 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.repeat', () async { + const retries = 3; + + await expectLater(Rx.repeat(_getRepeatStream('A'), retries), + emitsInOrder(['A0', 'A1', 'A2', emitsDone])); + }); + + test('RepeatStream', () async { + const retries = 3; + + await expectLater(RepeatStream(_getRepeatStream('A'), retries), + emitsInOrder(['A0', 'A1', 'A2', emitsDone])); + }); + + test('RepeatStream.onDone', () async { + const retries = 0; + + await expectLater(RepeatStream(_getRepeatStream('A'), retries), emitsDone); + }); + + test('RepeatStream.infinite.repeats', () async { + await expectLater( + RepeatStream(_getRepeatStream('A')), emitsThrough('A100')); + }); + + test('RepeatStream.single.subscription', () async { + const retries = 3; + + final stream = RepeatStream(_getRepeatStream('A'), retries); + + try { + stream.listen(null); + stream.listen(null); + } catch (e) { + await expectLater(e, isStateError); + } + }); + + test('RepeatStream.asBroadcastStream', () async { + const retries = 3; + + final stream = + RepeatStream(_getRepeatStream('A'), retries).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('RepeatStream.error.shouldThrow', () async { + final streamWithError = RepeatStream(_getErroneusRepeatStream('A'), 2); + + await expectLater( + streamWithError, + emitsInOrder([ + 'A0', + emitsError(TypeMatcher()), + 'A0', + emitsError(TypeMatcher()), + emitsDone + ])); + }); + + test('RepeatStream.pause.resume', () async { + late StreamSubscription subscription; + const retries = 3; + + subscription = RepeatStream(_getRepeatStream('A'), retries) + .listen(expectAsync1((result) { + expect(result, 'A0'); + + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); +} + +Stream Function(int) _getRepeatStream(String symbol) => + (int repeatIndex) async* { + yield await Future.delayed( + const Duration(milliseconds: 20), () => '$symbol$repeatIndex'); + }; + +Stream Function(int) _getErroneusRepeatStream(String symbol) => + (int repeatIndex) { + return Stream.value('A0') + // Emit the error + .concatWith([Stream.error(Error())]); + }; diff --git a/sandbox/reactivex/test/streams/replay_connectable_stream_test.dart b/sandbox/reactivex/test/streams/replay_connectable_stream_test.dart new file mode 100644 index 0000000..54b1527 --- /dev/null +++ b/sandbox/reactivex/test/streams/replay_connectable_stream_test.dart @@ -0,0 +1,229 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +class MockStream extends Stream { + final Stream stream; + var listenCount = 0; + + MockStream(this.stream); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + ++listenCount; + return stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} + +void main() { + group('ReplayConnectableStream', () { + test('should not emit before connecting', () { + final stream = MockStream(Stream.fromIterable(const [1, 2, 3])); + final connectableStream = ReplayConnectableStream(stream); + + expect(stream.listenCount, 0); + connectableStream.connect(); + expect(stream.listenCount, 1); + }); + + test('should begin emitting items after connection', () { + const items = [1, 2, 3]; + final stream = ReplayConnectableStream(Stream.fromIterable(items)); + + stream.connect(); + + expect(stream, emitsInOrder(items)); + stream.listen(expectAsync1((int i) { + expect(stream.values, items.sublist(0, i)); + }, count: items.length)); + }); + + test('stops emitting after the connection is cancelled', () async { + final ConnectableStream stream = + Stream.fromIterable([1, 2, 3]).publishReplay(); + + stream.connect().cancel(); // ignore: unawaited_futures + + expect(stream, neverEmits(anything)); + }); + + test('stops emitting after the last subscriber unsubscribes', () async { + final Stream stream = + Stream.fromIterable([1, 2, 3]).shareReplay(); + + stream.listen(null).cancel(); // ignore: unawaited_futures + + expect(stream, neverEmits(anything)); + }); + + test('keeps emitting with an active subscription', () async { + final Stream stream = + Stream.fromIterable([1, 2, 3]).shareReplay(); + + stream.listen(null); + stream.listen(null).cancel(); // ignore: unawaited_futures + + expect(stream, emitsInOrder([1, 2, 3])); + }); + + test('multicasts a single-subscription stream', () async { + final Stream stream = ReplayConnectableStream( + Stream.fromIterable([1, 2, 3]), + ).autoConnect(); + + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + }); + + test('replays the max number of items', () async { + final Stream stream = ReplayConnectableStream( + Stream.fromIterable([1, 2, 3]), + maxSize: 2, + ).autoConnect(); + + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + expect(stream, emitsInOrder([1, 2, 3])); + + await Future.delayed(Duration(milliseconds: 200)); + + expect(stream, emitsInOrder([2, 3])); + }); + + test('can multicast streams', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).shareReplay(); + + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + }); + + test('only holds a certain number of values', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).shareReplay(); + + expect(stream.values, const []); + expect(stream, emitsInOrder(const [1, 2, 3])); + }); + + test('provides access to all items', () async { + const items = [1, 2, 3]; + var count = 0; + final stream = Stream.fromIterable(const [1, 2, 3]).shareReplay(); + + stream.listen(expectAsync1((int data) { + expect(data, items[count]); + count++; + if (count == items.length) { + expect(stream.values, items); + } + }, count: items.length)); + }); + + test('provides access to a certain number of items', () async { + const items = [1, 2, 3]; + var count = 0; + final stream = + Stream.fromIterable(const [1, 2, 3]).shareReplay(maxSize: 2); + + stream.listen(expectAsync1((data) { + expect(data, items[count]); + count++; + if (count == items.length) { + expect(stream.values, const [2, 3]); + } + }, count: items.length)); + }); + + test('provide a function to autoconnect that stops listening', () async { + final stream = Stream.fromIterable(const [1, 2, 3]) + .publishReplay() + .autoConnect(connection: (subscription) => subscription.cancel()); + + expect(await stream.isEmpty, true); + }); + + test('refCount cancels source subscription when no listeners remain', + () async { + var isCanceled = false; + + final controller = + StreamController(onCancel: () => isCanceled = true); + final stream = controller.stream.shareReplay(); + + StreamSubscription subscription; + subscription = stream.listen(null); + + await subscription.cancel(); + expect(isCanceled, true); + }); + + test('can close shareReplay() stream', () async { + final isCanceled = Completer(); + + final controller = StreamController(); + controller.stream + .shareReplay() + .doOnCancel(() => isCanceled.complete()) + .listen(null); + + controller.add(true); + await Future.delayed(Duration.zero); + await controller.close(); + + expect(isCanceled.future, completes); + }); + + test( + 'throws StateError when mixing autoConnect, connect and refCount together', + () { + ReplayConnectableStream stream() => + Stream.value(1).publishReplay(maxSize: 1); + + expect( + () => stream() + ..autoConnect() + ..connect(), + throwsStateError, + ); + expect( + () => stream() + ..autoConnect() + ..refCount(), + throwsStateError, + ); + + expect( + () => stream() + ..connect() + ..refCount(), + throwsStateError, + ); + }); + + test('calling autoConnect() multiple times returns the same value', () { + final s = Stream.value(1).publishReplay(maxSize: 1); + expect(s.autoConnect(), same(s.autoConnect())); + expect(s.autoConnect(), same(s.autoConnect())); + }); + + test('calling connect() multiple times returns the same value', () { + final s = Stream.value(1).publishReplay(maxSize: 1); + expect(s.connect(), same(s.connect())); + expect(s.connect(), same(s.connect())); + }); + + test('calling refCount() multiple times returns the same value', () { + final s = Stream.value(1).publishReplay(maxSize: 1); + expect(s.refCount(), same(s.refCount())); + expect(s.refCount(), same(s.refCount())); + }); + }); +} diff --git a/sandbox/reactivex/test/streams/retry_test.dart b/sandbox/reactivex/test/streams/retry_test.dart new file mode 100644 index 0000000..10ee4fd --- /dev/null +++ b/sandbox/reactivex/test/streams/retry_test.dart @@ -0,0 +1,142 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.retry', () async { + const retries = 3; + + await expectLater(Rx.retry(_getRetryStream(retries), retries), + emitsInOrder([1, emitsDone])); + }); + + test('RetryStream', () async { + const retries = 3; + + await expectLater(RetryStream(_getRetryStream(retries), retries), + emitsInOrder([1, emitsDone])); + }); + + test('RetryStream.onDone', () async { + const retries = 3; + + await expectLater(RetryStream(_getRetryStream(retries), retries), + emitsInOrder([1, emitsDone])); + }); + + test('RetryStream.infinite.retries', () async { + await expectLater(RetryStream(_getRetryStream(1000)), + emitsInOrder([1, emitsDone])); + }); + + test('RetryStream.emits.original.items', () async { + const retries = 3; + + await expectLater(RetryStream(_getStreamWithExtras(retries), retries), + emitsInOrder([1, 1, 1, 2, emitsDone])); + }); + + test('RetryStream.single.subscription', () async { + const retries = 3; + + final stream = RetryStream(_getRetryStream(retries), retries); + + try { + stream.listen(null); + stream.listen(null); + } catch (e) { + await expectLater(e, isStateError); + } + }); + + test('RetryStream.asBroadcastStream', () async { + const retries = 3; + + final stream = + RetryStream(_getRetryStream(retries), retries).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('RetryStream.error.shouldThrow', () async { + final streamWithError = RetryStream(_getRetryStream(3), 2); + + await expectLater( + streamWithError, + emitsInOrder( + [ + emitsError(isA()), + emitsError(isA()), + emitsError(isA()), + emitsDone, + ], + ), + ); + }); + + test('RetryStream.error.capturesErrors', () { + RetryStream(_getRetryStream(3), 2).listen( + expectAsync1((_) {}, count: 0), + onError: expectAsync2( + (Object e, StackTrace st) { + expect(e, isA()); + expect(st, isNotNull); + }, + count: 3, + ), + onDone: expectAsync0(() {}, count: 1), + ); + }); + + test('RetryStream.pause.resume', () async { + late StreamSubscription subscription; + const retries = 3; + + subscription = RetryStream(_getRetryStream(retries), retries) + .listen(expectAsync1((result) { + expect(result, 1); + + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); +} + +Stream Function() _getRetryStream(int failCount) { + var count = 0; + + return () { + if (count < failCount) { + count++; + return Stream.error(Error(), StackTrace.fromString('S')); + } else { + return Stream.value(1); + } + }; +} + +Stream Function() _getStreamWithExtras(int failCount) { + var count = 0; + + return () { + if (count < failCount) { + count++; + + // Emit first item + return Stream.value(1) + // Emit the error + .concatWith([Stream.error(Error())]) + // Emit an extra item, testing that it is not included + .concatWith([Stream.value(1)]); + } else { + return Stream.value(2); + } + }; +} diff --git a/sandbox/reactivex/test/streams/retry_when_test.dart b/sandbox/reactivex/test/streams/retry_when_test.dart new file mode 100644 index 0000000..3d139b6 --- /dev/null +++ b/sandbox/reactivex/test/streams/retry_when_test.dart @@ -0,0 +1,224 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.retryWhen', () { + expect( + Rx.retryWhen(_sourceStream(3), _alwaysThrow), + emitsInOrder([0, 1, 2, emitsDone]), + ); + }); + + test('RetryWhenStream', () { + expect( + RetryWhenStream(_sourceStream(3), _alwaysThrow), + emitsInOrder([0, 1, 2, emitsDone]), + ); + }); + + test('RetryWhenStream.onDone', () { + expect( + RetryWhenStream(_sourceStream(3), _alwaysThrow), + emitsInOrder([0, 1, 2, emitsDone]), + ); + }); + + test('RetryWhenStream.infinite.retries', () { + expect( + RetryWhenStream(_sourceStream(1000, 2), _neverThrow).take(6), + emitsInOrder([0, 1, 0, 1, 0, 1, emitsDone]), + ); + }); + + test('RetryWhenStream.emits.original.items', () { + const retries = 3; + + expect( + RetryWhenStream(_getStreamWithExtras(retries), _neverThrow).take(6), + emitsInOrder([1, 1, 1, 2, emitsDone]), + ); + }); + + test('RetryWhenStream.single.subscription', () { + final stream = RetryWhenStream(_sourceStream(3), _neverThrow); + try { + stream.listen(null); + stream.listen(null); + } catch (e) { + expect(e, isStateError); + } + }); + + test('RetryWhenStream.asBroadcastStream', () { + final stream = + RetryWhenStream(_sourceStream(3), _neverThrow).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + expect(stream.isBroadcast, isTrue); + }); + + test('RetryWhenStream.error.shouldThrow', () { + final streamWithError = RetryWhenStream(_sourceStream(3, 0), _alwaysThrow); + + expect( + streamWithError, + emitsInOrder( + [ + emitsError(0), + emitsError(isA()), + emitsDone, + ], + ), + ); + }); + + test('RetryWhenStream.error.capturesErrors', () async { + final streamWithError = RetryWhenStream(_sourceStream(3, 0), _alwaysThrow); + + await expectLater( + streamWithError, + emitsInOrder([ + emitsError(0), + emitsError(isA()), + emitsDone, + ]), + ); + }); + + test('RetryWhenStream.pause.resume', () async { + late StreamSubscription subscription; + + subscription = RetryWhenStream(_sourceStream(3), _neverThrow) + .listen(expectAsync1((result) { + expect(result, 0); + + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('RetryWhenStream.cancel.ensureSubStreamCancels', () async { + var isCancelled = false, didStopEmitting = true; + Stream subStream(Object e, StackTrace s) => + Stream.periodic(const Duration(milliseconds: 100), (count) => count) + .doOnData((_) { + if (isCancelled) { + didStopEmitting = false; + } + }); + final subscription = + RetryWhenStream(_sourceStream(3, 0), subStream).listen(null); + + await Future.delayed(const Duration(milliseconds: 250)); + + await subscription.cancel(); + isCancelled = true; + + await Future.delayed(const Duration(milliseconds: 250)); + + expect(didStopEmitting, isTrue); + }); + + test('RetryWhenStream.retryStream.throws.originError', () { + final error = 1; + final stream = Rx.retryWhen( + _sourceStream(3, error), + (error, stackTrace) => Stream.error(error), + ); + expect( + stream, + emitsInOrder([ + 0, + emitsError(error), + emitsDone, + ]), + ); + }); + + test('RetryWhenStream.streamFactory.throws.originError', () { + final error = 1; + final stream = Rx.retryWhen( + _sourceStream(3, error), + (error, stackTrace) => throw error, + ); + expect( + stream, + emitsInOrder([ + 0, + emitsError(error), + emitsDone, + ]), + ); + }); +} + +Stream Function() _sourceStream(int i, [int? throwAt]) { + return throwAt == null + ? () => Stream.fromIterable(range(i)) + : () => + Stream.fromIterable(range(i)).map((i) => i == throwAt ? throw i : i); +} + +Stream _alwaysThrow(dynamic e, StackTrace s) => + Stream.error(Error(), StackTrace.fromString('S')); + +Stream _neverThrow(dynamic e, StackTrace s) => Stream.value(null); + +Stream Function() _getStreamWithExtras(int failCount) { + var count = 0; + + return () { + if (count < failCount) { + count++; + + // Emit first item + return Stream.value(1) + // Emit the error + .concatWith([Stream.error(Error())]) + // Emit an extra item, testing that it is not included + .concatWith([Stream.value(1)]); + } else { + return Stream.value(2); + } + }; +} + +/// Returns an [Iterable] sequence of [int]s. +/// +/// If only one argument is provided, [startOrStop] is the upper bound for +/// the sequence. If two or more arguments are provided, [stop] is the upper +/// bound. +/// +/// The sequence starts at 0 if one argument is provided, or [startOrStop] if +/// two or more arguments are provided. The sequence increments by 1, or [step] +/// if provided. [step] can be negative, in which case the sequence counts down +/// from the starting point and [stop] must be less than the starting point so +/// that it becomes the lower bound. +Iterable range(int startOrStop, [int? stop, int? step]) sync* { + final start = stop == null ? 0 : startOrStop; + stop ??= startOrStop; + step ??= 1; + + if (step == 0) throw ArgumentError('step cannot be 0'); + if (step > 0 && stop < start) { + throw ArgumentError('if step is positive,' + ' stop must be greater than start'); + } + if (step < 0 && stop > start) { + throw ArgumentError('if step is negative,' + ' stop must be less than start'); + } + + for (var value = start; + step < 0 ? value > stop : value < stop; + value += step) { + yield value; + } +} diff --git a/sandbox/reactivex/test/streams/sequence_equals_test.dart b/sandbox/reactivex/test/streams/sequence_equals_test.dart new file mode 100644 index 0000000..4cbc1d7 --- /dev/null +++ b/sandbox/reactivex/test/streams/sequence_equals_test.dart @@ -0,0 +1,112 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.sequenceEqual.equals', () async { + final stream = Rx.sequenceEqual(Stream.fromIterable(const [1, 2, 3, 4, 5]), + Stream.fromIterable(const [1, 2, 3, 4, 5])); + + await expectLater(stream, emitsInOrder([true, emitsDone])); + }); + + test('Rx.sequenceEqual.diffTime.equals', () async { + final stream = Rx.sequenceEqual( + Stream.periodic(const Duration(milliseconds: 100), (i) => i + 1) + .take(5), + Stream.fromIterable(const [1, 2, 3, 4, 5])); + + await expectLater(stream, emitsInOrder([true, emitsDone])); + }); + + test('Rx.sequenceEqual.equals.customCompare.equals', () async { + final stream = Rx.sequenceEqual(Stream.fromIterable(const [1, 1, 1, 1, 1]), + Stream.fromIterable(const [2, 2, 2, 2, 2]), + equals: (int? a, int? b) => true); + + await expectLater(stream, emitsInOrder([true, emitsDone])); + }); + + test('Rx.sequenceEqual.diffTime.notEquals', () async { + final stream = Rx.sequenceEqual( + Stream.periodic(const Duration(milliseconds: 100), (i) => i + 1) + .take(5), + Stream.fromIterable(const [1, 1, 1, 1, 1])); + + await expectLater(stream, emitsInOrder([false, emitsDone])); + }); + + test('Rx.sequenceEqual.notEquals', () async { + final stream = Rx.sequenceEqual(Stream.fromIterable(const [1, 2, 3, 4, 5]), + Stream.fromIterable(const [1, 2, 3, 5, 4])); + + await expectLater(stream, emitsInOrder([false, emitsDone])); + }); + + test('Rx.sequenceEqual.equals.customCompare.notEquals', () async { + final stream = Rx.sequenceEqual(Stream.fromIterable(const [1, 1, 1, 1, 1]), + Stream.fromIterable(const [1, 1, 1, 1, 1]), + equals: (int? a, int? b) => false); + + await expectLater(stream, emitsInOrder([false, emitsDone])); + }); + + test('Rx.sequenceEqual.notEquals.differentLength', () async { + final stream = Rx.sequenceEqual(Stream.fromIterable(const [1, 2, 3, 4, 5]), + Stream.fromIterable(const [1, 2, 3, 4, 5, 6])); + + await expectLater(stream, emitsInOrder([false, emitsDone])); + }); + + test('Rx.sequenceEqual.notEquals.differentLength.customCompare.notEquals', + () async { + final stream = Rx.sequenceEqual(Stream.fromIterable(const [1, 2, 3, 4, 5]), + Stream.fromIterable(const [1, 2, 3, 4, 5, 6]), + equals: (int? a, int? b) => true); + + // expect false, + // even if the equals handler always returns true, + // the emitted events length is different + await expectLater(stream, emitsInOrder([false, emitsDone])); + }); + + test('Rx.sequenceEqual.equals.errors', () async { + final stream = Rx.sequenceEqual( + Stream.error(ArgumentError('error A')), + Stream.error(ArgumentError('error A')), + errorEquals: (e1, e2) => e1.error.toString() == e2.error.toString(), + ); + + await expectLater(stream, emitsInOrder([true, emitsDone])); + }); + + test('Rx.sequenceEqual.notEquals.errors', () async { + final stream = Rx.sequenceEqual( + Stream.error(ArgumentError('error A')), + Stream.error(ArgumentError('error B')), + errorEquals: (e1, e2) => e1.error.toString() == e2.error.toString(), + ); + + await expectLater(stream, emitsInOrder([false, emitsDone])); + }); + + test('Rx.sequenceEqual.single.subscription', () async { + final stream = Rx.sequenceEqual(Stream.fromIterable(const [1, 2, 3, 4, 5]), + Stream.fromIterable(const [1, 2, 3, 4, 5])); + + await expectLater(stream, emitsInOrder([true, emitsDone])); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('Rx.sequenceEqual.asBroadcastStream', () async { + final future = Rx.sequenceEqual(Stream.fromIterable(const [1, 2, 3, 4, 5]), + Stream.fromIterable(const [1, 2, 3, 4, 5])) + .asBroadcastStream() + .drain(); + + // listen twice on same stream + await expectLater(future, completes); + await expectLater(future, completes); + }); +} diff --git a/sandbox/reactivex/test/streams/switch_latest_test.dart b/sandbox/reactivex/test/streams/switch_latest_test.dart new file mode 100644 index 0000000..ea3f055 --- /dev/null +++ b/sandbox/reactivex/test/streams/switch_latest_test.dart @@ -0,0 +1,88 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + group('SwitchLatest', () { + test('emits all values from an emitted Stream', () { + expect( + Rx.switchLatest( + Stream.value( + Stream.fromIterable(const ['A', 'B', 'C']), + ), + ), + emitsInOrder(['A', 'B', 'C', emitsDone]), + ); + }); + + test('only emits values from the latest emitted stream', () { + expect( + Rx.switchLatest(testStream), + emits('C'), + ); + }); + + test('emits errors from the higher order Stream to the listener', () { + expect( + Rx.switchLatest( + Stream>.error(Exception()), + ), + emitsError(isException), + ); + }); + + test('emits errors from the emitted Stream to the listener', () { + expect( + Rx.switchLatest(errorStream), + emitsError(isException), + ); + }); + + test('closes after the last event from the last emitted Stream', () { + expect( + Rx.switchLatest(testStream), + emitsThrough(emitsDone), + ); + }); + + test('closes if the higher order stream is empty', () { + expect( + Rx.switchLatest( + Stream>.empty(), + ), + emitsThrough(emitsDone), + ); + }); + + test('is single subscription', () { + final stream = SwitchLatestStream(testStream); + + expect(stream, emits('C')); + expect(() => stream.listen(null), throwsStateError); + }); + + test('can be paused and resumed', () { + // ignore: cancel_subscriptions + final subscription = + Rx.switchLatest(testStream).listen(expectAsync1((result) { + expect(result, 'C'); + })); + + subscription.pause(); + subscription.resume(); + }); + }); +} + +Stream> get testStream => Stream.fromIterable([ + Rx.timer('A', Duration(seconds: 2)), + Rx.timer('B', Duration(seconds: 1)), + Stream.value('C'), + ]); + +Stream> get errorStream => Stream.fromIterable([ + Rx.timer('A', Duration(seconds: 2)), + Rx.timer('B', Duration(seconds: 1)), + Stream.error(Exception()), + ]); diff --git a/sandbox/reactivex/test/streams/timer_test.dart b/sandbox/reactivex/test/streams/timer_test.dart new file mode 100644 index 0000000..4f5f62e --- /dev/null +++ b/sandbox/reactivex/test/streams/timer_test.dart @@ -0,0 +1,140 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('TimerStream', () async { + const value = 1; + + final stream = TimerStream(value, Duration(milliseconds: 1)); + + await expectLater(stream, emitsInOrder([value, emitsDone])); + }); + + test('TimerStream.single.subscription', () async { + final stream = TimerStream(1, Duration(milliseconds: 1)); + + stream.listen(null); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('TimerStream.pause.resume.A', () async { + const value = 1; + late StreamSubscription subscription; + + final stream = TimerStream(value, Duration(milliseconds: 1)); + + subscription = stream.listen(expectAsync1((actual) { + expect(actual, value); + + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('TimerStream.pause.resume.B', () async { + const seconds = 2; + const delay = 1; + + var stream = Rx.timer(99, const Duration(seconds: seconds)); + var stopwatch = Stopwatch()..start(); + var subscription = stream.listen(expectAsync1((_) { + stopwatch.stop(); + expect(stopwatch.elapsed.inSeconds, seconds + delay); + })); + + await Future.delayed(const Duration(milliseconds: 100)); + subscription.pause(); + subscription.pause(); + + await Future.delayed(const Duration(seconds: delay)); + + subscription.resume(); + subscription.resume(); + subscription.resume(); + }); + + test('TimerStream.pause.resume.C', () async { + const value = 1; + const delta = Duration(milliseconds: 100); + const duration = Duration(seconds: 1); + final stream = TimerStream(value, duration); + + var elapses = Duration.zero; + late Stopwatch watch; + + void startWatch() => watch = Stopwatch()..start(); + + Future delay() => + Future.delayed(const Duration(milliseconds: 200)); + + void stopWatch() => elapses = elapses + watch.elapsed; + + final subscription = stream.listen(expectAsync1((actual) { + expect(actual, value); + + stopWatch(); + expect( + duration - delta <= elapses && elapses <= duration + delta, + isTrue, + ); + })); + startWatch(); + + await delay(); + + subscription.pause(); + stopWatch(); + + await delay(); + + subscription.resume(); + startWatch(); + }); + + test('TimerStream.single.subscription', () async { + final stream = TimerStream(null, Duration(milliseconds: 1)); + + try { + stream.listen(null); + stream.listen(null); + } catch (e) { + await expectLater(e, isStateError); + } + }); + + test('TimerStream.cancel', () async { + const value = 1; + StreamSubscription subscription; + + final stream = TimerStream(value, Duration(milliseconds: 1)); + + subscription = stream.listen( + expectAsync1((_) { + expect(true, isFalse); + }, count: 0), + onError: expectAsync2((Exception e, StackTrace s) { + expect(true, isFalse); + }, count: 0), + onDone: expectAsync0(() { + expect(true, isFalse); + }, count: 0)); + + await subscription.cancel(); + }); + + test('Rx.timer', () async { + const value = 1; + + final stream = Rx.timer(value, Duration(milliseconds: 5)); + + stream.listen(expectAsync1((actual) { + expect(actual, value); + }), onDone: expectAsync0(() { + expect(true, isTrue); + })); + }); +} diff --git a/sandbox/reactivex/test/streams/using_test.dart b/sandbox/reactivex/test/streams/using_test.dart new file mode 100644 index 0000000..fcce284 --- /dev/null +++ b/sandbox/reactivex/test/streams/using_test.dart @@ -0,0 +1,378 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +const resourceDuration = Duration(milliseconds: 5); + +class MockResource { + var _closed = false; + + bool get isClosed => _closed; + + MockResource(); + + Future close() { + if (_closed) { + throw StateError('Resource has already been closed.'); + } + _closed = true; + return Future.delayed(resourceDuration); + } + + void closeSync() { + if (_closed) { + throw StateError('Resource has already been closed.'); + } + _closed = true; + } +} + +enum Close { + sync, + async, +} + +enum Create { + sync, + async, +} + +void main() async { + for (final close in Close.values) { + for (final create in Create.values) { + final groupPrefix = + 'Rx.using.${create.toString().toLowerCase()}.${close.toString().toLowerCase()}'; + + group(groupPrefix, () { + late MockResource resource; + var isResourceCreated = false; + + late FutureOr Function() resourceFactory; + late FutureOr Function() resourceFactoryThrows; + + late FutureOr Function(MockResource) disposer; + late FutureOr Function(MockResource) disposerThrows; + + setUp(() { + isResourceCreated = false; + + resourceFactory = () { + switch (create) { + case Create.sync: + isResourceCreated = true; + return resource = MockResource(); + case Create.async: + return Future.delayed( + resourceDuration, + () { + isResourceCreated = true; + return resource = MockResource(); + }, + ); + } + }; + + resourceFactoryThrows = () { + switch (create) { + case Create.sync: + throw Exception(); + case Create.async: + return Future.delayed( + resourceDuration, + () => throw Exception(), + ); + } + }; + + disposer = (resource) { + switch (close) { + case Close.async: + return resource.close(); + case Close.sync: + // ignore: unnecessary_cast + return resource.closeSync() as FutureOr; + } + }; + + disposerThrows = (resource) { + switch (close) { + case Close.async: + return Future.delayed( + resourceDuration, + () => throw Exception(), + ); + case Close.sync: + throw Exception(); + } + }; + }); + + test('$groupPrefix.done', () async { + final stream = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Stream.value(resource) + .flatMap((_) => Stream.fromIterable([1, 2, 3])), + disposer: disposer, + ); + + await expectLater( + stream, + emitsInOrder([ + 1, + 2, + 3, + emitsDone, + ]), + ); + + expect(isResourceCreated, true); + expect(resource.isClosed, true); + }); + + test('$groupPrefix.resourceFactory.throws', () async { + var calledStreamFactory = false; + var callDisposer = false; + + final stream = Rx.using( + resourceFactory: resourceFactoryThrows, + streamFactory: (resource) { + calledStreamFactory = true; + return Rx.range(0, 3); + }, + disposer: (resource) { + callDisposer = true; + return disposer(resource); + }, + ); + + await expectLater( + stream, + emitsInOrder([emitsError(isException), emitsDone]), + ); + + expect(isResourceCreated, false); + expect(calledStreamFactory, false); + expect(callDisposer, false); + }); + + test('$groupPrefix.disposer.throws', () async { + final subscription = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Rx.timer(0, resourceDuration), + disposer: disposerThrows, + ).listen(null); + + if (create == Create.async) { + await Future.delayed(resourceDuration * 1.2); + } + + await expectLater( + subscription.cancel(), + throwsException, + ); + }); + + test('$groupPrefix.streamFactory.throws', () async { + final stream = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => throw Exception(), + disposer: disposer, + ); + + await expectLater( + stream, + emitsInOrder([emitsError(isException), emitsDone]), + ); + + expect(isResourceCreated, true); + expect(resource.isClosed, true); + }); + + test('$groupPrefix.streamFactory.errors', () async { + final stream = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Stream.error(Exception()), + disposer: disposer, + ); + + await expectLater( + stream, + emitsInOrder([emitsError(isException), emitsDone]), + ); + + expect(isResourceCreated, true); + expect(resource.isClosed, true); + }); + + test('$groupPrefix.cancel.delayed', () async { + const duration = Duration(milliseconds: 200); + + final subscription = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Rx.concat([ + Rx.timer(0, duration), + Stream.error(Exception()), + ]), + disposer: disposer, + ).listen( + null, + cancelOnError: false, + ); + + // ensure the stream has started + await Future.delayed(resourceDuration + duration ~/ 2); + await subscription.cancel(); + await Future.delayed(resourceDuration * 1.2); + + expect(isResourceCreated, true); + expect(resource.isClosed, true); + }); + + test('$groupPrefix.cancel.immediately', () async { + final subscription = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Rx.concat([ + Rx.timer(0, const Duration(milliseconds: 10)), + Stream.error(Exception()), + ]), + disposer: disposer, + ).listen( + expectAsync1((v) => expect(true, false), count: 0), + onError: expectAsync2( + (Object e, StackTrace stackTrace) => expect(true, false), + count: 0, + ), + onDone: expectAsync0(() => expect(true, false), count: 0), + ); + + await subscription.cancel(); + await Future.delayed(resourceDuration * 2); + + expect(isResourceCreated, true); + expect(resource.isClosed, true); + }); + + test('$groupPrefix.errors.continueOnError', () async { + Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Rx.concat([ + Rx.timer(0, resourceDuration * 2), + Stream.error(Exception()) + ]), + disposer: disposer, + ).listen( + null, + onError: (Object e, StackTrace s) {}, + cancelOnError: false, + ); + + await Future.delayed(resourceDuration * 1.2); + expect(isResourceCreated, true); + expect(resource.isClosed, false); + }); + + test('$groupPrefix.errors.cancelOnError', () async { + Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Stream.error(Exception()), + disposer: disposer, + ).listen( + null, + onError: (Object e, StackTrace s) {}, + cancelOnError: true, + ); + + await Future.delayed(resourceDuration * 1.2); + expect(isResourceCreated, true); + expect(resource.isClosed, true); + }); + + test('$groupPrefix.single.subscription', () async { + final stream = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Rx.range(0, 3), + disposer: disposer, + ); + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + }); + + test('$groupPrefix.asBroadcastStream', () async { + final stream = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Stream.periodic( + const Duration(milliseconds: 50), + (i) => i, + ), + disposer: disposer, + ).asBroadcastStream(onCancel: (s) => s.cancel()); + + final s1 = stream.listen(null); + final s2 = stream.listen(null); + + // can reach here + expect(true, true); + + await Future.delayed(resourceDuration * 1.2); + await s1.cancel(); + await s2.cancel(); + expect(resource.isClosed, true); + }); + + test('$groupPrefix.pause.resume', () async { + late StreamSubscription subscription; + + subscription = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) => Stream.periodic( + const Duration(milliseconds: 20), + (i) => i, + ), + disposer: disposer, + ).listen( + expectAsync1( + (value) { + subscription.cancel(); + expect(value, 0); + }, + count: 1, + ), + ); + + subscription + .pause(Future.delayed(const Duration(milliseconds: 50))); + }); + + test('$groupPrefix.disposer.order', () async { + final stream = Rx.using( + resourceFactory: resourceFactory, + streamFactory: (resource) { + final controller = StreamController(); + + controller.onListen = () { + controller.add(1); + controller.add(2); + controller.close(); + }; + + controller.onCancel = () async { + expect(resource.isClosed, false); + await Future.delayed(resourceDuration * 10); + expect(resource.isClosed, false); + }; + + return controller.stream; + }, + disposer: disposer, + ).take(1); + + await expectLater( + stream, + emitsInOrder([1, emitsDone]), + ); + }); + }); + } + } +} diff --git a/sandbox/reactivex/test/streams/value_connectable_stream_test.dart b/sandbox/reactivex/test/streams/value_connectable_stream_test.dart new file mode 100644 index 0000000..e27def1 --- /dev/null +++ b/sandbox/reactivex/test/streams/value_connectable_stream_test.dart @@ -0,0 +1,295 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +class MockStream extends Stream { + final Stream stream; + var listenCount = 0; + + MockStream(this.stream); + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + ++listenCount; + return stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); + } +} + +void main() { + group('BehaviorConnectableStream', () { + test('should not emit before connecting', () { + final stream = MockStream(Stream.fromIterable(const [1, 2, 3])); + final connectableStream = ValueConnectableStream(stream); + + expect(stream.listenCount, 0); + connectableStream.connect(); + expect(stream.listenCount, 1); + }); + + test('should begin emitting items after connection', () { + var count = 0; + const items = [1, 2, 3]; + final stream = ValueConnectableStream(Stream.fromIterable(items)); + + stream.connect(); + + expect(stream, emitsInOrder(items)); + stream.listen(expectAsync1((i) { + expect(stream.value, items[count]); + count++; + }, count: items.length)); + }); + + test('stops emitting after the connection is cancelled', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).publishValue(); + + stream.connect().cancel(); // ignore: unawaited_futures + + expect(stream, neverEmits(anything)); + }); + + test('stops emitting after the last subscriber unsubscribes', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + + stream.listen(null).cancel(); // ignore: unawaited_futures + + expect(stream, neverEmits(anything)); + }); + + test('keeps emitting with an active subscription', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + + stream.listen(null); + stream.listen(null).cancel(); // ignore: unawaited_futures + + expect(stream, emitsInOrder(const [1, 2, 3])); + }); + + test('multicasts a single-subscription stream', () async { + final stream = ValueConnectableStream( + Stream.fromIterable(const [1, 2, 3]), + ).autoConnect(); + + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + }); + + test('replays the latest item', () async { + final stream = ValueConnectableStream( + Stream.fromIterable(const [1, 2, 3]), + ).autoConnect(); + + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + + await Future.delayed(Duration(milliseconds: 200)); + + expect(stream, emits(3)); + }); + + test('replays the seeded item', () async { + final stream = + ValueConnectableStream.seeded(StreamController().stream, 3) + .autoConnect(); + + expect(stream, emitsInOrder(const [3])); + expect(stream, emitsInOrder(const [3])); + expect(stream, emitsInOrder(const [3])); + + await Future.delayed(Duration(milliseconds: 200)); + + expect(stream, emits(3)); + }); + + test('replays the seeded null item', () async { + final stream = + ValueConnectableStream.seeded(StreamController().stream, null) + .autoConnect(); + + expect(stream, emitsInOrder(const [null])); + expect(stream, emitsInOrder(const [null])); + expect(stream, emitsInOrder(const [null])); + + await Future.delayed(Duration(milliseconds: 200)); + + expect(stream, emits(null)); + }); + + test('can multicast streams', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + expect(stream, emitsInOrder(const [1, 2, 3])); + }); + + test('transform Stream with initial value', () async { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValueSeeded(0); + + expect(stream.value, 0); + expect(stream, emitsInOrder(const [0, 1, 2, 3])); + }); + + test('provides access to the latest value', () async { + const items = [1, 2, 3]; + var count = 0; + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + + stream.listen(expectAsync1((data) { + expect(data, items[count]); + count++; + if (count == items.length) { + expect(stream.value, 3); + } + }, count: items.length)); + }); + + test('provides access to the latest error', () async { + final source = StreamController(); + final stream = ValueConnectableStream(source.stream).autoConnect(); + + source.sink.add(1); + source.sink.add(2); + source.sink.add(3); + source.sink.addError(Exception('error')); + + stream.listen( + null, + onError: expectAsync1((Object error) { + expect(stream.valueOrNull, 3); + expect(stream.value, 3); + expect(stream.hasValue, isTrue); + + expect(stream.errorOrNull, error); + expect(stream.error, error); + expect(stream.hasError, isTrue); + }), + ); + }); + + test('provide a function to autoconnect that stops listening', () async { + final stream = Stream.fromIterable(const [1, 2, 3]) + .publishValue() + .autoConnect(connection: (subscription) => subscription.cancel()); + + expect(await stream.isEmpty, true); + }); + + test('refCount cancels source subscription when no listeners remain', + () async { + { + var isCanceled = false; + + final controller = + StreamController(onCancel: () => isCanceled = true); + final stream = controller.stream.shareValue(); + + StreamSubscription subscription; + subscription = stream.listen(null); + + await subscription.cancel(); + expect(isCanceled, true); + } + + { + var isCanceled = false; + + final controller = + StreamController(onCancel: () => isCanceled = true); + final stream = controller.stream.shareValueSeeded(null); + + StreamSubscription subscription; + subscription = stream.listen(null); + + await subscription.cancel(); + expect(isCanceled, true); + } + }); + + test('can close shareValue() stream', () async { + { + final isCanceled = Completer(); + + final controller = StreamController(); + controller.stream + .shareValue() + .doOnCancel(() => isCanceled.complete()) + .listen(null); + + controller.add(true); + await Future.delayed(Duration.zero); + await controller.close(); + + await expectLater(isCanceled.future, completes); + } + + { + final isCanceled = Completer(); + + final controller = StreamController(); + controller.stream + .shareValueSeeded(false) + .doOnCancel(() => isCanceled.complete()) + .listen(null); + + controller.add(true); + await Future.delayed(Duration.zero); + await controller.close(); + + await expectLater(isCanceled.future, completes); + } + }); + + test( + 'throws StateError when mixing autoConnect, connect and refCount together', + () { + ValueConnectableStream stream() => Stream.value(1).publishValue(); + + expect( + () => stream() + ..autoConnect() + ..connect(), + throwsStateError, + ); + expect( + () => stream() + ..autoConnect() + ..refCount(), + throwsStateError, + ); + expect( + () => stream() + ..connect() + ..refCount(), + throwsStateError, + ); + }); + + test('calling autoConnect() multiple times returns the same value', () { + final s = Stream.value(1).publishValueSeeded(1); + expect(s.autoConnect(), same(s.autoConnect())); + expect(s.autoConnect(), same(s.autoConnect())); + }); + + test('calling connect() multiple times returns the same value', () { + final s = Stream.value(1).publishValueSeeded(1); + expect(s.connect(), same(s.connect())); + expect(s.connect(), same(s.connect())); + }); + + test('calling refCount() multiple times returns the same value', () { + final s = Stream.value(1).publishValueSeeded(1); + expect(s.refCount(), same(s.refCount())); + expect(s.refCount(), same(s.refCount())); + }); + }); +} diff --git a/sandbox/reactivex/test/streams/zip_test.dart b/sandbox/reactivex/test/streams/zip_test.dart new file mode 100644 index 0000000..feb7949 --- /dev/null +++ b/sandbox/reactivex/test/streams/zip_test.dart @@ -0,0 +1,395 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.zip', () async { + expect( + Rx.zip([ + Stream.fromIterable(['A1', 'B1']), + Stream.fromIterable(['A2', 'B2', 'C2']), + ], (values) => values.first + values.last), + emitsInOrder(['A1A2', 'B1B2', emitsDone]), + ); + }); + + test('Rx.zip.empty', () { + expect(Rx.zipList([]), emitsDone); + }); + + test('Rx.zip.single', () { + expect( + Rx.zipList([Stream.value(1)]), + emitsInOrder([ + [1], + emitsDone + ]), + ); + }); + + test('Rx.zip.iterate.once', () async { + var iterationCount = 0; + + final stream = Rx.zipList(() sync* { + ++iterationCount; + yield Stream.value(1); + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + stream, + emitsInOrder([ + [1, 2, 3], + emitsDone, + ]), + ); + expect(iterationCount, 1); + }); + + test('Rx.zipList', () async { + expect( + Rx.zipList([ + Stream.fromIterable(['A1', 'B1']), + Stream.fromIterable(['A2', 'B2', 'C2']), + Stream.fromIterable(['A3', 'B3', 'C3']), + ]), + emitsInOrder([ + ['A1', 'A2', 'A3'], + ['B1', 'B2', 'B3'], + emitsDone + ]), + ); + }); + + test('Rx.zipBasics', () async { + const expectedOutput = [ + [0, 1, true], + [1, 2, false], + [2, 3, true], + [3, 4, false] + ]; + var count = 0; + + final testStream = StreamController() + ..add(true) + ..add(false) + ..add(true) + ..add(false) + ..add(true) + ..close(); // ignore: unawaited_futures + + final stream = Rx.zip3( + Stream.periodic(const Duration(milliseconds: 1), (count) => count) + .take(4), + Stream.fromIterable(const [1, 2, 3, 4, 5, 6, 7, 8, 9]), + testStream.stream, + (int a, int b, bool c) => [a, b, c]); + + stream.listen(expectAsync1((result) { + // test to see if the combined output matches + for (var i = 0, len = result.length; i < len; i++) { + expect(result[i], expectedOutput[count][i]); + } + + count++; + }, count: expectedOutput.length)); + }); + + test('Rx.zipTwo', () async { + const expected = [1, 2]; + + // A purposely emits 2 items, b only 1 + final a = Stream.fromIterable(const [1, 2]), b = Stream.value(2); + + final stream = Rx.zip2(a, b, (int first, int second) => [first, second]); + + // Explicitly adding count: 1. It's important here, and tests the difference + // between zip and combineLatest. If this was combineLatest, the count would + // be two, and a second List would be emitted. + stream.listen(expectAsync1((result) { + expect(result, expected); + }, count: 1)); + }); + + test('Rx.zip3', () async { + // Verify the ability to pass through various types with safety + const expected = [1, '2', 3.0]; + + final a = Stream.value(1), b = Stream.value('2'), c = Stream.value(3.0); + + final stream = Rx.zip3(a, b, c, + (int first, String second, double third) => [first, second, third]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.zip4', () async { + const expected = [1, 2, 3, 4]; + + final a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4); + + final stream = Rx.zip4( + a, + b, + c, + d, + (int first, int second, int third, int fourth) => + [first, second, third, fourth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.zip5', () async { + const expected = [1, 2, 3, 4, 5]; + + final a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5); + + final stream = Rx.zip5( + a, + b, + c, + d, + e, + (int first, int second, int third, int fourth, int fifth) => + [first, second, third, fourth, fifth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.zip6', () async { + const expected = [1, 2, 3, 4, 5, 6]; + + final a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6); + + final stream = Rx.zip6( + a, + b, + c, + d, + e, + f, + (int first, int second, int third, int fourth, int fifth, int sixth) => + [first, second, third, fourth, fifth, sixth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.zip7', () async { + const expected = [1, 2, 3, 4, 5, 6, 7]; + + final a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7); + + final stream = Rx.zip7( + a, + b, + c, + d, + e, + f, + g, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh) => + [first, second, third, fourth, fifth, sixth, seventh]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.zip8', () async { + const expected = [1, 2, 3, 4, 5, 6, 7, 8]; + + final a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7), + h = Stream.value(8); + + final stream = Rx.zip8( + a, + b, + c, + d, + e, + f, + g, + h, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh, int eighth) => + [first, second, third, fourth, fifth, sixth, seventh, eighth]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.zip9', () async { + const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + final a = Stream.value(1), + b = Stream.value(2), + c = Stream.value(3), + d = Stream.value(4), + e = Stream.value(5), + f = Stream.value(6), + g = Stream.value(7), + h = Stream.value(8), + i = Stream.value(9); + + final stream = Rx.zip9( + a, + b, + c, + d, + e, + f, + g, + h, + i, + (int first, int second, int third, int fourth, int fifth, int sixth, + int seventh, int eighth, int ninth) => + [ + first, + second, + third, + fourth, + fifth, + sixth, + seventh, + eighth, + ninth + ]); + + stream.listen(expectAsync1((result) { + expect(result, expected); + })); + }); + + test('Rx.zip.single.subscription', () async { + final stream = + Rx.zip2(Stream.value(1), Stream.value(1), (int a, int b) => a + b); + + stream.listen(null); + await expectLater(() => stream.listen(null), throwsA(isStateError)); + }); + + test('Rx.zip.asBroadcastStream', () async { + final testStream = StreamController() + ..add(true) + ..add(false) + ..add(true) + ..add(false) + ..add(true) + ..close(); // ignore: unawaited_futures + + final stream = Rx.zip3( + Stream.periodic(const Duration(milliseconds: 1), (count) => count) + .take(4), + Stream.fromIterable(const [1, 2, 3, 4, 5, 6, 7, 8, 9]), + testStream.stream, + (int a, int b, bool c) => [a, b, c]).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.zip.error.shouldThrowA', () async { + final streamWithError = Rx.zip2( + Stream.value(1), + Stream.value(2), + (int a, int b) => throw Exception(), + ); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + /*test('Rx.zip.error.shouldThrowB', () { + expect( + () => Rx.zip2( + Stream.value(1), null, (int a, _) => null), + throwsArgumentError); + }); + + test('Rx.zip.error.shouldThrowC', () { + expect(() => ZipStream(null, () {}), throwsArgumentError); + }); + + test('Rx.zip.error.shouldThrowD', () { + expect(() => ZipStream(>[], () {}), + throwsArgumentError); + });*/ + + test('Rx.zip.pause.resume.A', () async { + late StreamSubscription subscription; + final stream = + Rx.zip2(Stream.value(1), Stream.value(2), (int a, int b) => a + b); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 3); + + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.zip.pause.resume.B', () async { + final first = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [1, 2, 3, 4][index]), + second = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [5, 6, 7, 8][index]), + last = Stream.periodic(const Duration(milliseconds: 10), + (index) => const [9, 10, 11, 12][index]); + + late StreamSubscription> subscription; + subscription = + Rx.zip3(first, second, last, (num a, num b, num c) => [a, b, c]) + .listen(expectAsync1((value) { + expect(value.elementAt(0), 1); + expect(value.elementAt(1), 5); + expect(value.elementAt(2), 9); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(Future.delayed(const Duration(milliseconds: 80))); + }); +} diff --git a/sandbox/reactivex/test/subject/behavior_subject_test.dart b/sandbox/reactivex/test/subject/behavior_subject_test.dart new file mode 100644 index 0000000..5f51cb3 --- /dev/null +++ b/sandbox/reactivex/test/subject/behavior_subject_test.dart @@ -0,0 +1,1475 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + final throwsValueStreamError = throwsA(isA()); + + group('BehaviorSubject', () { + test('emits the most recently emitted item to every subscriber', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(3); + + seeded.add(1); + seeded.add(2); + seeded.add(3); + + await expectLater(unseeded.stream, emits(3)); + await expectLater(unseeded.stream, emits(3)); + await expectLater(unseeded.stream, emits(3)); + + await expectLater(seeded.stream, emits(3)); + await expectLater(seeded.stream, emits(3)); + await expectLater(seeded.stream, emits(3)); + }); + + test('emits the most recently emitted null item to every subscriber', + () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(null); + + seeded.add(1); + seeded.add(2); + seeded.add(null); + + await expectLater(unseeded.stream, emits(isNull)); + await expectLater(unseeded.stream, emits(isNull)); + await expectLater(unseeded.stream, emits(isNull)); + + await expectLater(seeded.stream, emits(isNull)); + await expectLater(seeded.stream, emits(isNull)); + await expectLater(seeded.stream, emits(isNull)); + }); + + test( + 'emits the most recently emitted item to every subscriber that subscribe to the subject directly', + () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(3); + + seeded.add(1); + seeded.add(2); + seeded.add(3); + + await expectLater(unseeded, emits(3)); + await expectLater(unseeded, emits(3)); + await expectLater(unseeded, emits(3)); + + await expectLater(seeded, emits(3)); + await expectLater(seeded, emits(3)); + await expectLater(seeded, emits(3)); + }); + + test('emits errors to every subscriber', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(3); + unseeded.addError(Exception('oh noes!')); + + seeded.add(1); + seeded.add(2); + seeded.add(3); + seeded.addError(Exception('oh noes!')); + + await expectLater(unseeded.stream, emitsError(isException)); + await expectLater(unseeded.stream, emitsError(isException)); + await expectLater(unseeded.stream, emitsError(isException)); + + await expectLater(seeded.stream, emitsError(isException)); + await expectLater(seeded.stream, emitsError(isException)); + await expectLater(seeded.stream, emitsError(isException)); + }); + + test('emits event after error to every subscriber', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.addError(Exception('oh noes!')); + unseeded.add(3); + + seeded.add(1); + seeded.add(2); + seeded.addError(Exception('oh noes!')); + seeded.add(3); + + await expectLater(unseeded.stream, emits(3)); + await expectLater(unseeded.stream, emits(3)); + await expectLater(unseeded.stream, emits(3)); + + await expectLater(seeded.stream, emits(3)); + await expectLater(seeded.stream, emits(3)); + await expectLater(seeded.stream, emits(3)); + }); + + test('emits errors to every subscriber', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + final exception = Exception('oh noes!'); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(3); + unseeded.addError(exception); + + seeded.add(1); + seeded.add(2); + seeded.add(3); + seeded.addError(exception); + + expect(unseeded.value, 3); + expect(unseeded.valueOrNull, 3); + expect(unseeded.hasValue, true); + + expect(unseeded.error, exception); + expect(unseeded.errorOrNull, exception); + expect(unseeded.hasError, true); + + await expectLater(unseeded, emitsError(exception)); + await expectLater(unseeded, emitsError(exception)); + await expectLater(unseeded, emitsError(exception)); + + expect(seeded.value, 3); + expect(seeded.valueOrNull, 3); + expect(seeded.hasValue, true); + + expect(seeded.error, exception); + expect(seeded.errorOrNull, exception); + expect(seeded.hasError, true); + + await expectLater(seeded, emitsError(exception)); + await expectLater(seeded, emitsError(exception)); + await expectLater(seeded, emitsError(exception)); + }); + + test('can synchronously get the latest value', () { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(3); + + seeded.add(1); + seeded.add(2); + seeded.add(3); + + expect(unseeded.value, 3); + expect(unseeded.valueOrNull, 3); + expect(unseeded.hasValue, true); + + expect(seeded.value, 3); + expect(seeded.valueOrNull, 3); + expect(seeded.hasValue, true); + }); + + test('can synchronously get the latest null value', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(null); + + seeded.add(1); + seeded.add(2); + seeded.add(null); + + expect(unseeded.value, isNull); + expect(unseeded.valueOrNull, isNull); + expect(unseeded.hasValue, true); + + expect(seeded.value, isNull); + expect(seeded.valueOrNull, isNull); + expect(seeded.hasValue, true); + }); + + test('emits the seed item if no new items have been emitted', () async { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(1); + + await expectLater(subject.stream, emits(1)); + await expectLater(subject.stream, emits(1)); + await expectLater(subject.stream, emits(1)); + }); + + test('emits the null seed item if no new items have been emitted', + () async { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(null); + + await expectLater(subject.stream, emits(isNull)); + await expectLater(subject.stream, emits(isNull)); + await expectLater(subject.stream, emits(isNull)); + }); + + test('can synchronously get the initial value', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(1); + + expect(subject.value, 1); + expect(subject.valueOrNull, 1); + expect(subject.hasValue, true); + }); + + test('can synchronously get the initial null value', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(null); + + expect(subject.value, null); + expect(subject.valueOrNull, null); + expect(subject.hasValue, true); + }); + + test('initial value is null when no value has been emitted', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + expect(() => subject.value, throwsValueStreamError); + expect(subject.valueOrNull, null); + expect(subject.hasValue, false); + }); + + test('emits done event to listeners when the subject is closed', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + await expectLater(unseeded.isClosed, isFalse); + await expectLater(seeded.isClosed, isFalse); + + unseeded.add(1); + scheduleMicrotask(() => unseeded.close()); + + seeded.add(1); + scheduleMicrotask(() => seeded.close()); + + await expectLater(unseeded.stream, emitsInOrder([1, emitsDone])); + await expectLater(unseeded.isClosed, isTrue); + + await expectLater(seeded.stream, emitsInOrder([1, emitsDone])); + await expectLater(seeded.isClosed, isTrue); + }); + + test('emits error events to subscribers', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + scheduleMicrotask(() => unseeded.addError(Exception())); + scheduleMicrotask(() => seeded.addError(Exception())); + + await expectLater(unseeded.stream, emitsError(isException)); + await expectLater(seeded.stream, emitsError(isException)); + }); + + test('replays the previously emitted items from addStream', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + await unseeded.addStream(Stream.fromIterable(const [1, 2, 3])); + await seeded.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(unseeded.stream, emits(3)); + await expectLater(unseeded.stream, emits(3)); + await expectLater(unseeded.stream, emits(3)); + + await expectLater(seeded.stream, emits(3)); + await expectLater(seeded.stream, emits(3)); + await expectLater(seeded.stream, emits(3)); + }); + + test('replays the previously emitted errors from addStream', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + await unseeded.addStream(Stream.error('error'), + cancelOnError: false); + await seeded.addStream(Stream.error('error'), cancelOnError: false); + + await expectLater(unseeded.stream, emitsError('error')); + await expectLater(unseeded.stream, emitsError('error')); + }); + + test('allows items to be added once addStream is complete', () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + await subject.addStream(Stream.fromIterable(const [1, 2])); + subject.add(3); + + await expectLater(subject.stream, emits(3)); + }); + + test('allows items to be added once addStream completes with an error', + () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + unawaited(subject + .addStream(Stream.error(Exception()), cancelOnError: true) + .whenComplete(() => subject.add(1))); + + await expectLater(subject.stream, + emitsInOrder([emitsError(isException), emits(1)])); + }); + + test('does not allow events to be added when addStream is active', + () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.add(1), throwsStateError); + }); + + test('does not allow errors to be added when addStream is active', + () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.addError(Error()), throwsStateError); + }); + + test('does not allow subject to be closed when addStream is active', + () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.close(), throwsStateError); + }); + + test( + 'does not allow addStream to add items when previous addStream is active', + () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.addStream(Stream.fromIterable(const [1])), + throwsStateError); + }); + + test('returns onListen callback set in constructor', () async { + void testOnListen() {} + // ignore: close_sinks + final subject = BehaviorSubject(onListen: testOnListen); + + await expectLater(subject.onListen, testOnListen); + }); + + test('sets onListen callback', () async { + void testOnListen() {} + // ignore: close_sinks + final subject = BehaviorSubject(); + + await expectLater(subject.onListen, isNull); + + subject.onListen = testOnListen; + + await expectLater(subject.onListen, testOnListen); + }); + + test('returns onCancel callback set in constructor', () async { + Future onCancel() => Future.value(null); + // ignore: close_sinks + final subject = BehaviorSubject(onCancel: onCancel); + + await expectLater(subject.onCancel, onCancel); + }); + + test('sets onCancel callback', () async { + void testOnCancel() {} + // ignore: close_sinks + final subject = BehaviorSubject(); + + await expectLater(subject.onCancel, isNull); + + subject.onCancel = testOnCancel; + + await expectLater(subject.onCancel, testOnCancel); + }); + + test('reports if a listener is present', () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + await expectLater(subject.hasListener, isFalse); + + subject.stream.listen(null); + + await expectLater(subject.hasListener, isTrue); + }); + + test('onPause unsupported', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + expect(subject.isPaused, isFalse); + expect(() => subject.onPause, throwsUnsupportedError); + expect(() => subject.onPause = () {}, throwsUnsupportedError); + }); + + test('onResume unsupported', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + expect(() => subject.onResume, throwsUnsupportedError); + expect(() => subject.onResume = () {}, throwsUnsupportedError); + }); + + test('returns controller sink', () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + await expectLater(subject.sink, TypeMatcher>()); + }); + + test('correctly closes done Future', () async { + final subject = BehaviorSubject(); + + scheduleMicrotask(() => subject.close()); + + await expectLater(subject.done, completes); + }); + + test('can be listened to multiple times', () async { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(1); + final stream = subject.stream; + + await expectLater(stream, emits(1)); + await expectLater(stream, emits(1)); + }); + + test('always returns the same stream', () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + await expectLater(subject.stream, equals(subject.stream)); + }); + + test('adding to sink has same behavior as adding to Subject itself', + () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + subject.sink.add(1); + + expect(subject.value, 1); + + subject.sink.add(2); + subject.sink.add(3); + + await expectLater(subject.stream, emits(3)); + await expectLater(subject.stream, emits(3)); + await expectLater(subject.stream, emits(3)); + }); + + test('setter `value=` has same behavior as adding to Subject', () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + + subject.value = 1; + + expect(subject.value, 1); + + subject.value = 2; + subject.value = 3; + + await expectLater(subject.stream, emits(3)); + await expectLater(subject.stream, emits(3)); + await expectLater(subject.stream, emits(3)); + }); + + test('is always treated as a broadcast Stream', () async { + // ignore: close_sinks + final subject = BehaviorSubject(); + final stream = subject.asyncMap((event) => Future.value(event)); + + expect(subject.isBroadcast, isTrue); + expect(stream.isBroadcast, isTrue); + }); + + test('hasValue returns false for an empty subject', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + expect(subject.hasValue, isFalse); + }); + + test('hasValue returns true for a seeded subject with non-null seed', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(1); + + expect(subject.hasValue, isTrue); + }); + + test('hasValue returns true for a seeded subject with null seed', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(null); + + expect(subject.hasValue, isTrue); + }); + + test('hasValue returns true for an unseeded subject after an emission', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + subject.add(1); + + expect(subject.hasValue, isTrue); + }); + + test('hasError returns false for an empty subject', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + expect(subject.hasError, isFalse); + }); + + test('hasError returns false for a seeded subject with non-null seed', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(1); + + expect(subject.hasError, isFalse); + }); + + test('hasError returns false for a seeded subject with null seed', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(null); + + expect(subject.hasError, isFalse); + }); + + test('hasError returns false for an unseeded subject after an emission', + () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + subject.add(1); + + expect(subject.hasError, isFalse); + }); + + test('hasError returns true for an unseeded subject after addError', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + subject.add(1); + subject.addError('error'); + + expect(subject.hasError, isTrue); + }); + + test('hasError returns true for a seeded subject after addError', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(1); + + subject.addError('error'); + + expect(subject.hasError, isTrue); + }); + + test('error returns null for an empty subject', () { + // ignore: close_sinks + final subject = BehaviorSubject(); + + expect(subject.hasError, isFalse); + expect(subject.errorOrNull, isNull); + expect(() => subject.error, throwsValueStreamError); + }); + + test('error returns null for a seeded subject with non-null seed', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(1); + + expect(subject.hasError, isFalse); + expect(subject.errorOrNull, isNull); + expect(() => subject.error, throwsValueStreamError); + }); + + test('error returns null for a seeded subject with null seed', () { + // ignore: close_sinks + final subject = BehaviorSubject.seeded(null); + + expect(subject.hasError, isFalse); + expect(subject.errorOrNull, isNull); + expect(() => subject.error, throwsValueStreamError); + }); + + test('can synchronously get the latest error', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.add(3); + expect(unseeded.hasError, isFalse); + expect(unseeded.errorOrNull, isNull); + expect(() => unseeded.error, throwsValueStreamError); + + unseeded.addError(Exception('oh noes!')); + expect(unseeded.hasError, isTrue); + expect(unseeded.errorOrNull, isException); + expect(unseeded.error, isException); + + seeded.add(1); + seeded.add(2); + seeded.add(3); + expect(seeded.hasError, isFalse); + expect(seeded.errorOrNull, isNull); + expect(() => seeded.error, throwsValueStreamError); + + seeded.addError(Exception('oh noes!')); + expect(seeded.hasError, isTrue); + expect(seeded.errorOrNull, isException); + expect(seeded.error, isException); + }); + + test('emits event after error to every subscriber', () async { + // ignore: close_sinks + final unseeded = BehaviorSubject(), + // ignore: close_sinks + seeded = BehaviorSubject.seeded(0); + + unseeded.add(1); + unseeded.add(2); + unseeded.addError(Exception('oh noes!')); + expect(unseeded.hasError, isTrue); + expect(unseeded.errorOrNull, isException); + expect(unseeded.error, isException); + unseeded.add(3); + expect(unseeded.hasError, isTrue); + expect(unseeded.errorOrNull, isException); + expect(unseeded.error, isException); + + seeded.add(1); + seeded.add(2); + seeded.addError(Exception('oh noes!')); + expect(seeded.hasError, isTrue); + expect(seeded.errorOrNull, isException); + expect(seeded.error, isException); + seeded.add(3); + expect(seeded.hasError, isTrue); + expect(seeded.errorOrNull, isException); + expect(seeded.error, isException); + }); + + test( + 'issue/350: emits duplicate values when listening multiple times and starting with an Error', + () async { + final subject = BehaviorSubject(); + + subject.addError('error'); + + await subject.close(); + + await expectLater(subject, + emitsInOrder([emitsError('error'), emitsDone])); + await expectLater(subject, + emitsInOrder([emitsError('error'), emitsDone])); + await expectLater(subject, + emitsInOrder([emitsError('error'), emitsDone])); + }); + + test('issue/419: sync behavior', () async { + final subject = BehaviorSubject.seeded(1, sync: true); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null); + + expect(mappedStream.value, equals(1)); + + await subject.close(); + }, skip: true); + + test('issue/419: sync throughput', () async { + final subject = BehaviorSubject.seeded(1, sync: true); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null); + + subject.add(2); + + expect(mappedStream.value, equals(2)); + + await subject.close(); + }, skip: true); + + test('issue/419: async behavior', () async { + final subject = BehaviorSubject.seeded(1); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null, + onDone: () => expect(mappedStream.value, equals(1))); + + expect(() => mappedStream.value, throwsValueStreamError); + expect(mappedStream.valueOrNull, isNull); + expect(mappedStream.hasValue, false); + + await subject.close(); + }); + + test('issue/419: async throughput', () async { + final subject = BehaviorSubject.seeded(1); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null, + onDone: () => expect(mappedStream.value, equals(2))); + + subject.add(2); + + expect(() => mappedStream.value, throwsValueStreamError); + expect(mappedStream.valueOrNull, isNull); + expect(mappedStream.hasValue, false); + + await subject.close(); + }); + + test('issue/477: get first after cancelled', () async { + final a = BehaviorSubject.seeded('a'); + final bug = a.switchMap((v) => BehaviorSubject.seeded('b')); + await bug.listen(null).cancel(); + expect(await bug.first, 'b'); + }); + + test('issue/477: get first multiple times', () async { + final a = BehaviorSubject.seeded('a'); + final bug = a.switchMap((_) => BehaviorSubject.seeded('b')); + bug.listen(null); + expect(await bug.first, 'b'); + expect(await bug.first, 'b'); + }); + + test('issue/478: get first multiple times', () async { + final a = BehaviorSubject.seeded('a'); + final b = BehaviorSubject.seeded('b'); + final bug = + Rx.combineLatest2(a, b, (String _a, String _b) => 'ab').shareValue(); + expect(await bug.first, 'ab'); + expect(await bug.first, 'ab'); + }); + + test('angel3_reactivex #477/#500 - a', () async { + final a = BehaviorSubject.seeded('a') + .switchMap((_) => BehaviorSubject.seeded('a')) + ..listen(print); + await pumpEventQueue(); + expect(await a.first, 'a'); + }); + + test('angel3_reactivex #477/#500 - b', () async { + final b = BehaviorSubject.seeded('b') + .map((_) => 'b') + .switchMap((_) => BehaviorSubject.seeded('b')) + ..listen(print); + await pumpEventQueue(); + expect(await b.first, 'b'); + }); + + test('issue/587', () async { + final source = BehaviorSubject.seeded('source'); + final switched = + source.switchMap((value) => BehaviorSubject.seeded('switched')); + var i = 0; + switched.listen((_) => i++); + expect(await switched.first, 'switched'); + expect(i, 1); + expect(await switched.first, 'switched'); + expect(i, 1); + }); + + test('do not update latest value after closed', () { + final seeded = BehaviorSubject.seeded(0); + final unseeded = BehaviorSubject(); + + seeded.add(1); + unseeded.add(1); + + expect(seeded.value, 1); + expect(unseeded.value, 1); + + seeded.close(); + unseeded.close(); + + expect(() => seeded.add(2), throwsStateError); + expect(() => unseeded.add(2), throwsStateError); + expect(() => seeded.addError(Exception()), throwsStateError); + expect(() => unseeded.addError(Exception()), throwsStateError); + + expect(seeded.value, 1); + expect(unseeded.value, 1); + }); + + group('override built-in', () { + test('where', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.where((event) => event.isOdd); + expect(stream, emitsInOrder([1, 3])); + + behaviorSubject.add(2); + behaviorSubject.add(3); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.where((event) => event.isOdd); + expect(stream, emitsInOrder([1, 3])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(3); + } + }); + + test('map', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var mapped = behaviorSubject.map((event) => event + 1); + expect(mapped, emitsInOrder([2, 3])); + + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var mapped = behaviorSubject.map((event) => event + 1); + expect(mapped, emitsInOrder([2, 3])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + } + }); + + test('asyncMap', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var mapped = + behaviorSubject.asyncMap((event) => Future.value(event + 1)); + expect(mapped, emitsInOrder([2, 3])); + + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var mapped = + behaviorSubject.asyncMap((event) => Future.value(event + 1)); + expect(mapped, emitsInOrder([2, 3])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + } + }); + + test('asyncExpand', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = + behaviorSubject.asyncExpand((event) => Stream.value(event + 1)); + expect(stream, emitsInOrder([2, 3])); + + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = + behaviorSubject.asyncExpand((event) => Stream.value(event + 1)); + expect(stream, emitsInOrder([2, 3])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + } + }); + + test('handleError', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.handleError( + expectAsync1( + (dynamic e) => expect(e, isException), + count: 1, + ), + ); + + expect( + stream, + emitsInOrder([1, 2]), + ); + + behaviorSubject.addError(Exception()); + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.handleError( + expectAsync1( + (dynamic e) => expect(e, isException), + count: 1, + ), + ); + + expect( + stream, + emitsInOrder([1, 2]), + ); + + behaviorSubject.add(1); + behaviorSubject.addError(Exception()); + behaviorSubject.add(2); + } + }); + + test('expand', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.expand((event) => [event + 1]); + expect(stream, emitsInOrder([2, 3])); + + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.expand((event) => [event + 1]); + expect(stream, emitsInOrder([2, 3])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + } + }); + + test('transform', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.transform( + IntervalStreamTransformer(const Duration(milliseconds: 100))); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.transform( + IntervalStreamTransformer(const Duration(milliseconds: 100))); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + } + }); + + test('cast', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.cast(); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.cast(); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + } + }); + + test('take', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.take(2); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(2); + behaviorSubject.add(3); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.take(2); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(3); + } + }); + + test('takeWhile', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.takeWhile((element) => element <= 2); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(2); + behaviorSubject.add(3); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.takeWhile((element) => element <= 2); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(3); + } + }); + + test('skip', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.skip(2); + expect(stream, emitsInOrder([3, 4])); + + behaviorSubject.add(2); + behaviorSubject.add(3); + behaviorSubject.add(4); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.skip(2); + expect(stream, emitsInOrder([3, 4])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(3); + behaviorSubject.add(4); + } + }); + + test('skipWhile', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.skipWhile((element) => element < 3); + expect(stream, emitsInOrder([3, 4])); + + behaviorSubject.add(2); + behaviorSubject.add(3); + behaviorSubject.add(4); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.skipWhile((element) => element < 3); + expect(stream, emitsInOrder([3, 4])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(3); + behaviorSubject.add(4); + } + }); + + test('distinct', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject.distinct(); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(2); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject.distinct(); + expect(stream, emitsInOrder([1, 2])); + + behaviorSubject.add(1); + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(2); + } + }); + + test('timeout', () { + { + var behaviorSubject = BehaviorSubject.seeded(1); + + var stream = behaviorSubject + .interval(const Duration(milliseconds: 100)) + .timeout( + const Duration(milliseconds: 70), + onTimeout: expectAsync1( + (EventSink sink) {}, + count: 4, + ), + ); + + expect(stream, emitsInOrder([1, 2, 3, 4])); + + behaviorSubject.add(2); + behaviorSubject.add(3); + behaviorSubject.add(4); + } + + { + var behaviorSubject = BehaviorSubject(); + + var stream = behaviorSubject + .interval(const Duration(milliseconds: 100)) + .timeout( + const Duration(milliseconds: 70), + onTimeout: expectAsync1( + (EventSink sink) {}, + count: 4, + ), + ); + + expect(stream, emitsInOrder([1, 2, 3, 4])); + + behaviorSubject.add(1); + behaviorSubject.add(2); + behaviorSubject.add(3); + behaviorSubject.add(4); + } + }); + }); + + test('stream returns a read-only stream', () async { + final subject = BehaviorSubject()..add(1); + + // streams returned by BehaviorSubject are read-only stream, + // ie. they don't support adding events. + expect(subject.stream, isNot(isA>())); + expect(subject.stream, isNot(isA>())); + + expect( + subject.stream, + isA>().having( + (v) => v.value, + 'BehaviorSubject.stream.value', + 1, + ), + ); + + // BehaviorSubject.stream is a broadcast stream + { + final stream = subject.stream; + expect(stream.isBroadcast, isTrue); + await expectLater(stream, emitsInOrder([1])); + await expectLater(stream, emitsInOrder([1])); + } + + // streams returned by the same subject are considered equal, + // but not identical + expect(identical(subject.stream, subject.stream), isFalse); + expect(subject.stream == subject.stream, isTrue); + }); + + group('lastEventOrNull', () { + test('empty subject', () { + final s = BehaviorSubject(); + expect(s.lastEventOrNull, isNull); + expect(s.isLastEventValue, isFalse); + expect(s.isLastEventError, isFalse); + + // the stream has the same value as the subject + expect(s.stream.lastEventOrNull, isNull); + expect(s.stream.isLastEventValue, isFalse); + expect(s.stream.isLastEventError, isFalse); + }); + + test('subject with value', () { + final s = BehaviorSubject.seeded(42); + expect( + s.lastEventOrNull, + StreamNotification.data(42), + ); + expect(s.isLastEventValue, isTrue); + expect(s.isLastEventError, isFalse); + + // the stream has the same value as the subject + expect( + s.stream.lastEventOrNull, + StreamNotification.data(42), + ); + expect(s.stream.isLastEventValue, isTrue); + expect(s.stream.isLastEventError, isFalse); + }); + + test('subject with error', () { + final s = BehaviorSubject(); + final exception = Exception(); + s.addError(exception, StackTrace.empty); + + expect( + s.lastEventOrNull, + StreamNotification.error(exception, StackTrace.empty), + ); + expect(s.isLastEventValue, isFalse); + expect(s.isLastEventError, isTrue); + + // the stream has the same value as the subject + expect( + s.stream.lastEventOrNull, + StreamNotification.error(exception, StackTrace.empty), + ); + expect(s.stream.isLastEventValue, isFalse); + expect(s.stream.isLastEventError, isTrue); + }); + + test('add error and then value', () { + final s = BehaviorSubject(); + final exception = Exception(); + s.addError(exception, StackTrace.empty); + s.add(42); + + expect( + s.lastEventOrNull, + StreamNotification.data(42), + ); + expect(s.isLastEventValue, isTrue); + expect(s.isLastEventError, isFalse); + + // the stream has the same value as the subject + expect( + s.stream.lastEventOrNull, + StreamNotification.data(42), + ); + expect(s.stream.isLastEventValue, isTrue); + expect(s.stream.isLastEventError, isFalse); + }); + + test('add value and then error', () { + final s = BehaviorSubject(); + s.add(42); + final exception = Exception(); + s.addError(exception, StackTrace.empty); + + expect( + s.lastEventOrNull, + StreamNotification.error(exception, StackTrace.empty), + ); + expect(s.isLastEventValue, isFalse); + expect(s.isLastEventError, isTrue); + + // the stream has the same value as the subject + expect( + s.stream.lastEventOrNull, + StreamNotification.error(exception, StackTrace.empty), + ); + expect(s.stream.isLastEventValue, isFalse); + expect(s.stream.isLastEventError, isTrue); + }); + + test('add value and then close', () async { + final s = BehaviorSubject(); + s.add(42); + await s.close(); + + expect( + s.lastEventOrNull, + StreamNotification.data(42), + ); + expect(s.isLastEventValue, isTrue); + expect(s.isLastEventError, isFalse); + + // the stream has the same value as the subject + expect( + s.stream.lastEventOrNull, + StreamNotification.data(42), + ); + expect(s.stream.isLastEventValue, isTrue); + expect(s.stream.isLastEventError, isFalse); + }); + + test('add error and then close', () async { + final s = BehaviorSubject(); + final exception = Exception(); + s.addError(exception, StackTrace.empty); + await s.close(); + + expect( + s.lastEventOrNull, + StreamNotification.error(exception, StackTrace.empty), + ); + expect(s.isLastEventValue, isFalse); + expect(s.isLastEventError, isTrue); + + // the stream has the same value as the subject + expect( + s.stream.lastEventOrNull, + StreamNotification.error(exception, StackTrace.empty), + ); + expect(s.stream.isLastEventValue, isFalse); + expect(s.stream.isLastEventError, isTrue); + }); + }); + + group('errorAndStackTraceOrNull', () { + test('empty subject', () { + final s = BehaviorSubject(); + expect(s.errorAndStackTraceOrNull, isNull); + + // the stream has the same value as the subject + expect(s.stream.errorAndStackTraceOrNull, isNull); + }); + + test('seeded subject', () { + final s = BehaviorSubject.seeded(42); + expect(s.errorAndStackTraceOrNull, isNull); + + // the stream has the same value as the subject + expect(s.stream.errorAndStackTraceOrNull, isNull); + }); + + test('subject with error and stack trace', () { + final s = BehaviorSubject(); + final exception = Exception(); + s.addError(exception, StackTrace.empty); + + expect( + s.errorAndStackTraceOrNull, + ErrorAndStackTrace(exception, StackTrace.empty), + ); + + // the stream has the same value as the subject + expect( + s.stream.errorAndStackTraceOrNull, + ErrorAndStackTrace(exception, StackTrace.empty), + ); + }); + + test('subject with error', () { + final s = BehaviorSubject(); + final exception = Exception(); + s.addError(exception); + + expect( + s.errorAndStackTraceOrNull, + ErrorAndStackTrace(exception, null), + ); + + // the stream has the same value as the subject + expect( + s.stream.errorAndStackTraceOrNull, + ErrorAndStackTrace(exception, null), + ); + }); + + test('seeded subject and close', () { + final s = BehaviorSubject.seeded(42)..close(); + + expect(s.errorAndStackTraceOrNull, isNull); + + // the stream has the same value as the subject + expect(s.stream.errorAndStackTraceOrNull, isNull); + }); + + test('error and close', () { + final s = BehaviorSubject(); + final exception = Exception(); + s + ..addError(exception) + ..close(); + + expect( + s.errorAndStackTraceOrNull, + ErrorAndStackTrace(exception, null), + ); + + // the stream has the same value as the subject + expect( + s.stream.errorAndStackTraceOrNull, + ErrorAndStackTrace(exception, null), + ); + }); + }); + }); +} diff --git a/sandbox/reactivex/test/subject/publish_subject_test.dart b/sandbox/reactivex/test/subject/publish_subject_test.dart new file mode 100644 index 0000000..1561109 --- /dev/null +++ b/sandbox/reactivex/test/subject/publish_subject_test.dart @@ -0,0 +1,323 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:angel3_reactivex/subjects.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + group('PublishSubject', () { + test('emits items to every subscriber', () async { + // ignore: close_sinks + final subject = PublishSubject(); + + scheduleMicrotask(() { + subject.add(1); + subject.add(2); + subject.add(3); + subject.close(); + }); + + await expectLater( + subject.stream, emitsInOrder([1, 2, 3, emitsDone])); + }); + + test( + 'emits items to every subscriber that subscribe directly to the Subject', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + scheduleMicrotask(() { + subject.add(1); + subject.add(2); + subject.add(3); + subject.close(); + }); + + await expectLater(subject, emitsInOrder([1, 2, 3, emitsDone])); + }); + + test('emits done event to listeners when the subject is closed', () async { + final subject = PublishSubject(); + + await expectLater(subject.isClosed, isFalse); + + scheduleMicrotask(() => subject.add(1)); + scheduleMicrotask(() => subject.close()); + + await expectLater(subject.stream, emitsInOrder([1, emitsDone])); + await expectLater(subject.isClosed, isTrue); + }); + + test( + 'emits done event to listeners when the subject is closed (listen directly on Subject)', + () async { + final subject = PublishSubject(); + + await expectLater(subject.isClosed, isFalse); + + scheduleMicrotask(() => subject.add(1)); + scheduleMicrotask(() => subject.close()); + + await expectLater(subject, emitsInOrder([1, emitsDone])); + await expectLater(subject.isClosed, isTrue); + }); + + test('emits error events to subscribers', () async { + // ignore: close_sinks + final subject = PublishSubject(); + + scheduleMicrotask(() => subject.addError(Exception())); + + await expectLater(subject.stream, emitsError(isException)); + }); + + test('emits error events to subscribers (listen directly on Subject)', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + scheduleMicrotask(() => subject.addError(Exception())); + + await expectLater(subject, emitsError(isException)); + }); + + test('emits the items from addStream', () async { + // ignore: close_sinks + final subject = PublishSubject(); + + scheduleMicrotask( + () => subject.addStream(Stream.fromIterable(const [1, 2, 3]))); + + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + }); + + test('allows items to be added once addStream is complete', () async { + // ignore: close_sinks + final subject = PublishSubject(); + + await subject.addStream(Stream.fromIterable(const [1, 2])); + scheduleMicrotask(() => subject.add(3)); + + await expectLater(subject.stream, emits(3)); + }); + + test('allows items to be added once addStream completes with an error', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + unawaited(subject + .addStream(Stream.error(Exception()), cancelOnError: true) + .whenComplete(() => subject.add(1))); + + await expectLater(subject.stream, + emitsInOrder([emitsError(isException), emits(1)])); + }); + + test('does not allow events to be added when addStream is active', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.add(1), throwsStateError); + }); + + test('does not allow errors to be added when addStream is active', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.addError(Error()), throwsStateError); + }); + + test('does not allow subject to be closed when addStream is active', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.close(), throwsStateError); + }); + + test( + 'does not allow addStream to add items when previous addStream is active', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.addStream(Stream.fromIterable(const [1])), + throwsStateError); + }); + + test('returns onListen callback set in constructor', () async { + void testOnListen() {} + // ignore: close_sinks + final subject = PublishSubject(onListen: testOnListen); + + await expectLater(subject.onListen, testOnListen); + }); + + test('sets onListen callback', () async { + void testOnListen() {} + // ignore: close_sinks + final subject = PublishSubject(); + + await expectLater(subject.onListen, isNull); + + subject.onListen = testOnListen; + + await expectLater(subject.onListen, testOnListen); + }); + + test('returns onCancel callback set in constructor', () async { + Future onCancel() => Future.value(null); + // ignore: close_sinks + final subject = PublishSubject(onCancel: onCancel); + + await expectLater(subject.onCancel, onCancel); + }); + + test('sets onCancel callback', () async { + void testOnCancel() {} + // ignore: close_sinks + final subject = PublishSubject(); + + await expectLater(subject.onCancel, isNull); + + subject.onCancel = testOnCancel; + + await expectLater(subject.onCancel, testOnCancel); + }); + + test('reports if a listener is present', () async { + // ignore: close_sinks + final subject = PublishSubject(); + + await expectLater(subject.hasListener, isFalse); + + subject.stream.listen(null); + + await expectLater(subject.hasListener, isTrue); + }); + + test('onPause unsupported', () { + // ignore: close_sinks + final subject = PublishSubject(); + + expect(subject.isPaused, isFalse); + expect(() => subject.onPause, throwsUnsupportedError); + expect(() => subject.onPause = () {}, throwsUnsupportedError); + }); + + test('onResume unsupported', () { + // ignore: close_sinks + final subject = PublishSubject(); + + expect(() => subject.onResume, throwsUnsupportedError); + expect(() => subject.onResume = () {}, throwsUnsupportedError); + }); + + test('returns controller sink', () async { + // ignore: close_sinks + final subject = PublishSubject(); + + await expectLater(subject.sink, TypeMatcher>()); + }); + + test('correctly closes done Future', () async { + final subject = PublishSubject(); + + scheduleMicrotask(() => subject.close()); + + await expectLater(subject.done, completes); + }); + + test('can be listened to multiple times', () async { + // ignore: close_sinks + final subject = PublishSubject(); + final stream = subject.stream; + + scheduleMicrotask(() => subject.add(1)); + await expectLater(stream, emits(1)); + + scheduleMicrotask(() => subject.add(2)); + await expectLater(stream, emits(2)); + }); + + test('always returns the same stream', () async { + // ignore: close_sinks + final subject = PublishSubject(); + + await expectLater(subject.stream, equals(subject.stream)); + }); + + test('adding to sink has same behavior as adding to Subject itself', + () async { + // ignore: close_sinks + final subject = PublishSubject(); + + scheduleMicrotask(() { + subject.sink.add(1); + subject.sink.add(2); + subject.sink.add(3); + subject.sink.close(); + }); + + await expectLater( + subject.stream, emitsInOrder([1, 2, 3, emitsDone])); + }); + + test('is always treated as a broadcast Stream', () async { + // ignore: close_sinks + final subject = PublishSubject(); + final stream = subject.asyncMap((event) => Future.value(event)); + + expect(subject.isBroadcast, isTrue); + expect(stream.isBroadcast, isTrue); + }); + + test('stream returns a read-only stream', () async { + final subject = PublishSubject(); + + // streams returned by PublishSubject are read-only stream, + // ie. they don't support adding events. + expect(subject.stream, isNot(isA>())); + expect(subject.stream, isNot(isA>())); + + // PublishSubject.stream is a broadcast stream + { + final stream = subject.stream; + expect(stream.isBroadcast, isTrue); + + scheduleMicrotask(() => subject.add(1)); + await expectLater(stream, emitsInOrder([1])); + + scheduleMicrotask(() => subject.add(1)); + await expectLater(stream, emitsInOrder([1])); + } + + // streams returned by the same subject are considered equal, + // but not identical + expect(identical(subject.stream, subject.stream), isFalse); + expect(subject.stream == subject.stream, isTrue); + }); + }); +} diff --git a/sandbox/reactivex/test/subject/replay_subject_test.dart b/sandbox/reactivex/test/subject/replay_subject_test.dart new file mode 100644 index 0000000..1d9e949 --- /dev/null +++ b/sandbox/reactivex/test/subject/replay_subject_test.dart @@ -0,0 +1,478 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +// ignore_for_file: close_sinks + +void main() { + group('ReplaySubject', () { + test('replays the previously emitted items to every subscriber', () async { + final subject = ReplaySubject(); + + subject.add(1); + subject.add(2); + subject.add(3); + + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + }); + + test( + 'replays the previously emitted items to every subscriber, includes null', + () async { + final subject = ReplaySubject(); + + subject.add(null); + subject.add(1); + subject.add(2); + subject.add(3); + subject.add(null); + + await expectLater( + subject.stream, + emitsInOrder(const [null, 1, 2, 3, null]), + ); + await expectLater( + subject.stream, + emitsInOrder(const [null, 1, 2, 3, null]), + ); + await expectLater( + subject.stream, + emitsInOrder(const [null, 1, 2, 3, null]), + ); + }); + + test('replays the previously emitted errors to every subscriber', () async { + final subject = ReplaySubject(); + + subject.addError(Exception()); + subject.addError(Exception()); + subject.addError(Exception()); + + await expectLater( + subject.stream, + emitsInOrder([ + emitsError(isException), + emitsError(isException), + emitsError(isException) + ])); + await expectLater( + subject.stream, + emitsInOrder([ + emitsError(isException), + emitsError(isException), + emitsError(isException) + ])); + await expectLater( + subject.stream, + emitsInOrder([ + emitsError(isException), + emitsError(isException), + emitsError(isException) + ])); + }); + + test( + 'replays the previously emitted items to every subscriber that directly subscribes to the Subject', + () async { + final subject = ReplaySubject(); + + subject.add(1); + subject.add(2); + subject.add(3); + + await expectLater(subject, emitsInOrder(const [1, 2, 3])); + await expectLater(subject, emitsInOrder(const [1, 2, 3])); + await expectLater(subject, emitsInOrder(const [1, 2, 3])); + }); + + test( + 'replays the previously emitted items and errors to every subscriber that directly subscribes to the Subject', + () async { + final subject = ReplaySubject(); + + subject.add(1); + subject.addError(Exception()); + subject.addError(Exception()); + subject.add(2); + + await expectLater( + subject, + emitsInOrder([ + 1, + emitsError(isException), + emitsError(isException), + 2 + ])); + await expectLater( + subject, + emitsInOrder([ + 1, + emitsError(isException), + emitsError(isException), + 2 + ])); + await expectLater( + subject, + emitsInOrder([ + 1, + emitsError(isException), + emitsError(isException), + 2 + ])); + }); + + test('synchronously get the previous items', () async { + final subject = ReplaySubject(); + + subject.add(1); + subject.add(2); + subject.add(3); + + await expectLater(subject.values, const [1, 2, 3]); + }); + + test('synchronously get the previous errors', () { + final subject = ReplaySubject(); + final e1 = Exception(), e2 = Exception(), e3 = Exception(); + final stackTrace = StackTrace.fromString('#'); + + subject.addError(e1); + subject.addError(e2, stackTrace); + subject.addError(e3); + + expect( + subject.errors, + containsAllInOrder([e1, e2, e3]), + ); + expect( + subject.stackTraces, + containsAllInOrder([null, stackTrace, null]), + ); + }); + + test('replays the most recently emitted items up to a max size', () async { + final subject = ReplaySubject(maxSize: 2); + + subject.add(1); // Should be dropped + subject.add(2); + subject.add(3); + + await expectLater(subject.stream, emitsInOrder(const [2, 3])); + await expectLater(subject.stream, emitsInOrder(const [2, 3])); + await expectLater(subject.stream, emitsInOrder(const [2, 3])); + }); + + test('emits done event to listeners when the subject is closed', () async { + final subject = ReplaySubject(); + + await expectLater(subject.isClosed, isFalse); + + subject.add(1); + scheduleMicrotask(() => subject.close()); + + await expectLater(subject.stream, emitsInOrder([1, emitsDone])); + await expectLater(subject.isClosed, isTrue); + }); + + test('emits error events to subscribers', () async { + final subject = ReplaySubject(); + + scheduleMicrotask(() => subject.addError(Exception())); + + await expectLater(subject.stream, emitsError(isException)); + }); + + test('replays the previously emitted items from addStream', () async { + final subject = ReplaySubject(); + + await subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + }); + + test('allows items to be added once addStream is complete', () async { + final subject = ReplaySubject(); + + await subject.addStream(Stream.fromIterable(const [1, 2])); + subject.add(3); + + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + }); + + test('allows items to be added once addStream completes with an error', + () async { + final subject = ReplaySubject(); + + unawaited(subject + .addStream(Stream.error(Exception()), cancelOnError: true) + .whenComplete(() => subject.add(1))); + + await expectLater(subject.stream, + emitsInOrder([emitsError(isException), emits(1)])); + }); + + test('does not allow events to be added when addStream is active', + () async { + final subject = ReplaySubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.add(1), throwsStateError); + }); + + test('does not allow errors to be added when addStream is active', + () async { + final subject = ReplaySubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.addError(Error()), throwsStateError); + }); + + test('does not allow subject to be closed when addStream is active', + () async { + final subject = ReplaySubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.close(), throwsStateError); + }); + + test( + 'does not allow addStream to add items when previous addStream is active', + () async { + final subject = ReplaySubject(); + + // Purposely don't wait for the future to complete, then try to add items + // ignore: unawaited_futures + subject.addStream(Stream.fromIterable(const [1, 2, 3])); + + await expectLater(() => subject.addStream(Stream.fromIterable(const [1])), + throwsStateError); + }); + + test('returns onListen callback set in constructor', () async { + void testOnListen() {} + + final subject = ReplaySubject(onListen: testOnListen); + + await expectLater(subject.onListen, testOnListen); + }); + + test('sets onListen callback', () async { + void testOnListen() {} + + final subject = ReplaySubject(); + + await expectLater(subject.onListen, isNull); + + subject.onListen = testOnListen; + + await expectLater(subject.onListen, testOnListen); + }); + + test('returns onCancel callback set in constructor', () async { + Future onCancel() => Future.value(null); + + final subject = ReplaySubject(onCancel: onCancel); + + await expectLater(subject.onCancel, onCancel); + }); + + test('sets onCancel callback', () async { + void testOnCancel() {} + + final subject = ReplaySubject(); + + await expectLater(subject.onCancel, isNull); + + subject.onCancel = testOnCancel; + + await expectLater(subject.onCancel, testOnCancel); + }); + + test('reports if a listener is present', () async { + final subject = ReplaySubject(); + + await expectLater(subject.hasListener, isFalse); + + subject.stream.listen(null); + + await expectLater(subject.hasListener, isTrue); + }); + + test('onPause unsupported', () { + final subject = ReplaySubject(); + + expect(subject.isPaused, isFalse); + expect(() => subject.onPause, throwsUnsupportedError); + expect(() => subject.onPause = () {}, throwsUnsupportedError); + }); + + test('onResume unsupported', () { + final subject = ReplaySubject(); + + expect(() => subject.onResume, throwsUnsupportedError); + expect(() => subject.onResume = () {}, throwsUnsupportedError); + }); + + test('returns controller sink', () async { + final subject = ReplaySubject(); + + await expectLater(subject.sink, TypeMatcher>()); + }); + + test('correctly closes done Future', () async { + final subject = ReplaySubject(); + + scheduleMicrotask(subject.close); + + await expectLater(subject.done, completes); + }); + + test('can be listened to multiple times', () async { + final subject = ReplaySubject(); + final stream = subject.stream; + + subject.add(1); + subject.add(2); + + await expectLater(stream, emitsInOrder(const [1, 2])); + await expectLater(stream, emitsInOrder(const [1, 2])); + }); + + test('always returns the same stream', () async { + final subject = ReplaySubject(); + + await expectLater(subject.stream, equals(subject.stream)); + }); + + test('adding to sink has same behavior as adding to Subject itself', + () async { + final subject = ReplaySubject(); + + subject.sink.add(1); + subject.sink.add(2); + subject.sink.add(3); + + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + await expectLater(subject.stream, emitsInOrder(const [1, 2, 3])); + }); + + test('is always treated as a broadcast Stream', () async { + final subject = ReplaySubject(); + final stream = subject.asyncMap((event) => Future.value(event)); + + expect(subject.isBroadcast, isTrue); + expect(stream.isBroadcast, isTrue); + }); + + test('issue/419: sync behavior', () async { + final subject = ReplaySubject(sync: true)..add(1); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null); + + expect(mappedStream.value, equals(1)); + + await subject.close(); + }, skip: true); + + test('issue/419: sync throughput', () async { + final subject = ReplaySubject(sync: true)..add(1); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null); + + subject.add(2); + + expect(mappedStream.value, equals(2)); + + await subject.close(); + }, skip: true); + + test('issue/419: async behavior', () async { + final subject = ReplaySubject()..add(1); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null, + onDone: () => expect(mappedStream.value, equals(1))); + + expect(mappedStream.valueOrNull, isNull); + + await subject.close(); + }); + + test('issue/419: async throughput', () async { + final subject = ReplaySubject()..add(1); + final mappedStream = subject.map((event) => event).shareValue(); + + mappedStream.listen(null, + onDone: () => expect(mappedStream.value, equals(2))); + + subject.add(2); + + expect(mappedStream.valueOrNull, isNull); + + await subject.close(); + }); + + test('do not update buffer after closed', () { + final subject = ReplaySubject(); + + subject.add(1); + expect(subject.values, [1]); + + subject.close(); + + expect(() => subject.add(2), throwsStateError); + expect(() => subject.addError(Exception()), throwsStateError); + expect(subject.values, [1]); + }); + + test('stream returns a read-only stream', () async { + final subject = ReplaySubject()..add(1); + + // streams returned by ReplaySubject are read-only stream, + // ie. they don't support adding events. + expect(subject.stream, isNot(isA>())); + expect(subject.stream, isNot(isA>())); + + expect( + subject.stream, + isA>().having( + (v) => v.values, + 'ReplaySubject.stream.values', + [1], + ), + ); + + // ReplaySubject.stream is a broadcast stream + { + final stream = subject.stream; + expect(stream.isBroadcast, isTrue); + await expectLater(stream, emitsInOrder([1])); + await expectLater(stream, emitsInOrder([1])); + } + + // streams returned by the same subject are considered equal, + // but not identical + expect(identical(subject.stream, subject.stream), isFalse); + expect(subject.stream == subject.stream, isTrue); + }); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/buffer_count_test.dart b/sandbox/reactivex/test/transformers/backpressure/buffer_count_test.dart new file mode 100644 index 0000000..5e05ade --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/buffer_count_test.dart @@ -0,0 +1,125 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +void main() { + test('Rx.bufferCount.noStartBufferEvery', () async { + await expectLater( + Rx.range(1, 4).bufferCount(2), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + }); + + test('Rx.bufferCount.noStartBufferEvery.includesEventOnClose', () async { + await expectLater( + Rx.range(1, 5).bufferCount(2), + emitsInOrder([ + const [1, 2], + const [3, 4], + const [5], + emitsDone + ])); + }); + + test('Rx.bufferCount.startBufferEvery.count2startBufferEvery1', () async { + await expectLater( + Rx.range(1, 4).bufferCount(2, 1), + emitsInOrder([ + const [1, 2], + const [2, 3], + const [3, 4], + const [4], + emitsDone + ])); + }); + + test('Rx.bufferCount.startBufferEvery.count3startBufferEvery2', () async { + await expectLater( + Rx.range(1, 8).bufferCount(3, 2), + emitsInOrder([ + const [1, 2, 3], + const [3, 4, 5], + const [5, 6, 7], + const [7, 8], + emitsDone + ])); + }); + + test('Rx.bufferCount.startBufferEvery.count3startBufferEvery4', () async { + await expectLater( + Rx.range(1, 8).bufferCount(3, 4), + emitsInOrder([ + const [1, 2, 3], + const [5, 6, 7], + emitsDone + ])); + }); + + test('Rx.bufferCount.reusable', () async { + final transformer = BufferCountStreamTransformer(2); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]).transform(transformer), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]).transform(transformer), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + }); + + test('Rx.bufferCount.asBroadcastStream', () async { + final stream = Stream.fromIterable(const [1, 2, 3, 4]) + .asBroadcastStream() + .bufferCount(2); + + // listen twice on same stream + await expectLater( + stream, + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + + await expectLater(stream, emitsInOrder([emitsDone])); + }); + + test('Rx.bufferCount.error.shouldThrowA', () async { + await expectLater(Stream.error(Exception()).bufferCount(2), + emitsError(isException)); + }); + + test( + 'Rx.bufferCount.shouldThrow.invalidCount.negative', + () { + expect(() => Stream.fromIterable(const [1, 2, 3, 4]).bufferCount(-1), + throwsArgumentError); + }, + ); + + test('Rx.bufferCount.startBufferEvery.shouldThrow.invalidStartBufferEvery', + () { + expect(() => Stream.fromIterable(const [1, 2, 3, 4]).bufferCount(2, -1), + throwsArgumentError); + }); + + test('Rx.bufferCount.nullable', () { + nullableTest>( + (s) => s.bufferCount(1), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/buffer_test.dart b/sandbox/reactivex/test/transformers/backpressure/buffer_test.dart new file mode 100644 index 0000000..095d657 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/buffer_test.dart @@ -0,0 +1,118 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream getStream(int n) async* { + var k = 0; + + while (k < n) { + await Future.delayed(const Duration(milliseconds: 100)); + + yield k++; + } +} + +void main() { + test('Rx.buffer', () async { + await expectLater( + getStream(4).buffer( + Stream.periodic(const Duration(milliseconds: 160)).take(3)), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + }); + + test('Rx.buffer.sampleBeforeEvent.shouldEmit', () async { + await expectLater( + Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)) + .then((_) => 'end')).startWith('start').buffer( + Stream.periodic(const Duration(milliseconds: 40)).take(10)), + emitsInOrder([ + const ['start'], // after 40ms + const [], // 80ms + const [], // 120ms + const [], // 160ms + const ['end'], // done + emitsDone + ])); + }); + + test('Rx.buffer.shouldClose', () async { + final controller = StreamController() + ..add(0) + ..add(1) + ..add(2) + ..add(3); + + scheduleMicrotask(controller.close); + + await expectLater( + controller.stream + .buffer(Stream.periodic(const Duration(seconds: 3))) + .take(1), + emitsInOrder([ + const [0, 1, 2, 3], // done + emitsDone + ])); + }); + + test('Rx.buffer.reusable', () async { + final transformer = BufferStreamTransformer((_) => + Stream.periodic(const Duration(milliseconds: 160)) + .take(3) + .asBroadcastStream()); + + await expectLater( + getStream(4).transform(transformer), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + + await expectLater( + getStream(4).transform(transformer), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + }); + + test('Rx.buffer.asBroadcastStream', () async { + final stream = getStream(4).asBroadcastStream().buffer( + Stream.periodic(const Duration(milliseconds: 160)) + .take(10) + .asBroadcastStream()); + + // listen twice on same stream + await expectLater( + stream, + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + + await expectLater(stream, emitsInOrder([emitsDone])); + }); + + test('Rx.buffer.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()) + .buffer(Stream.periodic(const Duration(milliseconds: 160))), + emitsError(isException)); + }); + + test('Rx.buffer.nullable', () { + nullableTest>( + (s) => s.buffer(Stream.empty()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/buffer_test_test.dart b/sandbox/reactivex/test/transformers/backpressure/buffer_test_test.dart new file mode 100644 index 0000000..0d08c4c --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/buffer_test_test.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +void main() { + test('Rx.bufferTest', () async { + await expectLater( + Rx.range(1, 4).bufferTest((i) => i % 2 == 0), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + }); + + test('Rx.bufferTest.reusable', () async { + final transformer = BufferTestStreamTransformer((i) => i % 2 == 0); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]).transform(transformer), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]).transform(transformer), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + }); + + test('Rx.bufferTest.asBroadcastStream', () async { + final stream = Stream.fromIterable(const [1, 2, 3, 4]) + .asBroadcastStream() + .bufferTest((i) => i % 2 == 0); + + // listen twice on same stream + await expectLater( + stream, + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + + await expectLater(stream, emitsDone); + }); + + test('Rx.bufferTest.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()).bufferTest((i) => i % 2 == 0), + emitsError(isException)); + }); + + test('Rx.bufferTest.nullable', () { + nullableTest>( + (s) => s.bufferTest((i) => true), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/buffer_time_test.dart b/sandbox/reactivex/test/transformers/backpressure/buffer_time_test.dart new file mode 100644 index 0000000..8feea7d --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/buffer_time_test.dart @@ -0,0 +1,96 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +/// yield immediately, then every 100ms +Stream getStream(int n) async* { + var k = 1; + + yield 0; + + while (k < n) { + yield await Future.delayed(const Duration(milliseconds: 100)) + .then((_) => k++); + } +} + +void main() { + test('Rx.bufferTime', () async { + await expectLater( + getStream(4).bufferTime(const Duration(milliseconds: 160)), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + }); + + test('Rx.bufferTime.shouldClose', () async { + final controller = StreamController() + ..add(0) + ..add(1) + ..add(2) + ..add(3); + + scheduleMicrotask(controller.close); + + await expectLater( + controller.stream.bufferTime(const Duration(seconds: 3)).take(1), + emitsInOrder([ + const [0, 1, 2, 3], // done + emitsDone + ])); + }); + + test('Rx.bufferTime.reusable', () async { + final transformer = BufferStreamTransformer( + (_) => Stream.periodic(const Duration(milliseconds: 160))); + + await expectLater( + getStream(4).transform(transformer), + emitsInOrder([ + const [0, 1], const [2, 3], // done + emitsDone + ])); + + await expectLater( + getStream(4).transform(transformer), + emitsInOrder([ + const [0, 1], const [2, 3], // done + emitsDone + ])); + }); + + test('Rx.bufferTime.asBroadcastStream', () async { + final stream = getStream(4) + .asBroadcastStream() + .bufferTime(const Duration(milliseconds: 160)); + + // listen twice on same stream + await expectLater( + stream, + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + + await expectLater(stream, emitsInOrder([emitsDone])); + }); + + test('Rx.bufferTime.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()) + .bufferTime(const Duration(milliseconds: 160)), + emitsError(isException)); + }); + + test('Rx.bufferTime.nullable', () { + nullableTest>( + (s) => s.bufferTime(Duration.zero), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/debounce_test.dart b/sandbox/reactivex/test/transformers/backpressure/debounce_test.dart new file mode 100644 index 0000000..e8bc075 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/debounce_test.dart @@ -0,0 +1,145 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream _getStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 100), () => controller.add(1)); + Timer(const Duration(milliseconds: 200), () => controller.add(2)); + Timer(const Duration(milliseconds: 300), () => controller.add(3)); + Timer(const Duration(milliseconds: 400), () { + controller.add(4); + controller.close(); + }); + + return controller.stream; +} + +void main() { + test('Rx.debounce', () async { + await expectLater( + _getStream().debounce((_) => Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))), + emitsInOrder([4, emitsDone])); + }); + + test('Rx.debounce.dynamicWindow', () async { + // Given the input [1, 2, 3, 4] + // debounce 200ms on [1, 2, 4] + // debounce 0ms on [3] + // yields [3, 4, done] + await expectLater( + _getStream().debounce((value) => value == 3 + ? Stream.value(true) + : Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))), + emitsInOrder([3, 4, emitsDone])); + }); + + test('Rx.debounce.reusable', () async { + final transformer = DebounceStreamTransformer( + (_) => Stream.periodic(const Duration(milliseconds: 200))); + + await expectLater(_getStream().transform(transformer), + emitsInOrder([4, emitsDone])); + + await expectLater(_getStream().transform(transformer), + emitsInOrder([4, emitsDone])); + }); + + test('Rx.debounce.asBroadcastStream', () async { + final future = _getStream() + .asBroadcastStream() + .debounce((_) => Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))) + .drain(); + + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.debounce.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()).debounce((_) => Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))), + emitsError(isException)); + }); + + test('Rx.debounce.pause.resume', () async { + final controller = StreamController(); + late StreamSubscription subscription; + + subscription = Stream.fromIterable([1, 2, 3]) + .debounce((_) => Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))) + .listen(controller.add, onDone: () { + controller.close(); + subscription.cancel(); + }); + + subscription.pause(Future.delayed(const Duration(milliseconds: 50))); + + await expectLater(controller.stream, emitsInOrder([3, emitsDone])); + }); + + test('Rx.debounce.emits.last.item.immediately', () async { + final emissions = []; + final stopwatch = Stopwatch(); + final stream = Stream.fromIterable(const [1, 2, 3]).debounce((_) => + Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))); + late StreamSubscription subscription; + + stopwatch.start(); + + subscription = stream.listen( + expectAsync1((val) { + emissions.add(val); + }, count: 1), onDone: expectAsync0(() { + stopwatch.stop(); + + expect(emissions, const [3]); + + // We debounce for 100 seconds. To ensure we aren't waiting that long to + // emit the last item after the base stream completes, we expect the + // last value to be emitted to be much shorter than that. + expect(stopwatch.elapsedMilliseconds < 500, isTrue); + + subscription.cancel(); + })); + }, timeout: Timeout(Duration(seconds: 3))); + + test( + 'Rx.debounce.cancel.emits.nothing', + () async { + late StreamSubscription subscription; + final stream = Stream.fromIterable(const [1, 2, 3]).doOnDone(() { + subscription.cancel(); + }).debounce((_) => Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))); + + // We expect the onData callback to be called 0 times because the + // subscription is cancelled when the base stream ends. + subscription = stream.listen(expectAsync1((_) {}, count: 0)); + }, + timeout: Timeout(Duration(seconds: 3)), + ); + + test('Rx.debounce.last.event.can.be.null', () async { + await expectLater( + Stream.fromIterable([1, 2, 3, null]).debounce((_) => + Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)))), + emitsInOrder([null, emitsDone])); + }); + + test('Rx.debounce.nullable', () { + nullableTest( + (s) => s.debounce((_) => Stream.empty()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/debounce_time_test.dart b/sandbox/reactivex/test/transformers/backpressure/debounce_time_test.dart new file mode 100644 index 0000000..8501763 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/debounce_time_test.dart @@ -0,0 +1,126 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream _getStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 100), () => controller.add(1)); + Timer(const Duration(milliseconds: 200), () => controller.add(2)); + Timer(const Duration(milliseconds: 300), () => controller.add(3)); + Timer(const Duration(milliseconds: 400), () { + controller.add(4); + controller.close(); + }); + + return controller.stream; +} + +void main() { + test('Rx.debounceTime', () async { + await expectLater( + _getStream().debounceTime(const Duration(milliseconds: 200)), + emitsInOrder([4, emitsDone])); + }); + + test('Rx.debounceTime.reusable', () async { + final transformer = DebounceStreamTransformer( + (_) => Stream.periodic(const Duration(milliseconds: 200))); + + await expectLater(_getStream().transform(transformer), + emitsInOrder([4, emitsDone])); + + await expectLater(_getStream().transform(transformer), + emitsInOrder([4, emitsDone])); + }); + + test('Rx.debounceTime.asBroadcastStream', () async { + final future = _getStream() + .asBroadcastStream() + .debounceTime(const Duration(milliseconds: 200)) + .drain(); + + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.debounceTime.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()) + .debounceTime(const Duration(milliseconds: 200)), + emitsError(isException)); + }); + + test('Rx.debounceTime.pause.resume', () async { + final controller = StreamController(); + late StreamSubscription subscription; + + subscription = Stream.fromIterable([1, 2, 3]) + .debounceTime(Duration(milliseconds: 100)) + .listen(controller.add, onDone: () { + controller.close(); + subscription.cancel(); + }); + + subscription.pause(Future.delayed(const Duration(milliseconds: 50))); + + await expectLater(controller.stream, emitsInOrder([3, emitsDone])); + }); + + test('Rx.debounceTime.emits.last.item.immediately', () async { + final emissions = []; + final stopwatch = Stopwatch(); + final stream = Stream.fromIterable(const [1, 2, 3]) + .debounceTime(Duration(seconds: 100)); + late StreamSubscription subscription; + + stopwatch.start(); + + subscription = stream.listen( + expectAsync1((val) { + emissions.add(val); + }, count: 1), onDone: expectAsync0(() { + stopwatch.stop(); + + expect(emissions, const [3]); + + // We debounce for 100 seconds. To ensure we aren't waiting that long to + // emit the last item after the base stream completes, we expect the + // last value to be emitted to be much shorter than that. + expect(stopwatch.elapsedMilliseconds < 500, isTrue); + + subscription.cancel(); + })); + }, timeout: Timeout(Duration(seconds: 3))); + + test( + 'Rx.debounceTime.cancel.emits.nothing', + () async { + late StreamSubscription subscription; + final stream = Stream.fromIterable(const [1, 2, 3]).doOnDone(() { + subscription.cancel(); + }).debounceTime(Duration(seconds: 10)); + + // We expect the onData callback to be called 0 times because the + // subscription is cancelled when the base stream ends. + subscription = stream.listen(expectAsync1((_) {}, count: 0)); + }, + timeout: Timeout(Duration(seconds: 3)), + ); + + test('Rx.debounceTime.last.event.can.be.null', () async { + await expectLater( + Stream.fromIterable([1, 2, 3, null]) + .debounceTime(const Duration(milliseconds: 200)), + emitsInOrder([null, emitsDone])); + }); + + test('Rx.debounceTime.nullable', () { + nullableTest( + (s) => s.debounceTime(Duration.zero), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/pairwise_test.dart b/sandbox/reactivex/test/transformers/backpressure/pairwise_test.dart new file mode 100644 index 0000000..da89fa0 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/pairwise_test.dart @@ -0,0 +1,78 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +void main() { + test('Rx.pairwise', () async { + const expectedOutput = [ + [1, 2], + [2, 3], + [3, 4] + ]; + var count = 0; + + final stream = Rx.range(1, 4).pairwise(); + + stream.listen( + expectAsync1((result) { + // test to see if the combined output matches + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length), + onError: expectAsync2((Object e, StackTrace s) {}, count: 0), + onDone: expectAsync0(() {}, count: 1), + ); + }); + + test('Rx.pairwise.empty', () { + expect(Stream.empty().pairwise(), emitsDone); + }); + + test('Rx.pairwise.single', () { + expect(Stream.value(1).pairwise(), emitsDone); + }); + + test('Rx.pairwise.compatible', () { + expect( + Stream.fromIterable([1, 2]).pairwise(), + isA>>(), + ); + + Stream> s = Stream.fromIterable([1, 2]).pairwise(); + expect( + s, + emitsInOrder([ + [1, 2], + emitsDone + ]), + ); + }); + + test('Rx.pairwise.asBroadcastStream', () async { + final stream = + Stream.fromIterable(const [1, 2, 3, 4]).asBroadcastStream().pairwise(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.pairwise.error.shouldThrow.onError', () async { + final streamWithError = Stream.error(Exception()).pairwise(); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.pairwise.nullable', () { + nullableTest>( + (s) => s.pairwise(), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/sample_test.dart b/sandbox/reactivex/test/transformers/backpressure/sample_test.dart new file mode 100644 index 0000000..b0137d3 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/sample_test.dart @@ -0,0 +1,109 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream _getStream() => + Stream.periodic(const Duration(milliseconds: 20), (count) => count) + .take(5); + +Stream _getSampleStream() => + Stream.periodic(const Duration(milliseconds: 35), (count) => count) + .take(10); + +void main() { + test('Rx.sample', () async { + final stream = _getStream().sample(_getSampleStream()); + + await expectLater(stream, emitsInOrder([1, 3, 4, emitsDone])); + }); + + test('Rx.sample.reusable', () async { + final transformer = SampleStreamTransformer( + (_) => _getSampleStream().asBroadcastStream()); + final streamA = _getStream().transform(transformer); + final streamB = _getStream().transform(transformer); + + await expectLater(streamA, emitsInOrder([1, 3, 4, emitsDone])); + await expectLater(streamB, emitsInOrder([1, 3, 4, emitsDone])); + }, skip: true); + + test('Rx.sample.onDone', () async { + final stream = Stream.value(1).sample(Stream.empty()); + + await expectLater(stream, emits(1)); + }); + + test('Rx.sample.shouldClose', () async { + final controller = StreamController(); + + controller.stream + .sample(Stream.empty()) // should trigger onDone + .listen(null, onDone: expectAsync0(() => expect(true, isTrue))); + + controller.add(0); + controller.add(1); + controller.add(2); + controller.add(3); + + scheduleMicrotask(controller.close); + }); + + test('Rx.sample.asBroadcastStream', () async { + final stream = _getStream() + .asBroadcastStream() + .sample(_getSampleStream().asBroadcastStream()); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.sample.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).sample(_getSampleStream()); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.sample.error.shouldThrowB', () async { + final streamWithError = Stream.value(1) + .sample(Stream.error(Exception('Catch me if you can!'))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.sample.pause.resume', () async { + final controller = StreamController(); + late StreamSubscription subscription; + + subscription = _getStream() + .sample(_getSampleStream()) + .listen(controller.add, onDone: () { + controller.close(); + subscription.cancel(); + }); + + await expectLater( + controller.stream, emitsInOrder([1, 3, 4, emitsDone])); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.sample.nullable', () { + nullableTest( + (s) => s.sample(_getSampleStream()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/sample_time_test.dart b/sandbox/reactivex/test/transformers/backpressure/sample_time_test.dart new file mode 100644 index 0000000..f6c0386 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/sample_time_test.dart @@ -0,0 +1,99 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream _getStream() => + Stream.periodic(const Duration(milliseconds: 20), (count) => count) + .take(5); + +void main() { + test('Rx.sampleTime', () async { + final stream = _getStream().sampleTime(const Duration(milliseconds: 35)); + + await expectLater(stream, emitsInOrder([1, 3, 4, emitsDone])); + }); + + test('Rx.sampleTime.reusable', () async { + final transformer = SampleStreamTransformer((_) => + TimerStream(true, const Duration(milliseconds: 35)) + .asBroadcastStream()); + + await expectLater( + _getStream().transform(transformer).drain(), + completes, + ); + await expectLater( + _getStream().transform(transformer).drain(), + completes, + ); + }); + + test('Rx.sampleTime.onDone', () async { + final stream = Stream.value(1).sampleTime(const Duration(seconds: 1)); + + await expectLater(stream, emits(1)); + }); + + test('Rx.sampleTime.shouldClose', () async { + final controller = StreamController(); + + controller.stream + .sampleTime(const Duration(seconds: 1)) // should trigger onDone + .listen(null, onDone: expectAsync0(() => expect(true, isTrue))); + + controller.add(0); + controller.add(1); + controller.add(2); + controller.add(3); + + scheduleMicrotask(controller.close); + }); + + test('Rx.sampleTime.asBroadcastStream', () async { + final stream = _getStream() + .sampleTime(const Duration(milliseconds: 35)) + .asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.sampleTime.error.shouldThrowA', () async { + final streamWithError = Stream.error(Exception()) + .sampleTime(const Duration(milliseconds: 35)); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.sampleTime.pause.resume', () async { + final controller = StreamController(); + late StreamSubscription subscription; + + subscription = _getStream() + .sampleTime(const Duration(milliseconds: 35)) + .listen(controller.add, onDone: () { + controller.close(); + subscription.cancel(); + }); + + subscription.pause(Future.delayed(const Duration(milliseconds: 50))); + + await expectLater( + controller.stream, emitsInOrder([1, 3, 4, emitsDone])); + }); + + test('Rx.sampleTime.nullable', () { + nullableTest( + (s) => s.sampleTime(Duration.zero), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/throttle_test.dart b/sandbox/reactivex/test/transformers/backpressure/throttle_test.dart new file mode 100644 index 0000000..3a125e8 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/throttle_test.dart @@ -0,0 +1,160 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream _stream() => + Stream.periodic(const Duration(milliseconds: 100), (i) => i + 1).take(10); + +void main() { + test('Rx.throttle', () async { + await expectLater( + _stream() + .throttle( + (_) => Stream.periodic(const Duration(milliseconds: 250))) + .take(3), + emitsInOrder([1, 4, 7, emitsDone])); + }); + + test('Rx.throttle.trailing', () async { + await expectLater( + _stream() + .throttle( + (_) => Stream.periodic(const Duration(milliseconds: 250)), + trailing: true, + leading: false) + .take(3), + emitsInOrder([3, 6, 9, emitsDone])); + }); + + test('Rx.throttle.dynamic.window', () async { + await expectLater( + _stream() + .throttle((value) => value == 1 + ? Stream.periodic(const Duration(milliseconds: 10)) + : Stream.periodic(const Duration(milliseconds: 250))) + .take(3), + emitsInOrder([1, 2, 5, emitsDone])); + }); + + test('Rx.throttle.dynamic.window.trailing', () async { + await expectLater( + _stream() + .throttle( + (value) => value == 1 + ? Stream.periodic(const Duration(milliseconds: 10)) + : Stream.periodic(const Duration(milliseconds: 250)), + trailing: true, + leading: false) + .take(3), + emitsInOrder([1, 4, 7, emitsDone])); + }); + + test('Rx.throttle.leading.trailing.1', () async { + // --1--2--3--4--5--6--7--8--9--10--11| + // --1-----3--4-----6--7-----9--10-----11| + // --^--------^--------^---------^----- + + final values = []; + + final stream = _stream() + .concatWith([Rx.timer(11, const Duration(milliseconds: 100))]).throttle( + (v) { + values.add(v); + return Stream.periodic(const Duration(milliseconds: 250)); + }, + leading: true, + trailing: true, + ); + await expectLater( + stream, + emitsInOrder([1, 3, 4, 6, 7, 9, 10, 11, emitsDone]), + ); + expect(values, [1, 4, 7, 10]); + }); + + test('Rx.throttle.leading.trailing.2', () async { + // --1--2--3--4--5--6--7--8--9--10--11| + // --1-----3--4-----6--7-----9--10-----11| + // --^--------^--------^---------^----- + + final values = []; + + final stream = _stream().throttle( + (v) { + values.add(v); + return Stream.periodic(const Duration(milliseconds: 250)); + }, + leading: true, + trailing: true, + ); + await expectLater( + stream, + emitsInOrder([1, 3, 4, 6, 7, 9, 10, emitsDone]), + ); + expect(values, [1, 4, 7, 10]); + }); + + test('Rx.throttle.reusable', () async { + final transformer = ThrottleStreamTransformer( + (_) => Stream.periodic(const Duration(milliseconds: 250))); + + await expectLater(_stream().transform(transformer).take(2), + emitsInOrder([1, 4, emitsDone])); + + await expectLater(_stream().transform(transformer).take(2), + emitsInOrder([1, 4, emitsDone])); + }); + + test('Rx.throttle.asBroadcastStream', () async { + final future = _stream() + .asBroadcastStream() + .throttle( + (_) => Stream.periodic(const Duration(milliseconds: 250))) + .drain(); + + // listen twice on same stream + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.throttle.error.shouldThrowA', () async { + final streamWithError = Stream.error(Exception()).throttle( + (_) => Stream.periodic(const Duration(milliseconds: 250))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.throttle.pause.resume', () async { + late StreamSubscription subscription; + + final controller = StreamController(); + + subscription = _stream() + .throttle( + (_) => Stream.periodic(const Duration(milliseconds: 250))) + .take(2) + .listen(controller.add, onDone: () { + controller.close(); + subscription.cancel(); + }); + + await expectLater( + controller.stream, emitsInOrder([1, 4, emitsDone])); + + await Future.delayed(const Duration(milliseconds: 150)).whenComplete( + () => subscription + .pause(Future.delayed(const Duration(milliseconds: 150)))); + }); + + test('Rx.throttle.nullable', () { + nullableTest( + (s) => s.throttle((_) => Stream.empty()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/throttle_time_test.dart b/sandbox/reactivex/test/transformers/backpressure/throttle_time_test.dart new file mode 100644 index 0000000..a0d55bf --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/throttle_time_test.dart @@ -0,0 +1,102 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream _stream() => + Stream.periodic(const Duration(milliseconds: 100), (i) => i + 1).take(10); + +void main() { + test('Rx.throttleTime', () async { + await expectLater( + _stream().throttleTime(const Duration(milliseconds: 250)).take(3), + emitsInOrder([1, 4, 7, emitsDone])); + }); + + test('Rx.throttleTime.trailing', () async { + await expectLater( + _stream() + .throttleTime(const Duration(milliseconds: 250), + trailing: true, leading: false) + .take(3), + emitsInOrder([3, 6, 9, emitsDone])); + }); + + test('Rx.throttleTime.reusable', () async { + final transformer = ThrottleStreamTransformer( + (_) => Stream.periodic(const Duration(milliseconds: 250))); + + await expectLater(_stream().transform(transformer).take(2), + emitsInOrder([1, 4, emitsDone])); + + await expectLater(_stream().transform(transformer).take(2), + emitsInOrder([1, 4, emitsDone])); + }); + + test('Rx.throttleTime.asBroadcastStream', () async { + final future = _stream() + .asBroadcastStream() + .throttleTime(const Duration(milliseconds: 250)) + .drain(); + + // listen twice on same stream + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.throttleTime.error.shouldThrowA', () async { + final streamWithError = Stream.error(Exception()) + .throttleTime(const Duration(milliseconds: 200)); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.throttleTime.pause.resume', () async { + late StreamSubscription subscription; + + final controller = StreamController(); + + subscription = _stream() + .throttleTime(const Duration(milliseconds: 250)) + .take(2) + .listen(controller.add, onDone: () { + controller.close(); + subscription.cancel(); + }); + + await expectLater( + controller.stream, emitsInOrder([1, 4, emitsDone])); + + await Future.delayed(const Duration(milliseconds: 150)).whenComplete( + () => subscription + .pause(Future.delayed(const Duration(milliseconds: 150)))); + }); + + test('issue/417 trailing true', () async { + await expectLater( + Stream.fromIterable([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + .interval(Duration(milliseconds: 25)) + .throttleTime(Duration(milliseconds: 50), + trailing: true, leading: false), + emitsInOrder([1, 3, 5, 7, 9, emitsDone])); + }); + + test('issue/417 trailing false', () async { + await expectLater( + Stream.fromIterable([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + .interval(Duration(milliseconds: 25)) + .throttleTime(Duration(milliseconds: 50), trailing: false), + emitsInOrder([0, 2, 4, 6, 8, emitsDone])); + }); + + test('Rx.throttleTime.nullable', () { + nullableTest( + (s) => s.throttleTime(Duration.zero), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/window_count_test.dart b/sandbox/reactivex/test/transformers/backpressure/window_count_test.dart new file mode 100644 index 0000000..58d252f --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/window_count_test.dart @@ -0,0 +1,125 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +void main() { + test('Rx.windowCount.noStartBufferEvery', () async { + await expectLater( + Rx.range(1, 4).windowCount(2).asyncMap((stream) => stream.toList()), + emitsInOrder([ + [1, 2], + [3, 4], + emitsDone + ])); + }); + + test('Rx.windowCount.noStartBufferEvery.includesEventOnClose', () async { + await expectLater( + Rx.range(1, 5).windowCount(2).asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2], + const [3, 4], + const [5], + emitsDone + ])); + }); + + test('Rx.windowCount.startBufferEvery.count2startBufferEvery1', () async { + await expectLater( + Rx.range(1, 4).windowCount(2, 1).asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2], + const [2, 3], + const [3, 4], + const [4], + emitsDone + ])); + }); + + test('Rx.windowCount.startBufferEvery.count3startBufferEvery2', () async { + await expectLater( + Rx.range(1, 8).windowCount(3, 2).asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2, 3], + const [3, 4, 5], + const [5, 6, 7], + const [7, 8], + emitsDone + ])); + }); + + test('Rx.windowCount.startBufferEvery.count3startBufferEvery4', () async { + await expectLater( + Rx.range(1, 8).windowCount(3, 4).asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2, 3], + const [5, 6, 7], + emitsDone + ])); + }); + + test('Rx.windowCount.reusable', () async { + final transformer = WindowCountStreamTransformer(2); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + }); + + test('Rx.windowCount.asBroadcastStream', () async { + final future = Stream.fromIterable(const [1, 2, 3, 4]) + .asBroadcastStream() + .windowCount(2) + .drain(); + + // listen twice on same stream + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.windowCount.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()).windowCount(2), + emitsError(isException), + ); + }); + + test( + 'Rx.windowCount.shouldThrow.invalidCount.negative', + () { + expect(() => Stream.fromIterable(const [1, 2, 3, 4]).windowCount(-1), + throwsArgumentError); + }, + ); + + test('Rx.windowCount.startBufferEvery.shouldThrow.invalidStartBufferEvery', + () { + expect(() => Stream.fromIterable(const [1, 2, 3, 4]).windowCount(2, -1), + throwsArgumentError); + }); + + test('Rx.windowCount.nullable', () { + nullableTest>( + (s) => s.windowCount(2), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/window_test.dart b/sandbox/reactivex/test/transformers/backpressure/window_test.dart new file mode 100644 index 0000000..33dba73 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/window_test.dart @@ -0,0 +1,123 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +Stream getStream(int n) async* { + var k = 0; + + while (k < n) { + await Future.delayed(const Duration(milliseconds: 100)); + + yield k++; + } +} + +void main() { + test('Rx.window', () async { + await expectLater( + getStream(4) + .window(Stream.periodic(const Duration(milliseconds: 160)) + .take(3)) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + }); + + test('Rx.window.sampleBeforeEvent.shouldEmit', () async { + await expectLater( + Stream.fromFuture( + Future.delayed(const Duration(milliseconds: 200)) + .then((_) => 'end')) + .startWith('start') + .window(Stream.periodic(const Duration(milliseconds: 40)) + .take(10)) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const ['start'], // after 40ms + const [], // 80ms + const [], // 120ms + const [], // 160ms + const ['end'], // done + emitsDone + ])); + }); + + test('Rx.window.shouldClose', () async { + final controller = StreamController() + ..add(0) + ..add(1) + ..add(2) + ..add(3); + + scheduleMicrotask(controller.close); + + await expectLater( + controller.stream + .window(Stream.periodic(const Duration(seconds: 3))) + .asyncMap((stream) => stream.toList()) + .take(1), + emitsInOrder([ + const [0, 1, 2, 3], // done + emitsDone + ])); + }); + + test('Rx.window.reusable', () async { + final transformer = WindowStreamTransformer((_) => + Stream.periodic(const Duration(milliseconds: 160)) + .take(3) + .asBroadcastStream()); + + await expectLater( + getStream(4) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + + await expectLater( + getStream(4) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + }); + + test('Rx.window.asBroadcastStream', () async { + final future = getStream(4) + .asBroadcastStream() + .window(Stream.periodic(const Duration(milliseconds: 160)) + .take(10) + .asBroadcastStream()) + .drain(); + + // listen twice on same stream + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.window.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()) + .window(Stream.periodic(const Duration(milliseconds: 160))), + emitsError(isException)); + }); + + test('Rx.window.nullable', () { + nullableTest>( + (s) => s.window(Stream.empty()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/window_test_test.dart b/sandbox/reactivex/test/transformers/backpressure/window_test_test.dart new file mode 100644 index 0000000..b59f8f7 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/window_test_test.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +void main() { + test('Rx.windowTest', () async { + await expectLater( + Rx.range(1, 4) + .windowTest((i) => i % 2 == 0) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + }); + + test('Rx.windowTest.reusable', () async { + final transformer = WindowTestStreamTransformer((i) => i % 2 == 0); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + + await expectLater( + Stream.fromIterable(const [1, 2, 3, 4]) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [1, 2], + const [3, 4], + emitsDone + ])); + }); + + test('Rx.windowTest.asBroadcastStream', () async { + final future = Stream.fromIterable(const [1, 2, 3, 4]) + .asBroadcastStream() + .windowTest((i) => i % 2 == 0) + .drain(); + + // listen twice on same stream + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.windowTest.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()).windowTest((i) => i % 2 == 0), + emitsError(isException)); + }); + + test('Rx.windowTest.nullable', () { + nullableTest>( + (s) => s.windowTest((_) => true), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/backpressure/window_time_test.dart b/sandbox/reactivex/test/transformers/backpressure/window_time_test.dart new file mode 100644 index 0000000..8c0e1f4 --- /dev/null +++ b/sandbox/reactivex/test/transformers/backpressure/window_time_test.dart @@ -0,0 +1,99 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../../utils.dart'; + +/// yield immediately, then every 100ms +Stream getStream(int n) async* { + var k = 1; + + yield 0; + + while (k < n) { + yield await Future.delayed(const Duration(milliseconds: 100)) + .then((_) => k++); + } +} + +void main() { + test('Rx.windowTime', () async { + await expectLater( + getStream(4) + .windowTime(const Duration(milliseconds: 160)) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [0, 1], + const [2, 3], + emitsDone + ])); + }); + + test('Rx.windowTime.shouldClose', () async { + final controller = StreamController() + ..add(0) + ..add(1) + ..add(2) + ..add(3); + + scheduleMicrotask(controller.close); + + await expectLater( + controller.stream + .windowTime(const Duration(seconds: 3)) + .asyncMap((stream) => stream.toList()) + .take(1), + emitsInOrder([ + const [0, 1, 2, 3], // done + emitsDone + ])); + }); + + test('Rx.windowTime.reusable', () async { + final transformer = WindowStreamTransformer( + (_) => Stream.periodic(const Duration(milliseconds: 160))); + + await expectLater( + getStream(4) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [0, 1], const [2, 3], // done + emitsDone + ])); + + await expectLater( + getStream(4) + .transform(transformer) + .asyncMap((stream) => stream.toList()), + emitsInOrder([ + const [0, 1], const [2, 3], // done + emitsDone + ])); + }); + + test('Rx.windowTime.asBroadcastStream', () async { + final future = getStream(4) + .asBroadcastStream() + .windowTime(const Duration(milliseconds: 160)) + .drain(); + + // listen twice on same stream + await expectLater(future, completes); + await expectLater(future, completes); + }); + + test('Rx.windowTime.error.shouldThrowA', () async { + await expectLater( + Stream.error(Exception()) + .windowTime(const Duration(milliseconds: 160)), + emitsError(isException)); + }); + + test('Rx.windowTime.nullable', () { + nullableTest>( + (s) => s.windowTime(Duration.zero), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/concat_with_test.dart b/sandbox/reactivex/test/transformers/concat_with_test.dart new file mode 100644 index 0000000..6535b42 --- /dev/null +++ b/sandbox/reactivex/test/transformers/concat_with_test.dart @@ -0,0 +1,39 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.concatWith', () async { + final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); + final immediateStream = Stream.value(2); + const expected = [1, 2]; + var count = 0; + + delayedStream.concatWith([immediateStream]).listen(expectAsync1((result) { + expect(result, expected[count++]); + }, count: expected.length)); + }); + test('Rx.concatWith accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.concatWith([Stream.empty()]); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.concatWith on broadcast stream should stay broadcast ', () async { + final delayedStream = + Rx.timer(1, Duration(milliseconds: 10)).asBroadcastStream(); + final immediateStream = Stream.value(2); + final expected = [1, 2, emitsDone]; + + final concatenatedStream = delayedStream.concatWith([immediateStream]); + + expect(concatenatedStream.isBroadcast, isTrue); + expect(concatenatedStream, emitsInOrder(expected)); + }); +} diff --git a/sandbox/reactivex/test/transformers/default_if_empty_test.dart b/sandbox/reactivex/test/transformers/default_if_empty_test.dart new file mode 100644 index 0000000..d6325a1 --- /dev/null +++ b/sandbox/reactivex/test/transformers/default_if_empty_test.dart @@ -0,0 +1,88 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.defaultIfEmpty.whenEmpty', () async { + Stream.empty() + .defaultIfEmpty(true) + .listen(expectAsync1((bool result) { + expect(result, true); + }, count: 1)); + }); + + test('Rx.defaultIfEmpty.reusable', () async { + final transformer = DefaultIfEmptyStreamTransformer(true); + + Stream.empty().transform(transformer).listen(expectAsync1((result) { + expect(result, true); + }, count: 1)); + + Stream.empty().transform(transformer).listen(expectAsync1((result) { + expect(result, true); + }, count: 1)); + }); + + test('Rx.defaultIfEmpty.whenNotEmpty', () async { + Stream.fromIterable(const [false, false, false]) + .defaultIfEmpty(true) + .listen(expectAsync1((result) { + expect(result, false); + }, count: 3)); + }); + + test('Rx.defaultIfEmpty.asBroadcastStream', () async { + final stream = Stream.fromIterable(const []) + .defaultIfEmpty(-1) + .asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.defaultIfEmpty.error.shouldThrow', () async { + final streamWithError = Stream.error(Exception()).defaultIfEmpty(-1); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.defaultIfEmpty.pause.resume', () async { + late StreamSubscription subscription; + final stream = Stream.fromIterable(const []).defaultIfEmpty(1); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + test('Rx.defaultIfEmpty accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.defaultIfEmpty(1); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.defaultIfEmpty.nullable', () { + nullableTest( + (s) => s.defaultIfEmpty(null), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/delay_test.dart b/sandbox/reactivex/test/transformers/delay_test.dart new file mode 100644 index 0000000..3c24d34 --- /dev/null +++ b/sandbox/reactivex/test/transformers/delay_test.dart @@ -0,0 +1,127 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); + +void main() { + test('Rx.delay', () async { + var value = 1; + _getStream() + .delay(const Duration(milliseconds: 200)) + .listen(expectAsync1((result) { + expect(result, value++); + }, count: 4)); + }); + + test('Rx.delay.zero', () { + expect( + _getStream().delay(Duration.zero), + emitsInOrder([1, 2, 3, 4]), + ); + }); + + test('Rx.delay.shouldBeDelayed', () async { + var value = 1; + _getStream() + .delay(const Duration(milliseconds: 500)) + .timeInterval() + .listen(expectAsync1((result) { + expect(result.value, value++); + + if (result.value == 1) { + expect(result.interval.inMilliseconds, + greaterThanOrEqualTo(500)); // should be delayed + } else { + expect(result.interval.inMilliseconds, + lessThanOrEqualTo(20)); // should be near instantaneous + } + }, count: 4)); + }); + + test('Rx.delay.reusable', () async { + final transformer = + DelayStreamTransformer(const Duration(milliseconds: 200)); + var valueA = 1, valueB = 1; + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(result, valueA++); + }, count: 4)); + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(result, valueB++); + }, count: 4)); + }); + + test('Rx.delay.asBroadcastStream', () async { + final stream = _getStream() + .asBroadcastStream() + .delay(const Duration(milliseconds: 200)); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.delay.error.shouldThrowA', () async { + final streamWithError = Stream.error(Exception()) + .delay(const Duration(milliseconds: 200)); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.delay.pause.resume', () async { + late StreamSubscription subscription; + final stream = + Stream.fromIterable(const [1, 2, 3]).delay(Duration(milliseconds: 1)); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test( + 'Rx.delay.cancel.emits.nothing', + () async { + late StreamSubscription subscription; + final stream = Stream.fromIterable(const [1, 2, 3]).doOnDone(() { + subscription.cancel(); + }).delay(Duration(seconds: 10)); + + // We expect the onData callback to be called 0 times because the + // subscription is cancelled when the base stream ends. + subscription = stream.listen(expectAsync1((_) {}, count: 0)); + }, + timeout: Timeout(Duration(seconds: 3)), + ); + + test('Rx.delay accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.delay(Duration(seconds: 10)); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.delay.nullable', () { + nullableTest( + (s) => s.delay(Duration.zero), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/delay_when_test.dart b/sandbox/reactivex/test/transformers/delay_when_test.dart new file mode 100644 index 0000000..2e37a11 --- /dev/null +++ b/sandbox/reactivex/test/transformers/delay_when_test.dart @@ -0,0 +1,280 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); + +extension on Duration { + Stream asTimerStream() => Rx.timer(null, this); +} + +void main() { + test('Rx.delayWhen', () { + expect( + _getStream().delayWhen((_) => Stream.value(null)), + emitsInOrder([1, 2, 3, 4, emitsDone]), + ); + + expect( + _getStream() + .delayWhen((_) => const Duration(milliseconds: 200).asTimerStream()), + emitsInOrder([1, 2, 3, 4, emitsDone]), + ); + + expect( + _getStream() + .delayWhen((i) => Duration(milliseconds: 100 * i).asTimerStream()), + emitsInOrder([1, 2, 3, 4, emitsDone]), + ); + + expect( + _getStream().delayWhen( + (i) => Duration(milliseconds: 100 * i).asTimerStream(), + listenDelay: Rx.timer(null, Duration(milliseconds: 100)), + ), + emitsInOrder([1, 2, 3, 4, emitsDone]), + ); + }); + + test('Rx.delayWhen.zero', () { + expect( + _getStream().delayWhen((_) => Duration.zero.asTimerStream()), + emitsInOrder([1, 2, 3, 4, emitsDone]), + ); + }); + + test('Rx.delayWhen.shouldBeDelayed', () async { + { + var value = 1; + await _getStream() + .delayWhen((_) => const Duration(milliseconds: 500).asTimerStream()) + .timeInterval() + .forEach(expectAsync1((result) { + expect(result.value, value++); + + if (result.value == 1) { + expect( + result.interval.inMilliseconds, + greaterThanOrEqualTo(500), + ); // should be delayed + } else { + expect( + result.interval.inMilliseconds, + lessThanOrEqualTo(20), + ); // should be near instantaneous + } + }, count: 4)); + } + + { + var value = 1; + await _getStream() + .delayWhen((i) => Duration(milliseconds: 500 * i).asTimerStream()) + .timeInterval() + .forEach(expectAsync1((result) { + expect(result.value, value++); + + expect( + (result.interval.inMilliseconds - 500).abs(), + lessThanOrEqualTo(20), + ); // should be near instantaneous + }, count: 4)); + } + }); + + test('Rx.delayWhen.shouldBeDelayed.listenDelay', () { + var value = 1; + + void onData(TimeInterval result) { + expect(result.value, value++); + + if (result.value == 1) { + expect( + result.interval.inMilliseconds, + greaterThanOrEqualTo(500 + 300), + ); // should be delayed + } else { + expect( + (result.interval.inMilliseconds - 500).abs(), + lessThanOrEqualTo(20), + ); // should be near instantaneous + } + } + + _getStream() + .delayWhen( + (i) => Duration(milliseconds: 500 * i).asTimerStream(), + listenDelay: Rx.timer(null, const Duration(milliseconds: 300)), + ) + .timeInterval() + .listen(expectAsync1(onData, count: 4)); + }); + + test('Rx.delayWhen.reusable', () { + final transformer = DelayWhenStreamTransformer( + (_) => const Duration(milliseconds: 200).asTimerStream()); + + expect( + _getStream().transform(transformer), + emitsInOrder([1, 2, 3, 4, emitsDone]), + ); + + expect( + _getStream().transform(transformer), + emitsInOrder([1, 2, 3, 4, emitsDone]), + ); + }); + + test('Rx.delayWhen.asBroadcastStream', () { + { + final stream = _getStream() + .asBroadcastStream() + .delayWhen((_) => const Duration(milliseconds: 200).asTimerStream()); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + expect(true, true); + } + + { + final stream = _getStream() + .delayWhen((_) => const Duration(milliseconds: 200).asTimerStream()) + .asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + expect(true, true); + } + + { + final stream = _getStream() + .delayWhen( + (_) => const Duration(milliseconds: 200).asTimerStream(), + listenDelay: Stream.value(null), + ) + .asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + expect(true, true); + } + }); + + test('Rx.delayWhen.error.shouldThrowA', () { + expect( + Stream.error(Exception()) + .delayWhen((_) => const Duration(milliseconds: 200).asTimerStream()), + emitsInOrder([ + emitsError(isA()), + emitsDone, + ]), + ); + }); + + test('Rx.delayWhen.error.shouldThrowB', () { + expect( + Stream.value(0).delayWhen( + (_) => const Duration(milliseconds: 200).asTimerStream(), + listenDelay: Stream.error(Exception('listenDelay')), + ), + emitsInOrder([ + emitsError(isA()), + emitsDone, + ]), + ); + }); + + test('Rx.delayWhen.pause.resume', () async { + late StreamSubscription subscription; + final stream = Stream.fromIterable(const [1, 2, 3]) + .delayWhen((_) => Duration(milliseconds: 1).asTimerStream()); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.delayWhen.pause.resume.listenDelay', () { + late StreamSubscription subscription; + final stream = Stream.fromIterable(const [1, 2, 3]).delayWhen( + (_) => Duration(milliseconds: 1).asTimerStream(), + listenDelay: Rx.timer(null, const Duration(milliseconds: 200)), + ); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test( + 'Rx.delayWhen.cancel.emits.nothing', + () { + late StreamSubscription subscription; + final stream = _getStream() + .doOnDone(() => subscription.cancel()) + .delayWhen((_) => Duration(seconds: 10).asTimerStream()); + + // We expect the onData callback to be called 0 times because the + // subscription is cancelled when the base stream ends. + subscription = stream.listen(expectAsync1((_) {}, count: 0)); + }, + timeout: Timeout(Duration(seconds: 3)), + ); + + test( + 'Rx.delayWhen.cancel.emits.nothing.listenDelay', + () { + late StreamSubscription subscription; + final stream = + _getStream().doOnDone(() => subscription.cancel()).delayWhen( + (_) => Duration(seconds: 10).asTimerStream(), + listenDelay: Stream.periodic(const Duration(seconds: 1)), + ); + + // We expect the onData callback to be called 0 times because the + // subscription is cancelled when the base stream ends. + subscription = stream.listen(expectAsync1((_) {}, count: 0)); + }, + timeout: Timeout(Duration(seconds: 3)), + ); + + test('Rx.delayWhen.singleSubscription', () async { + final controller = StreamController(); + + final stream = controller.stream + .delayWhen((_) => Duration(seconds: 10).asTimerStream()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.delayWhen.nullable', () { + nullableTest( + (s) => s.delayWhen((_) => Duration.zero.asTimerStream()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/dematerialize_test.dart b/sandbox/reactivex/test/transformers/dematerialize_test.dart new file mode 100644 index 0000000..c4fdb57 --- /dev/null +++ b/sandbox/reactivex/test/transformers/dematerialize_test.dart @@ -0,0 +1,105 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:stack_trace/stack_trace.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.dematerialize.happyPath', () async { + const expectedValue = 1; + final stream = Stream.value(1).materialize(); + + stream.dematerialize().listen(expectAsync1((value) { + expect(value, expectedValue); + }), onDone: expectAsync0(() { + // Should call onDone + expect(true, isTrue); + })); + }); + + test('Rx.dematerialize.nullable.happyPath', () async { + const elements = [1, 2, null, 3, 4, null]; + final stream = Stream.fromIterable(elements).materialize(); + + expect( + stream.dematerialize(), + emitsInOrder(elements), + ); + }); + + test('Rx.dematerialize.reusable', () async { + final transformer = DematerializeStreamTransformer(); + const expectedValue = 1; + final streamA = Stream.value(1).materialize(); + final streamB = Stream.value(1).materialize(); + + streamA.transform(transformer).listen(expectAsync1((value) { + expect(value, expectedValue); + }), onDone: expectAsync0(() { + // Should call onDone + expect(true, isTrue); + })); + + streamB.transform(transformer).listen(expectAsync1((value) { + expect(value, expectedValue); + }), onDone: expectAsync0(() { + // Should call onDone + expect(true, isTrue); + })); + }); + + test('dematerializeTransformer.happyPath', () async { + const expectedValue = 1; + final stream = Stream.fromIterable([ + StreamNotification.data(expectedValue), + StreamNotification.done() + ]); + + stream.transform(DematerializeStreamTransformer()).listen( + expectAsync1((value) { + expect(value, expectedValue); + }), onDone: expectAsync0(() { + // Should call onDone + expect(true, isTrue); + })); + }); + + test('dematerializeTransformer.sadPath', () async { + final stream = Stream.fromIterable( + [StreamNotification.error(Exception(), Chain.current())]); + + stream.transform(DematerializeStreamTransformer()).listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('dematerializeTransformer.onPause.onResume', () async { + const expectedValue = 1; + final stream = Stream.fromIterable([ + StreamNotification.data(expectedValue), + StreamNotification.done() + ]); + + stream.transform(DematerializeStreamTransformer()).listen( + expectAsync1((value) { + expect(value, expectedValue); + }), onDone: expectAsync0(() { + // Should call onDone + expect(true, isTrue); + })) + ..pause() + ..resume(); + }); + + test('Rx.dematerialize accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.materialize().dematerialize(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); +} diff --git a/sandbox/reactivex/test/transformers/distinct_test.dart b/sandbox/reactivex/test/transformers/distinct_test.dart new file mode 100644 index 0000000..0775b7f --- /dev/null +++ b/sandbox/reactivex/test/transformers/distinct_test.dart @@ -0,0 +1,25 @@ +import 'dart:async'; + +import 'package:test/test.dart'; + +void main() { + test('Rx.distinct', () async { + const expected = 1; + + final stream = Stream.fromIterable(const [expected, expected]).distinct(); + + stream.listen(expectAsync1((actual) { + expect(actual, expected); + })); + }); + test('Rx.distinct accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.distinct(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); +} diff --git a/sandbox/reactivex/test/transformers/distinct_unique_test.dart b/sandbox/reactivex/test/transformers/distinct_unique_test.dart new file mode 100644 index 0000000..6c4c9dd --- /dev/null +++ b/sandbox/reactivex/test/transformers/distinct_unique_test.dart @@ -0,0 +1,157 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + group('DistinctUniqueStreamTransformer', () { + test('works with the equals and hascode of the class', () async { + final stream = Stream.fromIterable(const [ + _TestObject('a'), + _TestObject('a'), + _TestObject('b'), + _TestObject('a'), + _TestObject('b'), + _TestObject('c'), + _TestObject('a'), + _TestObject('b'), + _TestObject('c'), + _TestObject('a') + ]).distinctUnique(); + + await expectLater( + stream, + emitsInOrder([ + const _TestObject('a'), + const _TestObject('b'), + const _TestObject('c'), + emitsDone + ])); + }); + + test('works with a provided equals and hashcode', () async { + final stream = Stream.fromIterable(const [ + _TestObject('a'), + _TestObject('a'), + _TestObject('b'), + _TestObject('a'), + _TestObject('b'), + _TestObject('c'), + _TestObject('a'), + _TestObject('b'), + _TestObject('c'), + _TestObject('a') + ]).distinctUnique( + equals: (a, b) => a.key == b.key, hashCode: (o) => o.key.hashCode); + + await expectLater( + stream, + emitsInOrder([ + const _TestObject('a'), + const _TestObject('b'), + const _TestObject('c'), + emitsDone + ])); + }); + + test( + 'sends an error to the subscription if an error occurs in the equals or hashmap methods', + () async { + final stream = Stream.fromIterable( + const [_TestObject('a'), _TestObject('b'), _TestObject('c')]) + .distinctUnique( + equals: (a, b) => a.key == b.key, + hashCode: (o) => throw Exception('Catch me if you can!')); + + stream.listen( + null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException), + count: 3, + ), + ); + }); + + test('is reusable', () async { + const data = [ + _TestObject('a'), + _TestObject('a'), + _TestObject('b'), + _TestObject('a'), + _TestObject('a'), + _TestObject('b'), + _TestObject('b'), + _TestObject('c'), + _TestObject('a'), + _TestObject('b'), + _TestObject('c'), + _TestObject('a') + ]; + + final distinctUniqueStreamTransformer = + DistinctUniqueStreamTransformer<_TestObject>(); + + final firstStream = + Stream.fromIterable(data).transform(distinctUniqueStreamTransformer); + + final secondStream = + Stream.fromIterable(data).transform(distinctUniqueStreamTransformer); + + await expectLater( + firstStream, + emitsInOrder([ + const _TestObject('a'), + const _TestObject('b'), + const _TestObject('c'), + emitsDone + ])); + + await expectLater( + secondStream, + emitsInOrder([ + const _TestObject('a'), + const _TestObject('b'), + const _TestObject('c'), + emitsDone + ])); + }); + + test('Rx.distinctUnique accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.distinctUnique(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + }); + + test('Rx.distinctUnique.nullable', () { + nullableTest( + (s) => s.distinctUnique(), + ); + }); +} + +class _TestObject { + final String key; + + const _TestObject(this.key); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is _TestObject && + runtimeType == other.runtimeType && + key == other.key; + + @override + int get hashCode => key.hashCode; + + @override + String toString() => key; +} diff --git a/sandbox/reactivex/test/transformers/do_test.dart b/sandbox/reactivex/test/transformers/do_test.dart new file mode 100644 index 0000000..b99fe28 --- /dev/null +++ b/sandbox/reactivex/test/transformers/do_test.dart @@ -0,0 +1,489 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + group('DoStreamTranformer', () { + test('calls onDone when the stream is finished', () async { + var onDoneCalled = false; + final stream = Stream.empty().doOnDone(() => onDoneCalled = true); + + await expectLater(stream, emitsDone); + await expectLater(onDoneCalled, isTrue); + }); + + test('calls onError when an error is emitted', () async { + var onErrorCalled = false; + final stream = Stream.error(Exception()) + .doOnError((e, s) => onErrorCalled = true); + + await expectLater(stream, emitsError(isException)); + await expectLater(onErrorCalled, isTrue); + }); + + test( + 'onError only called once when an error is emitted on a broadcast stream', + () async { + var count = 0; + final subject = BehaviorSubject(sync: true); + final stream = subject.stream.doOnError((e, s) => count++); + + stream.listen(null, onError: (dynamic e, dynamic s) {}); + stream.listen(null, onError: (dynamic e, dynamic s) {}); + + subject.addError(Exception()); + subject.addError(Exception()); + + await expectLater(count, 2); + await subject.close(); + }); + + test('calls onCancel when the subscription is cancelled', () async { + var onCancelCalled = false; + final stream = Stream.value(1); + + await stream + .doOnCancel(() => onCancelCalled = true) + .listen(null) + .cancel(); + + await expectLater(onCancelCalled, isTrue); + }); + + test('awaits onCancel when the subscription is cancelled', () async { + var onCancelCompleted = 10, onCancelHandled = 10, eventSequenceCount = 0; + final stream = Stream.value(1); + + await stream + .doOnCancel(() => + Future.delayed(const Duration(milliseconds: 100)) + .whenComplete(() => onCancelHandled = ++eventSequenceCount)) + .listen(null) + .cancel() + .whenComplete(() => onCancelCompleted = ++eventSequenceCount); + + await expectLater(onCancelCompleted > onCancelHandled, isTrue); + }); + + test( + 'onCancel called only once when the subscription is multiple listeners', + () async { + var count = 0; + final subject = BehaviorSubject(sync: true); + final stream = subject.doOnCancel(() => count++); + + await stream.listen(null).cancel(); + await stream.listen(null).cancel(); + + await expectLater(count, 2); + await subject.close(); + }); + + test('calls onData when the stream emits an item', () async { + var onDataCalled = false; + final stream = Stream.value(1).doOnData((_) => onDataCalled = true); + + await expectLater(stream, emits(1)); + await expectLater(onDataCalled, isTrue); + }); + + test('onData only emits once for broadcast streams with multiple listeners', + () async { + final actual = []; + final controller = StreamController.broadcast(sync: true); + final stream = + controller.stream.transform(DoStreamTransformer(onData: actual.add)); + + stream.listen(null); + stream.listen(null); + + controller.add(1); + controller.add(2); + + await expectLater(actual, const [1, 2]); + await controller.close(); + }); + + test('onData only emits once for subjects with multiple listeners', + () async { + final actual = []; + final controller = BehaviorSubject(sync: true); + final stream = + controller.stream.transform(DoStreamTransformer(onData: actual.add)); + + stream.listen(null); + stream.listen(null); + + controller.add(1); + controller.add(2); + + await expectLater(actual, const [1, 2]); + await controller.close(); + }); + + test('onData only emits correctly with ReplaySubject', () async { + final controller = ReplaySubject(sync: true) + ..add(1) + ..add(2); + final actual = []; + + await controller.close(); + + expect(await controller.stream.doOnData(actual.add).drain(actual), + const [1, 2]); + + actual.clear(); + + expect(await controller.stream.doOnData(actual.add).drain(actual), + const [1, 2]); + }); + + test('emits onEach Notifications for Data, Error, and Done', () async { + StackTrace? stacktrace; + final actual = >[]; + final exception = Exception(); + final stream = Stream.value(1) + .concatWith([Stream.error(exception)]).doOnEach((notification) { + actual.add(notification); + + if (notification.isError) { + stacktrace = notification.errorAndStackTraceOrNull?.stackTrace; + } + }); + + await expectLater(stream, + emitsInOrder([1, emitsError(isException), emitsDone])); + + await expectLater(actual, [ + StreamNotification.data(1), + StreamNotification.error(exception, stacktrace), + StreamNotification.done() + ]); + }); + + test('onEach only emits once for broadcast streams with multiple listeners', + () async { + var count = 0; + final controller = StreamController.broadcast(sync: true); + final stream = + controller.stream.transform(DoStreamTransformer(onEach: (_) { + count++; + })); + + stream.listen(null); + stream.listen(null); + + controller.add(1); + controller.add(2); + + await expectLater(count, 2); + await controller.close(); + }); + + test('calls onListen when a consumer listens', () async { + var onListenCalled = false; + final stream = Stream.empty().doOnListen(() { + onListenCalled = true; + }); + + await expectLater(stream, emitsDone); + await expectLater(onListenCalled, isTrue); + }); + + test( + 'calls onListen once when multiple subscribers open, without cancelling', + () async { + var onListenCallCount = 0; + final sc = StreamController.broadcast() + ..add(1) + ..add(2) + ..add(3); + + final stream = sc.stream.doOnListen(() => onListenCallCount++); + + stream.listen(null); + stream.listen(null); + + await expectLater(onListenCallCount, 1); + await sc.close(); + }); + + test( + 'calls onListen every time after all previous subscribers have cancelled', + () async { + var onListenCallCount = 0; + final sc = StreamController.broadcast() + ..add(1) + ..add(2) + ..add(3); + + final stream = sc.stream.doOnListen(() => onListenCallCount++); + + await stream.listen(null).cancel(); + await stream.listen(null).cancel(); + + await expectLater(onListenCallCount, 2); + await sc.close(); + }); + + test('calls onPause and onResume when the subscription is', () async { + var onPauseCalled = false, onResumeCalled = false; + final stream = Stream.value(1).doOnPause(() { + onPauseCalled = true; + }).doOnResume(() { + onResumeCalled = true; + }); + + stream.listen(null, onDone: expectAsync0(() { + expect(onPauseCalled, isTrue); + expect(onResumeCalled, isTrue); + })) + ..pause() + ..resume(); + }); + + test('should be reusable', () async { + var callCount = 0; + final transformer = DoStreamTransformer(onData: (_) { + callCount++; + }); + + final streamA = Stream.value(1).transform(transformer), + streamB = Stream.value(1).transform(transformer); + + await expectLater(streamA, emitsInOrder([1, emitsDone])); + await expectLater(streamB, emitsInOrder([1, emitsDone])); + + expect(callCount, 2); + }); + + test('throws an error when no arguments are provided', () { + expect(() => DoStreamTransformer(), throwsArgumentError); + }); + + test('should propagate errors', () { + Stream.value(1) + .doOnListen(() => throw Exception('catch me if you can! doOnListen')) + .listen( + null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException), + ), + ); + + Stream.value(1) + .doOnData((_) => throw Exception('catch me if you can! doOnData')) + .listen( + null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException), + ), + ); + + Stream.error(Exception('oh noes!')) + .doOnError( + (_, __) => throw Exception('catch me if you can! doOnError')) + .listen( + null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException), + count: 2, + ), + ); + + // a cancel() call may occur after the controller is already closed + // in that case, the error is forwarded to the current [Zone] + runZonedGuarded( + () { + Stream.value(1) + .doOnCancel(() => + throw Exception('catch me if you can! doOnCancel-zoned')) + .listen(null); + + Stream.value(1) + .doOnCancel( + () => throw Exception('catch me if you can! doOnCancel')) + .listen(null) + .cancel(); + }, + expectAsync2( + (Object e, StackTrace s) => expect(e, isException), + count: 2, + ), + ); + + Stream.value(1) + .doOnDone(() => throw Exception('catch me if you can! doOnDone')) + .listen( + null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException), + ), + ); + + Stream.value(1) + .doOnEach((_) => throw Exception('catch me if you can! doOnEach')) + .listen( + null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException), + count: 2, + ), + ); + + Stream.value(1) + .doOnPause(() => throw Exception('catch me if you can! doOnPause')) + .listen(null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException), + )) + ..pause() + ..resume(); + + Stream.value(1) + .doOnResume(() => throw Exception('catch me if you can! doOnResume')) + .listen(null, + onError: expectAsync2( + (Exception e, StackTrace s) => expect(e, isException))) + ..pause() + ..resume(); + }); + + test( + 'doOnListen correctly allows subscribing multiple times on a broadcast stream', + () { + final controller = StreamController.broadcast(); + final stream = controller.stream.doOnListen(() { + // do nothing + }); + + controller.close(); + + expectLater(stream, emitsDone); + expectLater(stream, emitsDone); + }); + + test('issue/389/1', () { + final controller = StreamController.broadcast(); + final stream = controller.stream.doOnListen(() { + // do nothing + }); + + expectLater(stream, emitsDone); + expectLater(stream, emitsDone); // #issue/389 : is being ignored/hangs up + + controller.close(); + }); + + test('issue/389/2', () { + final controller = StreamController(); + var isListening = false; + + final stream = controller.stream.doOnListen(() { + isListening = true; + }); + + controller.close(); + + // should be done + expectLater(stream, emitsDone); + // should have called onX + expect(isListening, true); + // should not be converted to a broadcast Stream + expect(() => stream.listen(null), throwsStateError); + }); + + test('Rx.do accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.doOnEach((_) {}); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('nested doOnX', () async { + final completer = Completer(); + final stream = + Rx.range(0, 30).interval(const Duration(milliseconds: 100)); + final result = []; + const expectedOutput = [ + 'A: 0', + 'B: 0', + 'pause', + 'A: 1', + 'B: 1', + 'A: 2', + 'B: 2', + 'A: 3', + 'B: 3', + 'A: 4', + 'B: 4', + 'A: 5', + 'B: 5', + 'pause', + 'A: 6', + 'B: 6', + 'A: 7', + 'B: 7', + 'A: 8', + 'B: 8', + 'A: 9', + 'B: 9', + 'A: 10', + 'B: 10', + 'pause', + 'A: 11', + 'B: 11', + 'A: 12', + 'B: 12', + 'A: 13', + 'B: 13', + 'A: 14', + 'B: 14', + 'A: 15', + 'B: 15', + 'pause', + 'A: 16', + 'B: 16', + 'A: 17', + ]; + late StreamSubscription subscription; + + void addToResult(String value) { + result.add(value); + + if (result.length == expectedOutput.length) { + subscription.cancel(); + completer.complete(); + } + } + + subscription = Stream.value(1) + .exhaustMap((_) => stream.doOnData((data) => addToResult('A: $data'))) + .doOnPause(() => addToResult('pause')) + .doOnData((data) => addToResult('B: $data')) + .take(expectedOutput.length) + .listen((value) { + if (value % 5 == 0) { + subscription.pause(Future.delayed(const Duration(seconds: 2))); + } + }); + + await completer.future; + + expect(result, expectedOutput); + }); + + test('doOnData nullable', () { + nullableTest( + (s) => s.doOnData((d) {}), + ); + }); + }); +} diff --git a/sandbox/reactivex/test/transformers/end_with_many_test.dart b/sandbox/reactivex/test/transformers/end_with_many_test.dart new file mode 100644 index 0000000..ab28437 --- /dev/null +++ b/sandbox/reactivex/test/transformers/end_with_many_test.dart @@ -0,0 +1,78 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); + +void main() { + test('Rx.endWithMany', () async { + const expectedOutput = [1, 2, 3, 4, 5, 6]; + + await expectLater( + _getStream().endWithMany(const [5, 6]), emitsInOrder(expectedOutput)); + }); + + test('Rx.endWithMany.reusable', () async { + final transformer = EndWithManyStreamTransformer(const [5, 6]); + const expectedOutput = [1, 2, 3, 4, 5, 6]; + + await expectLater( + _getStream().transform(transformer), emitsInOrder(expectedOutput)); + await expectLater( + _getStream().transform(transformer), emitsInOrder(expectedOutput)); + }); + + test('Rx.endWithMany.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().endWithMany(const [5, 6]); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.endWithMany.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).endWithMany(const [5, 6]); + + await expectLater(streamWithError, emitsError(isException)); + }); + + test('Rx.endWithMany.pause.resume', () async { + const expectedOutput = [1, 2, 3, 4, 5, 6]; + var count = 0; + + late StreamSubscription subscription; + subscription = + _getStream().endWithMany(const [5, 6]).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + test('Rx.endWithMany accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.endWithMany(const [1, 2, 3]); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.endWithMany.nullable', () { + nullableTest( + (s) => s.endWithMany(['String']), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/end_with_test.dart b/sandbox/reactivex/test/transformers/end_with_test.dart new file mode 100644 index 0000000..d54562b --- /dev/null +++ b/sandbox/reactivex/test/transformers/end_with_test.dart @@ -0,0 +1,76 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); + +void main() { + test('Rx.endWith', () async { + const expectedOutput = [1, 2, 3, 4, 5]; + + await expectLater(_getStream().endWith(5), emitsInOrder(expectedOutput)); + }); + + test('Rx.endWith.reusable', () async { + final transformer = EndWithStreamTransformer(5); + const expectedOutput = [1, 2, 3, 4, 5]; + + await expectLater( + _getStream().transform(transformer), emitsInOrder(expectedOutput)); + await expectLater( + _getStream().transform(transformer), emitsInOrder(expectedOutput)); + }); + + test('Rx.endWith.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().endWith(5); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.endWith.error.shouldThrow', () async { + final streamWithError = Stream.error(Exception()).endWith(5); + + await expectLater(streamWithError, emitsError(isException)); + }); + + test('Rx.endWith.pause.resume', () async { + const expectedOutput = [1, 2, 3, 4, 5]; + var count = 0; + + late StreamSubscription subscription; + subscription = _getStream().endWith(5).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.endWith accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.endWith(1); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.endWith.nullable', () { + nullableTest( + (s) => s.endWith('String'), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/exhaust_map_test.dart b/sandbox/reactivex/test/transformers/exhaust_map_test.dart new file mode 100644 index 0000000..0f9137f --- /dev/null +++ b/sandbox/reactivex/test/transformers/exhaust_map_test.dart @@ -0,0 +1,110 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + group('ExhaustMap', () { + test('does not create a new Stream while emitting', () async { + var calls = 0; + final stream = Rx.range(0, 9).exhaustMap((i) { + calls++; + return Rx.timer(i, Duration(milliseconds: 100)); + }); + + await expectLater(stream, emitsInOrder([0, emitsDone])); + await expectLater(calls, 1); + }); + + test('starts emitting again after previous Stream is complete', () async { + final stream = Stream.fromIterable(const [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + .interval(Duration(milliseconds: 30)) + .exhaustMap((i) async* { + yield await Future.delayed(Duration(milliseconds: 70), () => i); + }); + + await expectLater(stream, emitsInOrder([0, 3, 6, 9, emitsDone])); + }); + + test('is reusable', () async { + final transformer = ExhaustMapStreamTransformer( + (int i) => Rx.timer(i, Duration(milliseconds: 100))); + + await expectLater( + Rx.range(0, 9).transform(transformer), + emitsInOrder([0, emitsDone]), + ); + + await expectLater( + Rx.range(0, 9).transform(transformer), + emitsInOrder([0, emitsDone]), + ); + }); + + test('works as a broadcast stream', () async { + final stream = Rx.range(0, 9) + .asBroadcastStream() + .exhaustMap((i) => Rx.timer(i, Duration(milliseconds: 100))); + + await expectLater(() { + stream.listen(null); + stream.listen(null); + }, returnsNormally); + }); + + test('should emit errors from source', () async { + final streamWithError = Stream.error(Exception()) + .exhaustMap((i) => Rx.timer(i, Duration(milliseconds: 100))); + + await expectLater(streamWithError, emitsError(isException)); + }); + + test('should emit errors from mapped stream', () async { + final streamWithError = Stream.value(1).exhaustMap( + (_) => Stream.error(Exception('Catch me if you can!'))); + + await expectLater(streamWithError, emitsError(isException)); + }); + + test('should emit errors thrown in the mapper', () async { + final streamWithError = Stream.value(1).exhaustMap((_) { + throw Exception('oh noes!'); + }); + + await expectLater(streamWithError, emitsError(isException)); + }); + + test('can be paused and resumed', () async { + late StreamSubscription subscription; + final stream = Rx.range(0, 9) + .exhaustMap((i) => Rx.timer(i, Duration(milliseconds: 20))); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 0); + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.exhaustMap accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.exhaustMap((_) => Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.exhaustMap.nullable', () { + nullableTest( + (s) => s.exhaustMap((v) => Stream.value(v)), + ); + }); + }); +} diff --git a/sandbox/reactivex/test/transformers/flat_map_iterable_test.dart b/sandbox/reactivex/test/transformers/flat_map_iterable_test.dart new file mode 100644 index 0000000..e1cb944 --- /dev/null +++ b/sandbox/reactivex/test/transformers/flat_map_iterable_test.dart @@ -0,0 +1,35 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + group('Rx.flatMapIterable', () { + test('transforms a Stream> into individual items', () { + expect( + Rx.range(1, 4) + .flatMapIterable((int i) => Stream>.value([i])), + emitsInOrder([1, 2, 3, 4, emitsDone])); + }); + + test('accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream + .flatMapIterable((int i) => Stream>.value([i])); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('nullable', () { + nullableTest( + (s) => s.flatMapIterable((v) => Stream.value([v])), + ); + }); + }); +} diff --git a/sandbox/reactivex/test/transformers/flat_map_test.dart b/sandbox/reactivex/test/transformers/flat_map_test.dart new file mode 100644 index 0000000..db994f0 --- /dev/null +++ b/sandbox/reactivex/test/transformers/flat_map_test.dart @@ -0,0 +1,267 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.flatMap', () async { + const expectedOutput = [3, 2, 1]; + var count = 0; + + _getStream().flatMap(_getOtherStream).listen(expectAsync1((result) { + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.flatMap.reusable', () async { + final transformer = FlatMapStreamTransformer(_getOtherStream); + const expectedOutput = [3, 2, 1]; + var countA = 0, countB = 0; + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(result, expectedOutput[countA++]); + }, count: expectedOutput.length)); + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(result, expectedOutput[countB++]); + }, count: expectedOutput.length)); + }); + + test('Rx.flatMap.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().flatMap(_getOtherStream); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.flatMap.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).flatMap(_getOtherStream); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.flatMap.error.shouldThrowB', () async { + final streamWithError = Stream.value(1) + .flatMap((_) => Stream.error(Exception('Catch me if you can!'))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.flatMap.error.shouldThrowC', () async { + final streamWithError = + Stream.value(1).flatMap((_) => throw Exception('oh noes!')); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.flatMap.pause.resume', () async { + late StreamSubscription subscription; + final stream = Stream.value(0).flatMap((_) => Stream.value(1)); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.flatMap.chains', () { + expect( + Stream.value(1) + .flatMap((_) => Stream.value(2)) + .flatMap((_) => Stream.value(3)), + emitsInOrder([3, emitsDone]), + ); + }); + + test('Rx.flatMap accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.flatMap((_) => Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.flatMap(maxConcurrent: 1)', () { + { + // asyncExpand / concatMap + final stream = Stream.fromIterable([1, 2, 3, 4]).flatMap( + (value) => Rx.timer( + value, + Duration(milliseconds: (5 - value) * 100), + ), + maxConcurrent: 1, + ); + expect(stream, emitsInOrder([1, 2, 3, 4, emitsDone])); + } + + { + // emits error + final stream = Stream.fromIterable([1, 2, 3, 4]).flatMap( + (value) => value == 1 + ? throw Exception() + : Rx.timer( + value, + Duration(milliseconds: (5 - value) * 100), + ), + maxConcurrent: 1, + ); + expect(stream, + emitsInOrder([emitsError(isException), 2, 3, 4, emitsDone])); + } + + { + // emits error + final stream = Stream.fromIterable([1, 2, 3, 4]).flatMap( + (value) => value == 1 + ? Stream.error(Exception()) + : Rx.timer( + value, + Duration(milliseconds: (5 - value) * 100), + ), + maxConcurrent: 1, + ); + expect(stream, + emitsInOrder([emitsError(isException), 2, 3, 4, emitsDone])); + } + }); + + test('Rx.flatMap(maxConcurrent: 2)', () async { + const maxConcurrent = 2; + var activeCount = 0; + + // 1 -> 500 + // 2 -> 400 + // 3 -> 500 + // 4 -> 200 + // -----1--4 + // ----2-----3 + // ----21--4-3 + final stream = Stream.fromIterable([1, 2, 3, 4]).flatMap( + (value) { + return Rx.defer(() { + expect(++activeCount, lessThanOrEqualTo(maxConcurrent)); + + final ms = (value.isOdd ? 5 : 6 - value) * 100; + return Rx.timer(value, Duration(milliseconds: ms)); + }).doOnDone(() => --activeCount); + }, + maxConcurrent: maxConcurrent, + ); + + await expectLater(stream, emitsInOrder([2, 1, 4, 3, emitsDone])); + }); + + test('Rx.flatMap(maxConcurrent: 3)', () async { + const maxConcurrent = 3; + var activeCount = 0; + + // 1 -> 400 + // 2 -> 300 + // 3 -> 200 + // 4 -> 200 + // 5 -> 300 + // 6 -> 400 + // ----1----6 + // ---2---5 + // --3--4 + // --3214-5-6 + final stream = Stream.fromIterable([1, 2, 3, 4, 5, 6]).flatMap( + (value) { + return Rx.defer(() { + expect(++activeCount, lessThanOrEqualTo(maxConcurrent)); + + final ms = (value <= 3 ? 5 - value : value - 2) * 100; + return Rx.timer(value, Duration(milliseconds: ms)); + }).doOnDone(() => --activeCount); + }, + maxConcurrent: maxConcurrent, + ); + + await expectLater( + stream, emitsInOrder([3, 2, 1, 4, 5, 6, emitsDone])); + }); + + test('Rx.flatMap.cancel', () { + _getStream() + .flatMap(_getOtherStream) + .listen(expectAsync1((data) {}, count: 0)) + .cancel(); + }, timeout: const Timeout(Duration(milliseconds: 200))); + + test('Rx.flatMap(maxConcurrent: 1).cancel', () { + _getStream() + .flatMap(_getOtherStream, maxConcurrent: 1) + .listen(expectAsync1((data) {}, count: 0)) + .cancel(); + }, timeout: const Timeout(Duration(milliseconds: 200))); + + test('Rx.flatMap.take.cancel', () { + _getStream() + .flatMap(_getOtherStream) + .take(1) + .listen(expectAsync1((data) => expect(data, 3), count: 1)); + }, timeout: const Timeout(Duration(milliseconds: 200))); + + test('Rx.flatMap(maxConcurrent: 1).take.cancel', () { + _getStream() + .flatMap(_getOtherStream, maxConcurrent: 1) + .take(1) + .listen(expectAsync1((data) => expect(data, 1), count: 1)); + }, timeout: const Timeout(Duration(milliseconds: 200))); + + test('Rx.flatMap(maxConcurrent: 2).take.cancel', () { + _getStream() + .flatMap(_getOtherStream, maxConcurrent: 2) + .take(1) + .listen(expectAsync1((data) => expect(data, 2), count: 1)); + }, timeout: const Timeout(Duration(milliseconds: 200))); + + test('Rx.flatMap.nullable', () { + nullableTest( + (s) => s.flatMap((v) => Stream.value(v)), + ); + }); +} + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3]); + +Stream _getOtherStream(int value) { + final controller = StreamController(); + + Timer( + // Reverses the order of 1, 2, 3 to 3, 2, 1 by delaying 1, and 2 longer + // than they delay 3 + Duration( + milliseconds: value == 1 + ? 15 + : value == 2 + ? 10 + : 5), () { + controller.add(value); + controller.close(); + }); + + return controller.stream; +} diff --git a/sandbox/reactivex/test/transformers/group_by_test.dart b/sandbox/reactivex/test/transformers/group_by_test.dart new file mode 100644 index 0000000..9b896ea --- /dev/null +++ b/sandbox/reactivex/test/transformers/group_by_test.dart @@ -0,0 +1,312 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +String _toEventOdd(int value) => value == 0 ? 'even' : 'odd'; + +void main() { + test('Rx.groupBy', () async { + await expectLater( + Stream.fromIterable([1, 2, 3, 4]).groupBy((value) => value), + emitsInOrder([ + TypeMatcher>() + .having((stream) => stream.key, 'key', 1), + TypeMatcher>() + .having((stream) => stream.key, 'key', 2), + TypeMatcher>() + .having((stream) => stream.key, 'key', 3), + TypeMatcher>() + .having((stream) => stream.key, 'key', 4), + emitsDone + ])); + + await expectLater( + Stream.fromIterable([1, 2, 3, 4]) + .groupBy((value) => value, durationSelector: (_) => Rx.never()), + emitsInOrder([ + TypeMatcher>() + .having((stream) => stream.key, 'key', 1), + TypeMatcher>() + .having((stream) => stream.key, 'key', 2), + TypeMatcher>() + .having((stream) => stream.key, 'key', 3), + TypeMatcher>() + .having((stream) => stream.key, 'key', 4), + emitsDone + ])); + }); + + test('Rx.groupBy.correctlyEmitsGroupEvents', () async { + await expectLater( + Stream.fromIterable([1, 2, 3, 4]) + .groupBy((value) => _toEventOdd(value % 2)) + .flatMap((stream) => stream.map((event) => {stream.key: event})), + emitsInOrder([ + {'odd': 1}, + {'even': 2}, + {'odd': 3}, + {'even': 4}, + emitsDone + ])); + + await expectLater( + Stream.fromIterable([1, 2, 3, 4]) + .groupBy( + (value) => _toEventOdd(value % 2), + durationSelector: (_) => + Stream.periodic(const Duration(seconds: 1)), + ) + .flatMap((stream) => stream.map((event) => {stream.key: event})), + emitsInOrder([ + {'odd': 1}, + {'even': 2}, + {'odd': 3}, + {'even': 4}, + emitsDone + ])); + }); + + test('Rx.groupBy.correctlyEmitsGroupEvents.alternate', () async { + await expectLater( + Stream.fromIterable([1, 2, 3, 4]) + .groupBy((value) => _toEventOdd(value % 2)) + // fold is called when onDone triggers on the Stream + .map((stream) async => await stream.fold( + {stream.key: []}, + (Map> previous, element) => + previous..[stream.key]?.add(element))), + emitsInOrder([ + { + 'odd': [1, 3] + }, + { + 'even': [2, 4] + }, + emitsDone + ])); + + await expectLater( + Stream.fromIterable([1, 2, 3, 4]) + .groupBy( + (value) => _toEventOdd(value % 2), + durationSelector: (_) => + Stream.periodic(const Duration(seconds: 1)), + ) + // fold is called when onDone triggers on the Stream + .map((stream) async => await stream.fold( + {stream.key: []}, + (Map> previous, element) => + previous..[stream.key]?.add(element))), + emitsInOrder([ + { + 'odd': [1, 3] + }, + { + 'even': [2, 4] + }, + emitsDone + ])); + }); + + test('Rx.groupBy.emittedStreamCallOnDone', () async { + await expectLater( + Stream.fromIterable([1, 2, 3, 4]) + .groupBy((value) => value) + // drain will emit 'done' onDone + .map((stream) async => await stream.drain('done')), + emitsInOrder(['done', 'done', 'done', 'done', emitsDone])); + + await expectLater( + Stream.fromIterable([1, 2, 3, 4]) + .groupBy((value) => value, durationSelector: (_) => Rx.never()) + // drain will emit 'done' onDone + .map((stream) async => await stream.drain('done')), + emitsInOrder(['done', 'done', 'done', 'done', emitsDone])); + }); + + test('Rx.groupBy.asBroadcastStream', () async { + { + final stream = Stream.fromIterable([1, 2, 3, 4]) + .asBroadcastStream() + .groupBy((value) => value); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + } + + { + final stream = + Stream.fromIterable([1, 2, 3, 4]).asBroadcastStream().groupBy( + (value) => value, + durationSelector: (_) => + Stream.periodic(const Duration(seconds: 2)), + ); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + } + }); + + test('Rx.groupBy.pause.resume', () async { + { + var count = 0; + late StreamSubscription subscription; + + subscription = Stream.fromIterable([1, 2, 3, 4]) + .groupBy((value) => value) + .listen(expectAsync1((result) { + count++; + + if (count == 4) { + subscription.cancel(); + } + }, count: 4)); + + subscription + .pause(Future.delayed(const Duration(milliseconds: 100))); + } + + { + var count = 0; + late StreamSubscription subscription; + + subscription = Stream.fromIterable([1, 2, 3, 4]) + .groupBy( + (value) => value, + durationSelector: (_) => Rx.timer(null, const Duration(seconds: 1)), + ) + .listen(expectAsync1((result) { + count++; + + if (count == 4) { + subscription.cancel(); + } + }, count: 4)); + + subscription + .pause(Future.delayed(const Duration(milliseconds: 100))); + } + }); + + test('Rx.groupBy.error.shouldThrow.onError', () async { + { + final streamWithError = + Stream.error(Exception()).groupBy((value) => value); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + } + + { + final streamWithError = Stream.error(Exception()).groupBy( + (value) => value, + durationSelector: (_) => Rx.timer(null, const Duration(seconds: 1)), + ); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + } + }); + + test('Rx.groupBy.error.shouldThrow.onGrouper', () async { + { + final streamWithError = + Stream.fromIterable([1, 2, 3, 4]).groupBy((value) { + throw Exception(); + }); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + }, count: 4)); + } + + { + final streamWithError = Stream.fromIterable([1, 2, 3, 4]).groupBy( + (value) => throw Exception(), + durationSelector: (_) => Rx.timer(null, const Duration(seconds: 1)), + ); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + }, count: 4)); + } + }); + test('Rx.groupBy accidental broadcast', () async { + { + final controller = StreamController(); + + final stream = controller.stream.groupBy((_) => _); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + } + + { + final controller = StreamController(); + + final stream = controller.stream.groupBy( + (_) => _, + durationSelector: (_) => Rx.timer(null, const Duration(seconds: 1)), + ); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + } + }); + + test('Rx.groupBy.durationSelector', () { + final g = [ + '0 -> 1', + '1 -> 1', + '2 -> 1', + '0 -> 2', + '1 -> 2', + '2 -> 2', + ]; + final take = 30; + + final stream = Stream.periodic(const Duration(milliseconds: 100), (i) => i) + .groupBy( + (i) => i % 3, + durationSelector: (i) => + Rx.timer(null, const Duration(milliseconds: 400)), + ) + .flatMap((g) => g + .scan((acc, value, index) => acc + 1, 0) + .map((event) => '${g.key} -> $event')) + .take(take); + + expect( + stream, + emitsInOrder([ + ...List.filled(take ~/ g.length, g).expand((e) => e), + emitsDone, + ]), + ); + }); + + test('Rx.groupBy.nullable', () { + nullableTest>( + (s) => s.groupBy((v) => v), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/ignore_elements_test.dart b/sandbox/reactivex/test/transformers/ignore_elements_test.dart new file mode 100644 index 0000000..9673be5 --- /dev/null +++ b/sandbox/reactivex/test/transformers/ignore_elements_test.dart @@ -0,0 +1,126 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 100), () => controller.add(1)); + Timer(const Duration(milliseconds: 200), () => controller.add(2)); + Timer(const Duration(milliseconds: 300), () => controller.add(3)); + Timer(const Duration(milliseconds: 400), () { + controller.add(4); + controller.close(); + }); + + return controller.stream; +} + +void main() { + test('Rx.ignoreElements', () async { + var hasReceivedEvent = false; + + _getStream().ignoreElements().listen((_) { + hasReceivedEvent = true; + }, + onDone: expectAsync0(() { + expect(hasReceivedEvent, isFalse); + }, count: 1)); + + expect( + _getStream().ignoreElements(), + emitsInOrder([emitsDone]), + ); + }); + + test('Rx.ignoreElements.cast', () { + final ignored = _getStream().ignoreElements(); + + expect(ignored, isA>()); + expect(ignored, isA>()); // ignore: prefer_void_to_null + expect(ignored, isA>()); + expect(ignored, isA>()); + expect(ignored, isA>()); + expect(ignored, isA>()); + + ignored as Stream; // ignore: unnecessary_cast + ignored as Stream; // ignore: unnecessary_cast, prefer_void_to_null + ignored as Stream; // ignore: unnecessary_cast + ignored as Stream; // ignore: unnecessary_cast + ignored as Stream; // ignore: unnecessary_cast + ignored as Stream; // ignore: unnecessary_cast + + expect(true, true); + }); + + test('Rx.ignoreElements.reusable', () async { + final transformer = IgnoreElementsStreamTransformer(); + var hasReceivedEvent = false; + + _getStream().transform(transformer).listen((_) { + hasReceivedEvent = true; + }, + onDone: expectAsync0(() { + expect(hasReceivedEvent, isFalse); + }, count: 1)); + + _getStream().transform(transformer).listen((_) { + hasReceivedEvent = true; + }, + onDone: expectAsync0(() { + expect(hasReceivedEvent, isFalse); + }, count: 1)); + }); + + test('Rx.ignoreElements.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().ignoreElements(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.ignoreElements.pause.resume', () async { + var hasReceivedEvent = false; + + _getStream().ignoreElements().listen((_) { + hasReceivedEvent = true; + }, + onDone: expectAsync0(() { + expect(hasReceivedEvent, isFalse); + }, count: 1)) + ..pause() + ..resume(); + }); + + test('Rx.ignoreElements.error.shouldThrow', () async { + final streamWithError = Stream.error(Exception()).ignoreElements(); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + }, count: 1)); + }); + + test('Rx.ignoreElements accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.ignoreElements(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.ignoreElements.nullable', () { + nullableTest( + (s) => s.ignoreElements(), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/interval_test.dart b/sandbox/reactivex/test/transformers/interval_test.dart new file mode 100644 index 0000000..0fa9315 --- /dev/null +++ b/sandbox/reactivex/test/transformers/interval_test.dart @@ -0,0 +1,87 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [0, 1, 2, 3, 4]); + +void main() { + test('Rx.interval', () async { + const expectedOutput = [0, 1, 2, 3, 4]; + var count = 0, lastInterval = -1; + final stopwatch = Stopwatch()..start(); + + _getStream().interval(const Duration(milliseconds: 1)).listen( + expectAsync1((result) { + expect(expectedOutput[count++], result); + + if (lastInterval != -1) { + expect(stopwatch.elapsedMilliseconds - lastInterval >= 1, true); + } + + lastInterval = stopwatch.elapsedMilliseconds; + }, count: expectedOutput.length), + onDone: stopwatch.stop); + }); + + test('Rx.interval.reusable', () async { + final transformer = + IntervalStreamTransformer(const Duration(milliseconds: 1)); + const expectedOutput = [0, 1, 2, 3, 4]; + var countA = 0, countB = 0; + final stopwatch = Stopwatch()..start(); + + _getStream().transform(transformer).listen( + expectAsync1((result) { + expect(expectedOutput[countA++], result); + }, count: expectedOutput.length), + onDone: stopwatch.stop); + + _getStream().transform(transformer).listen( + expectAsync1((result) { + expect(expectedOutput[countB++], result); + }, count: expectedOutput.length), + onDone: stopwatch.stop); + }); + + test('Rx.interval.asBroadcastStream', () async { + final stream = _getStream() + .asBroadcastStream() + .interval(const Duration(milliseconds: 20)); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.interval.error.shouldThrowA', () async { + final streamWithError = Stream.error(Exception()) + .interval(const Duration(milliseconds: 20)); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.interval accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.interval(const Duration(milliseconds: 10)); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.interval.nullable', () { + nullableTest( + (s) => s.interval(Duration.zero), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/join_test.dart b/sandbox/reactivex/test/transformers/join_test.dart new file mode 100644 index 0000000..008d2b5 --- /dev/null +++ b/sandbox/reactivex/test/transformers/join_test.dart @@ -0,0 +1,11 @@ +import 'dart:async'; + +import 'package:test/test.dart'; + +void main() { + test('Rx.join', () async { + final joined = await Stream.fromIterable(const ['h', 'i']).join('+'); + + await expectLater(joined, 'h+i'); + }); +} diff --git a/sandbox/reactivex/test/transformers/map_not_null_test.dart b/sandbox/reactivex/test/transformers/map_not_null_test.dart new file mode 100644 index 0000000..7f900be --- /dev/null +++ b/sandbox/reactivex/test/transformers/map_not_null_test.dart @@ -0,0 +1,100 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.mapNotNull', () { + expect( + Stream.fromIterable(['1', '2', 'invalid_num', '3', 'invalid_num', '4']) + .mapNotNull(int.tryParse), + emitsInOrder([1, 2, 3, 4])); + + // 0-----1-----2-----3-----...-----8-----9-----| + // 1-----null--3-----null--...-----9-----null--| + // 1--3--5--7--9--| + final stream = Stream.periodic(const Duration(milliseconds: 10), (i) => i) + .take(10) + .transform(MapNotNullStreamTransformer((i) => i.isOdd ? null : i + 1)); + expect(stream, emitsInOrder([1, 3, 5, 7, 9, emitsDone])); + }); + + test('Rx.mapNotNull.shouldThrowA', () { + expect( + Stream.error(Exception()).mapNotNull((_) => true), + emitsError(isA()), + ); + + expect( + Rx.concat([ + Stream.fromIterable([1, 2]), + Stream.error(Exception()), + Stream.value(3), + ]).mapNotNull((i) => i.isEven ? i + 1 : null), + emitsInOrder([ + 3, + emitsError(isException), + emitsDone, + ]), + ); + }); + + test('Rx.mapNotNull.shouldThrowB', () { + expect( + Stream.fromIterable([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).mapNotNull((i) { + if (i == 4) throw Exception(); + return i.isEven ? i + 1 : null; + }), + emitsInOrder([ + 3, + emitsError(isException), + 7, + 9, + 11, + emitsDone, + ]), + ); + }); + + test('Rx.mapNotNull.asBroadcastStream', () { + final stream = Stream.fromIterable([2, 3, 4, 5, 6]) + .mapNotNull((i) => null) + .asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + expect(true, true); + }); + + test('Rx.mapNotNull.singleSubscription', () { + final stream = StreamController().stream.mapNotNull((i) => i); + + expect(stream.isBroadcast, isFalse); + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + }); + + test('Rx.mapNotNull.pause.resume', () async { + final subscription = + Stream.fromIterable([2, 3, 4, 5, 6]).mapNotNull((i) => i).listen(null); + + subscription + ..pause() + ..onData(expectAsync1((data) { + expect(data, 2); + subscription.cancel(); + })) + ..resume(); + }); + + test('Rx.mapNotNull.nullable', () { + nullableTest( + (s) => s.mapNotNull((i) => i), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/map_to_test.dart b/sandbox/reactivex/test/transformers/map_to_test.dart new file mode 100644 index 0000000..6e7febf --- /dev/null +++ b/sandbox/reactivex/test/transformers/map_to_test.dart @@ -0,0 +1,67 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.mapTo', () async { + await expectLater(Rx.range(1, 4).mapTo(true), + emitsInOrder([true, true, true, true, emitsDone])); + }); + + test('Rx.mapTo.shouldThrow', () async { + await expectLater( + Rx.range(1, 4).concatWith([Stream.error(Error())]).mapTo(true), + emitsInOrder([ + true, + true, + true, + true, + emitsError(TypeMatcher()), + emitsDone + ])); + }); + + test('Rx.mapTo.reusable', () async { + final transformer = MapToStreamTransformer(true); + final stream = Rx.range(1, 4).asBroadcastStream(); + + stream.transform(transformer).listen(null); + stream.transform(transformer).listen(null); + + await expectLater(true, true); + }); + + test('Rx.mapTo.pause.resume', () async { + late StreamSubscription subscription; + final stream = Stream.value(1).mapTo(true); + + subscription = stream.listen(expectAsync1((value) { + expect(value, isTrue); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.mapTo accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.mapTo(1); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.mapTo.nullable', () { + nullableTest( + (s) => s.mapTo('String'), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/materialize_test.dart b/sandbox/reactivex/test/transformers/materialize_test.dart new file mode 100644 index 0000000..bcb81c4 --- /dev/null +++ b/sandbox/reactivex/test/transformers/materialize_test.dart @@ -0,0 +1,99 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.materialize.happyPath', () async { + final stream = Stream.value(1); + final notifications = >[]; + + stream.materialize().listen(notifications.add, onDone: expectAsync0(() { + expect(notifications, + [StreamNotification.data(1), StreamNotification.done()]); + })); + }); + + test('Rx.materialize.reusable', () async { + final transformer = MaterializeStreamTransformer(); + final stream = Stream.value(1).asBroadcastStream(); + final notificationsA = >[], + notificationsB = >[]; + + stream.transform(transformer).listen(notificationsA.add, + onDone: expectAsync0(() { + expect(notificationsA, + [StreamNotification.data(1), StreamNotification.done()]); + })); + + stream.transform(transformer).listen(notificationsB.add, + onDone: expectAsync0(() { + expect(notificationsB, + [StreamNotification.data(1), StreamNotification.done()]); + })); + }); + + test('materializeTransformer.happyPath', () async { + final stream = Stream.fromIterable(const [1]); + final notifications = >[]; + + stream + .transform(MaterializeStreamTransformer()) + .listen(notifications.add, onDone: expectAsync0(() { + expect(notifications, + [StreamNotification.data(1), StreamNotification.done()]); + })); + }); + + test('materializeTransformer.sadPath', () async { + final stream = Stream.error(Exception()); + final notifications = >[]; + + stream + .transform(MaterializeStreamTransformer()) + .listen(notifications.add, + onError: expectAsync2((Exception e, StackTrace s) { + // Check to ensure the stream does not come to this point + expect(true, isFalse); + }, count: 0), onDone: expectAsync0(() { + expect(notifications.length, 2); + expect(notifications[0].isError, isTrue); + expect(notifications[1].isDone, isTrue); + })); + }); + + test('materializeTransformer.onPause.onResume', () async { + final stream = Stream.fromIterable(const [1]); + final notifications = >[]; + + stream + .transform(MaterializeStreamTransformer()) + .listen(notifications.add, onDone: expectAsync0(() { + expect(notifications, >[ + StreamNotification.data(1), + StreamNotification.done() + ]); + })) + ..pause() + ..resume(); + }); + + test('Rx.materialize accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.materialize(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.materialize.nullable', () { + nullableTest>( + (s) => s.materialize(), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/max_test.dart b/sandbox/reactivex/test/transformers/max_test.dart new file mode 100644 index 0000000..cacd395 --- /dev/null +++ b/sandbox/reactivex/test/transformers/max_test.dart @@ -0,0 +1,124 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.max', () async { + await expectLater(_getStream().max(), completion(9)); + + expect( + await Stream.fromIterable([1, 2, 3, 3.5]).max(), + 3.5, + ); + }); + + test('Rx.max.empty.shouldThrow', () { + expect( + () => Stream.empty().max(), + throwsStateError, + ); + }); + + test('Rx.max.error.shouldThrow', () { + expect( + () => Stream.value(1).concatWith( + [Stream.error(Exception('This is exception'))], + ).max(), + throwsException, + ); + }); + + test('Rx.max.with.comparator', () async { + await expectLater( + Stream.fromIterable(['one', 'two', 'three']) + .max((a, b) => a.length - b.length), + completion('three'), + ); + }); + + test('Rx.max.errorComparator.shouldThrow', () { + expect( + () => _getStream().max((a, b) => throw Exception()), + throwsException, + ); + }); + + test('Rx.max.without.comparator.Comparable', () async { + const expected = _Class2(3); + expect( + await Stream.fromIterable(const [ + _Class2(0), + expected, + _Class2(2), + _Class2(-1), + _Class2(2), + ]).max(), + expected, + ); + }); + + test('Rx.max.without.comparator.not.Comparable', () async { + expect( + () => Stream.fromIterable(const [ + _Class1(0), + _Class1(3), + _Class1(2), + _Class1(3), + _Class1(2), + ]).max(), + throwsStateError, + ); + }); +} + +class ErrorComparator implements Comparable { + @override + int compareTo(ErrorComparator other) { + throw Exception(); + } +} + +Stream _getStream() => + Stream.fromIterable(const [2, 3, 3, 5, 2, 9, 1, 2, 0]); + +class _Class1 { + final int value; + + const _Class1(this.value); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is _Class1 && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; + + @override + String toString() => '_Class{value: $value}'; +} + +class _Class2 implements Comparable<_Class2> { + final int value; + + const _Class2(this.value); + + @override + String toString() => '_Class2{value: $value}'; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is _Class2 && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; + + @override + int compareTo(_Class2 other) => value.compareTo(other.value); +} diff --git a/sandbox/reactivex/test/transformers/merge_with_test.dart b/sandbox/reactivex/test/transformers/merge_with_test.dart new file mode 100644 index 0000000..ed6efdb --- /dev/null +++ b/sandbox/reactivex/test/transformers/merge_with_test.dart @@ -0,0 +1,62 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.mergeWith', () async { + final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); + final immediateStream = Stream.value(2); + const expected = [2, 1]; + var count = 0; + + delayedStream.mergeWith([immediateStream]).listen(expectAsync1((result) { + expect(result, expected[count++]); + }, count: expected.length)); + }); + + test('Rx.mergeWith accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.mergeWith([Stream.empty()]); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.mergeWith on single stream should stay single ', () async { + final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); + final immediateStream = Stream.value(2); + final expected = [2, 1, emitsDone]; + + final concatenatedStream = delayedStream.mergeWith([immediateStream]); + + expect(concatenatedStream.isBroadcast, isFalse); + expect(concatenatedStream, emitsInOrder(expected)); + }); + + test('Rx.mergeWith on broadcast stream should stay broadcast ', () async { + final delayedStream = + Rx.timer(1, Duration(milliseconds: 10)).asBroadcastStream(); + final immediateStream = Stream.value(2); + final expected = [2, 1, emitsDone]; + + final concatenatedStream = delayedStream.mergeWith([immediateStream]); + + expect(concatenatedStream.isBroadcast, isTrue); + expect(concatenatedStream, emitsInOrder(expected)); + }); + + test('Rx.mergeWith multiple subscriptions on single ', () async { + final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); + final immediateStream = Stream.value(2); + + final concatenatedStream = delayedStream.mergeWith([immediateStream]); + + expect(() => concatenatedStream.listen(null), returnsNormally); + expect(() => concatenatedStream.listen(null), + throwsA(TypeMatcher())); + }); +} diff --git a/sandbox/reactivex/test/transformers/min_test.dart b/sandbox/reactivex/test/transformers/min_test.dart new file mode 100644 index 0000000..6c2c772 --- /dev/null +++ b/sandbox/reactivex/test/transformers/min_test.dart @@ -0,0 +1,117 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.min', () async { + await expectLater(_getStream().min(), completion(0)); + + expect( + await Stream.fromIterable([1, 2, 3, 3.5]).min(), + 1, + ); + }); + + test('Rx.min.empty.shouldThrow', () { + expect( + () => Stream.empty().min(), + throwsStateError, + ); + }); + + test('Rx.min.error.shouldThrow', () { + expect( + () => Stream.value(1).concatWith( + [Stream.error(Exception('This is exception'))], + ).min(), + throwsException, + ); + }); + + test('Rx.min.errorComparator.shouldThrow', () { + expect( + () => _getStream().min((a, b) => throw Exception()), + throwsException, + ); + }); + + test('Rx.min.with.comparator', () async { + await expectLater( + Stream.fromIterable(['one', 'two', 'three']) + .min((a, b) => a.length - b.length), + completion('one'), + ); + }); + + test('Rx.min.without.comparator.Comparable', () async { + const expected = _Class2(-1); + expect( + await Stream.fromIterable(const [ + _Class2(0), + _Class2(3), + _Class2(2), + expected, + _Class2(2), + ]).min(), + expected, + ); + }); + + test('Rx.min.without.comparator.not.Comparable', () async { + expect( + () => Stream.fromIterable(const [ + _Class1(0), + _Class1(3), + _Class1(2), + _Class1(3), + _Class1(2), + ]).min(), + throwsStateError, + ); + }); +} + +Stream _getStream() => + Stream.fromIterable(const [2, 3, 3, 5, 2, 9, 1, 2, 0]); + +class _Class1 { + final int value; + + const _Class1(this.value); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is _Class1 && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; + + @override + String toString() => '_Class{value: $value}'; +} + +class _Class2 implements Comparable<_Class2> { + final int value; + + const _Class2(this.value); + + @override + String toString() => '_Class2{value: $value}'; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is _Class2 && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; + + @override + int compareTo(_Class2 other) => value.compareTo(other.value); +} diff --git a/sandbox/reactivex/test/transformers/on_error_resume_test.dart b/sandbox/reactivex/test/transformers/on_error_resume_test.dart new file mode 100644 index 0000000..ce9253c --- /dev/null +++ b/sandbox/reactivex/test/transformers/on_error_resume_test.dart @@ -0,0 +1,209 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [0, 1, 2, 3]); + +const List expected = [0, 1, 2, 3]; + +void main() { + test('Rx.onErrorResumeNext', () async { + var count = 0; + + Stream.error(Exception()) + .onErrorResumeNext(_getStream()) + .listen(expectAsync1((result) { + expect(result, expected[count++]); + }, count: expected.length)); + }); + + test('Rx.onErrorResume', () async { + var count = 0; + + Stream.error(Exception()) + .onErrorResume((e, st) => _getStream()) + .listen(expectAsync1((result) { + expect(result, expected[count++]); + }, count: expected.length)); + }); + + test('Rx.onErrorResume.correctError', () async { + final exception = Exception(); + + expect( + Stream.error(exception).onErrorResume((e, st) => Stream.value(e)), + emits(exception), + ); + }); + + test('Rx.onErrorResumeNext.asBroadcastStream', () async { + final stream = Stream.error(Exception()) + .onErrorResumeNext(_getStream()) + .asBroadcastStream(); + var countA = 0, countB = 0; + + await expectLater(stream.isBroadcast, isTrue); + + stream.listen(expectAsync1((result) { + expect(result, expected[countA++]); + }, count: expected.length)); + stream.listen(expectAsync1((result) { + expect(result, expected[countB++]); + }, count: expected.length)); + }); + + test('Rx.onErrorResumeNext.error.shouldThrow', () async { + final streamWithError = Stream.error(Exception()) + .onErrorResumeNext(Stream.error(Exception())); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.onErrorResumeNext.pause.resume', () async { + final transformer = + OnErrorResumeStreamTransformer((_, __) => _getStream()); + final exp = const [50] + expected; + late StreamSubscription subscription; + var count = 0; + + subscription = Rx.merge([ + Stream.value(50), + Stream.error(Exception()), + ]).transform(transformer).listen(expectAsync1((result) { + expect(result, exp[count++]); + + if (count == exp.length) { + subscription.cancel(); + } + }, count: exp.length)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.onErrorResumeNext.close', () async { + var count = 0; + + Stream.error(Exception()).onErrorResumeNext(_getStream()).listen( + expectAsync1((result) { + expect(result, expected[count++]); + }, count: expected.length), + onDone: expectAsync0(() { + // The code should reach this point + expect(true, true); + }, count: 1)); + }); + + test('Rx.onErrorResumeNext.noErrors.close', () async { + expect( + Stream.empty().onErrorResumeNext(_getStream()), + emitsDone, + ); + }); + + test('OnErrorResumeStreamTransformer.reusable', () async { + final transformer = OnErrorResumeStreamTransformer( + (_, __) => _getStream().asBroadcastStream()); + var countA = 0, countB = 0; + + Stream.error(Exception()) + .transform(transformer) + .listen(expectAsync1((result) { + expect(result, expected[countA++]); + }, count: expected.length)); + + Stream.error(Exception()) + .transform(transformer) + .listen(expectAsync1((result) { + expect(result, expected[countB++]); + }, count: expected.length)); + }); + + test('Rx.onErrorResume accidental broadcast', () async { + final controller = StreamController(); + + final stream = + controller.stream.onErrorResume((_, __) => Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.onErrorResumeNext accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.onErrorResumeNext(Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.onErrorResume still adds data when Stream emits an error: issue/616', + () { + { + final stream = Rx.concat([ + Stream.value(1), + Stream.error(Exception()), + Stream.fromIterable([2, 3]), + Stream.error(Exception()), + Stream.value(4), + ]).onErrorResume((e, s) => Stream.value(-1)); + expect( + stream, + emitsInOrder([1, -1, 2, 3, -1, 4, emitsDone]), + ); + } + + { + final stream = Rx.concat([ + Stream.value(1), + Stream.error(Exception()), + Stream.fromIterable([2, 3]), + Stream.error(Exception()), + Stream.value(4), + ]).onErrorResumeNext(Stream.value(-1)); + expect( + stream, + emitsInOrder([1, -1, 2, 3, -1, 4, emitsDone]), + ); + } + }); + + test('Rx.onErrorResumeNext with many errors', () { + final stream = Rx.concat([ + Stream.value(1), + Stream.error(Exception()), + Stream.value(2), + Stream.error(StateError('')), + Stream.value(3), + ]).onErrorResume((e, s) { + if (e is Exception) { + return Rx.timer(-1, const Duration(milliseconds: 100)); + } + if (e is StateError) { + return Rx.timer(-2, const Duration(milliseconds: 200)); + } + throw e; + }); + expect( + stream, + emitsInOrder([1, 2, 3, -1, -2, emitsDone]), + ); + }); + + test('Rx.onErrorResumeNext.nullable', () { + nullableTest( + (s) => s.onErrorResumeNext(Stream.empty()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/on_error_return_test.dart b/sandbox/reactivex/test/transformers/on_error_return_test.dart new file mode 100644 index 0000000..d4d0644 --- /dev/null +++ b/sandbox/reactivex/test/transformers/on_error_return_test.dart @@ -0,0 +1,80 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + const num expected = 0; + + test('Rx.onErrorReturn', () async { + Stream.error(Exception()) + .onErrorReturn(0) + .listen(expectAsync1((num result) { + expect(result, expected); + })); + }); + + test('Rx.onErrorReturn.asBroadcastStream', () async { + final stream = + Stream.error(Exception()).onErrorReturn(0).asBroadcastStream(); + + await expectLater(stream.isBroadcast, isTrue); + + stream.listen(expectAsync1((num result) { + expect(result, expected); + })); + + stream.listen(expectAsync1((num result) { + expect(result, expected); + })); + }); + + test('Rx.onErrorReturn.pause.resume', () async { + late StreamSubscription subscription; + + subscription = Stream.error(Exception()) + .onErrorReturn(0) + .listen(expectAsync1((num result) { + expect(result, expected); + + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.onErrorReturn accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.onErrorReturn(1); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.onErrorReturn still adds data when Stream emits an error: issue/616', + () { + final stream = Rx.concat([ + Stream.value(1), + Stream.error(Exception()), + Stream.fromIterable([2, 3]), + Stream.error(Exception()), + Stream.value(4), + ]).onErrorReturn(-1); + expect( + stream, + emitsInOrder([1, -1, 2, 3, -1, 4, emitsDone]), + ); + }); + + test('Rx.onErrorReturn.nullable', () { + nullableTest( + (s) => s.onErrorReturn('String'), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/on_error_return_with_test.dart b/sandbox/reactivex/test/transformers/on_error_return_with_test.dart new file mode 100644 index 0000000..7ffc726 --- /dev/null +++ b/sandbox/reactivex/test/transformers/on_error_return_with_test.dart @@ -0,0 +1,82 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + const num expected = 0; + + test('Rx.onErrorReturnWith', () async { + Stream.error(Exception()) + .onErrorReturnWith((e, _) => e is StateError ? 1 : 0) + .listen(expectAsync1((num result) { + expect(result, expected); + })); + }); + + test('Rx.onErrorReturnWith.asBroadcastStream', () async { + final stream = Stream.error(Exception()) + .onErrorReturnWith((_, __) => 0) + .asBroadcastStream(); + + await expectLater(stream.isBroadcast, isTrue); + + stream.listen(expectAsync1((num result) { + expect(result, expected); + })); + + stream.listen(expectAsync1((num result) { + expect(result, expected); + })); + }); + + test('Rx.onErrorReturnWith.pause.resume', () async { + late StreamSubscription subscription; + + subscription = Stream.error(Exception()) + .onErrorReturnWith((_, __) => 0) + .listen(expectAsync1((num result) { + expect(result, expected); + + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.onErrorReturnWith accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.onErrorReturnWith((_, __) => 1); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test( + 'Rx.onErrorReturnWith still adds data when Stream emits an error: issue/616', + () { + final stream = Rx.concat([ + Stream.value(1), + Stream.error(Exception()), + Stream.fromIterable([2, 3]), + Stream.error(Exception()), + Stream.value(4), + ]).onErrorReturnWith((e, s) => -1); + expect( + stream, + emitsInOrder([1, -1, 2, 3, -1, 4, emitsDone]), + ); + }); + + test('Rx.onErrorReturnWith.nullable', () { + nullableTest( + (s) => s.onErrorReturnWith((e, s) => 'String'), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/scan_test.dart b/sandbox/reactivex/test/transformers/scan_test.dart new file mode 100644 index 0000000..3913017 --- /dev/null +++ b/sandbox/reactivex/test/transformers/scan_test.dart @@ -0,0 +1,85 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.scan', () async { + const expectedOutput = [1, 3, 6, 10]; + var count = 0; + + Stream.fromIterable(const [1, 2, 3, 4]) + .scan((acc, value, index) => acc + value, 0) + .listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.scan.nullable', () { + nullableTest( + (s) => s.scan((acc, value, index) => acc, null), + ); + + expect( + Stream.fromIterable(const [1, 2, 3, 4]) + .scan((acc, value, index) => (acc ?? 0) + value, null) + .cast(), + emitsInOrder([1, 3, 6, 10]), + ); + }); + + test('Rx.scan.reusable', () async { + final transformer = + ScanStreamTransformer((acc, value, index) => acc + value, 0); + const expectedOutput = [1, 3, 6, 10]; + var countA = 0, countB = 0; + + Stream.fromIterable(const [1, 2, 3, 4]) + .transform(transformer) + .listen(expectAsync1((result) { + expect(expectedOutput[countA++], result); + }, count: expectedOutput.length)); + + Stream.fromIterable(const [1, 2, 3, 4]) + .transform(transformer) + .listen(expectAsync1((result) { + expect(expectedOutput[countB++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.scan.asBroadcastStream', () async { + final stream = Stream.fromIterable(const [1, 2, 3, 4]) + .asBroadcastStream() + .scan((acc, value, index) => acc + value, 0); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.scan.error.shouldThrow', () async { + final streamWithError = Stream.fromIterable(const [1, 2, 3, 4]) + .scan((acc, value, index) => throw StateError('oh noes!'), 0); + + streamWithError.listen(null, + onError: expectAsync2((StateError e, StackTrace s) { + expect(e, isStateError); + }, count: 4)); + }); + + test('Rx.scan accidental broadcast', () async { + final controller = StreamController(); + + final stream = + controller.stream.scan((acc, value, index) => acc + value, 0); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); +} diff --git a/sandbox/reactivex/test/transformers/skip_last_test.dart b/sandbox/reactivex/test/transformers/skip_last_test.dart new file mode 100644 index 0000000..6c5349c --- /dev/null +++ b/sandbox/reactivex/test/transformers/skip_last_test.dart @@ -0,0 +1,110 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.skipLast', () async { + final stream = Stream.fromIterable([1, 2, 3, 4, 5]).skipLast(3); + await expectLater( + stream, + emitsInOrder([1, 2, emitsDone]), + ); + }); + + test('Rx.skipLast.zero', () async { + var count = 0; + final values = [1, 2, 3, 4, 5]; + final stream = + Stream.fromIterable(values).doOnData((_) => count++).skipLast(0); + await expectLater( + stream, + emitsInOrder([1, 2, 3, 4, 5, emitsDone]), + ); + expect(count, equals(values.length)); + }); + + test('Rx.skipLast.skipMoreThanLength', () async { + final stream = Stream.fromIterable([1, 2, 3, 4, 5]).skipLast(100); + + await expectLater( + stream, + emits(emitsDone), + ); + }); + + test('Rx.skipLast.emitsError', () async { + final stream = Stream.error(Exception()).skipLast(3); + await expectLater(stream, emitsError(isException)); + }); + + test('Rx.skipLast.countCantBeNegative', () async { + Stream stream() => Stream.fromIterable([1, 2, 3, 4, 5]).skipLast(-1); + expect(stream, throwsA(isArgumentError)); + }); + + test('Rx.skipLast.reusable', () async { + final transformer = SkipLastStreamTransformer(1); + Stream stream() => Stream.fromIterable([1, 2, 3, 4, 5]).skipLast(2); + var valueA = 1, valueB = 1; + + stream().transform(transformer).listen(expectAsync1( + (result) { + expect(result, valueA++); + }, + count: 2, + )); + + stream().transform(transformer).listen(expectAsync1( + (result) { + expect(result, valueB++); + }, + count: 2, + )); + }); + + test('Rx.skipLast.asBroadcastStream', () async { + final stream = + Stream.fromIterable([1, 2, 3, 4, 5]).skipLast(3).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.skipLast.pause.resume', () async { + late StreamSubscription subscription; + + subscription = Stream.fromIterable([1, 2, 3, 4, 5]) + .skipLast(3) + .listen(expectAsync1((data) { + expect(data, 1); + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.skipLast.singleSubscription', () async { + final controller = StreamController(); + + final stream = controller.stream.skipLast(3); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.skipLast.nullable', () { + nullableTest( + (s) => s.skipLast(1), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/skip_until_test.dart b/sandbox/reactivex/test/transformers/skip_until_test.dart new file mode 100644 index 0000000..fa3a97c --- /dev/null +++ b/sandbox/reactivex/test/transformers/skip_until_test.dart @@ -0,0 +1,130 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 100), () => controller.add(1)); + Timer(const Duration(milliseconds: 200), () => controller.add(2)); + Timer(const Duration(milliseconds: 300), () => controller.add(3)); + Timer(const Duration(milliseconds: 400), () { + controller.add(4); + controller.close(); + }); + + return controller.stream; +} + +Stream _getOtherStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 250), () { + controller.add(1); + controller.close(); + }); + + return controller.stream; +} + +void main() { + test('Rx.skipUntil', () async { + const expectedOutput = [3, 4]; + var count = 0; + + _getStream().skipUntil(_getOtherStream()).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.skipUntil.shouldClose', () async { + _getStream() + .skipUntil(Stream.empty()) + .listen(null, onDone: expectAsync0(() => expect(true, isTrue))); + }); + + test('Rx.skipUntil.reusable', () async { + final transformer = SkipUntilStreamTransformer( + _getOtherStream().asBroadcastStream()); + const expectedOutput = [3, 4]; + var countA = 0, countB = 0; + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countA++], result); + }, count: expectedOutput.length)); + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countB++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.skipUntil.asBroadcastStream', () async { + final stream = _getStream() + .asBroadcastStream() + .skipUntil(_getOtherStream().asBroadcastStream()); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.skipUntil.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).skipUntil(_getOtherStream()); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.skipUntil.error.shouldThrowB', () async { + final streamWithError = + Stream.value(1).skipUntil(Stream.error(Exception('Oh noes!'))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.skipUntil.pause.resume', () async { + late StreamSubscription subscription; + const expectedOutput = [3, 4]; + var count = 0; + + subscription = + _getStream().skipUntil(_getOtherStream()).listen(expectAsync1((result) { + expect(result, expectedOutput[count++]); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.skipUntil accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.skipUntil(Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.skipUntil.nullable', () { + nullableTest( + (s) => s.skipUntil(Stream.empty()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/start_with_error_test.dart b/sandbox/reactivex/test/transformers/start_with_error_test.dart new file mode 100644 index 0000000..7a61c09 --- /dev/null +++ b/sandbox/reactivex/test/transformers/start_with_error_test.dart @@ -0,0 +1,86 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/src/transformers/start_with_error.dart'; +import 'package:test/test.dart'; + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); + +void main() { + test('Rx.startWithError', () async { + final transformer = StartWithErrorStreamTransformer( + Exception(), StackTrace.fromString('oh noes!')); + const expectedOutput = [1, 2, 3, 4]; + + await expectLater(_getStream().transform(transformer), + emitsInOrder([emitsError(isException), ...expectedOutput])); + }); + + test('Rx.startWithError.reusable', () async { + final transformer = StartWithErrorStreamTransformer( + Exception(), StackTrace.fromString('oh noes!')); + const expectedOutput = [1, 2, 3, 4]; + + await expectLater(_getStream().transform(transformer), + emitsInOrder([emitsError(isException), ...expectedOutput])); + await expectLater(_getStream().transform(transformer), + emitsInOrder([emitsError(isException), ...expectedOutput])); + }); + + test('Rx.startWithError.asBroadcastStream', () async { + final transformer = StartWithErrorStreamTransformer( + Exception(), StackTrace.fromString('oh noes!')); + final stream = _getStream().asBroadcastStream().transform(transformer); + const expectedOutput = [1, 2, 3, 4]; + + // listen twice on same stream + await expectLater( + stream, + emitsInOrder( + [emitsError(isException), ...expectedOutput, emitsDone])); + await expectLater(stream, emitsDone); + }); + + test('Rx.startWithError.error.shouldThrow', () async { + final transformer = StartWithErrorStreamTransformer( + Exception(), StackTrace.fromString('oh noes!')); + final streamWithError = + Stream.error(Exception()).transform(transformer); + + await expectLater(streamWithError, emitsError(isException)); + }); + + test('Rx.startWithError.pause.resume', () async { + final transformer = StartWithErrorStreamTransformer( + Exception(), StackTrace.fromString('oh noes!')); + const expectedOutput = [1, 2, 3, 4]; + var count = 0; + + late StreamSubscription subscription; + subscription = _getStream().transform(transformer).listen( + expectAsync1((result) { + expect(expectedOutput[count++], result); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length), + onError: (Object e, StackTrace s) => expect(e, isException)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.startWithError accidental broadcast', () async { + final transformer = StartWithErrorStreamTransformer( + Exception(), StackTrace.fromString('oh noes!')); + final controller = StreamController(); + + final stream = controller.stream.transform(transformer); + + stream.listen(null, onError: (Object e, StackTrace s) {}); + expect(() => stream.listen(null, onError: (Object e, StackTrace s) {}), + throwsStateError); + + controller.add(1); + }); +} diff --git a/sandbox/reactivex/test/transformers/start_with_many_test.dart b/sandbox/reactivex/test/transformers/start_with_many_test.dart new file mode 100644 index 0000000..7159e3b --- /dev/null +++ b/sandbox/reactivex/test/transformers/start_with_many_test.dart @@ -0,0 +1,87 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); + +void main() { + test('Rx.startWithMany', () async { + const expectedOutput = [5, 6, 1, 2, 3, 4]; + var count = 0; + + _getStream().startWithMany(const [5, 6]).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.startWithMany.reusable', () async { + final transformer = StartWithManyStreamTransformer(const [5, 6]); + const expectedOutput = [5, 6, 1, 2, 3, 4]; + var countA = 0, countB = 0; + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countA++], result); + }, count: expectedOutput.length)); + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countB++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.startWithMany.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().startWithMany(const [5, 6]); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.startWithMany.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).startWithMany(const [5, 6]); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.startWithMany.pause.resume', () async { + const expectedOutput = [5, 6, 1, 2, 3, 4]; + var count = 0; + + late StreamSubscription subscription; + subscription = + _getStream().startWithMany(const [5, 6]).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + test('Rx.startWithMany accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.startWithMany(const [1, 2, 3]); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.startWithMany.nullable', () { + nullableTest( + (s) => s.startWithMany([]), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/start_with_test.dart b/sandbox/reactivex/test/transformers/start_with_test.dart new file mode 100644 index 0000000..235b6ff --- /dev/null +++ b/sandbox/reactivex/test/transformers/start_with_test.dart @@ -0,0 +1,102 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable(const [1, 2, 3, 4]); + +void main() { + test('Rx.startWith', () async { + const expectedOutput = [5, 1, 2, 3, 4]; + var count = 0; + + _getStream().startWith(5).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.startWith.reusable', () async { + final transformer = StartWithStreamTransformer(5); + const expectedOutput = [5, 1, 2, 3, 4]; + var countA = 0, countB = 0; + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countA++], result); + }, count: expectedOutput.length)); + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countB++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.startWith.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().startWith(5); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.startWith.error.shouldThrow', () async { + final streamWithError = Stream.error(Exception()).startWith(5); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.startWith.pause.resume', () async { + const expectedOutput = [5, 1, 2, 3, 4]; + var count = 0; + + late StreamSubscription subscription; + subscription = _getStream().startWith(5).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.startWith accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.startWith(1); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test( + 'Rx.startWith broadcast stream should not startWith on multiple subscribers', + () async { + final controller = StreamController.broadcast(); + + final stream = controller.stream.startWith(1); + + await controller.close(); + + stream.listen(null); + + await Future.delayed(const Duration(milliseconds: 10)); + + await expectLater(stream, emits(emitsDone)); + }, skip: true); + + test('Rx.startWith.nullable', () { + nullableTest( + (s) => s.startWith('String'), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/switch_if_empty_test.dart b/sandbox/reactivex/test/transformers/switch_if_empty_test.dart new file mode 100644 index 0000000..c1f15be --- /dev/null +++ b/sandbox/reactivex/test/transformers/switch_if_empty_test.dart @@ -0,0 +1,96 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.switchIfEmpty.whenEmpty', () async { + expect( + Stream.empty().switchIfEmpty(Stream.value(1)), + emitsInOrder([1, emitsDone]), + ); + }); + + test('Rx.initial.completes', () async { + expect( + Stream.value(99).switchIfEmpty(Stream.value(1)), + emitsInOrder([99, emitsDone]), + ); + }); + + test('Rx.switchIfEmpty.reusable', () async { + final transformer = SwitchIfEmptyStreamTransformer( + Stream.value(true).asBroadcastStream()); + + Stream.empty().transform(transformer).listen(expectAsync1((result) { + expect(result, true); + }, count: 1)); + + Stream.empty().transform(transformer).listen(expectAsync1((result) { + expect(result, true); + }, count: 1)); + }); + + test('Rx.switchIfEmpty.whenNotEmpty', () async { + Stream.value(false) + .switchIfEmpty(Stream.value(true)) + .listen(expectAsync1((result) { + expect(result, false); + }, count: 1)); + }); + + test('Rx.switchIfEmpty.asBroadcastStream', () async { + final stream = + Stream.empty().switchIfEmpty(Stream.value(1)).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.switchIfEmpty.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).switchIfEmpty(Stream.value(1)); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.switchIfEmpty.pause.resume', () async { + late StreamSubscription subscription; + final stream = Stream.empty().switchIfEmpty(Stream.value(1)); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.switchIfEmpty accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.switchIfEmpty(Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.switchIfEmpty.nullable', () { + nullableTest( + (s) => s.switchIfEmpty(Stream.value('String')), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/switch_map_test.dart b/sandbox/reactivex/test/transformers/switch_map_test.dart new file mode 100644 index 0000000..cb86396 --- /dev/null +++ b/sandbox/reactivex/test/transformers/switch_map_test.dart @@ -0,0 +1,359 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 10), () => controller.add(1)); + Timer(const Duration(milliseconds: 20), () => controller.add(2)); + Timer(const Duration(milliseconds: 30), () => controller.add(3)); + Timer(const Duration(milliseconds: 40), () { + controller.add(4); + controller.close(); + }); + + return controller.stream; +} + +Stream _getOtherStream(int value) { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 15), () => controller.add(value + 1)); + Timer(const Duration(milliseconds: 25), () => controller.add(value + 2)); + Timer(const Duration(milliseconds: 35), () => controller.add(value + 3)); + Timer(const Duration(milliseconds: 45), () { + controller.add(value + 4); + controller.close(); + }); + + return controller.stream; +} + +Stream range() => + Stream.fromIterable(const [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + +void main() { + test('Rx.switchMap', () async { + const expectedOutput = [5, 6, 7, 8]; + var count = 0; + + _getStream().switchMap(_getOtherStream).listen(expectAsync1((result) { + expect(result, expectedOutput[count++]); + }, count: expectedOutput.length)); + }); + + test('Rx.switchMap.reusable', () async { + final transformer = SwitchMapStreamTransformer(_getOtherStream); + const expectedOutput = [5, 6, 7, 8]; + var countA = 0, countB = 0; + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(result, expectedOutput[countA++]); + }, count: expectedOutput.length)); + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(result, expectedOutput[countB++]); + }, count: expectedOutput.length)); + }); + + test('Rx.switchMap.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().switchMap(_getOtherStream); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.switchMap.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).switchMap(_getOtherStream); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.switchMap.error.shouldThrowB', () async { + final streamWithError = Stream.value(1).switchMap( + (_) => Stream.error(Exception('Catch me if you can!'))); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.switchMap.error.shouldThrowC', () async { + final streamWithError = Stream.value(1).switchMap((_) { + throw Exception('oh noes!'); + }); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.switchMap.pause.resume', () async { + late StreamSubscription subscription; + final stream = Stream.value(0).switchMap((_) => Stream.value(1)); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.switchMap stream close after switch', () async { + final controller = StreamController(); + final list = controller.stream + .switchMap((it) => Stream.fromIterable([it, it])) + .toList(); + + controller.add(1); + await Future.delayed(Duration(microseconds: 1)); + controller.add(2); + + await controller.close(); + expect(await list, [1, 1, 2, 2]); + }); + + test('Rx.switchMap accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.switchMap((_) => Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.switchMap closes after the last inner Stream closed - issue/511', + () async { + final outer = StreamController(); + final inner = BehaviorSubject.seeded(false); + final stream = outer.stream.switchMap((_) => inner.stream); + + expect(stream, emitsThrough(emitsDone)); + + outer.add(true); + await Future.delayed(Duration.zero); + await inner.close(); + await outer.close(); + }); + + test('Rx.switchMap every subscription triggers a listen on the root Stream', + () async { + var count = 0; + final controller = StreamController.broadcast(); + final root = + OnSubscriptionTriggerableStream(controller.stream, () => count++); + final stream = root.switchMap((event) => Stream.value(event)); + + stream.listen((event) {}); + stream.listen((event) {}); + + expect(count, 2); + + await controller.close(); + }); + + test('Rx.switchMap.nullable', () { + nullableTest( + (s) => s.switchMap((v) => Stream.value(v)), + ); + }); + + test( + 'Rx.switchMap pauses subscription when cancelling inner subscription, then resume', + () async { + var isController1Cancelled = false; + final cancelCompleter1 = Completer.sync(); + final controller1 = StreamController() + ..add(0) + ..add(1) + ..onCancel = () async { + await Future.delayed(const Duration(milliseconds: 10)); + await cancelCompleter1.future; + isController1Cancelled = true; + }; + + final controller2 = StreamController() + ..add(2) + ..add(3) + ..onListen = () { + expect( + isController1Cancelled, + true, + reason: + 'controller1 should be cancelled before controller2 is listened to', + ); + }; + + final controller = StreamController>() + ..add(controller1); + final stream = controller.stream.switchMap((c) => c.stream); + + var expected = 0; + stream.listen( + expectAsync1( + (v) async { + expect(v, expected++); + + if (v == 1) { + // switch to controller2.stream + controller.add(controller2); + + await Future.delayed(const Duration(milliseconds: 10)); + cancelCompleter1.complete(null); + } + }, + count: 4, + ), + ); + }, + ); + + test('Rx.switchMap forwards errors from the cancel()', () { + var isController1Cancelled = false; + + final controller1 = StreamController() + ..add(0) + ..add(1) + ..onCancel = () async { + await Future.delayed(const Duration(milliseconds: 10)); + isController1Cancelled = true; + throw Exception('cancel error'); + }; + + final controller2 = StreamController() + ..add(2) + ..add(3) + ..onListen = () { + expect( + isController1Cancelled, + true, + reason: + 'controller1 should be cancelled before controller2 is listened to', + ); + }; + + final controller = StreamController>() + ..add(controller1); + final stream = controller.stream.switchMap((c) => c.stream); + + var expected = 0; + stream.listen( + expectAsync1( + (v) async { + expect(v, expected++); + + if (v == 1) { + // switch to controller2.stream + controller.add(controller2); + } + }, + count: 4, + ), + onError: expectAsync1( + (Object error) => expect(error, isException), + count: 1, + ), + ); + }); + + test( + 'Rx.switchMap pauses the next inner StreamSubscription when pausing while cancelling the previous inner Stream', + () { + var isController1Cancelled = false; + final cancelCompleter1 = Completer.sync(); + final controller1 = StreamController() + ..add(0) + ..add(1) + ..onCancel = () async { + await Future.delayed(const Duration(milliseconds: 10)); + await cancelCompleter1.future; + isController1Cancelled = true; + }; + + final controller2 = StreamController() + ..add(2) + ..add(3) + ..onListen = () { + expect( + isController1Cancelled, + true, + reason: + 'controller1 should be cancelled before controller2 is listened to', + ); + }; + + final controller = StreamController>() + ..add(controller1); + final stream = controller.stream.switchMap((c) => c.stream); + + var expected = 0; + late StreamSubscription subscription; + subscription = stream.listen( + expectAsync1( + (v) async { + expect(v, expected++); + + if (v == 1) { + // switch to controller2.stream + controller.add(controller2); + + await Future.delayed(const Duration(milliseconds: 10)); + + // pauses the subscription while cancelling the controller1 + subscription.pause(); + + // let the cancellation of controller1 complete + cancelCompleter1.complete(null); + + // make sure the controller2.stream is added to the controller + await pumpEventQueue(); + + // controller2.stream should be paused + expect(controller2.isPaused, true); + + // resume the subscription to continue the rest of the stream + subscription.resume(); + } + }, + count: 4, + ), + ); + }, + ); +} + +class OnSubscriptionTriggerableStream extends Stream { + final Stream inner; + final void Function() onSubscribe; + + OnSubscriptionTriggerableStream(this.inner, this.onSubscribe); + + @override + bool get isBroadcast => inner.isBroadcast; + + @override + StreamSubscription listen(void Function(T event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + onSubscribe(); + return inner.listen(onData, + onError: onError, onDone: onDone, cancelOnError: cancelOnError); + } +} diff --git a/sandbox/reactivex/test/transformers/take_last_test.dart b/sandbox/reactivex/test/transformers/take_last_test.dart new file mode 100644 index 0000000..64474c6 --- /dev/null +++ b/sandbox/reactivex/test/transformers/take_last_test.dart @@ -0,0 +1,109 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.takeLast', () async { + final stream = Stream.fromIterable([1, 2, 3, 4, 5]).takeLast(3); + await expectLater( + stream, + emitsInOrder([3, 4, 5, emitsDone]), + ); + }); + + test('Rx.takeLast.zero', () async { + var count = 0; + final values = [1, 2, 3, 4, 5]; + final stream = + Stream.fromIterable(values).doOnData((_) => count++).takeLast(0); + await expectLater( + stream, + emitsInOrder([emitsDone]), + ); + expect(count, equals(values.length)); + }); + + test('Rx.takeLast.emitsError', () async { + final stream = Stream.error(Exception()).takeLast(3); + await expectLater(stream, emitsError(isException)); + }); + + test('Rx.takeLast.countCantBeNegative', () async { + Stream stream() => Stream.fromIterable([1, 2, 3, 4, 5]).takeLast(-1); + expect(stream, throwsA(isArgumentError)); + }); + + test('Rx.takeLast.reusable', () async { + final transformer = TakeLastStreamTransformer(3); + Stream stream() => Stream.fromIterable([1, 2, 3, 4, 5]).takeLast(3); + var valueA = 3, valueB = 3; + + stream().transform(transformer).listen(expectAsync1((result) { + expect(result, valueA++); + }, count: 3)); + + stream().transform(transformer).listen(expectAsync1((result) { + expect(result, valueB++); + }, count: 3)); + }); + + test('Rx.takeLast.asBroadcastStream', () async { + final stream = + Stream.fromIterable([1, 2, 3, 4, 5]).takeLast(3).asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('Rx.takeLast.pause.resume', () async { + late StreamSubscription subscription; + + subscription = Stream.fromIterable([1, 2, 3, 4, 5]) + .takeLast(3) + .listen(expectAsync1((data) { + expect(data, 3); + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.takeLast.singleSubscription', () async { + final controller = StreamController(); + + final stream = controller.stream.takeLast(3); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.takeLast.cancel', () { + final subscription = + Stream.fromIterable([1, 2, 3, 4, 5]).takeLast(3).listen(null); + subscription.onData( + expectAsync1( + (event) { + subscription.cancel(); + expect(event, 3); + }, + count: 1, + ), + ); + }, timeout: const Timeout(Duration(seconds: 1))); + + test('Rx.takeLast.nullable', () { + nullableTest( + (s) => s.takeLast(1), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/take_until_test.dart b/sandbox/reactivex/test/transformers/take_until_test.dart new file mode 100644 index 0000000..23efaf2 --- /dev/null +++ b/sandbox/reactivex/test/transformers/take_until_test.dart @@ -0,0 +1,120 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 100), () => controller.add(1)); + Timer(const Duration(milliseconds: 200), () => controller.add(2)); + Timer(const Duration(milliseconds: 300), () => controller.add(3)); + Timer(const Duration(milliseconds: 400), () { + controller.add(4); + controller.close(); + }); + + return controller.stream; +} + +Stream _getOtherStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 250), () { + controller.add(1); + controller.close(); + }); + + return controller.stream; +} + +void main() { + test('Rx.takeUntil', () async { + const expectedOutput = [1, 2]; + var count = 0; + + _getStream().takeUntil(_getOtherStream()).listen(expectAsync1((result) { + expect(expectedOutput[count++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.takeUntil.shouldClose', () async { + _getStream() + .takeUntil(Stream.empty()) + .listen(null, onDone: expectAsync0(() => expect(true, isTrue))); + }); + + test('Rx.takeUntil.reusable', () async { + final transformer = TakeUntilStreamTransformer( + _getOtherStream().asBroadcastStream()); + const expectedOutput = [1, 2]; + var countA = 0, countB = 0; + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countA++], result); + }, count: expectedOutput.length)); + + _getStream().transform(transformer).listen(expectAsync1((result) { + expect(expectedOutput[countB++], result); + }, count: expectedOutput.length)); + }); + + test('Rx.takeUntil.asBroadcastStream', () async { + final stream = _getStream() + .asBroadcastStream() + .takeUntil(_getOtherStream().asBroadcastStream()); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.takeUntil.error.shouldThrowA', () async { + final streamWithError = + Stream.error(Exception()).takeUntil(_getOtherStream()); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.takeUntil.pause.resume', () async { + late StreamSubscription subscription; + const expectedOutput = [1, 2]; + var count = 0; + + subscription = + _getStream().takeUntil(_getOtherStream()).listen(expectAsync1((result) { + expect(result, expectedOutput[count++]); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.takeUntil accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.takeUntil(Stream.empty()); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.takeUntil.nullable', () { + nullableTest( + (s) => s.takeUntil(Stream.empty()), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/take_while_inclusive_test.dart b/sandbox/reactivex/test/transformers/take_while_inclusive_test.dart new file mode 100644 index 0000000..7b2f774 --- /dev/null +++ b/sandbox/reactivex/test/transformers/take_while_inclusive_test.dart @@ -0,0 +1,92 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.takeWhileInclusive', () async { + final stream = Stream.fromIterable([2, 3, 4, 5, 6, 1, 2, 3]) + .takeWhileInclusive((i) => i < 4); + await expectLater( + stream, + emitsInOrder([2, 3, 4, emitsDone]), + ); + }); + + test('Rx.takeWhileInclusive.shouldClose', () async { + final stream = + Stream.fromIterable([2, 3, 4, 5, 6, 1, 2, 3]).takeWhileInclusive((i) { + if (i == 4) { + throw Exception(); + } else { + return true; + } + }); + await expectLater( + stream, + emitsInOrder( + [ + 2, + 3, + emitsError(isA()), + emitsDone, + ], + ), + ); + }); + + test('Rx.takeWhileInclusive.asBroadcastStream', () async { + final stream = Stream.fromIterable([2, 3, 4, 5, 6]) + .takeWhileInclusive((i) => i < 4) + .asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + await expectLater(true, true); + }); + + test('Rx.takeWhileInclusive.shouldThrowB', () async { + final stream = + Stream.error(Exception()).takeWhileInclusive((_) => true); + await expectLater( + stream, + emitsError(isA()), + ); + }); + + test('Rx.takeWhileInclusive.pause.resume', () async { + late StreamSubscription subscription; + + subscription = Stream.fromIterable([2, 3, 4, 5, 6]) + .takeWhileInclusive((i) => i < 4) + .listen(expectAsync1((data) { + expect(data, 2); + subscription.cancel(); + })); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.takeWhileInclusive accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.takeWhileInclusive((_) => true); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.takeWhileInclusive.nullable', () { + nullableTest( + (s) => s.takeWhileInclusive((_) => true), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/time_interval_test.dart b/sandbox/reactivex/test/transformers/time_interval_test.dart new file mode 100644 index 0000000..9c1d1f4 --- /dev/null +++ b/sandbox/reactivex/test/transformers/time_interval_test.dart @@ -0,0 +1,112 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() => Stream.fromIterable([0, 1, 2]); + +void main() { + test('Rx.timeInterval', () async { + const expectedOutput = [0, 1, 2]; + var count = 0; + + _getStream() + .interval(const Duration(milliseconds: 1)) + .timeInterval() + .listen(expectAsync1((result) { + expect(expectedOutput[count++], result.value); + + expect( + result.interval.inMicroseconds >= 1000 /* microseconds! */, true); + }, count: expectedOutput.length)); + }); + + test('Rx.timeInterval.reusable', () async { + final transformer = TimeIntervalStreamTransformer(); + const expectedOutput = [0, 1, 2]; + var countA = 0, countB = 0; + + _getStream() + .interval(const Duration(milliseconds: 1)) + .transform(transformer) + .listen(expectAsync1((result) { + expect(expectedOutput[countA++], result.value); + + expect( + result.interval.inMicroseconds >= 1000 /* microseconds! */, true); + }, count: expectedOutput.length)); + + _getStream() + .interval(const Duration(milliseconds: 1)) + .transform(transformer) + .listen(expectAsync1((result) { + expect(expectedOutput[countB++], result.value); + + expect( + result.interval.inMicroseconds >= 1000 /* microseconds! */, true); + }, count: expectedOutput.length)); + }); + + test('Rx.timeInterval.asBroadcastStream', () async { + final stream = _getStream() + .asBroadcastStream() + .interval(const Duration(milliseconds: 1)) + .timeInterval(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.timeInterval.error.shouldThrow', () async { + final streamWithError = Stream.error(Exception()) + .interval(const Duration(milliseconds: 1)) + .timeInterval(); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.timeInterval.pause.resume', () async { + late StreamSubscription> subscription; + const expectedOutput = [0, 1, 2]; + var count = 0; + + subscription = _getStream() + .interval(const Duration(milliseconds: 1)) + .timeInterval() + .listen(expectAsync1((result) { + expect(result.value, expectedOutput[count++]); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.timeInterval accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.timeInterval(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.timeInterval.nullable', () { + nullableTest>( + (s) => s.timeInterval(), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/timeout_test.dart b/sandbox/reactivex/test/transformers/timeout_test.dart new file mode 100644 index 0000000..5460b1d --- /dev/null +++ b/sandbox/reactivex/test/transformers/timeout_test.dart @@ -0,0 +1,19 @@ +import 'dart:async'; + +import 'package:test/test.dart'; + +void main() { + test('Rx.timeout', () async { + late StreamSubscription subscription; + + final stream = Stream.fromFuture( + Future.delayed(Duration(milliseconds: 30), () => 1)) + .timeout(Duration(milliseconds: 1)); + + subscription = stream.listen((_) {}, + onError: expectAsync2((Object e, StackTrace s) { + expect(e is TimeoutException, isTrue); + subscription.cancel(); + }, count: 1)); + }); +} diff --git a/sandbox/reactivex/test/transformers/timestamp_test.dart b/sandbox/reactivex/test/transformers/timestamp_test.dart new file mode 100644 index 0000000..0a4cccf --- /dev/null +++ b/sandbox/reactivex/test/transformers/timestamp_test.dart @@ -0,0 +1,105 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.Rx.timestamp', () async { + const expected = [1, 2, 3]; + var count = 0; + + Stream.fromIterable(const [1, 2, 3]) + .timestamp() + .listen(expectAsync1((result) { + expect(result.value, expected[count++]); + }, count: expected.length)); + }); + + test('Rx.Rx.timestamp.reusable', () async { + final transformer = TimestampStreamTransformer(); + const expected = [1, 2, 3]; + var countA = 0, countB = 0; + + Stream.fromIterable(const [1, 2, 3]) + .transform(transformer) + .listen(expectAsync1((result) { + expect(result.value, expected[countA++]); + }, count: expected.length)); + + Stream.fromIterable(const [1, 2, 3]) + .transform(transformer) + .listen(expectAsync1((result) { + expect(result.value, expected[countB++]); + }, count: expected.length)); + }); + + test('timestampTransformer', () async { + const expected = [1, 2, 3]; + var count = 0; + + Stream.fromIterable(const [1, 2, 3]) + .transform(TimestampStreamTransformer()) + .listen(expectAsync1((result) { + expect(result.value, expected[count++]); + }, count: expected.length)); + }); + + test('timestampTransformer.asBroadcastStream', () async { + final stream = Stream.fromIterable(const [1, 2, 3]) + .transform(TimestampStreamTransformer()) + .asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(stream.isBroadcast, isTrue); + }); + + test('timestampTransformer.error.shouldThrow', () async { + final streamWithError = + Stream.error(Exception()).transform(TimestampStreamTransformer()); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('timestampTransformer.pause.resume', () async { + final stream = Stream.fromIterable(const [1, 2, 3]) + .transform(TimestampStreamTransformer()); + const expected = [1, 2, 3]; + late StreamSubscription> subscription; + var count = 0; + + subscription = stream.listen(expectAsync1((result) { + expect(result.value, expected[count++]); + + if (count == expected.length) { + subscription.cancel(); + } + }, count: expected.length)); + + subscription.pause(); + subscription.resume(); + }); + test('Rx.timestamp accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.timestamp(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.timestamp.nullable', () { + nullableTest>( + (s) => s.timestamp(), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/where_not_null_test.dart b/sandbox/reactivex/test/transformers/where_not_null_test.dart new file mode 100644 index 0000000..fd9c77e --- /dev/null +++ b/sandbox/reactivex/test/transformers/where_not_null_test.dart @@ -0,0 +1,87 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +void main() { + test('Rx.whereNotNull', () { + { + final notNull = Stream.fromIterable([1, 2, 3, 4]).whereNotNull(); + + expect(notNull, isA>()); + expect(notNull, emitsInOrder([1, 2, 3, 4])); + } + + { + final notNull = Stream.fromIterable([1, 2, null, 3, 4, null]) + .transform(WhereNotNullStreamTransformer()); + + expect(notNull, isA>()); + expect(notNull, emitsInOrder([1, 2, 3, 4])); + } + }); + + test('Rx.whereNotNull.shouldThrow', () { + expect( + Stream.error(Exception()).whereNotNull(), + emitsError(isA()), + ); + + expect( + Rx.concat([ + Stream.fromIterable([1, 2, null]), + Stream.error(Exception()), + Stream.value(3), + ]).whereNotNull(), + emitsInOrder([ + 1, + 2, + emitsError(isException), + 3, + emitsDone, + ]), + ); + }); + + test('Rx.whereNotNull.asBroadcastStream', () { + final stream = + Stream.fromIterable([1, 2, null]).whereNotNull().asBroadcastStream(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + // code should reach here + expect(true, true); + }); + + test('Rx.whereNotNull.singleSubscription', () { + final stream = StreamController().stream.whereNotNull(); + + expect(stream.isBroadcast, isFalse); + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + }); + + test('Rx.whereNotNull.pause.resume', () async { + final subscription = Stream.fromIterable([null, 2, 3, null, 4, 5, 6]) + .whereNotNull() + .listen(null); + + subscription + ..pause() + ..onData(expectAsync1((data) { + expect(data, 2); + subscription.cancel(); + })) + ..resume(); + }); + + test('Rx.whereNotNull.nullable', () { + nullableTest( + (s) => s.whereNotNull(), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/where_type_test.dart b/sandbox/reactivex/test/transformers/where_type_test.dart new file mode 100644 index 0000000..2eb0158 --- /dev/null +++ b/sandbox/reactivex/test/transformers/where_type_test.dart @@ -0,0 +1,94 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +Stream _getStream() { + final controller = StreamController(); + + Timer(const Duration(milliseconds: 100), () => controller.add(1)); + Timer(const Duration(milliseconds: 200), () => controller.add('2')); + Timer( + const Duration(milliseconds: 300), () => controller.add(const {'3': 3})); + Timer(const Duration(milliseconds: 400), () { + controller.add(const {'4': '4'}); + }); + Timer(const Duration(milliseconds: 500), () { + controller.add(5.0); + controller.close(); + }); + + return controller.stream; +} + +void main() { + test('Rx.whereType', () async { + _getStream().whereType>().listen(expectAsync1((result) { + expect(result, isMap); + }, count: 1)); + }); + + test('Rx.whereType.polymorphism', () async { + _getStream().whereType().listen(expectAsync1((Object result) { + expect(result is num, true); + }, count: 2)); + }); + + test('Rx.whereType.null.values', () async { + await expectLater( + Stream.fromIterable([null, 1, null, 'two', 3]).whereType(), + emitsInOrder(const ['two'])); + }); + + test('Rx.whereType.asBroadcastStream', () async { + final stream = _getStream().asBroadcastStream().whereType(); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + // code should reach here + await expectLater(true, true); + }); + + test('Rx.whereType.error.shouldThrow', () async { + final streamWithError = Stream.error(Exception()).whereType(); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.whereType.pause.resume', () async { + late StreamSubscription subscription; + final stream = Stream.value(1).whereType(); + + subscription = stream.listen(expectAsync1((value) { + expect(value, 1); + + subscription.cancel(); + }, count: 1)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.whereType accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream.whereType(); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.whereType.nullable', () { + nullableTest( + (s) => s.whereType(), + ); + }); +} diff --git a/sandbox/reactivex/test/transformers/with_latest_from_test.dart b/sandbox/reactivex/test/transformers/with_latest_from_test.dart new file mode 100644 index 0000000..5191440 --- /dev/null +++ b/sandbox/reactivex/test/transformers/with_latest_from_test.dart @@ -0,0 +1,541 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +import '../utils.dart'; + +/// creates 5 Streams, deferred from a source Stream, so that they all emit +/// under the same Timer interval. +/// before, tests could fail, since we created 5 separate Streams with each +/// using their own Timer. +List> _createTestStreams() { + /// creates streams that emit after a certain amount of milliseconds, + /// the List of intervals (in ms) + const intervals = [22, 50, 30, 40, 60]; + final ticker = + Stream.periodic(const Duration(milliseconds: 1), (index) => index) + .skip(1) + .take(300) + .asBroadcastStream(); + + return [ + ticker + .where((index) => index % intervals[0] == 0) + .map((index) => index ~/ intervals[0] - 1), + ticker + .where((index) => index % intervals[1] == 0) + .map((index) => index ~/ intervals[1] - 1), + ticker + .where((index) => index % intervals[2] == 0) + .map((index) => index ~/ intervals[2] - 1), + ticker + .where((index) => index % intervals[3] == 0) + .map((index) => index ~/ intervals[3] - 1), + ticker + .where((index) => index % intervals[4] == 0) + .map((index) => index ~/ intervals[4] - 1) + ]; +} + +void main() { + test('Rx.withLatestFrom', () async { + const expectedOutput = [ + Pair(2, 0), + Pair(3, 0), + Pair(4, 1), + Pair(5, 1), + Pair(6, 2) + ]; + final streams = _createTestStreams(); + + await expectLater( + streams.first + .withLatestFrom( + streams[1], (first, int second) => Pair(first, second)) + .take(5), + emitsInOrder(expectedOutput)); + }); + + test('Rx.withLatestFrom.iterate.once', () async { + var iterationCount = 0; + + final combined = Stream.value(1).withLatestFromList(() sync* { + ++iterationCount; + yield Stream.value(2); + yield Stream.value(3); + }()); + + await expectLater( + combined, + emitsInOrder([ + [1, 2, 3], + emitsDone, + ]), + ); + expect(iterationCount, 1); + }); + + test('Rx.withLatestFrom.reusable', () async { + final streams = _createTestStreams(); + final transformer = WithLatestFromStreamTransformer.with1( + streams[1], (first, second) => Pair(first, second)); + const expectedOutput = [ + Pair(2, 0), + Pair(3, 0), + Pair(4, 1), + Pair(5, 1), + Pair(6, 2) + ]; + var countA = 0, countB = 0; + + streams.first.transform(transformer).take(5).listen(expectAsync1((result) { + expect(result, expectedOutput[countA++]); + }, count: expectedOutput.length)); + + streams.first.transform(transformer).take(5).listen(expectAsync1((result) { + expect(result, expectedOutput[countB++]); + }, count: expectedOutput.length)); + }); + + test('Rx.withLatestFrom.asBroadcastStream', () async { + final streams = _createTestStreams(); + final stream = + streams.first.withLatestFrom(streams[1], (first, int second) => 0); + + // listen twice on same stream + stream.listen(null); + stream.listen(null); + + await expectLater(true, true); + }); + + test('Rx.withLatestFrom.error.shouldThrowA', () async { + final streams = _createTestStreams(); + final streamWithError = Stream.error(Exception()) + .withLatestFrom(streams[1], (first, int second) => 'Hello'); + + streamWithError.listen(null, + onError: expectAsync2((Exception e, StackTrace s) { + expect(e, isException); + })); + }); + + test('Rx.withLatestFrom.error.shouldThrowB', () async { + final streams = _createTestStreams(); + final stream = streams[1].take(1).withLatestFrom( + Stream.value(0), (first, int second) => throw Exception()); + + expect( + stream, + emitsInOrder([ + emitsError(isException), + emitsDone, + ])); + }); + + test('Rx.withLatestFrom.pause.resume', () async { + late StreamSubscription subscription; + const expectedOutput = [Pair(2, 0)]; + final streams = _createTestStreams(); + var count = 0; + + subscription = streams.first + .withLatestFrom(streams[1], (first, int second) => Pair(first, second)) + .take(1) + .listen(expectAsync1((result) { + expect(result, expectedOutput[count++]); + + if (count == expectedOutput.length) { + subscription.cancel(); + } + }, count: expectedOutput.length)); + + subscription.pause(); + subscription.resume(); + }); + + test('Rx.withLatestFrom.otherEmitsNull', () async { + const expected = Pair(1, null); + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFrom( + Stream.value(null), + (a, int? b) => Pair(a, b), + ); + + await expectLater( + stream, + emits(expected), + ); + }); + + test('Rx.withLatestFrom.otherNotEmit', () async { + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFrom( + Stream.empty(), + (a, int b) => Pair(a, b), + ); + + await expectLater( + stream, + emitsDone, + ); + }); + + test('Rx.withLatestFrom2', () async { + const expectedOutput = [ + _Tuple(2, 0, 1), + _Tuple(3, 0, 1), + _Tuple(4, 1, 2), + _Tuple(5, 1, 3), + _Tuple(6, 2, 4), + ]; + final streams = _createTestStreams(); + var count = 0; + + streams.first + .withLatestFrom2( + streams[1], + streams[2], + (item1, int item2, int item3) => _Tuple(item1, item2, item3), + ) + .take(5) + .listen( + expectAsync1( + (result) => expect(result, expectedOutput[count++]), + count: expectedOutput.length, + ), + ); + }); + + test('Rx.withLatestFrom3', () async { + const expectedOutput = [ + _Tuple(2, 0, 1, 0), + _Tuple(3, 0, 1, 1), + _Tuple(4, 1, 2, 1), + _Tuple(5, 1, 3, 2), + _Tuple(6, 2, 4, 2), + ]; + final streams = _createTestStreams(); + var count = 0; + + streams.first + .withLatestFrom3( + streams[1], + streams[2], + streams[3], + (item1, int item2, int item3, int item4) => + _Tuple(item1, item2, item3, item4), + ) + .take(5) + .listen( + expectAsync1( + (result) => expect(result, expectedOutput[count++]), + count: expectedOutput.length, + ), + ); + }); + + test('Rx.withLatestFrom4', () async { + const expectedOutput = [ + _Tuple(2, 0, 1, 0, 0), + _Tuple(3, 0, 1, 1, 0), + _Tuple(4, 1, 2, 1, 0), + _Tuple(5, 1, 3, 2, 1), + _Tuple(6, 2, 4, 2, 1), + ]; + final streams = _createTestStreams(); + var count = 0; + + streams.first + .withLatestFrom4( + streams[1], + streams[2], + streams[3], + streams[4], + (item1, int item2, int item3, int item4, int item5) => + _Tuple(item1, item2, item3, item4, item5), + ) + .take(5) + .listen( + expectAsync1( + (result) => expect(result, expectedOutput[count++]), + count: expectedOutput.length, + ), + ); + }); + + test('Rx.withLatestFrom5', () async { + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFrom5( + Stream.value(2), + Stream.value(3), + Stream.value(4), + Stream.value(5), + Stream.value(6), + (a, int b, int c, int d, int e, int f) => _Tuple(a, b, c, d, e, f), + ); + const expected = _Tuple(1, 2, 3, 4, 5, 6); + + await expectLater( + stream, + emits(expected), + ); + }); + + test('Rx.withLatestFrom6', () async { + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFrom6( + Stream.value(2), + Stream.value(3), + Stream.value(4), + Stream.value(5), + Stream.value(6), + Stream.value(7), + (a, int b, int c, int d, int e, int f, int g) => + _Tuple(a, b, c, d, e, f, g), + ); + const expected = _Tuple(1, 2, 3, 4, 5, 6, 7); + + await expectLater( + stream, + emits(expected), + ); + }); + + test('Rx.withLatestFrom7', () async { + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFrom7( + Stream.value(2), + Stream.value(3), + Stream.value(4), + Stream.value(5), + Stream.value(6), + Stream.value(7), + Stream.value(8), + (a, int b, int c, int d, int e, int f, int g, int h) => + _Tuple(a, b, c, d, e, f, g, h), + ); + const expected = _Tuple(1, 2, 3, 4, 5, 6, 7, 8); + + await expectLater( + stream, + emits(expected), + ); + }); + + test('Rx.withLatestFrom8', () async { + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFrom8( + Stream.value(2), + Stream.value(3), + Stream.value(4), + Stream.value(5), + Stream.value(6), + Stream.value(7), + Stream.value(8), + Stream.value(9), + (a, int b, int c, int d, int e, int f, int g, int h, int i) => + _Tuple(a, b, c, d, e, f, g, h, i), + ); + const expected = _Tuple(1, 2, 3, 4, 5, 6, 7, 8, 9); + + await expectLater( + stream, + emits(expected), + ); + }); + + test('Rx.withLatestFrom9', () async { + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFrom9( + Stream.value(2), + Stream.value(3), + Stream.value(4), + Stream.value(5), + Stream.value(6), + Stream.value(7), + Stream.value(8), + Stream.value(9), + Stream.value(10), + (a, int b, int c, int d, int e, int f, int g, int h, int i, int j) => + _Tuple(a, b, c, d, e, f, g, h, i, j), + ); + const expected = _Tuple(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + + await expectLater( + stream, + emits(expected), + ); + }); + + test('Rx.withLatestFromList', () async { + final stream = Rx.timer( + 1, + const Duration(microseconds: 100), + ).withLatestFromList( + [ + Stream.value(2), + Stream.value(3), + Stream.value(4), + Stream.value(5), + Stream.value(6), + Stream.value(7), + Stream.value(8), + Stream.value(9), + Stream.value(10), + ], + ); + const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + await expectLater( + stream, + emits(expected), + ); + }); + + test('Rx.withLatestFromList.emptyList', () async { + final stream = Stream.fromIterable([1, 2, 3]).withLatestFromList([]); + + await expectLater( + stream, + emitsInOrder( + >[ + [1], + [2], + [3], + ], + ), + ); + }); + test('Rx.withLatestFrom accidental broadcast', () async { + final controller = StreamController(); + + final stream = controller.stream + .withLatestFrom(Stream.empty(), (_, dynamic __) => true); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.withLatestFrom.nullable', () { + nullableTest>( + (s) => s.withLatestFromList([Stream.value('String')]), + ); + }); +} + +class Pair { + final int? first; + final int? second; + + const Pair(this.first, this.second); + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + return other is Pair && first == other.first && second == other.second; + } + + @override + int get hashCode { + return first.hashCode ^ second.hashCode; + } + + @override + String toString() { + return 'Pair{first: $first, second: $second}'; + } +} + +class _Tuple { + final int? item1; + final int? item2; + final int? item3; + final int? item4; + final int? item5; + final int? item6; + final int? item7; + final int? item8; + final int? item9; + final int? item10; + + const _Tuple([ + this.item1, + this.item2, + this.item3, + this.item4, + this.item5, + this.item6, + this.item7, + this.item8, + this.item9, + this.item10, + ]); + + @override + bool operator ==(Object other) { + return identical(this, other) || + other is _Tuple && + item1 == other.item1 && + item2 == other.item2 && + item3 == other.item3 && + item4 == other.item4 && + item5 == other.item5 && + item6 == other.item6 && + item7 == other.item7 && + item8 == other.item8 && + item9 == other.item9 && + item10 == other.item10; + } + + @override + int get hashCode { + return item1.hashCode ^ + item2.hashCode ^ + item3.hashCode ^ + item4.hashCode ^ + item5.hashCode ^ + item6.hashCode ^ + item7.hashCode ^ + item8.hashCode ^ + item9.hashCode ^ + item10.hashCode; + } + + @override + String toString() { + final values = [ + item1, + item2, + item3, + item4, + item5, + item6, + item7, + item8, + item9, + item10, + ]; + final s = values.join(', '); + return 'Tuple { $s }'; + } +} diff --git a/sandbox/reactivex/test/transformers/zip_with_test.dart b/sandbox/reactivex/test/transformers/zip_with_test.dart new file mode 100644 index 0000000..36839c9 --- /dev/null +++ b/sandbox/reactivex/test/transformers/zip_with_test.dart @@ -0,0 +1,63 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + test('Rx.zipWith', () async { + Stream.value(1) + .zipWith(Stream.value(2), (int one, int two) => one + two) + .listen(expectAsync1((int result) { + expect(result, 3); + }, count: 1)); + }); + + test('Rx.zipWith accidental broadcast', () async { + final controller = StreamController(); + + final stream = + controller.stream.zipWith(Stream.empty(), (_, dynamic __) => true); + + stream.listen(null); + expect(() => stream.listen(null), throwsStateError); + + controller.add(1); + }); + + test('Rx.zipWith on single stream should stay single ', () async { + final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); + final immediateStream = Stream.value(2); + final expected = [3, emitsDone]; + + final concatenatedStream = + delayedStream.zipWith(immediateStream, (a, int b) => a + b); + + expect(concatenatedStream.isBroadcast, isFalse); + expect(concatenatedStream, emitsInOrder(expected)); + }); + + test('Rx.zipWith on broadcast stream should stay broadcast ', () async { + final delayedStream = + Rx.timer(1, Duration(milliseconds: 10)).asBroadcastStream(); + final immediateStream = Stream.value(2); + final expected = [3, emitsDone]; + + final concatenatedStream = + delayedStream.zipWith(immediateStream, (a, int b) => a + b); + + expect(concatenatedStream.isBroadcast, isTrue); + expect(concatenatedStream, emitsInOrder(expected)); + }); + + test('Rx.zipWith multiple subscriptions on single ', () async { + final delayedStream = Rx.timer(1, Duration(milliseconds: 10)); + final immediateStream = Stream.value(2); + + final concatenatedStream = + delayedStream.zipWith(immediateStream, (a, int b) => a + b); + + expect(() => concatenatedStream.listen(null), returnsNormally); + expect(() => concatenatedStream.listen(null), + throwsA(TypeMatcher())); + }); +} diff --git a/sandbox/reactivex/test/utils.dart b/sandbox/reactivex/test/utils.dart new file mode 100644 index 0000000..2a8f4fd --- /dev/null +++ b/sandbox/reactivex/test/utils.dart @@ -0,0 +1,25 @@ +import 'dart:async'; + +/// Explicitly ignores a future. +/// +/// Not all futures need to be awaited. +/// The Dart linter has an optional ["unawaited futures" lint](https://dart-lang.github.io/linter/lints/unawaited_futures.html) +/// which enforces that futures (expressions with a static type of [Future]) +/// in asynchronous functions are handled *somehow*. +/// If a particular future value doesn't need to be awaited, +/// you can call `unawaited(...)` with it, which will avoid the lint, +/// simply because the expression no longer has type [Future]. +/// Using `unawaited` has no other effect. +/// You should use `unawaited` to convey the *intention* of +/// deliberately not waiting for the future. +/// +/// If the future completes with an error, +/// it was likely a mistake to not await it. +/// That error will still occur and will be considered unhandled +/// unless the same future is awaited (or otherwise handled) elsewhere too. +/// Because of that, `unawaited` should only be used for futures that +/// are *expected* to complete with a value. +void unawaited(Future future) {} + +void nullableTest(Stream Function(Stream s) transform) => + transform(Stream.fromIterable(['1', '2', '3'])); diff --git a/sandbox/reactivex/test/utils/composite_subscription_test.dart b/sandbox/reactivex/test/utils/composite_subscription_test.dart new file mode 100644 index 0000000..66a01e3 --- /dev/null +++ b/sandbox/reactivex/test/utils/composite_subscription_test.dart @@ -0,0 +1,316 @@ +import 'dart:async'; + +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + group('CompositeSubscription', () { + test('cast to StreamSubscription of any type', () { + final cs = CompositeSubscription(); + + expect(cs, isA>()); + // ignore: prefer_void_to_null + expect(cs, isA>()); + expect(cs, isA>()); + expect(cs, isA>()); + expect(cs, isA>()); + expect(cs, isA>()); + + cs as StreamSubscription; // ignore: unnecessary_cast + // ignore: unnecessary_cast, prefer_void_to_null + cs as StreamSubscription; + cs as StreamSubscription; // ignore: unnecessary_cast + cs as StreamSubscription; // ignore: unnecessary_cast + cs as StreamSubscription; // ignore: unnecessary_cast + cs as StreamSubscription; // ignore: unnecessary_cast + + expect(true, true); + }); + + group('throws UnsupportedError', () { + test('when calling asFuture()', () { + expect( + () => CompositeSubscription().asFuture(0), throwsUnsupportedError); + }); + + test('when calling onData()', () { + expect(() => CompositeSubscription().onData((_) {}), + throwsUnsupportedError); + }); + + test('when calling onError()', () { + expect(() => CompositeSubscription().onError((Object _) {}), + throwsUnsupportedError); + }); + + test('when calling onDone()', () { + expect(() => CompositeSubscription().onDone(() {}), + throwsUnsupportedError); + }); + }); + + group('Rx.compositeSubscription.clear', () { + test('should cancel all subscriptions', () { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + final composite = CompositeSubscription(); + + composite + ..add(stream.listen(null)) + ..add(stream.listen(null)) + ..add(stream.listen(null)); + + final done = composite.clear(); + + expect(stream, neverEmits(anything)); + expect(done, isA>()); + }); + + test( + 'should return null since no subscription has been canceled clear()', + () { + final composite = CompositeSubscription(); + final done = composite.clear(); + expect(done, null); + }, + ); + }); + + group('Rx.compositeSubscription.onDispose', () { + test('should cancel all subscriptions when calling dispose()', () { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + final composite = CompositeSubscription(); + + composite + ..add(stream.listen(null)) + ..add(stream.listen(null)) + ..add(stream.listen(null)); + + final done = composite.dispose(); + + expect(stream, neverEmits(anything)); + expect(done, isA>()); + }); + + test('should cancel all subscriptions when calling cancel()', () { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + final composite = CompositeSubscription(); + + composite + ..add(stream.listen(null)) + ..add(stream.listen(null)) + ..add(stream.listen(null)); + + final done = composite.cancel(); + + expect(stream, neverEmits(anything)); + expect(done, isA>()); + }); + + test( + 'should return null since no subscription has been canceled on dispose()', + () { + final composite = CompositeSubscription(); + final done = composite.dispose(); + expect(done, null); + }, + ); + + test( + 'should return Future completed with null since no subscription has been canceled on cancel()', + () { + final composite = CompositeSubscription(); + final done = composite.cancel(); + expect(done, completion(null)); + }, + ); + + test( + 'should throw exception if trying to add subscription to disposed composite, after calling dispose()', + () { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + final composite = CompositeSubscription(); + + composite.dispose(); + + expect(() => composite.add(stream.listen(null)), throwsA(anything)); + }, + ); + + test( + 'should throw exception if trying to add subscription to disposed composite, after calling cancel()', + () { + final stream = Stream.fromIterable(const [1, 2, 3]).shareValue(); + final composite = CompositeSubscription(); + + composite.cancel(); + + expect(() => composite.add(stream.listen(null)), throwsA(anything)); + }, + ); + }); + + group('Rx.compositeSubscription.remove', () { + test('should cancel subscription on if it is removed from composite', () { + const value = 1; + final stream = Stream.fromIterable([value]).shareValue(); + final composite = CompositeSubscription(); + final subscription = stream.listen(null); + + composite.add(subscription); + final done = composite.remove(subscription); + + expect(stream, neverEmits(anything)); + expect(done, isA>()); + }); + + test( + 'should not cancel the subscription since it is not present in the composite', + () { + const value = 1; + final stream = Stream.fromIterable([value]).shareValue(); + final composite = CompositeSubscription(); + final subscription = stream.listen(null); + + final done = composite.remove(subscription); + + expect(stream, emits(anything)); + expect(done, null); + }, + ); + }); + + test('Rx.compositeSubscription.pauseAndResume()', () { + final composite = CompositeSubscription(); + final s1 = Stream.fromIterable(const [1, 2, 3]).listen(null), + s2 = Stream.fromIterable(const [4, 5, 6]).listen(null); + + composite.add(s1); + composite.add(s2); + + void expectPaused() { + expect(composite.allPaused, isTrue); + expect(composite.isPaused, isTrue); + + expect(s1.isPaused, isTrue); + expect(s2.isPaused, isTrue); + } + + void expectResumed() { + expect(composite.allPaused, isFalse); + expect(composite.isPaused, isFalse); + + expect(s1.isPaused, isFalse); + expect(s2.isPaused, isFalse); + } + + composite.pauseAll(); + + expectPaused(); + + composite.resumeAll(); + + expectResumed(); + + composite.pause(); + + expectPaused(); + + composite.resume(); + + expectResumed(); + }); + + test('Rx.compositeSubscription.resumeWithFuture', () async { + final composite = CompositeSubscription(); + final s1 = Stream.fromIterable(const [1, 2, 3]).listen(null), + s2 = Stream.fromIterable(const [4, 5, 6]).listen(null); + final completer = Completer(); + + composite.add(s1); + composite.add(s2); + composite.pauseAll(completer.future); + + expect(composite.allPaused, isTrue); + expect(composite.isPaused, isTrue); + + completer.complete(); + + await expectLater(completer.future.then((_) => composite.allPaused), + completion(isFalse)); + await expectLater(completer.future.then((_) => composite.isPaused), + completion(isFalse)); + }); + + test('Rx.compositeSubscription.allPaused', () { + final composite = CompositeSubscription(); + final s1 = Stream.fromIterable(const [1, 2, 3]).listen(null), + s2 = Stream.fromIterable(const [4, 5, 6]).listen(null); + + expect(composite.allPaused, isFalse); + expect(composite.isPaused, isFalse); + + composite.add(s1); + composite.add(s2); + + expect(composite.allPaused, isFalse); + expect(composite.isPaused, isFalse); + + composite.pauseAll(); + + expect(composite.allPaused, isTrue); + expect(composite.isPaused, isTrue); + + composite.remove(s1); + composite.remove(s2); + + /// all subscriptions are removed, allPaused should yield false + expect(composite.allPaused, isFalse); + expect(composite.isPaused, isFalse); + }); + + test('Rx.compositeSubscription.allPaused.indirectly', () { + final composite = CompositeSubscription(); + final s1 = Stream.fromIterable(const [1, 2, 3]).listen(null), + s2 = Stream.fromIterable(const [4, 5, 6]).listen(null); + + s1.pause(); + s2.pause(); + + composite.add(s1); + composite.add(s2); + + expect(composite.allPaused, isTrue); + expect(composite.isPaused, isTrue); + + s1.resume(); + s2.resume(); + + expect(composite.allPaused, isFalse); + expect(composite.isPaused, isFalse); + }); + + test('Rx.compositeSubscription.size', () { + final composite = CompositeSubscription(); + final s1 = Stream.fromIterable(const [1, 2, 3]).listen(null), + s2 = Stream.fromIterable(const [4, 5, 6]).listen(null); + + expect(composite.isEmpty, isTrue); + expect(composite.isNotEmpty, isFalse); + expect(composite.length, 0); + + composite.add(s1); + composite.add(s2); + + expect(composite.isEmpty, isFalse); + expect(composite.isNotEmpty, isTrue); + expect(composite.length, 2); + + composite.remove(s1); + composite.remove(s2); + + expect(composite.isEmpty, isTrue); + expect(composite.isNotEmpty, isFalse); + expect(composite.length, 0); + }); + }); +} diff --git a/sandbox/reactivex/test/utils/notification_test.dart b/sandbox/reactivex/test/utils/notification_test.dart new file mode 100644 index 0000000..45191f9 --- /dev/null +++ b/sandbox/reactivex/test/utils/notification_test.dart @@ -0,0 +1,234 @@ +import 'package:angel3_reactivex/angel3_reactivex.dart'; +import 'package:test/test.dart'; + +void main() { + group('StreamNotification', () { + test('hashCode', () { + final value1 = 1; + final value2 = 2; + + final st1 = StackTrace.current; + final st2 = StackTrace.current; + + expect( + StreamNotification.data(value1).hashCode, + StreamNotification.data(value1).hashCode, + ); + expect( + StreamNotification.data(value1).hashCode, + StreamNotification.data(value1).hashCode, + ); + expect( + StreamNotification.data(value1).hashCode, + isNot(StreamNotification.data(value2).hashCode), + ); + + expect( + StreamNotification.done().hashCode, + StreamNotification.done().hashCode, + ); + expect( + StreamNotification.done().hashCode, + StreamNotification.done().hashCode, + ); + + expect( + StreamNotification.error(value1, st1).hashCode, + StreamNotification.error(value1, st1).hashCode, + ); + expect( + StreamNotification.error(value1, st1).hashCode, + isNot(StreamNotification.error(value2, st1).hashCode), + ); + expect( + StreamNotification.error(value1, st1).hashCode, + isNot(StreamNotification.error(value1, st2).hashCode), + ); + expect( + StreamNotification.error(value1, st1).hashCode, + isNot(StreamNotification.error(value2, st2).hashCode), + ); + + expect( + StreamNotification.data(value1).hashCode, + isNot(StreamNotification.done().hashCode), + ); + expect( + StreamNotification.data(value1).hashCode, + isNot(StreamNotification.error(value1, st1).hashCode), + ); + expect( + StreamNotification.done().hashCode, + isNot(StreamNotification.error(value1, st1).hashCode), + ); + }); + + test('==', () { + final value1 = 1; + final value2 = 2; + + final st1 = StackTrace.current; + final st2 = StackTrace.current; + + expect( + StreamNotification.data(value1), + StreamNotification.data(value1), + ); + expect( + StreamNotification.data(value1), + isNot(StreamNotification.data(value1)), + ); + expect( + StreamNotification.data(value1), + isNot(StreamNotification.data(value2)), + ); + + expect( + StreamNotification.done(), + StreamNotification.done(), + ); + expect( + const StreamNotification.done(), + StreamNotification.done(), + ); + expect( + StreamNotification.done(), + StreamNotification.done(), + ); + + expect( + StreamNotification.error(value1, st1), + StreamNotification.error(value1, st1), + ); + expect( + StreamNotification.error(value1, st1), + isNot(StreamNotification.error(value2, st1)), + ); + expect( + StreamNotification.error(value1, st1), + isNot(StreamNotification.error(value1, st2)), + ); + expect( + StreamNotification.error(value1, st1), + isNot(StreamNotification.error(value2, st2)), + ); + + expect( + StreamNotification.data(value1), + isNot(StreamNotification.done()), + ); + expect( + StreamNotification.data(value1), + isNot(StreamNotification.error(value1, st1)), + ); + expect( + StreamNotification.done(), + isNot(StreamNotification.error(value1, st1)), + ); + }); + + test('toString', () { + expect( + StreamNotification.data(1).toString(), + 'DataNotification{value: 1}', + ); + + expect( + StreamNotification.done().toString(), + 'DoneNotification{}', + ); + + expect( + StreamNotification.error(2, StackTrace.empty).toString(), + 'ErrorNotification{error: 2, stackTrace: }', + ); + }); + + test('requireData', () { + expect( + StreamNotification.data(1).requireDataValue, + 1, + ); + + expect( + () => StreamNotification.done().requireDataValue, + throwsA(isA()), + ); + + expect( + () => + StreamNotification.error(2, StackTrace.empty).requireDataValue, + throwsA(isA()), + ); + }); + + test('errorAndStackTraceOrNull', () { + expect( + StreamNotification.data(1).errorAndStackTraceOrNull, + isNull, + ); + + expect( + StreamNotification.done().errorAndStackTraceOrNull, + isNull, + ); + + expect( + StreamNotification.error(2, StackTrace.empty) + .errorAndStackTraceOrNull, + ErrorAndStackTrace(2, StackTrace.empty), + ); + }); + + test('isOnData', () { + expect( + StreamNotification.data(1).isData, + isTrue, + ); + + expect( + StreamNotification.done().isData, + isFalse, + ); + + expect( + StreamNotification.error(2, StackTrace.empty).isData, + isFalse, + ); + }); + + test('isOnDone', () { + expect( + StreamNotification.data(1).isDone, + isFalse, + ); + + expect( + StreamNotification.done().isDone, + isTrue, + ); + + expect( + StreamNotification.error(2, StackTrace.empty).isDone, + isFalse, + ); + }); + + test('isOnError', () { + expect( + StreamNotification.data(1).isError, + isFalse, + ); + + expect( + StreamNotification.done().isError, + isFalse, + ); + + expect( + StreamNotification.error(2, StackTrace.empty).isError, + isTrue, + ); + }); + }); +}

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⩛XZh{hi7WxYa=* zSPePk?=qzY@qN~2JG#ApZGRF0SUwG)Y` z_Fz416jUO9bM6)a+UDZ=N1wft9%&@9P{I32pha^hq`a)~itrVY+niac_9-94n0SS<8O?cc;+HagS@0uUFP7C4A2|K=3ecsn-2KSdG5sn;V@ ze?EI+%SUxtc}hK#b+aeNI~POX+2!Q5KZ0b$+-=H;v3Mq8|E%#!Hg!cJrQ+F(Gqm&- z;f{hw85X(O6Sow~avpl;#%0`tC?g)*VV^bTK0gz12bj8JA_9rnH}c8P4WCDA2V&?D zQ(}rcHM5y7FXv2v7zLuoNkeADHF-D%!MCz+p#rU z8Zb0g3&JfP@|-cp-^79T<54z*qJ7VCMj8duO^>29;r4N_c21@q-iw>$FV>!n+{A?A zQ<381&$cr_A)2@-LgFrq41=D8ND#=0g#ez84ll@#F@$;$pG66!!-QTLJMWWbq7 zSv(v>E;->NR-}$?F@L3|nYe@n;g|?02{gX^+-q`688Wc@;45f*@Noj-U0g_XN?B0# zYt_lSM&T$ShjOpMrwR{>zEOkHpBF3JWzh8lITjTG;0kS@jF*%C;J>(f{{xZlSJ(q! zE@*5c>>+2ecG?$D)QXrMhUFGl)_>)$_aReK(g3;c<^{ew8q7Lx-luW}28HSGhYing zhZ`(SOigr?XYCUz3)7WDtzpf@y0y=D?wTPYQ@akm?J(03yF8(2>q;olYkXuTHL6SH-(J*fbk=}9zeAvvct+23i?%B{v zQA)q293aBg)=hEy*0^0YmIp#wju43k$^9{|Fb11zoY3Df#&xaWW(LAW>-JrJI&5W# z-r_gX)HSukuS+C&TyD=ECq3Ac4z9d=EyQm;vWa^{0`_KtTer+rQ<0ut=k~I=>s?w^ zBizXau2AH1dN0>Bm%GisIX^*!-Hbb%&i=vX>O^+-R%uE2^~+H@o${v;flG*Rj!rt4 z&1S2pD37djMPs-_>s-LZQ&Lg_(i;Bom4OL1w-W~mT-{L1A^{DL4+wHrT1EI{HX@uk zAjMhXswgRNYOxH4LF52aP01E;*kp?7QmS%Rg3^GVhfZUtp~+S<_)N5JQ9+biC<~1x z%a~FU3TSBsOj-wRjwVMy?S|w7_K=5OoM+Nd2vSBiVh@CfEk!6Uke0I zv<~9V6h=|On4y}McOI)FN-na10c2E>4GdN4Fq7sery>VQ;FR?;fN07jvv!y}X6Zyu zuqPL&*=E|)BRgm@YPvvfWLw;jlrT&jqGa|mtV5$p66kpeWbfi;79-I*T?>eIfH*2s zLAr#^=ow&^sAy<~QajSMSiQjS0@K$5yZ9^40kX7T0nbL>0|q$JW0>yw~PN@1I1z*$S7`Un1YHu*dnUEktPRUqrr> z>5k69^dpIXH*aNOo1*G-@-Jb}Gno@Zp$=2Oi+uk)>|s1U`Fq&Y^UC4x!yZ87`#tPg zUHT>Ry{lSV}>pDn(aHMt@3O>Kld3crb8FPM78 z(Azs*+!@nLA@Z33A|FJ^bwlLaJ5x5Cm$j9CYd$g=l6@h&# zhXn9CqJIw^A{Of2*4r*}(AGyN$o0~euCTygbgg25HvVys)XmJ4eg z+QRPN>$XNb?Y8gLcY#*F`aTHX`WB21>=fqHw_B-eK|gudKr7_-a{-(vW20-IpyiiN zh1S0_IY0wjzX<~U2n={8hd%zmj!D!amqBuya5@ZqD}yBwO-`%|E0RjowXHVcV@b`X zo`hf89VXl%8*=l^qdV@SH4<|pcjU4%1Uxtrhv*oJ7CIBl3p1$QDKQ&vV3aAG+)yi{ zIU7OR*tatHAa5}nY2KVETH5eI$$R!L8T}YnZ&0U_G8<)U^jM<1p-!!0HrhGrvE-;h z{i*gH9>l!IQoz1dLJv5^YwB7uWKV-mq;6QKk+i;PPJ^CzFeN4`OIr3sqoKuI0<}4- zLnH}x%6ksa|M7$D#=KR^Tw;#V6M3`7CewwCJ5nDrY6g2 zHfHoxv%9g?y<+|$E9$A%=!rJ(-uZM+^V1_sjl4F$mH9^?fgB>zkP#@s-q^R&5o=`Yusj-Gl`dyF^xF<#)Af&Tx5$agCDY;sd)w&ub!Qgp7#Q^U`> z77MxNExD$pO`r4sBJvq_6{RfX*`9iC(cRQlQnB#DIr_Qfs9|?S??S$3%X6!xrtYeh zg_jh8JTmfRPmRQ4LHMb>t70E}>NFP%N4N1cd?|F~qHx-hQh{F1k zG-`Gi)rTlg;RSB}_lSJAys7xh>tUhl{XZsEJ)5r@&nIs=SQw z18O}>X*T0&UTuzQu=G{*He%lcfiq>=RI}7r&CY=Bl!X1%FU?_lH3ngOZ1-o}zcw0J zAP(Qzqq7+o*YC^PwSA&pmCQ(kC{PEtACjXu&j(Bds7iEY5$e_9_aQ3S`BgpkJ#5kEX$HX9d-Vit>#cBWoAwk zkHmxbill0$lsF%*B8J{BUH$s0op1yli1GEkg1Sjo7hx%G+vHFoaFpyWB+7sW+Kl#| zBUa-koP%*1T8B7h?VT7ji`5sIu2@^121sy&5R`Ui4+8}ng z-vy{T{YB*4FVuo+SMP4g-+BTwT!Xm0zt7{Et=f`LvuOIpd#WsdbB&+g^{2khu6tA> z*VTf;ZVf*4^X#%r{n@QooVjr0%a%N%L`Q+i;3#*oesYjsny%Wrm6vkomKEN!6q$3p zg`yVcry=5WKw$to>7BE(5GWS@GCwkQU49meUR1<32Ug z`kYsg)9rV(ukRkM-(b0fc)#lV8P$D+=QMH{=5tJYWhl0#{7VK4-oxx2f7CpE#y@V8 z0~K?Fs4XZb1wD{;a6Mf1wlE2Hlj(Af;s@%H;LwrMHm-6uKJ&?x5TSs_Vcr~u>oqdM zfPmQF?IDbl*phQov;Ni*52#=Ao$XZdEuMku6t`^!Zs(l6_w3_aj^Lk|zt zr^BSlftQm*RjHw|OYSIb--Ce2Weg12}m9Z_&c8~W)VpSA$B&X z7YHDO0-3RH!x$1fC=qt*-t%H`U~G!V0=v+|f_B{Ht4699fUY{jEC^kB<`nH3$Gl>O>*MMQ@(f&dqQJ&Tz$#8QJ z@^LmY(>CV1(CsJ=<^}_Lh=ed;LH6Kn=cr=WL){&-5z5XmXFLMLfXZ=V?fsi(}alr7X*R7mcPa}%3rxL7=k2f+XJ@!gZhGkf^+F(mkl@VbZ^Y;V)r9#?@iEpdlxbxqC9OIEo3g)kjG-N{;!i7Iq)`|6L0SruVeO&7cOy&AxY z4MnFb@ue`MzBMWPzl{6`+`t(#72t zF{KpP`JKzH&68A9QeZRWx<-Cg!-n4L`CKAU-%Ge06}!mGJ47 zQIhVRN93&05RE%kgWs90P+IL zSt!p9UIXaNI+v>D+yl@VfQr4DA^;2m{M8vF2hdqkE6ww|YDoS93Ue`E3L?yNWG2+*btyaYs*@+3emc9D();kGC|tYNE*OEQ(A4N zL~ThIBSAtp&Jz!i6o8PH8r2yGl->eqqDeH<+_9KBx{PUfZ>udEo`a*kRu{|tfXKp zGhG@W!3H+tY+!MmHQ8PbpkPM;UHhlT0Fq@euyvUlQqC-ZsS6rR0Jt`BwB67gY^ALN z!(~hvfDX{l9qVB;oQoR(F5Yl1es#V!i~yka1$4nSfN{eJ0Qhl(B{!6T4M*VLV#c#+ z^Ra>dTo4dEH5dD=Flr*Ub2bAOMuVP$}0Wer+QA=~@BI__y-c1~abLN2@At2m-9bU~r7q;@B>aIoAC5 zI9<_3%Q(GX<*)z0G2=%0%Q3rx`@Xv1Z-T%FMb>EuLrH%4=-dV~_PbBsI4y_L{ZRTR zX8a`xY%n7s^yJUC4aSt8RqrM~{(M)~yNN}2$)sDuTOU%{m_%Lx1c4UY!#x%+Ub}EDD_`4? zx!)JMdvB0IUktX*o`&1*9ihCxQGZ7kX7lleN97K><|0C{pLc0HV2s6V?aOaCy7b>Qe*l|PlgaEAp}r}Tb%?qajt zV7xk`9ir%B?SalZ^s{zJWU>0eLv9-@)CC+U==^ASU)YCxZ#aUfd)m0p;Lb~HOTs(K z4|9f3BkP*J-@9GWQ9f$5Zaq_aoU@wP8hdSJUj%(sXf*cgbMQ*Vwsd(K&JgrycrUfW3M2lPnNe-_`p)@GT;cs1D39ZZMZeRZVGI%I19<+&b43TaSCCcjIH;h*O6RTj$BOd~Ei1mV znGUd4P-tigjh|1A(0Sy~7FW5EbOSf_9lX^@hEXW+o`x(MStNqnLiWrbzMdKw$oO*F zyejO7>f6zu#AT_QaUk@N@_3I*0RA%_NmCOD5kcYMzlG~NV(_p))r@xcreY#n2qQ(M z@$uue#hsr|9Qxq($wjmQZiPkQqiCOc!K}kFhsTj3biOOZ8aVLc!<4ON>k>{|v=bj9 z?3U5_wWKxs`(OyNA6PU66dEjj-0ie1{gYH6!U!L-pL_+aj)i7Te@#9;z&AtCA!1Sb(LC4L(Xhgz~Xnp-&9*<7hIx+36xLHGM34fsY z3)%H&@nF+e8NC*VkhzCG7n_fmEfwzz{6Twu@w=kBrW^JJdz2zRe#*l*6)AOlknncm zHCQvKywV}}`+YdsCg5qYUmVeA+vF4NCI6Sk=Juo@xEc9#VR?-E52LlI+mBkl&Zc|3 z^}pD=`{yASQ0$c5{3X^)?ZvH9Kvf8{Z8qqg{#Hu?hkY=qxffsDz8w5ItHRanQKf6y zSxeWD$_qVJ*VDbAPl+iqmgX`DEp zIhM7AxC(+MJq zDQ2C9QKUd^@bEo!gkgBtop#ECEX9-rI?KW+l~F+9w&97hZjaP}S6dKQ2#BHj-~?1C z2>}%*0u3ZVa~4F5088tM2nYXmg93suU^YZ2U9#7+oJg+{I~)mqiVW*EgV=e7l;Fgd z=m>u*{45bR8tNE=i}J|u`c#5|lVF$eh}Qb3ur6P)C~}sBc&ujEWE&k8>NHD;Ikptd zYzVzk=J2#MYBWb|(%f^ZC&o>P%rf_!8;fA)L`{17FL~mwntDI7j#=}(i^_3_9K80& zb?|>U^YK>|d;}&32}|FJmiDd#_Ba4+D=I2>ad8O?ivVtTF-=@XnE~KG$KFOC4Q|*W zC2~;hpr$-b6%XU5u0*{4R?^M&DxG7#f(2iPdD1!J{=GCBt@|hU;}F-I43l@QlyPqc z?rkE$to|xFK%DMcbr5yt_zE>n^Y z5Dq|4fHDmn(!yncCva$ns#=~!4FDekT!(jJ1-oH^bDfrBC)%9`fEFN5%bcZqruPq3 zV)MFa06_r^cD-b3Y>deoz>{;B0NP#8Z|Gt(6f^6NofNJV2pcF+_m4U~yxPGjvne@Js_@i6ape z%8(kMs43XW&Jfc=0|s6Cz@)j=z1V7eQJ0}Cbq zS4-_ArbOWYv;%MsU^xKrHem0U4Zd*~{9OfKX9Fm>aUlG6Rd9uWaUDE{{KxB{n&f}D z4&HJVNIA}={#ga@y|H@p#lT-x@b_-7SjYdE`Pg{;h8b6S|L?AY6~*KKQ3YQleh}dH z{-J_T*PyOa3|PO75YfAb0(79h`j`unx?8$dTPi z>;oG!AOE0&|8?dg9V+$f^_#yVJ>!Fw8#5ojtKdETV9gB`eBdi+7$Cjz{=>gW@AdNg z|1B!`zq}6qb>?HL(9`=2Vq@mxkLzF-9|-jN?#|`dk{xw?BI)BE2;3kKkVtH&js$cV7vfV)+qR?D zZX4IZ4wrWevV zqFq_FOKxo+(!M-axw=$qpS$?g8G9UGuGQN{y0fK zt%4;(;Ia9&(r(Arwa+)8$N-_y`ZjFSz{i`sTk9GZcxznsQh(lhu4D#`^Jcr`Pp>k= zYSG2}f&6JLN^ww9g8~);8k)eU(~(w!J7^!)9=nMae?DBirJ`I~N&eNQE7QFm$saS~ zLK@FypdB7pmRu4D*x$Uv-YWFK{c6(x3)1_~u7jEhk$y*uA4@f=)F=%*#mai)@kl#i zi11w8E-%ndv4aWI%5(8?e|H@ONKaF6>MlTf+7ROZy$=2{^YMTFb?`A>(>WrqKmiUt zv3&){7rc#|$+x$*M&$p4nGaD+a6PxzlX?LyP*ZTNE^mY|AIy{CQRY*=Oj*-#Hrt&T?SiV{4Ymwr$a;^J zcL=G?Jf6;qJ-TaUJ1xEVmR9t{*<)0xg3#CL=hq}r$r+uOv4Nsm+iWckjeh2tL*P~v zkV12BcVk4s^ZSH=(^`XqiW-okp3#m!5_>;M(15RWN&taF2R^lry$tJv8Gmd1R4@WY z<&faYs$l4GGWhk~RAfL@igA8dy>J>9goe?O+ey`8xJ%PNq8^}S$&}5WSh#8I){muC zF-7la5P=*D8pcz>sW@#ThiNvGZ3*s{irAAjUf&0J%bwLw=UMmFWjmCf8h^a@XBGU` z57rI{@#jITjgs2{%;LxKmjVw?KXmJ(NQ|F~ZTa*#pKWsPp=!dBmClz+DM?4SjadHl zPTi|GX&83+Kzue*BA9}(+P*qvzJ34UDth3iN+zt%TC@M;{wv;uzAyN2_o|GlB}SrV zA9@UgAhM>NC*QKJnyGK8VLG9W0^mWiTEmCFkM9=A_y(2(V@zlv%{Q&4eq+?|S&@SI z%mcpb#gyG)&%$?`OMXw;uF_<4^h)Mtucg^#)qB+-1edzTw!K{OGae(c>1g`0%f98l zj6bR1vB^J1wU!Dltgm+4^9UYGAcE6FXhuBK;ZZiuAj=w3C z1L1cD6P+Q#R6i+ON`4*2kPHsczCz}%BB}+XR05IoLhF{Hd5A24GevsGo&a2DYfk(jRs$gH<900Zn zx8X%6800cJw8}wMz_QGv5=y!jotzwv&lc8-T+twQ zvKM^44-1pSS?A4qi;C#z=(@l9`K=U5RwabpKmw;Wpz@kxZ1e@Fq#nR5n;J_8Gl6Pr zU|?|QRT$iNaktFwtzKP6c4C39>`C>F!&-hc()%iGgta2QjjzMXgfE0M^&YjW`~pcNIyhNJ&-!{M0FiK)~e*`+)ANpgVUFsJuq4 z5(uhuT<*$e3*CGQTB7lX`fk%-M zxMp(^dks1;G-x0QJVPL|XnGwL#c(caP?A=dF=Zrlju}TfH)lDfXI?K!@l>%iNyuRo zg=%HaFaaSEdqe>!xQ>))F&J7>66D3J=20nf0JgE&EZ{^|JjAr@&;rg=iK#JOA$g!PcfU(P$8+LgjYI(-7qBq*4?;$0sUCOo!mHu{kn;vftx1;f>u&d*ic*n zt+EyHTmLZh~dI$U>0$sI%~i{12*LqBaw9| zGelCechF`OY*L6hxEt_)BQ#fSMZuBp+h=%v!-u(9e%V!aP z*_6L#5&vRS{;fLeJ~>^=6!vI3x-p7f5-^W&7#3j`3{`t5np2JlQeV*yU{r!O4|M z?t$u^XCw+M+0;Qc9eDpFxHh$&i-l^@xeO$a7{A~AoX9Y!RsYd$wvE;>4GTVfNLLjh z6ry|#hf<&Jl+y9s*1akHI9OLloqlij*eds0QIGSe8F6#k9#)VJKQ11u%jWVvo$jaH z>p9)$^`x-v8>;=22Q%uuA!aZ_-O3EYXRv<$DAghK;E=#?P6sU1>8D|VAR+aUXrJJ+oKlRMAYcr5hHy1>DO9-EhI zi~Sz^9QwL__Eovv-28+tkf=Ctb2A7Vtf@T_%VT0LiGYf%_}Ldh+DN(J*WAz@7tS~` zs>0D35dOFnD=dK!u?0)nIY%L0B?#yJm<0XU9|=R69zeOu`072YIoc4Kuvvr&1sX@- zglw@)FIEW7>)W~OqQVL&=@1?{8X8 z+3-`)1i+>gmO);6^~|?fmJVeBu~ys-Zp;RdD(M z^TKwd+J_@wZ{7?tl0G?ODv4o`;^T@Xq{QbM3@kbh*-?je48+nt{P>x0Mkgx;LQ6PY zH5^VW7TL8Kf)VaIZm$>A)Q20R{y*%Udo+}f{_mfeXD$!PJV`DQqvV!qNOCtyQK=@C zq}x>+v-Y3X@~|w{v%Ej=_xttMgDY{%{MLh!dZ~MI3fAAbRWqfifKpT>YXq8?*(ShQ z+4F`p{UX-S)%JPH=@w=16&=+V53h?<88~+`<*n&CcCq-0XVO9=UDH~OeFT$tGWN)q zZAv1-<^adb1~MLwqKDE3^09#{606r;IAcL3rtnIRh28~MT{wE-NY)}}y?=X}GT>Z7 z%%;TNjp>wF%;!nH(e@j#T2aEU* zu!uVgPzhF4t>g5HBCqYq32CQVZ7s&uHXY*x^VB{pJ&#}4Hv4}8i+Efwcw5LirKkT4 z77?k=Iy`>dWu}=~BGqDD`~wy-xkuY-#^ulx#fmVJJm+OUD;h^n!k_T=Eu4PAC!n#j^LS z0ud#%nwhv5)*6X>S*ZFhY$8a=lrt8w=B}nj2?E__p|h;7b+zNv{rGqfIvZe%#9MS1 zIHy&!#0TE zV4ZpsvH(&`d=sb%ozkL(FDh2iWw68Xr;#wtnJc73@6Pq{$<=VojdlUTKw=n87`Sv*Oo9U=(=(95@D0lik~%Pq zTw|4YGAC2Qdk4Op@^qcg%#7BmiA~8>CAJ(#+l6Ozt44H3TvCaw33WUO$$d&Cf>p|Me}An);zV{HC3lJ#i-c#pYhXXl9SWwv1Hm$%dZr+ z;9gi*zsHf7kg467MDz`7H88HRaS5sG6(E|eAc^m?PQCMvds0zm zLK3fdGu7CSGs>g77jh4}Ia&FYbRy6NDuAZ@p97lxMTpd-8ehl}6Vd@Rp?g&F@ zG?$2u6SuUuKQb^&bEHle*5X9_92F7a#Mq2fCxr>=oEm|9YLc+OhQcf19ki!f6>=vg z#0ba8ao_gsmBQn`j^4|t;u`9n)#`;;O9EU;qa3pFGAD0iJ~vnUPB*u3Vmi7>33E?U zx99S;@7&=SYnZv#lWklSRqC0fWoF$qbVOkyZeb^xiSU_>!}_}_9q-iSBUYP%cL^dR zP34YmSZIj2iyno-b#mIxNmQ#Gfrhc!!Z7l7daI+02_l$HNq*Vtl>w`XR^`G3DzT)H zS0JwqhjEQv91n(N85OPZY+FPbPK(AV$-k1ET(u!~ z{oiccol#EuYkjyeocd?9(%IOCzmLuTD}6YP&7bzu3O@e{t)#K(Z}@4yWAp#qwmT3; zC9>AZ;fORv=056pOy^A7Zowi5XL)gjR7?hO5u1KhCHFK;`)M^9G2t2?tYUlfviUP@ zyEoW=U`>#MqNoCEq)10u2!DK;)`v9J*-He>X9P!AF*tj+M6_29)brqfPSj?dx^a&kMT(Ms1h z=v`G=oNVXZ{^{%tT4~PhPlwW-@@lltA=rGKOs|RJ&!?SBr?L5|xraDT!Kz;@f^Y`i z+(@NqeHc92V7b#U_?bqcac{TfX_pD5>**e{O*R*OAJy1g33zuiCp#T$e>1mB`{gt? z-#d>NAYHsAzp!-s%V})>k=rGkcWn8CpY~tL$)9bzX?^(kEft(jP9pj+ddYD|ZK&{T z@z1v1U-@Z&Kr0!F_!#A*qMymhzl+WP*|y6#I$W!F88M)dUIA*-R9MLi9+Pj!CRhfOW8wsu=SAxE zZvDPiuxE;T#mes3t&4MI{@jITqPwiWcL%9>h-nIW45&tP^N%;v* zY-hY>XS;j|#yEwO_F`B=_4l^jzmS~df9T~rL)vyxjJ0oNvd=w@^Kck0tLa*L#-%yC z`K!`f#~?|bT$02=>wDmfBbyrB#Kphn`7)FJf>)e3ukkRyd%xPNeT~LY$&FP{kmQ_^ zVSxtYqV5Bs-clmt0I(58p?oLs=O|(){dXIveHYQ!i&_0h0wC79tA}@ zCP?Y9ueSZIS>~e1BMfRT454IgWX-kfweV?8OO~#I+3IxGJ##MJnn_{F>X}@Od$M?u zYLDZmd8t_)g-1LNonG>CernLye7vp0k>`OH!D|_XR-T(L6 zcK^|b|3Dx9o3Z&mngx8#MME(*1~xg%sp?u&VzcTp#o?4Uxt%(Hh0Xsrpq0WhlH)J- zKQXd=7k+K@{*ArFP4u7G{7;WHQ+TJ24^I(F=YG~0i>G ztz_yt3JFqion=2JUK9F!YKL#y^9vBRr@HIF;edowZNqsz65G{b0Zliezw6mP>DvNM z{(7W!g!jgw&r|a}r|!S0*m1AoCm>EW8s&+5Ppq8A?34=F-%p4 zYQ1vUgB!t%VpXd%PEF85e`K)FY-KBThmbN=jf;bqxt>}{izxOyr6Oiqs;H`UN1#!W zcE7jnoEYwIqDVJEq_85yxhA4xXH=?PlxuO+o|dS6;;14Qb_G5<;U4=?Zj`%<%H;<> z^J5}tnbAz6ketBK?y+ckw{qX90xhfCcAgtkHzODlCEiqA2 zm6+Z1@bL`vRc=IbjdJN2VK0%1p)qwCQ5m$@#c!~4Vb)v*cm;~f(o=pIgVKQ5!Y}Mw zv8PwiP6e37UlpHTTFfraRj$#ESxYEj3kU z{TXK;1nZ8yYld!qbH+wyUcGLjzsf0x^_()ZSoGU81J&e(dS`cT4Sq&D`@JOuGbhE( zJmpYs;6I}{XBTirHhwcQ=9KD51G7E+8<{T7EbAO$`oXSwEbH)%Bm>FO=L zGMrs8Qc+p4)?76t<;F4osO*L`nlt8jaLAXQ&q%j#V@N?juph#GIo&8xo-2pc0U0I3 z(Dt-F4)R%DlF$QkN-lnLLf&|VrQW=8MM2wY;Zbhr)v{?(I5=5dV6U^pr0ARE#w!Wh zDj35Wb-6tf5*caZop7{3e5O&dFz!opiG5LVF@|7q@cQRa-WS*4v^lInBoAuDtg=2; zytzQ~qVd)Jw~`|TAF25tc^#7UtJ#PniF5>e2ftZpW9}4WC*_pjJWAev8i^~YM_PkO zfe&d7_Li$ZD(6R+j?7PLJzrFhxiI-2NqinGDQ)NsbHU^z4Z_rV4IB64afR&jB{@Zv zpC=`^f4TSl`!|Cwg{!!|A>bAVjcQQ79rMD(yQ}I0 z+RZfqEclaaVDRdR?q9t_aMtrJM(k8b2yYtM}FRMK5sr*1g^^(!r*+6>VPG_b|8XM~oxrxY1 z9J0?gV?iP|<;+Bz-0xjI6ee*X1Ro>7h30Jx-a{-5x_^R}pNrrW2eT z{nZQqJIr^Q?=qd>MEEY#3C{l~e3y*tk_dk8e+{*{+>?ru(L9}p9gFVI47Cj#wAn5i zL14bW^IiVpNFqCXjV|%ssAi9idPVO7-s|3Pi{AYS6voXsl4=JY_7+{}k{_tLkfXgM z%>Hi449xfb+lpjs2`>No!l_hy-ai;>`!B_5gpwou&UYyxE|lsmoZ-6+;FNl&`7X;# z?09y{x4qTQHZKw2R;te4jg^x3o|j3B_MyDq{2=<6T#nD~9wp0!dv?w47Fk|O?l*3a zzN?M)!MvweFCDwJiy2+a5R_~#dIuRZ*b894Be z<4P&5UX-l&!~F0e$=r&T8&{Gb)ueU5fCs->=YEG)BYRK0&vge=MD6dXZw8IXbD@Bj+R+qw82E z>&DZfoq31-4dzRf%Yqyn%N3m0YogoF%j~RK{dEDbZ|T3-)%%AD&Y7;>4BzFix_Yrr z*$b6tx_bXT!TF!A-oK0Q()Y}tWJ(UGade+sAYX0MY>`qEdwBWo%P%%p{sP@J^!z7a zzW);6W%OaSb+->;y0cr8C#G zq-1OD_iOQLxo;cxHQ6NF?oDNq|DxWl$#XVpYt|Qica2Q!Kd{kKGpRTr-~UH)u*qt4 zVUeSC`O<;A;!he8DwWn9K7`fX=NC-TE9IaRT=4eCbATIot*#?;92t+>_TFU6#!;eH zMFOCfkdFpXiE0$4tQL=Nt4+rnIPSs1(&|}O5+FI8W`}1p@e4vYELAcWqc21+KyD|y zM!1?`)S$Y-g|YfVGT`S}sgN#;vDGU>o9MB$B7u_zj$FJ*WC!Mu{2u4BAea;}KZnf1 zj*w?jxo8NcLokL9Zg)j8rUHOy*zS~_Lt7XNL}3yZ$a=i7L)RnYT`ldhI65D2=VPqp zQ0R@W7`b;_vFk>N;KG-wSJ!_%8ac249rmDnu96V9KuDFL<+2ud1Avto7peD@fpP%b zpU<7MgSUpD#2GhO8{8QDwUZj`k-dTbdhwvSMn8G7d6v7G- z=);5hn0SC36-tQ;;i3ejqaG?pJ}A@n^DtWglnoJD>9Msq`p8${=n$WckqUwvbg|A< z$eDs)BLZiUjttSGg&s#;Rv-F7_FO*xJ&O3Sxf|hYG05PVIigzQkY{?K4K5>&p zgIo@>isEx}w^rbwbwu=fB33pRzn+hi7ow3pyTYoYMUL~6)8|{Jd#Qhp=m#LO5N%2Y ztjK^Z2ScEPHe$jH#{5^Y)H5z@m3io;Fj}nzjfDXm3?Ll<6EbMVV_~$YIX+3*bG)?X zq0ssq4I#=T7K1&9-e$&;)91JipK^%ZdY?$R4@37kcqs=zUmwd7qzsEvl-H*OiBit% zdQE-V3W=~c4nlKDC_{4;`T(?_3VC#R5qF>$H;V{n56|pHROa{@vTE9D^ECVMZ{Con8rW>4n1i`jcEwU*TqXW{j*mukeIAm$7$z|7sd)1sz?f=f1TkWA_}H9~@v4 zcmD=1_IgWv?0O}29h|)gqa*|)0#eVID-m-JpgF)HmGn#F^GpLEHi@0O>->SNv!S); z4EFP41=^izyfsI% zW3$$R*`Z;qWM8>oekuIr-NZrmwcYFFS7nWE+`2>Xz>0eC@V(S|u}?;B=jRg_=_Vy{ z43FPvZf=~v*$-(=UTT+w?nY9;iz8l0Hr*e`VX!Izg&RyUOGB#Bi?_?D8$QV>=rUohqtt_@O8s9KXQ~$ z9QJ%Nxy}HCmbV(Jz@BHqrRk7&Y9V+*@}{Fdzd?MkPO>4aaA-*6=9{2!RWk5na`eZf zPEu3N^Jf#^$B+$jT>1o(9+foBLqfi|q%i|y6J+D&`{?(H2}JTvG*nd@8=F*BRifj@ zYpY5St&C{jy2jS&DrJKrI<6m=j_j0U5FHs3tZu`}WSjB}D-8`gnIn}grp6(q+-^fN z6JLI2*mn2QezKTPjqVp3sw#pL^VxdXd{%$K@3? z@r5G@WtCo6+$1h0hLu_kPjr`#a7iR`eND@#hm)}ec^WNhDrixnlvW95EdBm*|R?4OcdMh*gT@^`sR&=J&n6&*oQ&?J`mK5u%_=s=9 z6ou_EsVlF!SSPq>Mt0v|QfWb3w#;Oiu}NK3WnEQ0B5)B+{8JxKi{SK`J|kkgB9%r& z9H%34xgN1*8=LF@73cNP<~@I}$>{kvnvCxMt;x9QPlM&$)0jI?eh!vTJFl6BXP!j; zOy>R_=XKrt!_?S{Yrl`$EL z{e|pz{vrYh&(8c9rsyQP0-@P}R)qQtv&IcmZmVcdW6hgO>Ar$pc$EGzT5Bemt3-Qd zJC|H&hhHJCUNrZx$h9hTRWstesvRCnKJI9`UUinV5PY@Fs6SP0)^j5xRQke;-JR2; zHaRC_9#+^}dKw!!9{=h`F2fy~87%j%@<^w3y=_Q$YVP@Rg^Am+^Z3!LwK`d+9rb4h z%X4>n%@6jtoMPkcp$#$D3Xs(`*ZVeysRi`mG(- zT{*LwAB-1XAUqggUr2s5vSH!7|pvOEn~|D zt+?HzLz0nc9enpY_rj0wt*f4dTGs}eEPwRj56tHF;wHQR^6y&%7-VuSNKiiFS z;-Zyn_&5ua*Vl!PvT>_mvdJJzr9WxWoyI$zL8uLZGFLil`1veOGEupnn=-*+vqQ?3 zZEo2!OBD^xv%p2#`K*@F|7NK+Au^iXqGc~FA;O9yi{)&c7J8ni*slu7LgyPDoc*-O zj!oyrY_M0DBei=Ru41&3(% z&cINzV6LMq>L;^iMhAP%G#NLg>^oc#Sk9;4(hQ62l+@5v9lVFn*lVrUwN_Ozrt=}Q z?WgBNa|pd>0Sax6-ryi?{5N$mROgEQUp&xBWXgr-duith%?v#Bm1aZ9gR?zaidW z*V-7K%`HvUEt_b6xv?Q$;eGr%Yi*ewT)TS*+R+~$v-7MsSlz#6zJyS5e!|JAbjf)s zJ<|1MoXbW36$kWb%(+&4mf}bjVT@j`XeD40kKVr%JA3_H1Lg)a%#!P?2WGjF0adE8 zfjal_!9~FfbWMcnn}`we6egP#nT1vr*v-3iu;JKorK|e6Wb6ctAxOE**~T?YydM`N zKtlh!vyZQH?}Nz2D6B;+a~34PpmMWh`19`g={uvAbFz>v?b~X-WzoTctB+sLK4I^^ zarY|2h}qXxf`wKT)BHzF+71wSsp z+c*thOio*Qm|Q ziRQ;s-+9ST`aQQyzI#74TKw|KK;X;Cw#lh6KA}_;vqjROCjBQyZSEeHevukYi7sdc zWZV8_)JBwS`_6p-)U~-CQ?%S|6WBH3<1x8NlaYzqwy-l$8K4Dhq`>iHXyNPd$ua+M zP7vsWmFqS_JWjML5w8cUiT#&zK#Uzrb4|E*3(G^9ptXk0p|G_xS%YOkK}@VN9qr0z zt8}ybj0oXOES7|pr+@(!Y_o2SZxqOq37T<00vBLW*lUov99Li`2aJKSnjEaDIMQ5< z-^E2Qhq0yta8nEWumcni8;6q!SU7r@V*r~7&ucLniNWt;;*aGYG62j3t%Ue0SNPZ1gj_QfIdL>vOXg!ue0wo8%aPEF%!L!7S;deQ55jTqE0M`` zGcL-D3Ybx&Ju<;aGC>|dOj7hBa+IfD!X%U3@0eI`mdZW=NJSiwiIH+}pb%hl@m_Sa z0r#vt2ZQ6_Op$4G5gM852oivrFhJm8Ot}~@CdQP9(dA)5CJ0afe>#T1L#Bg}BS6Y# z8P0RPvn&=qh)9qUql1`uWiE!sMX#knR$}yeGB${U4~HWh;ONL$yd@87LPu@kM|#!Z zQ*UC{60t!5PL6^NCnH}O_a>Gd_g2N4j@c*xO^^cu8QcM2P6$9(Dzf(svM2zGjtWNt z10obl0HVnFjr8*>T)>qKl0~RwRRH;^aM4U)fdC~3U={<&D?Vw{!wZoIz(v62Gd;j| z3f2MHMG>Pma)EFz+BOr5;(#0BOCvDAqFz`oLcO~Q>=K~>Q3M0XRAB;%RBSaBwSbJ| ztr4&mR?!^3>uT)f8mp#<6n(*yy8vs_IgkSGqGNmopfwrmMgg~z@Xz0Z1P-{HgV!Y! za1=q45tfOf zKs%%&WZM&8262|IAQ+iNxH^VS>G@a_GY#FYtYl(QM2rc14M#_>^#C9h zbR=TtQ-LL1%;B4;Ll4o5V310RPUHh3DyqPoAWH{E&u8jMw}n~IAm>bw%>*|xqt4Cu z8KFZ1ddXqJ6gDMuhzuF&Ly`2v5mL$%2DD{K@*4f*F|+usM+i#iz_kJt14%0b=u=cw z92FHU$dYF!r<}j5AWqmTjyj+Mp`QEPW5iED$zdd!F|$H3Se^=(@SP7iT~P- zUkZR^Kqi`umg7Q1dJ&Zl0DQ1X@21Y{=;>OF|Cd+W+gsSfAkWu-XC6GCc-O2%%^_TlVs^Q#NO9rch@ z@NAFMGb#DmHp6Fee8{r|zdr%8{#H590Ub+5)1A-~QnkN&HNBn?oL^ndt(J1D{nTs1 z>j{{w>O{I+gj0>hz$d1z!}aYGgd|A~$FNquy#~z!G7@Stt!gjGT}j!B&Dev5h;{R{ z>bOpDwiSG}wf1sr-5p6CPyKm;)$_tV4#)RA&+~a+Y&ic>$@43(o|mfEms{0;ivDF4 zRA0GA6l%j7gKVA%X1)Ce&$rd zRp^-Ns6>!8^itu2YRjHi3HRz%zN#udd39c^L1R-xd&n!T7vb_RLjReZ%x_F<01!^^ zAR(RlJHJlc>yezToam|`I)~&xDlI{%)$~9EiVJ@G$DB_~b5Z>aP-H-j(0{ zJy%ar(YI-#=3EzU`-fs>5Q}5wH9Z-X=r9H4SLKl#&DIAJiUsEN=WzrvW^A&et*ur4 zs(9(rr96qGw6ZcI^Spn+sm9VhhgsKzJwwzBue=JrnVkRDQAhJCoiJrqtUdd|%{#KO z@x_TV50D*e)1+4?ONWt0|ADKW_s+<0)yKp}F7n%{f%v*d+X z;+$M>>HE-352Kg-rS`5pw@#d0(i&Jens;{j)N5SV=TF=7zx7KbAy357FD2I2RzitH zK4JJ)?XY^rxEi~44pI>dEA7@0_OIjwU4OflHc12x}wX`jEiP z@V8M6V+2{k1{3?M8e50UF{8)X>ex_@e7dTL2FwI7$-nbaik9pEE932{A1=@FmN zBt-HmNS*|_wbhMsx#!*Mn$r|js1{)&`;uvT+JK5!pAFjQASzHe}NhA<5>bsR}JGN88nuYO2E@=Gu2n2uLTXxK8r+Y<^yYpiW3$ zXk&%22zn>F>pJ=N`&4qgW0&QT2ZqU}a(eb*gWTx+fy*K|WC&R0f8uaBCHhcHoN|S*6 z+a;sDeLtHS%(bHAdzI6p*K7j;=C>Ur4HFjjSC5}e>zQW8^bXRjJ=m_CjRr-%MQR3* zkrL+N(6uXxgHLw2kq3PbNnWE$f!z=8`u^yJMP%%V)1SY7{bR z7V?v6eQLC2TWz&=pMHTg@${a5atG?nKcHkjt1 zhB4nuS-dyqb`cu`XWOmDlsqZg%a?$Il%^7+2b;gMq))~^D&(QWK_`~v?|v7dn+amfi^Jyg`3f5(($Jqq(|N!PnS(@+|1F~wOH?cQpQ|b zpN(bZdaK88yM3j{CF}RKChqDlTkvXph;QmME~?C$B*+Rp_ZN+}E?V`d>_d!ncg<|& zLCRV9?ujO9c|IPb4g`>ZwM-J^ZY$bsK9VSc0-tpwoIYtCF z#;$&gMcLf03y0V4A=c6&*qUq{0g zvKnL-U~l)XZL=vRjf-CY##A1C;N)5Hkyt$ycJ0}sV~d=REjE09uHpWDHko8SXmaS` z`}|OR+3Te`kt;6hiEj_?QlFw{QCgQM-!-Ef-x*3eW#tkscCfa&tgb`?z;UTgkWa^} zSQQ2zKD`X8-m!UpuyE0=)kL%%u=!*gKSCo(SOME#zIA9UWR<8Julb0`F?)&3d}LKy zHVUHbi3=6ZHW)X}u1HSRzC@5Wi?Gt$blU912h$N|wIzQFxn>>E5Lp-JEjcDydTV?A z4>8_a^2$HBbMIjA;G?#lAwn3xLIh^T2v-(}%U?%`IMRomGT|^o@=1g>vTDE01Td~> z%`+J#?JG}=hl#C+j*ElrB$uQ0bNPS{2Oaw?&*bnnm-s0 zw#$Z+F-|NQM_&1-$vMHDkIP2dlBZq{X@*M1u6^G^K`T+wl6f*|U3iE^D|(>)xcZcC z6iUiR@8aNO=%5T8KOrQTRud+8p%P-4go>3R!6Cvxp>mieBS_vTY$PL?6%!(O5TcVy zs9D8`!!yKi$dCZNoR9Jn5sr}2+5&V8A3p&T;sP19F(Dl{0^5|s-gyQmjj?V!;1<)D z>cBE#q*DqzVOhp0`;O!O8O}&-B)$rhzz5J}gcv3^gea3r#SU>oeo#;CO~*#+z%Bw- z;+VXTNM0<26PY2-MU1`8&}0>12*&^5gshX+_-?Nv1oC~sGT(}7bP5rGI9MYdZZ*QX zRw1Oq_!vGx%)!M#9{Y+ygC2xuWCUCr3%|1yy&bUK)s0W19^UV&?WaSC7I^LeXt*2B zyNU269w-G)(m8;O0KH0t9Ne&uJmh$WH$+yxVE~*1LI7cc4DTgj6`2@$ACLiHw~??i zOkfTJTus8hqJeZFu$%`%B6*09mM6lNTV= zG*~Pnks>c5KCpudMZ+>qOf0Kv{|-KYr5+FCLOVndbCj?{L{O#UW!rtFWbYt7I1UMi z!Pqzw!G@2Bh$rsY~^>r@HXU9F!{2`?SXyJ%7+t zaBc&M;Lk&Q5aA6R^hP3t7J(oIdyoW}Q!qP41PwAY3K6C_usj!%azKy@JM%&G9Ar@& zv>^dVz>0Pg4~x>QxY1G`n!>ygOa>29U=$DiPE3IKK$w(>Q|4iVRRMhfwN;2xCSq;K zm?fN(YxVISdcbM(P@T-6u0TA}Q{>3l)*eEci7<3eIOFuWO-eFyB*+dpauRo5Z!vB) zjCUpy)-bVN0th1Fo#@ydNT7)XJU@qW;h?-*KvN)O77N8D!Tv%JGY8KQ5p0MU0`aOm z2W=n(okW1HEOOBT4Cts06s)!2vbBgHM@$2?uxG0Xid0C22a@=J4fFCVbASLG>AZ=t z;bQ!#cqbxZR6ktDHPoObHh&fNBn7>QnX1bKb$KX*o+v4g3B?`WDg@-_W8_3fP8K;k z3qWSq4W$XfF8U?d@tVJs3{IK>j&w*BK+Y|o5gjt=h9E7p3JJf2ikAW?k_EhUj9|}4 zlZaQlA6}EcnMdA$UNdn?g^ZR0tWzSwd;J`~IWpJ4+7W!c=NyN?#A;KpZ;LOIV2l$L zI-D1J2G6L|jlcT^dzg+^B7ws~d^{bO=5>QHUwfDn|DBX^-b}`ah_5nD*y6BNfsa1h zjBe7Gv83PyG*BI2X`Sb&0t8j!RcjuY%DHJ|0IL(xQr<0DpS*S4Jd63PS$!ZH$d;0_ z7v>=sX~IIjOa}dyl#KEra!M@VrgLa81qA`OlmW;FK>5L#qq}mh1u|Y*1aDgvkC7Im zl#oj|30y3~ZecPFgKki37OfzAZFV6XdwBH4=+Q5xY5LEyKo;OczGf%_kui#$WH4a^ zxPg232Nk=VjA8QuODa~xy@@dbmTrIz1@~pNFuUOkw|aRMZ$X7gf-?DZ2egH4|BYy2%`mH-t^*a z`|$D%uC+5RE#QQc5_TsUpU6Fyvd-J^GfJb+H${YJ@=-QaD2{)YXmJtbphBoJ3yHut zB2+Pp5JEh;m5AlO^Fy}hw;h4^%YgghE}tagoOnF6&jVj6jBnD1z4Xz%4X87eC+Mup zaWE8In-R(_sn~$t%18T9Fd9Ti13<+AzZm!B9}%;rI5;{N9WTPF(Q&h=sKeabhw;?h z=Zie)gp>NmzHyOE+wso<$6;^h<&+emD!7WuQl%uWLXM0?j46ptVFD98LXrUOEJF8n zvllLb`}N@EykyuXaVZC-D2TYE%sRb32|NIL5YH~BrpSoU4)ti=)=CN$TurWkI5^-f zT80nIqRukr0nzlV7&uBt9H?#1mxs|SL|6kdPK%877Gcr?;5n^}@MA~5!Dn{D$0{X2rl_E+bA% zFma6x;e;g;WqNmp#bx4b88yinHE}JmHOhpwjy6mNLz5W8AXS$Zt<(tLTK`vq*vN^BR1_hmuHENu-z=(&8Cbs~h_2 zMv!St7;Qd3d{xw43B%kB{*Vy*+A}T$j{V>e{?0JMBscOR9=nDZxrPoxOu{5LC}=D) zsrtf^)3|W5Oe_bo-H6*S!s;u(SaYQMVa@&p*3qiRoIfXoh5&@Ij5F^u8rzRHe2%&D zS<+x&#+bYj@>OaGH^|0k?R@_a4Js3vin1@7RZL zoxq<}Jqa4&Ulzae{Gz<<$(xtK@Nhrmd=4V3Av^T`!s<`~z9BJ#q25C95TX6)I7naR zR;b^HJ&cc%7u*C`!V56uSG8KGJpORl!`0(Kgs%>`L`_NYgBs`7t{_O{q6@s<_Yfvg^!wj_zE&Vtc`ce4@7VU$J7uEM! zt7-{RT0|I}B509>*f1fo%Obn)1G@dAbgAkVQajeJ9W-j+LWfnB!BBDPoXu*nMUZBx z8o951k-VDdtZ!{-$GHO?hEpA+%iF~MbXTQMdG`+ctb1%~Gk0=&lqkpCg-Pn%Cid1b1I~`1v)o8D|`RbQJXAV10$4@4?Y8 z30l-&96m>r@ZD+{RW4?44>NAF%Gb|PZaFl07!$yUo&}u97*Ls5+`D7k-5v%B!b|y& zJFab3_H^-z15i7O0ilxKq?;ogd-L}nl4<5t#cI%9mnc1r6 z?Gv3923RciM3uxn@sV>@-=SNBc^@UkZzmfbti5qFfBGmJ{Ay+DsDW>BbNQZ__~eW2 zlDQ$DinGmiPWK%9WrP&{tD|rJzVjXLCnQzFlHO8GOirDwcju1=OhAC&!N-!bxmB~H zzMVdXAZ*nWUr4_FkjN#9KXi*V7AUF^WP(e-pRbuH&rx&=E{fs3t;tjT@fx>(lZ;Me zquQaHPSNE$Fh)Q4#m(nK59&IQDaQw$5-@dQw8=3by`(V@GyBX0CG7*@ie%rFCTi9v zv`78m3w>lHvZt@_`wNB2UnTjag5lwQB*JRVt{nO{*3;E{>fzXGV~p=+Om$-`E^eZ$ zf3o6PB`#|0+cONBJuV;D>-SLH+|lWGPaMMg21azhdfPtG+X*K0YlMxweD%`5blkTH zxjK&r-|1{@ZWFDYi9UciN=x?a2Gz;k0wz8V&?jM$PGdsvlRW&tLEzu*w`pTNh zrp)8+oeA2N?j79G?)ue5+zhiDi#4M}sG>skE3Vn##xHKItWPpL?_OeF)Ze~T1}0J$-(4~&eqDL8bunpp6dt6kt|fG=>maik&x`BNV&*ApGQUR$^*Uq z2&}icxoKi_WMULK=Oc$_gpzZdn90*I-W#FRLO3UbNw& z{d?;NHLW z<}S4&?zf%AaDz<-oFnfZ&_C7vwzD`GO~3Hq?#JKOH|QVkhs>U#$Gv_bFRze!Kig8F{XtSDsnrz3)I@H(c zoyDK)8&{jj;P`0Y;8R45(u=jB&N8ICnLxo{m-LG&UdiF;B=K6pGo-wyaZ*8l&DfsnB^$!Es zZ$)QOD`S;j*9X5>(n|qtO#CvjFjD!rxII?)j<_RX)l6n}+4#@yW~S%#&SD^PlU~$3 zd!jo#2RZbt2cO;>LWSa_|J>_y%z=axQRqfY+uXuW<`hXZO-cYcjCZ8V;dI_Jjk;x4zoP{z8 zZR?l0mL=J9aqCp<@b_|3Fw5xL{wfFTot5VNxG9Q~H+Vw zpVl`7S1-JGi>cJdLWnt`m^r1br)r^8%`l=utp#b-t2Ho?ciy4Z&a|3!3mxL5 z6n8tnnA9{oUhIan>_ty<*BjocOub;30X=T2WsA0Izc^K^zh+!t$skfzW9}hWms&;B zc`^oDIM>%}L;UmkWeNF)X%~aL??*LJF^|+8hu4i0R=Z#`olxi%i|0OP72jK2Dd)j0 zRY@^T{j24`$$=TTzf((d`3$vyK($2mjx zOr-Jmn;J62?KgT;8P4DT*xl4TJa=)~hUQpa?b*YdZn?dgrpbQ4O;5bF=RY*r$Kq$C zqGHh>+^n?_}%VOuDxb3v13PYVYcq3o(;R_*9DY_Gu*u1f0HK(V-z;LQNrcdr;&SB%QM9F`9ZoK; z)ZIK3w_DPo^75ag$(|2?)@FK_aMS$7w~L>?EEp!2%eyfnos!)&Y&;2qASPO-klI8J z3~YQjcVxB+3U8uE#<_`-bGIz89;TGbASW$!u@Ga`ZPD;FX#w{HfHf%wQ4ocR?dN`p z+>E#AeMQ(=dq{njAVNc67ctkBs(!?C(%(1{GY4Q2PL5UJINSk^Yl{|q7oO4@O-TwD z{gCg0LS4lBlCQjsdcD+@IV)9&Cie?99mjlZ1?^E`o!2yR#5FckEO{enAECE9WV`Ve zPW`oOHeI_?cQG1H&MM)dm#UDI6O;xLayLekw-K##|g&fZ6i#J~W>m|C_w zQ}eqVY)1&8p+8^0e5gO;gUm3E1?4;iWvr+uH31g;KiGTkpr#&%&-WxbX_O>bXi`EE z5EWtrq!|=xDh7Wlh>B5>E`}Ni0YdK(M5Sv$1Qf+6NLM2&pd!XbS3@r%29zGnJ^r3& z_kG^oeed4cyR)-%@A3!CK*&snB%E`;-|y!`Ud!a-K|kiaAMU54Y`Y=OnhY*D26DB- zY>5~HD$GWJAW;BoDr`Lssmn#I;{u1@g2*jl8G}%i5NN{%RH+z!DlDY+Y_~QBWJSqC zmvq>8TQVTehv&{SCTHnGe30OQ*Z>4cdYtXD2E!?E^)|#d0kp+LKwZjZchu-R-$GR2 zEEllk;wRZq3(<9)g|j7t1~i1cj+ZGFg#=(Gd?Y~CE2#0rEk-bCVDZs-GlMX*aX69! zIC25cY#4yOW`n9iSO7VEUt8=rO#((jSOb8n5TV0`snd|FpeuVM*4OC3 zbtKd(8mP|ky=-&VT?eC20!-KtIT3M^l7b|H>$r$0g1!wo&;cE^D;`G(L6~r2)oE}& zDzJeZp4uH`K@X&RgpZT)mI64y2Nh_bApq!+p}rqNOJ0AI}|QiU@uwKXEC%d?ZIBM*?H-}2DZ)3tV7t#N=5Y0!A$jeTn2Qt zk%QhI8bea_(pWr<|toD4u0)hFp->lB?%Ki$<52n&F;y~IhGs2 z2d_@#7TnCev=c2~gpXk7E(>$-yvVCu%GFTIO~1LSq!f_g;UuW?3EX^{w{dx;s0T}{ zN=8w!98@e-zIA7Tp4`5@2 zERIATN2-A%ErCy=A!Lk;Ryh|L0(dzF;y$ZLKCeh#u}I0eNKK+xVX{c8w@6J_QZ~8R zkXoF?FP2{}*0d{DWfUtIU)Qp`Zs=T;LQTBaMJSx7KPiVgbJ$fdJZ)<#7z1Btz@JVobrjc!u6Hs0UM|YOEx$MFm{HbjTM;W4Y%M}hQq|Azv?gDWI&&98NbN7J9+88b48Uz zMNLCi-SRD4GQy1uORSB)E03NgVPZINK@M2#%*dgKVvE=`|G?EAumjeCzt;w3kkBgv zWLVdol3M!u(9qAum1@T>s@YZ!GAdXj@2c6}{lU2VtaP(9jLu%#Hb>ql#=@?~C|}`?=^UO>uq}KKGJVJzXpRzF}CE+C-&A z#eIu?jFz(WE&Hm7o|VyTa2pRl#EJFpN<^n@w`1Mj&d%KCc~Qn&`$L;&2nnT1q{n3k z|GMFsERYnk@sr#tqufy9y1RZA_b27=?lHMP(R<(5yE@dQ%H-Ak$gfo+FYnJy-r2da ziWquVdmkerrPjKl@@pO5mJJi}@SLOEeZ3ejHd>9nU4nI+$<9nlA?WYaau|zSM@8vz zZ~=~h12I;F42;RctZ>sK8q)_~R_TT{+J;u@R8+CQ)~Gi&#`e|5gw^eORhiUSotmE& zYf`m2thynkdV59V_H~)NH`Xf%3lF8#bIa-r#3|clIKW930wgx*rf9!Q25qRZ#m*t> z{EI*5=!+bbcLh$Zud(xZT}sORVcoiR$=VYpP0O!pgO1n5O7a4|YvcQx)HXg0TB*hN z)Ftk#{LohoT@MqHQ@7Q5`f=;m2)3^gqIFpaUh94OyTsJ75LFUAkqaZYl?dl>HWb|a z@y5?D?|(H8)9k~W7qDdtvSbx9KZey+wbHw?8|5bMytaE{yzkl6t!Hwfb%FU$YrL5r zPQf4u1AE? zwV%$+;f6>!f7;`RVRd$WHB2@R1(oPiL(z|F@w=Fnair(8l+0h;mtQ) zwI+9499txETE2I}^ZQ!t_rTRzw|)8^1T_cD@(}uD1cMm9Wz*vy$hHw88ZrmoQM$Wr zg@&@WxMx921-Ba(1SEX2$v6v&H52;qH-?7VjVuAO|VzNX%FX!q3ieUrF+ zlWkJlV0J|KLnFj*@zm`NK7rHLAX9+;G4^l~*=9p(^V!!#G^tu)A?#V8A2-s5g^wa8 z*^m&PHo&*>^wqiX9uno-A!4UT^BT{rGvu;@GTfZUjqf?QIUS7GGAsvOzC)qRPmzJd zygb9fEi9&YXX8`}8Q*mU_i5V99wiYH9An+7GUJ#|v zjx}Y$U_^|O0R1ThK1hdePR7U+VH@~x4SC>qKmN8PloNyURMZhR4g`SaG}u5H8v1?o zW(JrDptWhBH80hO1y4wWSyNE}4e{CI(F!+yGz~tw5sKWqKcvBr3E>J3UPQnvE8t#+HgJ}UihKjbKqSXj+b!wj;8BxfH zzY(6mvIe&c;U_u4{r#__Hhp-KaDVAI{%rzUEC7#?!6gCGfD4f20}ZLb)*R2x1k6ru z|5P75hxh0^yVWxsIrA#y03rN+LdYT?RE2Jt2981py^i-*0Z2PS>bn>Hm%89>cAz!k z!O|Fbj5Rzwk-Ia&Y zvjUty3uO7CG5j9RtFRmUv`r0h0jxnAouO^NTZedffl`lj`~4r%EE67L13B&(0N9go z>J*e71%?oSa;!LA0BKK*mZZTQAy|qwZ1gxDW`fA^Mfn>6C^qa(`jjaRPJM(3ARssM z;m!bR>$k7!f>Co0d@~o}K)|Sbz_DED`H9eiRHdxpxJraB3sfKjk_5CJZS*l_JlbUt zsDo(%j%8<w400nQ0*LthTQMLDJ}&^5-QiE|$C%K8noYuBKR%8% z?8kybn~zm&07ivvCc>h0;jnbzI|;#{0CrrMp%5T&VG2-|%tf$-ktUR6xpL5)6{pSx zB#H1L7VHc}u~>kyI2Z&U??&v_XCnd3_$Ur`loqpDfUvlRJoOtd`S{sa=W6ZEGpogT z8!}Ey2-Bl}-%130*)UbYJ%jo|(*+ixEx|7F<}$MF*6&{Y{)YxVF-UF{Kuuiq#YnP# zplHDe9s)W}=U{%W17H=Bivbvbmw=0A4Tn%sUW>r%Hbe*qp-KUca}fjqBAGJ>u+SI8 z=y@?|{$wN~D0?1BMIcz{#K#B|VYpZjWm5^Bk;FKh#OqLT9gg&MYRdx<=x_&~1rp z2=_D)1)!{D4(4hL6!64(#A;UG}8!nx;+=aJhNM?R${x548Ae8R0$=kdm>g-XuHAC z7PXsCz-=FBdvGQ{g?k8l*7#YjdJz3pX{X>tnOTZf^Vj0QMdP7f%Nf}8a(Irk=Sv7Fwlv#?*_2G6(#Lk<(?6DSNriQ zcBh)St~srg;hZys@XibYlZ-@*)O0^61O-fk*@7s8_x&&e%P{PHw2|F$po`9?z*u9& zG42I0Oro4BMi$f2*d@O=`oTs^-X5$8+o`-L>4cAdangKdhB-yK1e;;GSUz?wa5)Kk zH-h$P$%zwV{z|#jeErQny1XdyXiJ62cM=2+!4?9*|^w*ZTBeu}KE9Ylb<~3DyP*<~zT)bn#<$+uz zbM}>?nE7p>S^GINCwwMEZo*c*g*k7leJ${v%=N3`KN~ev&8PO@SGuitNsJdq{2ai| zzdB|-oDG@*B-O?D$M!Gs5}2A6F*|?k7Mp45+|XP@ij;0Ywd+F>&TQNwMzS3(lSssD z>0Td0*u;_J%dAeJxW;NUJyrfmj$JJztJo1>m3f?m%LiP~O*wpKp6RR*zBqf>K!d%? zbG9n8{CXr{c}gyF@5WH41D;SOnUN{Yv%*@^r%x}B zd)TX5;NLyBB*dZ&K1zNJkC-2Y4Kd=+mrh)q4nX_B= zUD_T>90)7g>b9+LX}^b6me-4y&crcsNK@q#4>Nj>%cb$tt#kaRm!zM)k~X=C3*_%f zPY*2FaLRIDWze=udb;kLO?qDJ4*cs{K!2G@*V&gi^HrDg7(|&Vc^-q8b*?A&;I8e1 zsGO)ttu#Pui$?S|Pq&}s>O-UNQf1B4;t!W-toO8i<6nIHAv$a1gr{0#ZtJ1h)uDz3 zpIrijpGHp3Tv}D{y56%PJ7ru(-@uY+IUdz<$o@^da`kD$^Tw?V(&ckIZxfAu7GGJb&KWhRF_^XIBV~%@F9VBxIFgLP5I>o0`94s-cgO83(C zPgqq0tWN%kh%|XNfSED;qWoF^@xn)a+)Vy1(O~VPrS-yyxyC)e;oUs38TZ$!0_v~b zi#!P&Eo#LgW1Z4&Y0Eu#7-pi=gaoH&8upT5%3Cm-iRv=TPJSuJrqHsj-OsmO@k{e$ zo?SO4-)hq7ml4`@Mqb?Ax~F9e>M#e`@l0&dr0M3LRVZ@R$ujaB^N3YiLr#xu-}CB6 z;-d#{fhG|R}+X~bnAPP5khHgr2$FDkf)ONv?!CN0YYR* z^9EnPq-`gL6b{xs+mh~=7{DAt9$aLa-bma!+1KS-fPFY|$3Lg_#OQY0UZcgRjDU9Q zv7NinZ|J`RuA!C3_sB8cCPf5Z*H)e&>ofRSl|RcCL`wDd7uxaC=BOSov<;Wh_0T-v zbl-`oZ(1weuU&$xubuqn>AuqY>2q-19PLLka`WjjW0b+0M~Qe5JMwj zU!)^L9%sqq>bToM8*sT$(?`2^l!=BnpQ>)#h8f8n6OF2gLtiJT{J2(T{IRty^qpb( z&!REYQL|kw#r0R`@~xLXd*9vuOm11jgbT%+5(2m!ZNo^tcEn7f$Z}Zw)Y2>Wh#!Sw z=J>8Ji>-HSky1p=ubBbRuKeZChvINy!YPr0S2xa{h&ix|12}kC$V={uSZqD@`$yR> zdzZhEyCMMOnyt>ieu*OiDe~Qz;u{mu9YzH^yJbsd$S5B&n#n6+->+~|)bxPMEwk1o z#w^5;aZ_Zx(qm~&{m_*J*F(^;XA&?TeQSj*>ti8j+C+%meBD;7qZ=)k6QgXCC)aPG zGG)O$3tP2vHIlnF#wKACKU$V2p?YGsmd|c&DaB>}Wm%|TCy3c1*mXPciFW^Py{X;$ z`z57MQH(A}4!~kkbAQA-r`;ufBFb=B16D~gd zxjD8IZASCD5O8%+ghUfwzIthVt{^>-fMiVfSINXZUUtmwx^|=V(WL0i0WAJ(`Mc)r zcLrCEmwsc0GhK+_!9xyP^fyEB@~v54JI0o`2Hd<|c`H4W9UIGxEo(X&QGGLg&7Jls zQsCp=h4TZ?EzdvrX_@iS&dySMlWy?sA5BZ5roP4353KXLMMpiELr*uUD#|2xh?JOJ zx!kw18S@t8t)Q2%Z+tHDB)BGjQP#KV%?ea&k(!?Vwk@(5g*!36vH~q8A>#Pj#M!5J zG`peoiC;) z)-b=rWy#J7kAoV2uJUS2eRnlr+%oTf=gYPdo9!OZVD1>fw5m9 zsCifCM^xP0?5{sNOW)ED5!DObeO)W_^AS%(vp=R9T0Tf5FHipxNu)0$Q>I3z7K0yr zg~}}uryQD84i0@`w1~nQeooIVLk=p5&J;;AF$#+wtGHn9?G+3hl6jY!R z%b%u7w21LY)cNk&-vyOFJr-y~2~}SpKC5m zlJF;tf7V+5i6k#Pv-jaYYb`$@Npkjg5t1aIdnCpjeDnv!cG=(N%^wMta4#>+_&18p-_;^f^AD0->N)FAtz~>Lh18;RHteP;X(-KT zblgR9{rDdwxmTCvYKuQe@|R0{G%xNqnD|p`*)Z})f;Dp4$?Z?AC3s@w4~lIRsHmx*-}sHTRuuE3I$f_`^Pdu|>5?zI4C4QD zt>s@NSnG!B=10A6!4nZN|^QV_Bn&$h0uTTy816%W--u8Mb-1})J z4nnejshJ~wm1ll${r;&2X6h}qcNn&3pd1(FEyMnUB)814*z%{=vh%fu`1<_VKWZ&y zmCKW>+IlMa7UAEzC%>wT5YLFji-Ok%VL0|IpO(Tgd`>gSx{x`RZa>zpa|<{obkuVLr(o`|w~(-b|{;{_Bdn z_S6gR%%su&b!s_;$*xA3Eze}IniAm#a&5c+&(!iyt>ym@Q_CIS%-*Gxn7clEh^=pB z^hg#hxjcLHbB++P{{EMkHp9mNj?4O=KDA7ldu(p?hB0E|sxFRcn?K;seh`2U6RKf0 z(w@Mpg=mX57GO$xri^*_W&J_xM~aIGrBzg1K;l!SFdG1Si5RO+?-9RxbFWo7mCFL! zS(w0_R#S0uS9*l>HR3 zA@H<{WsU_PI{+!wS+x}pl$v^f>|svN=lR1lZ=6v#(8-&n_@cQp{*vr zWpDu*2-N{VqN&v{5drJjY@^a<7RzNRtT}_aAisS#=^NZiTL5nAzE7En%J3^VtupFV ziyL&9*w%!=Pf$ayjQ+r<*WP%sx2Dxh31W|z41qYY;ORqYb#QYk6^^TWS{JiC?VmG% zl_a!DX!2sUq3P%T9I`Yw8owMUSREi!pT8yCCjhg1)fdy$7bR|$) zKvou0EEN3pqC8KHyanrbFm%`xwJfE+UKf@^I~kN4?t4sU*SFopeV~sc@H=Q^;%y*G zwT&mKWfTR*lHG4(iitJ8?<2nx7dF-ns9xmNM2>8nz5Xah$*qlr@K3{-K8wNasIw%@ zMtq|lQ-6Qp5khkn4f*zL<0~tdo%Lf;=xwHF_#25VSvzy2fj0~0lD#csPCh3Tkz|AXVc+U2b^&% z1L2j^tcof|&6)^6m$%H0)=-1}-wfNYGZFtW5#QAo*PWR5b}{WkUEF(2`rGofcim~7Hfg0>!*6Lskm znDnl?xPGIw?(X!@IcZ83eqw&yZ<`oH9-zd9g-|fhyJ`93XPn7cXD(a%1skW3N!Xc* zKbE=5GjmO7rZY=MsveK)$yA+StGr;V!!o69&#_5JfP_&cAti|zhq_EuR3;v~MuP6L zPK;5^0WhM=p42fMH~{WGhG!7b3_eVnk2}qWp@^4U93^rDi4|MW0eqPND%O>C`3ec6 z#D~oS7+Dtl;TAwyfVnI{xUw&M+FlNTPTP-NHolT2rG}j)U}lNo~xoPz|5lPwXo@_TKnJ5A#JrqAn z1ym?fEE0es!u6?u5=}~l3eZE*vwXb8s-O$jamy%w|DJv0f)_~z9Xku2gciK-Dd2||G~X<2smFBX7JPnD_(J@mV5lC~Gf|++ z1rz}pixB)lEm$NmE}3*qOhwv|VF(t)_rfTXQ7jf1E&vgH03kqM;Nr|LhSk$u3*GbY zqx?}e6iZnUAOLQ`G80s{8Je5>l_DiCoQjv5Vs8=Axma_uC?mL7%garrp-3;Uc%5iXmjuz3- zQ3UKH2N%x9K!`bKo9k4?Qdc95oTH@=Um)~|7&ZqP%|kkso(rp`Blo&qqy$@1F!E}i zQeCtk+_E8_cbIM}^Cj(jXPFebJYm^4si7=fJed^FC=W}L>9SI&4@p6OK{ z*KjlcR{6!ra*l3llM#W}a&?|s7QO82&cZ{$yGa^anG6fL8Awb(AOP5%WKER3o2}h- z^+}XE5$u)qLG5*g+Bq}i#2a3UAU7Xz8XwLU0#!0j}A3=yIZVo-$20S3PA zR>frM&D<#xheOg&$#P4I6yufReV)!-`7cjgb*Y<%S_UqSH7#>oxb-8+_2x30=lN5*TR zdbPMHQB3ikvqEkoVbum|3>pcuYq2R*T(w(mr!yvt(*UsVN((?mLR}yyu~RojIGVD# zm?JVkERztre8!0u&b$C_NkyT@fOvlHFU{IjGI(PS0(tr&-U0Vj7QeU6_dzgmG!Ksa{KlrE_A-*#o_k-KIHnRwQ+S{Ggj=fhDW(q5imvJ{}M>y1> z{4l;>U)I|;)F(E2J0%!oLl^9TbQVILjBynJt05Gn77k0qO^`h05-@tRr_{BvCrETl z4rr$xc|yzmxpR}NH-2Z>>hHw6+5q+h+v^|+e|RGS(vUzB;yc0k7p9z`Zd@{v0@_z521DLlp3#yM;zM6m<# zYQ7f<-m4w3M}>GR+DEy!HQ~J1wb@m~_NPCzp3an}{Y4~1k`Oz1D2a0L3F3cJMX%$h2-h3$&a8VJCjU-M@LqEOw}aqyQiul$=cLFH zifrg#AZS5G?3NCiTp*-Yk)b%d-8u5ApUQKNQD)yTYj^jRv=v6~rb7auPGG>K2I=K#OI zp|E7og@)eFfs^hCHeS52Ac**`T_e8y;fXAFm2p4L;R0C1qzmAVd_uJ;VH@X@m}AY%?>qL#Z>4S|nEv{7 zv_jzM167&OYIAUS||CN&VG!;^xcV&YN9xj~s! zM&ux*j;+3f~gN72)aJ ztLWNMxl_M1AFVPa!E9BgcT0y2>2S_(gUyL=WTM3vx)2U4%-6p9 zQWxTgF&j3g4ijUxF0S|c~eNWNR^lwSXVoH$|8P?oXTN& z+_eLl=ouw{nes0Wb1Y&?_t^wo=jVKHeyCxcrT#S6=7#+Z=Z}*|ZvO|hmd-@?|Yth!9Id%bk8m>ZZ-ZAvu@_x z(->uh+mcZg^?9;)Wero&-SYz|9`F?JA+j|&^q{cIwS5a01W)4d+AjTze#0*=>$`tu z`nUvzYmzw8`U9TbIS=shg@r4g!hy!Kz6V0XMx%!Ismd0*1iE!ceK{L1dKfYE9=Y$! zer>DFc#{t=Ue|w`CPKBA)rV;osC9ut3yj7kc4gQH1rRMGAJW=@%?;DOO8=SJjNQ7- zuh>%~W$Cw9_ITjTUiq_^{Hzq;zpTJ-eMdO0y1AND(yAH``rD|bNX^=)XKvqWtCbyi z$W|vmb=G!6Mait4o$O+(jOqs&t`&C~2-v^%)%G9zx4%Cea3FrVUYnpgp1B8)u)A5N zvVZ#7pG$}zejMEOYw9nGxuo<5ig-8dNFc>bVaEpt@=9zV#b)h;!|!aQd6xK{Oo25I z*0Uz)@S%M><_;hJ>&TIfhTkS)RJZnLek?rW@!-MH6Bj=2aCD*1J#eH(t~GEvldz-4 z$u%P=R_dUIbkGrx>z9L_y(%8e_ty5eZ)7_zDa5MMmL`Hv&`#ZXcEbPpX8OsXz5@#< zgI}0sUke>O(&ZBJ>4xE{z@d|Jry%!7-No<~wxzz|y(1xq&#(J!eLR-vyKNwDW6k23 zRCgbFWBn0_)}f3&sGhSI_sA{{U$i#ZdG3;lZ|=FAQ&)Dn<+<17j$HY8uk~2+w)tZ% zX{)a+o=%SWz2s4nbrjMN%UBtC{Ik|lQM2rIyQkqApPaaZ6ovC!MQT;@Yd;+WuJ4Xt?0Kw_&73V+ zsuB6OZ~Kzx-;vU&jZu+ZjFJw=sky6skW`CK)RSiuq4)Lg%-~+{+VIy!7rM-j7c1Ln z!AeJM(S8AgTeOvpy}C76EuTLB3LU?m9l@CN+hsF_?dF_S*%Co|g2ZYPA=ez76OGe_ zvjw==3c5IaaVR_Tx4>T#&Qkcf;aLHeR;O{dse2Db9YZ$lA3vHZX5`BIQO(z%G)v z7s*E>VcmP+&?N-9`;^2znrCDl2CH`{NTan$XqkQiYaTli1Ld%5ln7vtf&ao1X znbgeV{*MlsDXy*>%DI=#F|XO-`+2(x2zzgi$3-VGUA4`YY$?H8^cTKH8`%qXC8+Jq z2$4Fs@#K=7lR4f;Tz3lSpuvF~hjbcJ&*_IR?V~Oq@K_-9NgUV$!?#7b4w9qQaI%9U}Tecdz+wa^r*u!Vo}7 z?T%{;gM*(M-%c|+L?^BeZ%=+{&S(ISmD@*D_x}=wJ(@do>{QJa@Y$T`*L(EmX%R-# z=IkR8aSeFr=B$*{r5|(i!H>RSN=0BucRY%gp34H1zk*JAJnz;E(Wba#m z$P=A^Ahf*F4u&j9q%5WTO4)A(*9W&k+xV+O5mz8OUG;r_b_yQ75Kun{iLypV1mRDY z5J_Ld9xS7h7Jt4YjnAwgqbIOY^H5~#TQ#hrX9}gW5U=&eOH4~^D`d=qSOzUEO`k?* zgPWHJKlejO0w12J?{oj;_o=?#4~&N4(aCYhB@NB#Y0U!PQqxT?C$4tz2V2@p_yw~Z zn_e=jWs)=z#xgDC_ukhsW)m zdpp}9a~MRmg|gep$>GV#DF|{4CAEJ7S}2rVhC#oGfrC@IN36SmyuNWC7z% z{{>kf$Y0r+dj4O@0$(eG{)H?c?5~OcHyf6!s|Ne-zb6Y!_sGtSzc2q!wA+7>1?GEd zE^O-i{JOFB`~R~D_GyZk{%KS-5xT2CHZ0fF$i2OLlJC!{zd!$4I^0Zse5f&6`q)%I$x*$NxMCol1JF%^mSYg?pFcPZqHOB zumk@_7WkJ4*8BS(8`j+rm^%0Sp1EE;qX6fSkmKi z>%711xNwRk3Ob#+eG{b%zIQgG`)uubH5~fM0YdG`Ix~4ROd^hj4_*)#s!O@8Y&J?~ zzMtpyRwbJuQey5J`uUiMVkGV)Zjbmfa3497@%Rc|?{aUo#SA|4>fdC6KM|~s#S4S4 z+^#XkRP`S#blq5G*q6V)Pn#UC0wqDpe!QuDMpeOrIVsnJ(E2?)tdmoeEI-Yl0+$Ry0aQFA_(YxOxE>>DY3aqyJrex92@9XM|LZ;H0vriag zmJy|{vE;6KKZDgjo4s+JfE;q+Nq>YM${01O8(NT`0$w|0D%pZNA8?F_R?|^f#Sq5c z359o|cAKtgpcrhPI=bRw^Hi}{7;n^Ggrm1TRaqAPJFqR$Y_ALfA(Tddx@6ei~nPV{#UX9Rl35d)voh?-rQ}E|F4h* zE@&u}og(B~DF51g(HPit5r&qxLLIe<#{W;J-PS(??fs8pOxZ})9z8&Xn{`d;s?NTp zmrfn`uhh1W=!HQA*(+NwubiPO|5PKSk*)JSrs515L&dLYz5xYaHjNp-U+M_xs4ARG zb>Hzg1_yx`123kIM6Pjeho9aWjJ}P~yd)sZJ0+M6p3bm!%zJmGV|%G#_=LT8@B4z^ z)#ZB*cv13uRfL@Frt@!EtL2^FzEU7*1PYMS1a(4GHyk99S=RD-s!5-xSvv?U7+GC) zPRH7Ow#dhA?Ch%7<~3DC4}Cm0=Jzgf=c}$iobnC`>-{nx{GjpSH@}$t{;sRBQd=D@GZ_r=S=E)q29tSMl;hKe zhDnSCajM8CHQ#Iq3H5%vD(7peetq-JXzZc82pPkBkYVGkmr|bM;fF0y4*E|d$04F6 zm5PY<;9bAr0!K7CH;(eq##2vxV!fM`UUZm_8eaI>q55zv|4Y-Twf^$EESDehZ@VxIAs2D5EU{!XyvHgdr3^MQf z)JsTL2yH}+5~)42oY2JtTKg5B)>^-g-~faXng-#5N!TnB16J;HE}I7C1Q4_<{;I|VF(%qIw8>(Mx5E}8C`_SGz@LE4!?=Us&jEd z65vXM-PD4k>S7Rv=n6-iT@F5g5?~X;T%zLl<=|mdOauu~Ct=~%5J^^oP4TpM!n-Dh z?$nM$Cj@4@heP|tQPLV5d9~-;@cORs&40#=7qo>K)pDFO0kidw!x|iwJE~2O5m6%N zf%Dnc3{cz^>A;0;7UEsFunhv1Rkx3kWBjYm^C>#Co?susc+w^gQl5bPJr?syHfpyH zY6F07Eo0sDh`*8@c(ax9jT62*({LtqsvaPb1NeD?j8S=_2PQD66`@E5v?;JP01!?F)#}J{@K%~>j?ejSe2d>XHyUIp0_v}XK0qa6CW#nrK9K53do>nN(Zz_hRdQ?z%-|qIqv5Ex z;UYn{AsZf@bn=Z8bIo`n(*3eA6hTOH;@oxu>#4}5QrKDm29g12M5vz)6!E=L6eL;* z$=V!HX-5W~b^_}-I5ZU|1HuPyp)F(EIaX!7MPE17G6i#naI1xd2E7wsR2j zG?+Y}?nkTeBcdE>fS3b1(oi4~1JWusL&j3BpL7p<=R(ozBqdSsIcyOwg9Bz9g-cNq z51q@kApq=|)B^JL9nK8U9ly1^LZ2FT)fl;*igIDYJxPEcr9_qtpdl#8Ekqy}W5dJf z67ceT9F~esOSs`|T#;{wjDy&eER;GGSs7d!$U#!s@Ochb%7pbIw;(4Qe`hSJ{q(tC zR)kO1R}E7W4+$&?OMTmz15<#;U}R`t>ut|LZRvp@ z;{nbz;3%mil?r1~ZxKi(%?(IN(p7kJ291EJc7sLmpx6yu&qrGyhnez96j@jNsBndB z#(T&3kS?4$L%GxwlOjNIb1~cHk9;LYCY5H#ybV_)g`V$8^gfRN3c#)}c@ZeMIC4dx z4WJ-|bFjDe>0)Flw?tgn7!MuI!>W|y2waQ;`}(C@Fk?2Z_9mQ7M8xx={n+>*Lct^t z<19cQ_6ShOXUy>mm?j=cWKi)KT#*;}S5OWJgPrV>7ZF0wX0vK?f^+Dg0=3D83bPjA z)hQSl7pfLuvfB_Fh^S4_>)+lM?Lb3sprJN!s-^gt_pc!JAP~rdQ%# zuFih)8zXTXbN(d?OYlg??ko`zFf1-U#Upk`;3F@E&osb}hTwEI#LWwuv$)LHeMRdk z8Zo8?88rAqtHQ%Um>KpH%sre_rq@>8;7g9z6~lr>bi^7Ke5-)PsY^a#bAFvKbitq|cC>(leVDfXY%Ox>Pqzic+FXe56ioc4%v<(uq4{6Mv)s#f}Ds^f9`1`Ry{( zI&}^#nv4%Kb#s>qjwL<6yb#)Ih(@rGUVQvtEciJHAIwH21K5L!K2Mb5rcPX!Ph;zeZlu>MCuB#ds4K!Zp8G?$n#FAwo5f{O zFrIwa4hRP#0MvM(1_!sF3pe8crkte0oDX()K5T=I%=(iKoP1CD_F?<44_i;-XZV=? zJgl2Ae&e^4&A+hwIbbXeFYZAsXOgc=Ydb1;ya%NzdrT;>dRqa`$?D+ zh3`~L@nUxPPr+wlVM-Vo|Bduz?i21O`ODAqU*>;(t}p*GcjwEzvS9YWm&Nk}#OE*I z@6Yh`FA^PJP&mQT0fFe70BJw4czz&^Dr1zB;wD6={X#=1Vht7edcDCy65Ratg_h0O zEkrDlkI#qNX{137d#q8!(9ZNBla3){`$1FOu(`_cuF4?;-yuyENVSKG=HoKDl+|8k z{?c-b)B4L>h;zI;;`C_5`SXa=^oTcqS4TYTN4?BP&)`Nqu8vYWM*Lky zy@mK77a5=wf#RZMsjxIIDv*ncG#`)tjY|UnB{2_Zeu3XF98{%(t!79GGB^&5%MwNd zX%naI#|!kv(*$GDDwAoX@j{i!K;c-C?_^}eB=a){OZ4ECzIju0E^Ob3tnJsf2N;VK(hZ0TQVd0!sKEyIpeWcdU?KE`P(l#`B3%sF0wP90L_iEh zIv6Z;H5BP$K%`41zQ6OY>&(nKGi%m-%jc|}{j5CqeP7qW%#=aZ&7(W%M;@QAK6+Wm zyj;<6`K9W2?&lj&Jiy-g)5Idt=^|9u#Q(yc;Dz z?*1wMTp%eFNcqM{pO0P#fkPxu;7`mV)i2rIpUY3h#3_SSc~B1kjOBvQrbsqOD)*qkVSug!3^Dv5}iibOho#SisAU*4rh+zR|Dm07VUz>`Bl(_F=>+MdwIS3fnNE z(N=%>SgAjt+R9X1@BD>)f7&9*`p0tI*!!`2N|7_l#}zT-_ij#w)*OFa> z+;;yQ{gO5KwcG$Q(9_MYe;a;nL%~OB$A(;K=Nr?%PkmXrIo%GN~iIQ3-Z z2KLAJd#{dTuA)cYv-bSd7U$GRfVV0gY?5bYKDDHD&>HXOS8Wpz?udWj!#|hdx0n^D zZeyT83rRH)2;25Q$O1{51jf5MBqjWo9Dt+&aQ(gXb+h_=^o7?KH3$nehNYeMv15QK z#Cxz1`uJBKO=%Khmn8S&^)o=xAw|0W&B(zaF-vDWSD!CGgoxJ#y{<8pdh%}(><*)| zl14}-n;K0AAz|TR#@aQn3}iK&HB>k2UA-@Dg5yUB#fjy47>I})Yh|+o_YkZ=akQ4) zt$6YJ$1hCXJj-YtMRu_hvb(#A}lx#Ns?jiSccW)j&e)&&9eVlVsfvT#sw$r`C zn3lMAmIYI@IMc2;wq-KkSM>9T=y-sR9w7`Nv3P#8ntdsUK%>Eo>W=!=gp;>g!vgFO zZ`KFrjvRhfJ{Wa1TYK?z@UPGQXZHKHH^oXrh-V+_ZsdWX+o9Vp4#3xsIlxRkdBbXw zNFEEKiNxU~;H8APGt4~&b0_&rlXHh<-L7u;Og(XH`FuJwXxpZ0w6UkAIfa9xORQVZ zvY-Ven{v%lA{{-F_~3f4!P4S=6O!w*8X%$h43~<9_w5>tOs`B}e@Z@JZ)g+o$zuct z8c0%yLe?i5|A}CID*k-dmKm|AU`5hrkOUe!(0)8t2Y!d2*Ph_hXqlX9)dW!(kS9^) z%GVvrO$K_XNn(BCnLfM|x>Kw-s;+r3iZh82%{$@$=VniD=?M+p^=9jLbO?ufUuu^k z4!zBovq?r`tw-sdauLZUjw@+erTNe|4;&w+IF2*kR=nOAV|gz6l$k$mGswvwg6Ct4 z-?)W^EcE{@eUZ>5aMVG$P6;h$86M8Y(zO2yxt<)<6_7Vv}-no9>6QH`&kjZ=t{(${-*uWS*K_8xDlV z8Cv6Q@Cb^k6Pl8Y?6t*O%B1Z=5~AdmoWnIEj;%B$Be#3%$S4X(E9sOy`WIZ|O0tkS z>sXKigAeEV<;sirf10p7@Mc2n23~pO_VvvmA>r(&;BwPcoI2Ej9F3H%p<7|k?zZrD zhr?NW((XoX?f(!iUBugHXMZsHj;EU3=Hv(3X3eU*hMH7h^O<2>y6%2jbb`-Nl(}iE z-VD!mALzy=Xl&GGGew@d9Uo2royA6*)|*|pW9mE_r{CzDi{4M5Zq(Y6-s*W_o9%_# zIAoIt!sxhttk4G6cLh$cp|!YNkWOW_MQPY(AWPhhvrenpq~w)0nmrs+@QP|X)Z%)< z;)f`LEox4d*0Hnb@VH}J7`e$teSCNJT*|NbxvVqTSX0qZz6Io*s)u^Am8Ow$v#mh~ z*75{z`Q6Yzg!AApS)c@(4K%&aM1e1e=$9J~YSgR2js-|;Zf`c(Fm6LTcIXcL z2-|jZfhFx+lmQR<1Q*e`OMEs_YC8AA+GJyYY~Yc?3rC)+K+u~Dwm?}GZCjw1F4~12 z4!6(dDj)jdX5LeA%}XrxZn)I+>8qc*-zug)FN77I zxoW}^9z<_^5&IIWr>AtRPJBlR{rA&z3YEvae%~#Qd!v7T`-z@z@{ZCw-=BI22NP`E z`D)ocbuX4SBO5x8ysG?u_1d1YG)rm*&<_-+tHZKL2$|8Egn)9n>bcun&H4RbS1a7!*7RHp z8&*2A-ZA`kuKj1w)aq%7TKOBuZ%#LcK#Ov|rRNwbB?$DaMeS2*< zC|C$-c0?O9?_C+uQZs9DU7uw>t@2dgrqC#=^lsk2R83t?=0U>lqtP3W69x?A&q@Gf2>9`^ z;nRi_Uxm;ulo~0kYkcGo>;`AAVVc%s_;`dT;tA!QL8x!)k39$jLhWu(P@=iMSe`%g zBubHokcgEX*7FKzJ!QE0CW#M;r8a7wUQIlyIs*8R>ommQ?P6A+9Jk#P*cotW8{UL< ze~MWn(Le`FUIC#lSJ6gJ6ZYItIyH4-EU^2~*^Mfiqyq)bT;G-p=q@o5R;Z1ZhpCgF zH=dfgo>*D9?*esD*#_>&3#Zim5WSN5=*^DQjr{%o^;=HQ_B-7~zK>M4mOuN0%7SjP ze+3A|xGFo5)TfGXDZJ>@^NeMSDu+c}=^y%$g@dmuAYkOq0T60PCFIA|uvKn~>eoRf zVY}>UW(CYfa}dP9qz{H!b;q81V9t<^HkIMY`e+A1nbS z!OH2`7`{+S62cl6Ls!2D*Y!h}djol)EVx+22iLyN?oG-P4@cI-_Xn2=)<)~Kp0FRqeOi0exiZ{z zTx3-qo>_EAAD{U#)mFO4@A`G^;Fe4ZOe|~7Kk=cyXNpc#_x7MSBFRL5Ur$u^%Kns= zgZ|n5mHH{wKkt56>l|JcDU~(sy+uOjGY`isEiJXhVVYTsQoBf^8p-w2S#-e~#`pDw zT`-@~HRsp{bA4Fw+a*!)!{Xk;df#T5hdi{DcWmy?9OD^OKp{CYRHCMu9DbUDKJrELtI&MB%dX`7FTV3hVQ{cb}$ z(4LP?j?Dg9>*^aoq^yd{8>6Gc7f##7b9%}e2K+kKFn1P2Y6>8*tL|OnTpPZ=wkk7+ zb@svyc>K!xM;J0<$;vO~_dA$ielf6gWxumYR8Ez6+)7Tv0Fpi_n&@|QG>JsXpFXrf z!j~YiOXQM~n^nJ&ag!|#^`Aa}TKgn-t9I>T@$$mT+R8_ysD*N=Oypo_SYKK6saU&J zJ$<2QL?o^d*(OAd3*#ZGAD7=yG%eCaz*ENMvsv;$y)l~*C4v_e4SeWo`qaQXY~q=m zpd3HLkDVdJdXh#*nw%-qEOx|)qVj>sPuT^^&gI#8qdZZWWMqIO>XWoJ^i(}87ile= zLkXhdM}igiR=Pz)eA`e{TWUN%N6}N%?r=HIH8gZl-J#Ep&yH=f7_g#xbEmV@-Rt=T zQTfEm&{Q<{Qt{!@ymE)rOk?wp=( zangNgls}Wx=2y}5w-yrhS92`tjrdiIcKa|<8${F_85$bsXld)}suzipFBSc5iCiig z5!FjX`ig&S7HuL0g-GV{w=~ir`H!GNq*VTA)t|8T|E@ryEZXY+&o}(Kr&>z$KmPX( z|9@6f08%1d@<-5#|Ex>Cb@SUVHH03nYX8(k1_+rqF~qa8EqG`;VHUCu!f~N8|sfDIO4pu$sfS z|LT&XB$0L`G1$7dNKIk21hSTdW&GXnJDowONZOshd+_gu|D%d4uHn7I5u z8~*>Krg(Ad$jQRlGSszcqcW8+{o;pvq+dQfyx-L1U6Ve7O=x}st^#T?0TZ6BrY8_3 z-W!^#h)t3K0fY{_bN+J|Fz(nSh=MWeqz`n{KqIHiC0Y z3&HL3+?o2g_ey2#{!ikMzAOxUd?WSB+xy#X=GPmG!uElFKmUlb)3;Wy{@~s4-iW4ZV&>(vlna_~4#8|czq)^8ZlmOc>+fxd zT$$im^;#Sc>_+)r^;!WqY-yt>DfQ;G?HaU{s9@502(?c$n*euk+nr!L8e7wmG*XjHbh6>uGYG$IA+EHPAvn^|ljhj~~;> z5^#V4%8d7#(l%G$faz(StUbHZbFg`WNQor6y|LC?roNM8Ma@CZLr|S+s-w8Gj3Zho z&$6Y<5~x-#c_JB^&E{RMcCP*3Wd5x{QXh|lM#u?gci<=WZYB)n4QSBp zx7kdfK~*jaj~Hp@$RYHNDks@5@>{XxL}OP`o6imel_${?dBwF$AhT>8c_0a_N5Fp9 z&R(VMQ#V~})KqV79^Dr~yC?a`H*efB66CRYi(am_TXVXxYHkXu`GJ&Jp7YVudO;oq z>bA~gY3quS#IjOZ%!b<1&EP~s&?ePGo@sQpGIy`3g1RJ2LB{%|ae7GXaT#@uR;VW- z98gd++2-vnEo{x3?%ehJ#@M49 z7nzg><4f@KEj&Yt(v^DGEhx)oc`;{K?#NY~+-)a2y_U{$+5I@R$Yy(U=Y#$6r4O}l zwmTha`H)&M{|J9O-^I)MV`ks{W7GEh{r)WJ{3{ACW|IrOuR3Ki)Bn4g z;@GKv)ND(4^~w=VjQhwL#NM7-#RU#yU*TD~)}Dr43on?r3q7~&?QJ=}P@LXgcwuL2 zZ%5!l2}|mkx5M7P519+4?0wHJxwZCnRV=*Z+|8fVVqaoU*$)lAkpY3K4R`3sr$Lm%OFO4IfT@Cqvs;2PE zS{)eQ|Ei+9edbo>>K8%6tE#bmKLh*!T}@FV`ZbukBP}m{xdu!qZbEFO#7X;LqvRsG z#mAU+Ta0HJ|66K`{!d7o%&98hmWr-Y-JokdI8M$BC5yukKWKpGAB!oG#9v$WmLHUrt zst?V(i-d^X>w{=YIbE-HELv>b8q@acv0B6uS4xw>>=ZtjU**&Z6&7A3O3mLJ_`?cC zN*e+Gg5l*8z7A#`EO96HrtaDr1jL5`wpgP>ba_x?5?GWri}VVzEM!$0guR6_?tu9v z0E-O~7jfQ`E6g)x+Hy$y+M5*fP-0L`@MmU%-rU%yAM$K!U8}u^c4kwquB;5hl@bsnU2=JrGIPn_HIyX^)7Ggn$%6VK~BZxg@`(u1>_cEBpv;MCc zK!rWh4oIpIYJoPQ5<`)+mhwmx7!yrOK1Rht0QeRL_6!cTu`}`v61Dh5Y0?G=O(R=+ z1DdEL>0>Fw_94ygiG&QmA_nWkgG6w^a@gBKCK5>sw&a3=&fs_kJee3$gQZlClB?`R z0%6!H5RPPd63Ge^uMoS<7~->FnhxO3gd{9u&QrlqP7w1VrwXILOCz;fbyaY2(b`#V+waux2&ot*58A8)h6uolx}LYFh(sJMF*k{tp0#`tm?6Uj zNXj1$c#VbJ1&EC@Kv)*Uhzms%SX*YnSUkFNIq5s~_8{uc8zXWADJF&kqp)C-O-!c+ zgskY_*KBkQDN$lD2>Jq?&VqoL5F#FwzyaHlV2(@(PLx7%U}{(aUOT4MGsB>a@$ z7%+})Opm9rv(O&2H8Nb91-S@9N--f?tgQCFdoL&tRcMhjps>E!{1;0p<_zWUPRMO6 zh%^=P#tR|K6IsG(gZI$c0TVk6PJ&?=))5Dk23;dFEtO7lSaMEDjC zR0;$#u7vI4-TNxclzHKf_Q4fVor`*&gh=B-medse3HtXa%p@M;$$JDkQ7qQ^Y$Kba zB|yk=KoJ1wn>7d~fM^S#G&1}6CieAnZU%2Tdus506;+m7{4Zhk8{hsf$ z@EW1c1s|ruB>G=TtUebO1PjP;A6&_H0^&RitVlwG0feDBH~@qoNtB13c8>hs=9ue&B+rJg|R5MXE~eK=P6oSRar4ML?+$Fju$`2_7hn3@^W2*|A#HzFPH4@6D&Zl`l+D@d9uV9&<~9?RN3e znDA)2Iv^ngrHObOW7O)&AoN6k^%xliVIt5}5fT8TPc0Si#YhMs3_fyvs(O0$t+2KF zM;7u&Ts1rx4UgweWO1STT*P$s94^3v3%STa+&q@Y#rl75_IEsrjCIAx%vNw)k&6V> zbpk4mjL{pY)i11#!y_f|5Ji5jA_@KnfQVJr{Sl~M=OA_4YW1gU4XTj#`t<~tdi+|g zfpYzx__&UKIu2X11x3k%>vJK$iI_-kgU>(% zxvD{*h*TtjB>4V8EU*NpQGzUPsSNT}Zn`$zK-X`II@uHv+$0i;H<7a&+?1ofJgo?r zpx&82cS2I}bbg&W6Fx<%$%$`ZO*c<*&=-jq_g2Wu)W$e&V>}TxgKgogH5V(ldRw%V z1-F)4w3O(#yv~O2vcL@VSG@5EAr%5{uSwHRRDY+C^8&Ck4#ZQ&%;G?^RMaPn_RkjW zj{ppV50L@Eo1TELa~mW1pzQ)kcXr3;!j7K!_AdSQiId`=^g(kc-_N_epXIc#WWS%( z2X*O#9-n{*;mP@NnK7>_QuHZDd+Ckwq?ZlQ@}0^h@J?f4}-1%c3*#Pn5eH-(HJx}8RU!)euwCRc40Dj(809N7&9PX{Bx63WS}KFmH-Ag zBHt8Lh65GHgLmWm<(q+$XT8nBKYhgX0b);ge~5~2T1fv`SQs&I`d&|%0Fieo^x{1p zawEi2K>M83+x(_rn1j)i5aDe=dV2g|_JE{yzw}TX)Ea{nz+`z(g-i&<8!XBYk!++7 z6(N}(sHjgea~UA*Qkm)P>-&SCQDJ0GP%I1P%tFrS6ae5vI9mOe0RVjkcBUetS+Jd) zbmcavwmj0E1;bIn=mk*`MdhYS_ndD3pcE$a)K>|kVb!GP+}odSKFzfDMmiHjXnnDV zj^v3gfJiFf4no*5gC$bygaUTfi(b>tAZGxXw}P10EpRm~z*}M6?@7BAQLaT}j&q`} zy0hGTqSJ)kr1}trb7n(X(&M7DE_0k3*9Xxvh|Tx^wD=kNRZam}q;u^Rv$7{{)ZKSf zH~z;;QS8iUylsqV5UP^h^@WnKlbJ9@X-1WeCxbJgo!yzqU7?6+^ z%)tm}!uPw$adqfwsB6y7UJ>32)Z}xf0!?7^f^oV@hUJrSzx+=Z z^2)SkBo|9?%mmBzvGsQoOxw>6@{<)!nFo6yLL#bn|C#<7U@_M8u-j#+uVIs@LW!dS z@ z>Rb{w|GuH_So+h-SlAn9@LSzqnCH{!u7w2$;bWOa-0rBEmY>_+Pp10{I@Wc19bPzd zU?6hfU5ANs+<%}e(oJ@TD^o!=A!$Kfsd@``W$gLPh6@FK3AIWuai zw3muRvM_Yl#pILWC*EI7TEPsAFU(^n#SN}_kcLCwZ&1DV)$71F2P>tG(>lf|%7?F{ zmt7^ER7FqTa&B_ww5o@tHj15#zNw?@bZ=S0Hwv{c#(wJbijP^K0=6b$>DBI8+O?ap ziw}?pM1G@cG@V4R8Jbkg_*n5JCasjazS+kUOM4 z4r+L{`thyO(HL-30Q(jP^W#)6J%3P2dwKYpGQt6AL1gzO!fec`8@@tt1cntyKPombTzWIxv@{c^%3M$jLvO#)+#)Zm@#)Q?~%S!9ZwelXy1LdrfBT zWDgzoefcdrNXoKw-H2fxwPMZ3V(+uA?NJSypLM{|Ws4tfT=c`f0cV*5xuM1KxN0RU zman7k)6zL-{gO}Dn2HKPO|9TN^$zgOoJ}^#n_r4H{5$$@{Az#k!R{9hucV7_HvU=% zmC!d`lH5;#Zn#0Tk@$^72%{Ff_1i)3lb;sCbf`mW;Pw0nSKDo$ZyefhzG3dw-njb1 z_NB-{b&0*H#G%A6Q#|i~6i7A~URU3>?^70C=#yv3=UXRyDj!|4H(y0TB~Zb|b!b%J64&us|INiyl;J<#$08+b2?!MA z7z6}(@-*zVzHgwA!X>oI3xhWEa-+v3Z!LK+Hd%Gy4Dei>gh31Yz}W=zg{5;lc3Mby zChy&`JR%#GC4K&%0?8~VGT=hy<+A0f6W6)|ymEqOVmq=!HU@g<#reeSdT{4x;Kj#A z$*=#Vrcf^UyWvl`-w=4YsB&TDGN*21md&ol9jjMTp^*P&A~r}w#7>7qcf2qj8XA0- zESH>|{PO;`#A{*>se|r2;IOon&9xRzd!4$vK09m^3k(dP$)JfZ#c<<@ zU7mN_J`|$*D%7mxQRnT%bSW<_&CUMwBdx9Nc3yrF)xP%96;6v_y#2PSj}jZKaj@P5 z4>>Cah$B97FHgKh4u@PDTV3;%7ng~h9pvg?xpIZWd7+m!Zyj8-)V;r~tTgBQ+ElCY z?>WKIr@ws9U=R2tX43V3^CUPQm)_<{H0a3BcN+M+ip7nsr3WII6v?VLRr587-^+{K zg*DgwlhDY;=|+hUBP-=@dtsO7ilMMAl-AZu0?mH z3pUqxdi?8$$C(jInp@#<)7uQU&U9I3<-hb4ywz?dWybOWE))ywX>ERyV z(ucs64R!H(JXXs%D>Olqdjsdrz@?57M(5iErlxGJzBt$7a7B8{3_(j^p{dMGPQg8% zVVyN5@lALPKNd5bA5}^?Yfs8F;qsjs1@a_(3jl#gie}fMh|SQ@Wc`DrD4kppVX{B` zP25B=+=}Q!m*mO^5jcBoy$dFa)eH^wArRQV(zMMeS^0ejpN9!G3D*Bj^sZv)$pDMP z8LGSe+8qB8y>E(jX)ZqBd{>CSal@(PaeJ2O^~r(ek|*!)6X@b9&ZUpqn6lns?3#7Y*fuFZ5Rmb02MYp+QDItQuW1JyX5M{_fbJ>2+T4etW^Z z434^<m(>3AL} zbYM1`NCoeY=nY;{pXcwMs~HA--;FORS|~@!jWB#)r1SlD79aLt3}YuoBEVY56n$Oo zmq+g2c$eOp?A~xh0%)3cF@&_c+>4cPLHhEwa`Gw1SoqyW^F`OC%l5~=#<~?1{T`|d-gOk7s4G3V+kQxOsSmx7jms?;0?CTq)t*l4kbuF!u;{W<_HXK1u2 zXbjID(9Aj8b-?Jl-9fsdP?Jf}5Q zW8h_Vx+|J&XpMs6G)o}}ok^2nPNQMa32^~YVL;N=!naQr<9F=QoIOt*p}%%$an^v0 z*1Q|5O=#rPTJ?V`Pj&eG`CT@LC!mBTc~ryxy<|tT%>-Wt>^9MoFd>xWhoWpq97|i9 z^80}{!ox>wcE{rC-%Lt6$uGbixsc-#M#+6HXdt`{epK=pA{{!gV;F*Eg!>@PR3%J# zvB(}LLNwD(%Gjt}`hzt%**yU)B4T4ZC)L>J7-TpVT<~WY$KHDni1_tZo0Sk`;~0+- zDi~8kbJ5YlrMlgDAnr!d9D9E~x`NVJ8GCBl)wDKV$FPSvJQyzL*o1AxxzeRI?8rjU z9`=gZyB!t2JE9r&6V5nV0lxFnj`))*gGq>YCM@yXvkYDVb62<&-&=SHG#U87uHo=A z(zW=9nw47Mm-xIZ2*(=e=N&I(1?q^q;VGK(2k19s_JG&K5>Ml&0=!)a^Tw`F zC&zQi}j=*l*2 zL$areOkSL=2@7U5Pt#yAT_PRtkfg~qHWAFX(Krt@wEVFKf{IqR^N1c7wBUV9OTsee zAAX`mW0zP?`;WFsd4oTdps_T_Nr3*-L{*hSH3JQftBvRm@(bw?9d9=O(Zs=a z<;;XY$M>izt{^TRJPf%`Vgrx`qMCTkgCoP>$zU8U$|e^Z#;+Mp7Kz>!9d=I`dG%QY zh}<}>Viuz1(1B%)>lFgFso8DfMv{1Li@pqt8BsCN($iq2NkS)aL7?91FoJb4_3(Xe z8{n#a*yE`}PdJUWdQ87-RR04#sHwWeL~j0vr|%80#VFae@peyzp&(kq z`0qf--PJcfBIG1*x6Jitbp*8Wet8%wae|7mpu#j0?92jsbs~~UFj)$%R(7Vzo{(t^ zlg|YagZ9 zA25PH6Q`AvcmuOXv*o_L|85#!-Vqrs!Q>pZKe6&bTOsRqU|?>#I96G6tk)d&X_rd~e<0w9oX`v^Re) zx>Y&$qvRrHi&?Jjr|`@Ob@17Tw=NCc0!>6-OKp0(yUs}Fjfac@-5}eh*nV;DaL5$a zHESQ{6{=#p=Lg1KC5_Dm0Hs5j`(vPapQ*6m^giy@`(j6&IvbL7;;Z(_B%T|{5*+== z^tw77zxRA!saAQ_uTl&C%a$>d7-{5&ukR&(?B(l(ov=lhJ(Sqa-u$^g@tY`nlyvU=T{GT$*l_F|1 zM#YmWV4SHOLYXerD6RiYJX1CD9JUk&vVuyIs8~NH-N67*H^bMA4X+PD56}{5^Jank?o7YrW^vd`5>&tJ2 z>mM_OOW$Uhxala#@G_VBwn zjP5ufPr)jChdZW6IGYBnMFV%qaA(1OIS?J~OE)&9LcOWTCc4!))wT!NR~~WJG|E#u z;3pB~RZf-c0jx=pczLRcDSewewfz;{gh$`a4nN}_72FdYYI^M_!0;-MMt4R@V(B~6 z8OPX>eq^Y>aGV}P1w59bQ`}=x<-Nk?8JH%(guF9Ko4!Lk+KmlSWYTXjq9v^vY2~qn zJ+Zex)4bB7By(Xx0(2)1A;*jINoVYI2P+c6d%27RhIRgUYy%~}Y5YJ2J4T8Dl)A_H zkwU=8Xg|kTMFQBJ0NzIg8?dQXO)X(Mm!jO+;O=qBMTVF=NOWs#aJwhwJ(4M( zk)+tXZK6B|*%{Nxj;nSD&o`l>n9wMySSDXI`h%>psY(iWjLq(p4Mk$G$tJ=c<_aKw z&tF_u$4HS0*(Hx1bi899kmBg1LSKr=ro?qQ#QLyMD+I9CxkQVLNGdZCJxG6-o^pEm zF6o$}gLVwYk>SS+-;|H);4>E~pj@u#K}Z5O0hT?$9)(m&Mp|I6>>>`MX^Q>9hAcB~ zXNore1aLMp{WmpnD+StcJ*mAsE!iw1rB_DPG!@!Qby5{!LGeN45Eba7 zZZpHGET!49!-?ey_W~eSdy+G$VqhL5lPIy52Mc7OWQBO@u5kvkhI*Qkq3y_Q@6DNU z$~Z$|qMTxNSg35WIE4cfiY_X-s6!cvP0RZU-dQiS89xJ9$k-H*@@Qsnczz7f+XSot zlD$q~>i`If60MJCO&k+_XSuk{r0I!>8@(Aqe54Tr(Xfp1W~KwNVtaYX;Fa5G?TF0r zO!dqMyC!4P6*6=kG)WE`CakMp4=;a zPeLz+hXg!=UcBQQ827pf*c>2EI-a;BL?VojCsCSmFRnaEIiBx5mIg1#7@GicVgOxH zhDQcHAtm-TA?%NX_gzZzVj{O+$}d_esB>Ve#Q=wvFje{BwdMQ!h{;Bi$xoK(Q1Pd= zy9zHYQZF|FUMMoHdSX~b1vs4+*y^d(^m6;1_gS24C(nEkCZVo(AxE}vt{yxgDZ zc0A%*Y(9W|l>@*%$YO4+SK(aD(U!2aZZYECa`~pPkcrH_dSP=2T4+YuaCe!jc?_q# z%taK7I@U#}bf?ngl*>UO791|Hq6o+udAOz$oR+VH;jt18&Gz!T0 z;AKw~R|DWX*4{)by_7gvJ)zCsClNkc8J4C1SK}ZY;$c`S?DQ2Fge;arrS)gkJ>u3y z;KGO&ulj;s&XX~x2v7}9UFTC6t)Q$jPIR(V24^RaY-HyGo_fjA0K>wJtJH`GI-Dl!LX)KzYBF{iaFmuF-o zWH>iVZer&z(U}T0Qm$b6EA(i_j3}Vu4 zHf(YWhCzlVl+(R%VRI~)91bEz1Zj|=FNgS8?Hs7^`120S z5{n>13)>s9xybrG@be<9Hn#6R8Ma$^62%FL`*1Jx7cXPz8SK*2u4h35=gE16?Jcd- zsGY1Y*@ya+2=F-myGYhY8%L-%6MUcR5Aoo_!yXN1Ps_`Z zyH5$k5@#ThKs)wFw-y;3&VqsVU)*%`n^s}*9cSq0P%#H$*E$Eh%17xl!B2c@Pw}7! zSb|L_N0+FhXAMm3u8xP2#SZ_;o)-aH)=<&JJ_r{s^&Y+x_+svkI>3S!pS+cO>Zb<> z0}_JxSm0JVbyAQ6r3cOsww2Qdy07E{ zc55la-wMFH2p7+ug5NIcxToLgaPph`jn~IlKh7ttC=lTgE;z+d^s>M#2?Q6~Teok8 zgp->C)KDENoxaau3EX!Xkj~TD;5$5M1kg?wzDp9!O?@4=U&l<)fK$BDW5S=ht>$@> zHPmbgYGVSB*YihAHoRkom$I?%!Jqb;HLzUBpQ$#G3Aa1fpzrcE@U`6+Yb1f4M9(Ez zr_Lu*r)q=a?VTC1Gz?n{@>yT7(mnj=Mtu8KU zZTp=|c~s?qxp5tx??yHcV-*szH{75<(FoJpf$ZS{58Cl^h7*F-Uko+yoj~tg=MpAW z$;BYFgu#sBL>evf)fX9yP2%cY~Hpye?fe{JDEgUTn+w+57&iX%Dp>KIPPS;{-u#wS+~| z7D?=yMp>NUfG6uobntm9&BoM(1`1qodMNwb1>mdTcE4P{kbPa0rj32|nC}ZqAr0Q= zM;uD<5)rXQXULPvPL=dP(N1t z1uv|jv2^ge&$!Lr(Y z*NUUw1N2H+vkeLRg`sP|y2HX!Y#w zr5;|RCFl3lyECs_3(e&TbV}Qp9-tFJA9qD@I}O8s$n3KnB^0X8Q#S(_n|9j)@Xhh@ zCr33H)*42fLKa^ybVW3&AVh_b_UN4ws9J`0LU(9eqcz;E`wa6QD^bE#J$g>nk`Kn{ z8{`>b1&Ds<&yq4tgYqY?G;bN@TW_wnRn1}6HPsq#uqbF$_jGr!Bibac-%bppYkI0n zp;Q72e{S=ls*w#zr9(YGnRgy~ZZ>$W%tl?iq_$Eot~H3Xrf8((a2rvtu19R%lLsg` z9<#6J$DASjl(8VaLx8w6%s4VlJgGl$622EyufGXBC&|w&2G@!?n{0b6$|5?&913d_ zV6ix*X`%e4bKX9gyG=TcU>@K@WDhZW*`v|x=^HYABLN8M3CIeEw2r8OoTM^zGd&{o zeZ2gI#E9BZ@T1hVku5=k5NPJ$9h1?i0M%6zW(13QKC%ZJi6a>LraVwSmFscB#YujR z-L&_w=>7XQb55Q#OYDber(ol(wdY`Z!{NuNE)x4eO)hy~2v5w9K$^Z{sk-_^k-0qv&ogTrXCe>}?A8fO3U^&tyfFTJ#B4kRM z21yyG0+%u_UJF_6-%pcuj9+mH93j(EAM+1#&-+}z7grK=<;Eov?ZC~!a}X@vMYVBU z-(^<{GiYr{JY3Ax9!B^-C^{2IrvE>Ve|DeP=8l*#cg$6kV`G^6Oo$>=Diu;GVw<@o z$CNJSs8lLll1iI%j&kH%D%Bj7N*T#fvfqAx!{_~ef8MXx`}ul2SjspZ$FhP8-Ih_C zYKsyM4gJZn$XN%H8QCywf|+N;yut=vG$bZy$9|YF+tt(~w#9g>t7s5H)}%g_gb5L) zd|2oZ6Q38gGh~F2y_DAN=&mLS@W!ERB3-p`;iY(W{znRry-(dJ3(#V;e;%)GNLRm( zO7_3CGg&#>O$-M835-k|mQEhV&^Xy@Nk@B{`QW+-_aP_wJ~>wJ%h zT{N-wG$cFCEfDk~BwM7*(VoVZo9#Dukn#Q=?e>bNGty#{D|}HoB!BdY)oJhQbLC-? zgs+xYrVP|wdgRs;{mHRYXa~W!J?9_QWhjZ!e{CP>Rz2Rc^a(2-% z=t#BRhqp05n#%_d9KrNG+v(qx_C~qw-TMUI{W|r-DHpAtpFF@vL|*Cj zHqu=&POdYE?9F@9>m;wgr`-A_?6SnWeR1e}dPywo#^U{Px5d*(4O?&|al(b|6ADkp z-YL4>RPf{(zsmk7_!OwXjiVPIDd+ySjp%@-1fFqU%hk$7a#81x>%JP&ZLA7S zdv;=8fj%hj`;N!O zIWfxsFQp-)5dhB+qJ(2q~$^7F`#H{<^hb;4Yh{@DG1qncLhl4^E;Z>lsfH1(+8F|qvx)csk5%N z_Jd|bh>o1ox+(`36nQ~+$iFR4r{cdb?GyfO2F!a7doLCIaxgTNqwXqqc-J;WF~X0b z(G3DARY#2+e@V~NCKlq-)92i}k`?DcS_8|Wy=$g-UAmF0l3-VA#xJJaFUQ}hy9y4KQRrKDGHv1$BIi5~-7eETmqf5{W^n1}J?biW&bbXeIo<_M zW2dt2dsNPNRIPgOv7VPajH*pNYwbPjyge^3bp2Luy`1J*U+8)5Vy~wru;@kHe$W*XnM`lJnq_i-S_r-5aHDn@AWXvtGTc*zF+-Jva3^X=N(gzM@+|y zV_wfzy^aSn;zsiCQ$5Bl`_5l3V=!3nL%7^pyI#r^ux*(^ zVRohZb6ON%4CI=`Q#|AdBS<6M zT)}nw9|bvcyWJyPqD|e zp_)p)`DYdeBqOi3Y#4}f9oW78^{4lE1mJ8`aU8v=~aQ<`N{ z1mWF}o>2pWc)2-hP&s@QDe1jB5PGj%tQfrSZuZI6bCH2#;m_!z(m_6LD9~tI3SlN~ zd%Htb#fTsr3cN0`$u37b{IESc9ft0&%`oJ+Cql{fA+I5iE$g9(g)$@#z~HQ8*X#`B zqw{tgU7TWRBhz_5N?f{2Vg=L-~K*klf zd03aTo^;;J*F!fM7>>0+S5ghTS62IuCwmDAwjZQcU=82%kdJ-p(5Zc8TFZrHc9|(D z-SVyDUltJHQRm~$EL|#FFAh{LDf1B*@S6Ec7&)yKgk{B5WJ;Zw^@iw{cc1`pQVRg{ zb{_FjFuB|gZp@41}CG-WWL+bBEhBj5657&9>$QPw4j?(N>@-;zqj$0cKZaOjvauKt(mNygDa;25+do3cDCst&H+|>}jZ=Q=YW;_`%Jg*C6gV-1aYPXBUT^CPl+|bC?amGO^S|3u~P(>SEj&&(D z%qzA%=6AP%6mexS79g``_S=2sL9edxra9PLmJ6Jv_8}**nXl#s?*0nC+rzb5*#W6RQsnuG0u3J6S&U4hIR1Pt?3eAsrp`nT*5^goCLxr`Iv56)ZaH(jA zgNocoTN$2)D@}a7rMO7xczN{XmOM`hd!W20MCtp<*ANfRCpmdc!o4>-VBO|w zIP9?IAiaD*chQC(3(?x?e zOkmU(e#{32ZsD|O*|q!5hRGzZU)(-O|r;ahWn?4GtxXcCdv>+WZ*#sd1V2pXvZC0B=;D_ z;mlzuevqwU2!^MaW=CiTa}rdyDUk&(*oE6lT7#$lQ+be{x7{MpE&(ckn0?ZQz4cK( zMQ!qr<+BfsqZBI$HGBM&74<{5Jh=_88xXfl%*$Kbb358v!%?TehVaaLay0qL7(F{8Z&d3MXH#04`+XK0bg%NNH-3G zT8ty{f>8eXu;^Nl1ybG#$^CYuW#hJkG=7fWrw654VHh!!Pg@T#8nu8+kAHFLje#R8 z;0HfBmM33(A9#4qa5l59fKPA%{P)z;lJ4j-b}@!IN;7k6?oxQ4Q)2 zeRxKGjINZZZ1mMzJGS7*pPJ&~r~5IXqZzm-soS-`H$6P}PeAxnD`?&XPZ6IKJv~%+ zbYPQG+5Aq-zMQu{dz;Q(_ES>>1V{xtu;wyM)3(Bo${zJCpc?}ACvHoR+may}oRcg= z3le67KZi11q=DmlhO&{(<blaX8laT)z&4p;*Dc<7SXgZwW#7oyMWPDWPSk%0%L zPj9P{EE|P%VkYA+bOROY-pqy+L$G*=r34l+BpdFd;MG>XJ;dsOkzj{4i{%BB2b)s9 zR&s6x0zg22*KX$ei+fwaF#R7}?oRa3kE^UHrx=KqHt0Jpx;f0WAc)h zgBAvIr^-qnn;QR|ZDJ}))BkO+=cY`ZRMdT$n>Kst^XNo(nfakL`#%fcUf(-3yXLUE zJpWu5EEsppF_>>lqk_aP>3_pmU=R>7)M*}RAN^5zN%V{0v<;WrrdZQcE0$AsR2xu) zt{rxDL=P7;9OuP=KyS$q2>{aM#CAmF*sp<@Swl91Wd8JUC&F)R(nA$kUZSg=Cp%{n zA_sqUAP~KW{nQ|6BDKu?BoY7_Mp*bc=82^heq>L>l3aUf8pVUO>%=ZylBI9bXQ$}k z&?vQTQ6{5Q>dmPs@EaTa?6|Wbq1`;!ekkkMZsUN@24te&QTUr(O!1>8vv#>HtCSABm%T-&a{I#p z^S48gL*z)}^04DahrBuS({?F-3OWPQnDMe_&E9^@^F#Me7nu*ebXAZH+g`A@dtoSJ zLOrvxN|{%4ScoYvbQ|bzIFL3FV>zokIq0S>_o3@q2jq6?QuB<3!>nZ_>gB90Bc{Pa zsz`WUF1V3+%6tD&KhbRSrF*s88YBt>2z-*B16>@VXd8Ur+%=Z1IMym;rR5UW|=brg3Mv1Inhn{;q;sLih;^NmuEjawr(0=}Xs?=e5yuitE z<=TPW4~7<+Z%%a02a~M+gbd`ay`b!r?zkjkzh0gy<6c<*tXVKgl&U{>4w=}#e>nDm zH1g)YNJHWq!gA5Exd9q;*ZIt8gLPSQKiEHB_Gf;0D1aCj##C7OSeM0B zeF$%XTY`CE;Hqv*P`W|1`#l^&8r|c9JDODHj@_}p#?7N{eR2BVKJrWIo=r>az|zuS zz9?<^l6UE_&1vSC18;Yq?!0c9aoWyPp(vXxCkt&%?vLRW&rtdvS?=!rg|+p{6HHv{ z<4xE{_j@1rrM3LJG=1(1QIVm3w6g2cH?+@y7W6@qhvamwy`i(>^}#I55z9k=$x{8E zevc~y0S$IBEtN9C%RYbWJ!3lii71?!*lY(nHy zvMt}K{qPN;VJ&T}cYB@QvUNq;=-2hK{PNUQjoJFHdBCDt^~ipse=2=*V|R`nzsYog zn2ZVuO^pgJ{;DbyB8<%(lc2YYaX4<{wVzwhl=okM5j^c#|1GFNV69%WF;0-0o9FEy z)C)S965wt2D*XZ|(f~ioD3LpGLCC9`S7{1ozB-sWj|=)ct>Rr*lx)4L^oo&H1?}X) z-RCboHL~BEkd0s;WxKv(l8f)R3SF(@Q{GnPPt9R=-HE(tf5He_Gbi_ltGqPk0UzLob`gvZt9zP&!@7x`^iJ*2(XLlPlIx=Y&e9byu5 zb08oqydBK~fJ(uQ&R&=*BZkZZ^W`jEEB6*;ZK8o@#=BD0ybB`J9;y2@-a;nxt`8UF z9*j+KG9+eduM#;L+;R5JymIYq%^S5g^T&T}|FClA+@5<+4H0h5Y=g?;y3X+FJvGtc zii-lc$#ugc)*?1?>a)mfCZ=Dtq8prnxMzu*U`d++PDZzHg-#(da~|q6s|**Fx+L?&Ed5xwzdDwi9KCRFT1RYN7oJ3bl`aU zh5z=9#Q6J6id=jbrMJ({?BCs?d@$4VO@sIrrRC+#pGOn|wPGa*(8kXeDP&R1EM{!L z`Alon_1t*1ck20H7Yj%io*!>tf6Mh;h~@JW2VypJ){Tp|!Cm8tIF+-IBZrz2PUJ?x zZ29h>b@Q0H-PnD8fjZBb!Ki_uNi0^mJ^K-C;d| zdMHlp%FVQH!yj*qhUnY2!Op~&m|zdYsnzCa)8%cxT)Ml@anI2=%=^y=&OI5@pmx+P zI`2inPsN#6gXBJ_T2@^slw(XZ9=)QkK+9zrKMMRk=+EN1K9RVjDpvkVU*adie`({1 z7<8R3;`HwBq-ANOX4{u7>pR}7>>sN=D0iqyVH-2&pfZ~N7peo0OlxTGVkjqn{q_A@ za`?dhm$fq{+Aj46ULLyEUK@Pa@7#}+33w`C;}&afnQ7SI-<5 z@7*5sAqIGS{+TE37KWh0D3p9NlGH#o0a%|6g=i#jncRk-5hDEAu!eDj z8jYydXKznC)9fs=8?QvlCduKLyKquru0gzx)DBKcqh{co$r1!Rw70;NqXJM#X@G7G z^|-PR38}M+cV1D?Hy@2uKm+pk-&`{kTBM(n5{_IG>?aD@}y+|>9) z04S_n__+CVHnTV+R;-=D*RE$_*w*OSWZE%PoyLkDJwd<4272{fI z5nyEjJfXw;L%U)FKp@hf#X@C4VfR1h^}{YkhT!0D04Y>}=FwC`sqh8?kk3*xlzn7C zJwl)bymc7qIuLw0Dw}46Vf)tF5NOu+%3-NLgg_k)D*lL zOSLLy+lPL;x^X?>K9$hnYm^KMzAw;63T_#(QHCrXJ&<}ayJ8B!M}?Y|2uV0#wK~^c zi3;ZnSacS0rX7|t=D;1h=0-IN6(FVscqPzHLnMCn&8|{5M^gZ66ryth_cXyINXmjC zSuzT(-wT*dAXIL7uR0X0o=d$DM-TZ^k!=a6#}Gn9buI<$_Y;I^ z@Bl$Mu!T!VO*Se`Xb-$oo)I2;al{1PqJWB71eZ>inRv` z$^qir^v4WJG==a`mO&^>B`Q`eIC6B=MV4WHvYTbM`@J%;?PVBX+Q7QDPCFukN=yUD zbRs{N4l<_&1|SQx770(Imk?4$v=r^HV9;_+D}H;m(tCbv&|oGpl{(*Re9hizXi(0 z!aHrXr3oyjcq(}ThUebU#IcbTpAjjS2@3-C84#pi8xP&CfTLRRgbp}?LH!kjC)?;_ zEMS^Tpi8zZRT7wj;C^vGH;+K~Zz%>5u(1JPfx0GjZLQ5e`OAZJfkOnR>kRF)*hL|} zHv8u~bV>&-4PYH*pB@)*|0EnhQoE8toEK7)@m>m@4=^iODk*f(vP5;7Wv6ltRxH%Q zaVkbb@glZb=vQ+nN1N!ZphQ(qpsVrUsB3;AM^N!VoPx{+J^>j33rLI(M^k!VK1<%P zgdmtU#&*N}X~YN)flm!w5SZ(MF~MM+xI?{^=jx#`=VQq+n_bl?`Whq8Gxa!XP>#!> z#ZJbChrxa3$ukII+uQ-)^SMJ&3xG(Os%jT9H|8R*Db%OvJ48_7NMQ5)c@_UoCrzr6 zc&=*=!iRlSp9RS!%#QzaS@X=^yxG#jmL8ica9))eU}1LGXSIluq!eHG7lmrFvhBXf z@5P&%fB-+GlR@SnO{HzBPcrd5qa|N>(Qm%R77iiV@|0WGgG%mB!LKcZwySn+)D)wB z30>PAe%mI_0deTD8SJH`W7-%*+Z5-gSy@Kn$Xow%;>IlHn@c*pbsR$L^X{iqEX3MZ z_~1`_R%v)*Le;Imsa&4bILMI#>82Myh^D3s8W|9EtsDOH}e@||> zt*zJg;9zuDI8{`FIuJFG8c8+s_8^W?bf#QD61PAr!J_`0;Hit~K!dhkk2w(=MASjF zQ*5-n-V}GAp*NsA&qKMVg6w7j^}32 zR|gvQWFA%916A*6Lh|MhEwW1c`{nBPycm6OM+?BuuuT?#7~2lzc&fZF_qiTtPvEb@ zMFCmQ@F5VcfcuJ(?{eJy@bGt5`K>8D(OEni#Kbu(&=bR;U{?*H4DiTYSU-P&>O*(S zeCy|kbVh%FLDSv2aCswZ|81r%6tp_;RQDs*qZ`ENI$Hce+4d``+4!S%=W`r5Nr_eT zuiXv+OrOY$4w zk#p^)Gx;Jr`Kcdy^gTWe+!6wIy#NsEry{pr8h$kIuzWu$a8p2VTcnhu{Um|;vR^f7 zU<-fxG?=9_M3&PO6r%xE3IKli!eb`$=$AVubS)rH3^<#AxAnB^RS?7E#c-ytebfn3 zMT^Qf#NlF-jq&@sT$XmIk;vyDXw^_P4Xhd=AP-XUGk1?--L;O*Sp-YlYA^VlTB%P{ zq{8E8*WY8=ThA|cWwOq&%~=ttOH}gJ^{@#S#QV&nsq-$TCf7G*zak+^(g6%M8y5G# zaPt+-6z`w57h~htX~$?Eb!h4{nMw72VJ`}1eOH{~w`^6TfsmX9+k3@LDNOHowrxpv zo>pbQS!KUqUtP21muW|obnZq9vkkm2&bhYQ-UA|Tw3>F1;{VFcbhf33AJJ=5U*4WP znlyV*poKjY>&+cBalapZvdEtC;J=Re+k)6D_726dwaEp#%O_&h4l=1ZOhXXBq`vd( zLeB`DO*_WMCgHbFnzt@rnR4KpgZNU3>5G-EJ)c0?#u<~h zV$|`pc=O z%d)onNMx9fv@gjE6pul2dsD;j#STYgrAn;rgK(gE01;v%tbo+RW9pHxO4L$N%kw@ zcfeU$8T8&zDzBE6MY>Ekd~;$e;Q^s@vD&Q~i17G7QM)?JwcJG! zZ&bS!IwMZAFS((()^v@F1 z>{SK~4NX@+HtYlnUvqeWWAfvb=D*^W6Zv<&#uTK}T8YoCi}_}p-QBL>ZKMdA%>QtQ z$m)L!2CtFxyxfu}Gt%pkl3(UYfz3?+Ch|W&tBB*3;+nOG!qt_GZ8E~j1)W>+>r%IO zZ+*JdGOeH3et7v*IVQxyNElXQhZrz5uFeGHG;A0Et@u)upLonsES zjmmGe^w6CA8u(n<&-947R5r~tZLEcue#1SNv|GU7t3)iYMZ zqFbBQ3~RGg&zXGEQb+yzQssIu>c>NAMtW*ZY3rCP*o5pYetn;W8HL6eBAV?zxVw+Nn?vk8 zVH_reDv7V_nPtc~>)cg770AyFR zB1^O8;&ci#KIbhdE_oMxFO*ZU-+mW~oE9Q`e}+|Kk9$FW!q-pb?$3I&7#d-jk+QsJ zFYPVo`!%fp=pM$)*6HXzr2jlOJ4>1f>dded6ar;onO@(X8YUO+UhaL_ukdbd1>C9? zvfOR+$Z>YV_Y9JF(=7+q&O=$!GN~1tEfkZW*FQ{#Ghvmkvmmvl-kR@Keye$`LJGmI zt;%K1V-~6R_Fp6p-w`Uw)ABd$cz-TnVd`r$sacKjERU5ccBT#?cNt3)pc=^Baz6}7lPb`nwc2*SGE^o^dXee_)TD`FJNr za2_@+PCMSe4L_MwA9@lWGSA==Uf@n!8CDZK8vJve^-hnD4Eeiy(>0GY*Ld~^kJKrm?kSp>rXJ+oo>xx?{6MaTAI@{w!DVP3)RI-k)7B(6gs19(7x67^1}*? zQzz;`n3SXSw$4U$*SnMEQ;Beui)`mhOdThl08Ib-U7NArD-V}U(w!(ZGl*B#NR4$N zC$kU3Cp0w(pevi#zWV0@7j(@>vbGs}IA@pQ9MTiJus`HTe;ZOTyTVZdgw`R6b?V4#fp(h2!3-+IX9vR#(f_LM8UlgUEz=dV>cA2{l@|6(>+_D(a#Efvar zIrj4vIorm;tsWhQG_Usr;1wrVfeXjS6cz+eE}p(<3__@=^}~|egPT{C%${X>fi_B@ z;cj_afj_1Z;CoH%#cX!lIQS36AW|=8U&rYDY5b2YIc=gm37i?;lq^)7$%~5s zAO6pv!P;#2v2gap;M<2CZX5BnGx)Fghkbv*`?n<+p>Gj4s>@|RV&44fI^LGOlRFM^ z)BSPVFy>{^`4Q#or=Baeu6sy_>if19%ZDx{Rn_UKnz<=nAS?=Q8n-Dv!-99Gn~i%( zjnhkWUDx5)r^fcv#Q=VO6oEm@$e?@}%+ob+vlX{Z?Z`NWP30DnOu(RsPk`^-gwh73 zFtUA_>!Ck2XNxypNfkrz%+dDDPJdusg_Uc`@9#JAZO3VzJq5pTLai1)H^;%&h-S~@ z$#;OArre;LkrO$=h8?66)9Vwt(GQOrlggLA3(vXgZeF9zjKzPKUEms4Je8c|mOY#923}uFO_L z%wrs=%FDX!8KiEqsVGKM?ze)4noghTYMDJf0ZPipg_Id~f+%1XMNRq#Qn8U8@WDa> zn$Jd>6uYP{;}vxM=+LqX#CnrY1sH2Ka$}PvCB)|FzoPyE zKk+%HzPB#%!n4@V#XlzZT|ttg+Oljk;Y00t$)9%oOAClr@f(IcI=$1L4JsJ2-M`~l zmaY>2`AZbkYjVOye@)ZgXH0=Kz>)oXw5RU_@57O~c@H-u1 zr#b%DkO~J9{!49c6Gqp8MnkWQQ6)dMA61j)pE2ELUzTXCZUG?8GL3lh)cW!|IdZBb z>+AySa#rAS^}O1e#_~A0XxbroZL(yctjt-$hMDQ$>Z$1wrx|hNxe1+oHS$g<=w-41 z4DTP`efvxPEpW6RRwRI;iMalO`%JwvyLt+{m_5?qTslKFyfWx;y^6qKa}9S0Y(u>N9X zF5fhiidADl=;DktcJ@!bbQxw8$^zZ(R^&y&R^euE8}m)+@Ka*NUUFUw73lf`cK){D z9H8W05;mguess#OZ3@0o3?^~&)|iYYJ^!YIhMN8 z0t-D})qVc#v#X!k*+N&z45&+zzrch_jX%wNp6r?)$F^kIHd{ATaJJQ$_igNjf#ufG?gQlCP5ZvTRzXRv84h?F=|4n2yX;(uy}i+ zVkHY8?K8A4&@-GwwdLNe{E1vQxARHQtv@K(Zpd{I4GUd66bBPX*cp={4@uLI9W$f}6#_;xwUyh)t0x z*o%=NG)o8@^x-ghDf*#EpjZ#Uxa)O(fAQvK&2WRx!X`FDOANP$IhKbZ$^IyB zpTXRKzMslHMZx$azfD`8+1{0eD)-q323u_n*(A?cHQRQ(Cs;aR9kln>4^dsO^D&`*?OYklsf}5#8hrkHR zU5NvvnxKMd9c>;FqQpk{8{kZ3Bw&HIx2y*o1&JVn3&mhgn+$;plaJEYuLf4dTAJgS z<{AX@MPV;1;=4W)KTZ${fKDn3mn#dSq9SCgKnEu;klQ3U^!5n0?0<_NCK+QI!{6b!P*2 zD?C9aW-hLsu=Z~JFGG6veZ+sxw;pJ2BX4uHsr>Vhb_Q9(fo?U?3))p4en|deQh+*J zIp8XkreqTqro1)Xb?cpew$#Uh=x$pHKjQWx;AbO~lriUG{eYPB+kJ6 zOa?AVE$BbB-+DRaTZ7i8WUeTkg8$CVtk6-l4LYeu8`Jy{0+1;F>`} zCntu$nlrI)0hWx9ZMLt*TCyM;qvKtp3>sg7Wzqr>9|7={HwwVGIG8103GI%F(A_z1 zzQ_D9UKFJWu&`!P+G=x1Itv?mXb1KTu7!Boh(Mn>% zy|6yYF~uA$+B8zrQWAQ@61&yJIMA zQE=3oXayox$`fzKCQMaQv3maGWkuMc`0#L}QVa33qgYj|3moc)vX9mt#+8jrfW~}K zp%}7Y)iLqK#IYDVMZ|{qOLq){SE-27D8*(L2*=(7t7V+MvYE(1FODbHa#NqnAwmQS zP%+TKLccJTH8GJ$z}Sk2@ID5Sb*TQF0|geur;1UwwFnUlNdm)?sn8apo?rpp%ECIf zz+}#dda4=atzta^M$&Z)%tk^5;MH27UX0i)MlZ6EZ_i;0S@4Oj4{P9K1svzoWRhwc?J(-%HHpz<|p|w~nw*KL}I%FN?fA&u?^r z(wzI$w(`tq;FjUZz)ya6;y<5({=k*%+FUl+dSEN<@x6P??#Y+$eUi`0L;Xn53)`~H zR^~oDJfvB!_uwiy+~*KW?m<&Q>Q{ooqk%gT$FCu;%{17sVehZ^_Hft#=5CAs8&qq1 z#CZ07@6a7uJ(efH_ll8I;})=}IQtf|icsMMYkNesg74Ywl~D@4f;D+QZiEM_m^HdD zK4d$jfU8D+P^r@Vsl_sfj3kq_Rxm{@s)`WiFFyBEM=MTDpi?(JX_4h0i^)d|cFeM| zAp(-h8+;t`z<j6;J@pp_B9KBnl7{VdcE1F_^rYUO z0Kb8F7kjy>d-j0I6xGR`CWHr}h+o!=V$wMt1l;NjywkBn^BER47 zyYTVv`tT7{^QL$7#rKy=mBre1{>mx7Cz8U{(la-05vK-vzOcwX)XY5&yQfo`_pm~o z)%;lXi0?tdSEZ!P^{t`E(Y%xME*FnXYPM>kDrko06YSU=gr&-nE$l=81#N5ATzWqh z{o$iJQ=pvdaPU-|`z*MKYH@_fX*gifLTo@a0iiA!v{=b(I(o`1w}Q>CKH0HJfaE-X)kMNcx%2k7sK?J`!nJ-KZV{{ItH4D6;6KBF z`ly;S!OZb1|Bz3*4%wSw5P373y6Eq%asRZZqG0=KC3GZd zmx3%y*rLz8iyk5qiE{Y2J+VDVdO1}Z-ty#&5mueFDg9H7%kEC)ilk)G9M7;{6%I=q zN_8K2sb^uw8?3!r$C9@|to3N1#jl^%OHEg0`Atq1#?5T-G3AIcCbLYWd2Pg%iun`Ftm?{2Ho7uWnKYB=mNooa(540R*Xc%^AO+b-b6Hjv7c&=p`5 zv8O^&1Q9L=H28Ze{58a1gpnHfbcH1#Wxb9&D}|=8)08CGQZ5cbku;R33V8@L$vxj; zP_YW>(Nm2B3iRsQBVf7y9-yXAsv=Olnla$ee5oYYz*+^DOY|(>Q+Tezjr=Yl@X}Bx z%+QXMqsC2{_sZhVxD?wjC_U3_HeDYAIsy?Nd;F!*2abN&=l-UFEzh-ahr=Q>c9j#gQ7hn8t0s(4U<$9v>muq3i5+;O;+ zN>}sL!KdkwZ~+BKQl+Fib=pII8xf-ZGXM?O6PidFBBylM%$Q*CX53x0!#sP-Gmx1l zclqKA{ze6w{RW6;=q|NUe-;wQII70En(NhO8xb-LQ99@@{CKeVd9JnCs9;TqF8nd)ZgqYR1()4zqh&+5#R7<`3;=6DSdgZ(3pBTnGlR>;CcL~(gDlgKKOK>Z&J>e_MFbMr(9SyBzX9wzp-7Re6t zm5uZnHnu3?B?&p0sbDI*H!XL=J0!egW0Obq4Kq2R_j6K_&h8u{BUZ%XW-ModawYWB zB5D?Ong!$Vg&@Z{lxpxk?eft~l$4XlaVGACXg}?C*xb`{a*6_BNMb2hMSvcik6kME z@Nya|%FxvDd`)1Rzu@M&Qm`oNf58ssBseJLn`7G?Ox-LX@8qiU7Q+hP4r3vwJQ-xW z!G;F6q(W$oV#l>y0enZ(7R6}+>ymdxdvXoeODT$7*$hBd=dg+uV)(W{-Eu{DP8&23 z!Lb-99vKbFs}w3mCh%^{OPm+~O^{5QSupBCL6U3K?xWvdIoU2KSj4lErHp)6jiyFq z@Hg&--{cfZ9i`BXpM}o_2x=-QAi~`;q0rsVNr-es3PQ>aGu!uF!1X3K#2CoAfI4t@ zj>UhsE0=3e(#?~;pV_x$u{7xAg?)SHNB*%VQyXp{*XUtq07QJ#`3?k6@Q5C-3_y`y zYEu>^^qE?WpFbx}5d;92tY?`9;3F%b zz$o#)0v~|+NjmJO6JhdW)YjHz1SrX^%HxiZ&oOM%TE)S`$rEr*hRn8>kVPkQ+Ls0; zeNEq9Q|#I8>HRsx#n7!c>WsZOQ4l$vIPVjQj9qx(W#1UoM#0+Qe@QwN-BuO;h-!Vo z@)o2ucBUZl=lV(kD5r;?rAM(%$kt8FG>BFwLn|QgbjdmW#7{8{eXTtoCX}a!vP`7M zXj&m%N#sfZ&=f$utR)?qu2h~zgR^`RgBud{xxm5PE~qdsBbJf+W6 z`5#5+{ZHll$MO3t=a}c%o8ve*Av>FM>{Stp$~d;N4k|lm;n*{2**hVXq;*h83!jFT zj+x98vU9$^f583I^|-G4JzlTp3p**d#)_e36CnD)OwVeU9j288k)ne}EKY#=Rcpr8 zMk{$U=h{qXd$_#M5+Qc>S!!TD!-G=(!e!CEIQ~~$GU`#ojLJ2H4VsMke)Ty`UrV4B z5eb1XMIna}zYx81r9c82H_K$;S-dt$i{0J?y3qKT_iJ}cZpX5Lz<1dPDf658QY&2p zc!AY|$8^f=LRAUT?GD$LuY+9bUS19v#oic5)I);}h7)lO&i6dd9F9+ghNx|*kPB2| z-%e8QTZT}F{V{q-mXf5jqSl*}i4VX!@@r8Lkb;*A#R!q`uQZi28^iVpUu=-}+e+iA zf(E*9wUQG3?2-5XAeARP#0k;|{-Th{3r`y2k{ZNMhs5vHN-G~ZH_~hLPd`nwA#Kc# zD)S%xb6rsT)yw&a%mP1Aaq-M6p_x}1nbYE0NJes^Mbc43Qo^9n`e?$L*;IA|HP@b! zzOMc4DktNUfn?N+)Vi0{dm-70p;;}VWRuJ`h%`ym}j_xXEqNb`^PW4 zmj>yq2eI4t<90kyb@oXUFH?%DsC98vC5gCy{b#R`MAmh3UVcu|9Js*H3laQfBQ30T zJT#A2D4N!o^_G!W7m~fYD)LwL@%f$u4dM zUYKZ?n`M|=#we6*DwKXzDEmA5o>)qB!-X+}L?2JJ$6XmxvDwgvXODYI7FO98cV(ZD zNPK++xyD4U#L0T2?L1Xt`MK?iPN;nry}*SyXO)>>KagCLk$cpkq-3J#>p)3n30a)m z?(z$ckXk(1y(x~j!)slLy8R*Nl*QqTztU{4#rcMah8buH!Ptv&jj=ba4zG2@ zW@-iS_}|#yDk$wh#;j%>)SQb-nyW;@eqH{;#0oeh_!} zle>K4(19?sd@@K<*+OiCj&N2$M)*OEPzYy|?|MP;k-s2V0px(H=txrbhz+QVg>(vW zkb7j2Vl)6JKraJ;pO&3TEMUx{ls_VJ*p=6>UeF^!t%*OH6}wfX7e?8)pA~pu=EhfNA#ph)d^oB zRFVkt6$;;F@hn@=FjwUJ?&E^cU84Tll=ni_q2wM^q9q$^H2sx+% zQBzWIB3OnXwxaEj#smUp!1pdl*)jnc7eJW>hn?h6);epH?qG|C$J_;H78o4@)fTEY z6+1RvIp1`(+kTe-$=334Z$AoVA)NbQ?kt3@j>1&}Gy(%QMssAp*(y_AfFSfi(mNNm z0Qu}90B1=VYc)QGsFdd&K(_H=PAr`i3-($%uBxqwZ*%Kmx>!1&6bECKa&T zcfl(buxHf?&8|F8CZyj9A9WuFn~y;Bn1`t3rltAT6`r;~s%?J~`2g!e%H%_Ow^Q5!v?_VTQ(S7Hapc zobKC%-JgAkNESR&+2^#5_Jp-NQwtFGegv}v{++Q4@CU_(E`%JYlAlg+zxkalZRzxF zhw|CN(zqRQ`j2gCjCF*gUf&MXt`dUicEq`y@JCCR2_sH-D1}TtfTJtCD=m#@q&=80 zI0>44fV|T}nmz?B?grrWhz6S(kDJq>KiOJO(QhLA3u4t&(k% z2$0M~h}E>*)CF0!1?fxFdUr+O!~7=w0a%1=FsRst6I@Pk%-84Mx*_u5f+or`S=M6=&L1_1E2gUv{{$E(kV^h$4m>M6yZaJFzXMM#bI%pj-F zsHM;3X!(VE&s6>>dalA0EfGRzdC-BeucVJUQxIUSmNS0x?v+q@0fcFNJ^SOoNCL83Uc=AUT1R!0^eE=34HtQUbVxZ3i z!k^0%>83{q)4~Tcat2uj?Z#}Rd^`8y9*=P5p#Rzr1z8w*4RO4pLh6O(CD00fkYpjdkgO6=JN9f40eOA#=nWgd8vuO%O4EWG)5zdS z95Rq~bQlX4N``fZK?N&?^VS?5&S<0!^oRckd2!u{BqI5=tB3zeeRz zLR?tw%1f}%<-Hp7d7$LGM4D1rMvEc+^*J?16377E{otQO6aUwSrLV?`-f6X&UkoHh ze|-J1^yBA0Nu#o>1)ZO(Hfd)zY;VD%l_jH5=Te4VdW~;h$+F9762G?Uk!JThs^;@J z^BCvn`j4Cs-q&~IE@v?$t+>azTUorz_HD<$SCy5R7?s2bQ3G&{TVIO8>Pvh?N)3Nq zUL$DQhkU=+nS040PGjye_jc5dQXcy$i7-gj+5C317}+7qN?-Rj@X3C_U-;HAnfi!S zGI9;~<$7^+s(jzXhe7ezGx1p^u@-V=r<*dC$EJpYiuk`!%U_*E?AxI-lo#_O+02`}GQ(!lz|`-z=A_^MSv}u(8Fl6=0Rp_&9z8UcHK0ul30dd`t0h4f zb*s}utbO8_ch+H)%1d=8vAv35CrdSz2XU&_(S9c1Tu-N|KAc~#YzkyOyNu?Vuws-a zaMUzvsJS8YK4pk)H2Cr`DUbx}NJ5IE5ZkYd>@=rQ=Ey&OVC!}`jv#-0EMv6HIl3X^ zUxWCV`2y?Z!dJM$r~k%MVjw0B=Gm5P=Mahs!~P#m8-FP7=jE(13xLRKcr}epw){(IG z$}`V`pDSwknnWxq0T*|Xk!>X_Ok^+@hCL%x`|%^~@()?ffB(t1VNeLOTIfxvT}OsU zSy4gywHpfF&j%Fh(a`fF$;$UF<}03IAa{{4wBqjHBWmq%kR_z$P=4fZZap?f9Ts#8 zxSK!DjJq<&eYAuzZj#Pr_QQ}#evQ|`lsx&ix%^X;vYVKE`cIvmc;aUF_nOVNTGJ~K z`JG2-M!F!E&G@ywt39G-Y3tp4MRu#>&r|s_pP7`ca6yEj(}4^uf%t@`LJ<)=Hm zGtV7YyM`9dNSvE$+mtAkO^Rxqp?bqDeGu0pk=Aw+afiS4-3uB_dwj~+$z|MJ#?E?J z>H1j%$y8yFy)-Tt`+IctDOlXF(yw#(FN1qcUv|3B7p*5)`c zOr$)NH;wNUfaWvGLz8*z%sm6s@RQm$~VKg>(~tnw&C-SftUr z#k8|-c|t7YKjl!%D+Sxq&Pf_Oz^ej?Do~-d2yHb>dP6IX$D$VzU@WzcC8K=1iL{(l zN56m~Sv*U)P(}GmMy^WeoaKRp(Z#YJQecP?bnZq6z&IWo+*8~l2&SL0Ovzktu}Y(9 zy^!hwcoe}a^zWB}lBv-wx0}lrt0GA#VKP$>)K2&$pOJOy)cJE*R%Svs@!Tm9U|lpr zFEytjTRLx$Y~#HDMX}y-)$b!z_8AH*C`DfMA5hykF$qy(Z^L2IZCxR9-XZ@0Kcg^f zKhMO$WH4F&aJvLqZTgW)g$e>)>DR5t>o}EjvM8e>>jaA^lFDq9o!W5UV*p_%-X;ooFE zAfI6x^Gc=RNz7}_0n^yG2EV>rffC1>;h^Pzb{~2VdrlNPGjPP$sYi)C++6A|{)M|@ zhb#r~*7FmYWZ!LBF~(XuvHlG~P|j;h1;sl}B;${=k-XtdSllDB{Qe(R zqHHDHgH4l9Y`>|v=m(>aptrp~LI4?-@cx*O#9$?j9l?agkY4bAhm(1q)$wk*P-Wf$ za$JqAhmfYds~A)!|6&hppF;$sdkgyb%FtkG^gERt0>t@A0Az^`7t+^4PXD7F;*5P2 z?*B#Q8wN~`J&PS?Rlqtj3Vb04=IETBbkQ<&RNx>%aBL2ldLV140;7e>1wkS?O~ACS z?;5}qQM6_rJCZ{NL@q&glY3zR%T8Q%Bux(GFUYr*vBOiKCRH0LV2`%KBv#TtG-;yN zhpQ3Iwp@vPLfpz)6vX#Q$FXabz&h&Wb^%*D(QuO2xC_+7^+Hc+m_}1W^_YQs4!U(l zp)aBj|BjF!kHu(=>}6PPQ1mUIyi|uPKp_ZHk#$KSk0Z)UVt4=m7363boS=%&R6>-6 zY@nP<5a$H&qU+t?|0+1pPy)=@g(~);68`kNX3T1Sl29FQt0#!v%0}YjtNA2ZOl2tf zjhswRo)}6<(r_$`pD(*m5@!R_IpE+!ow45btgKUn^kd1De7<8D2#Iz|5?5~)6T+>~ z-3~tO(hIKZB1i!3a1BpD{xud2KQ&~*rCxp75mBr-R%xg@?FO$q7-(x0Ae82qP=|H` zNP+|zen35FO8fB)G+8a)zXqc~7i&z1WbOGIB>@DB5U($&1^o{eQ-)abWpE|2y_afI}c3b2$Zd zC+7j`Op54M57=XjET&$76x^rrUp+j|Qvwu8?@{@BZRn>@Tc>{(V*w6hP;mh=1cA}# zu0!=`S`(>^6B~$cZwL+}!QgWd1o*$NeS-Rh&?~Bba+zHNnx+2W^RQlo?;KTTkeq$& zer2}DSRdYy2+~3M`ChIp78pcvC3unfYz*h|czBGxQGz^8kr}r^ z*PnK9?V5MhHM4+d2NtVt9{Bk7zX>PI&9@hK{j7pcWTv1n5Zu;FP1TX+ZXth|niju! zIXgQUfpPa{!0~x^{gp>)g`Bxwylu89z4XhQ5Zl=6AD;ws^dDZUjCzDQF;oe)YnhQ< z5F#j@BA!&b;7mP`@j(n+$m6nAd~%O0xOgbmT=y3g&%~btUvYtQ5j$*l=cs^G?u$Mh zpfL&c3Ug3rdo3x-sk3Q_mgKR+nJ(~yo?F1JQu3`Ad_WAKYehNenvI*hSo3E+Qm>HZjX<3TGsOj4+&w( zy-LAEbT5+L%Kwqj(a`6Et`PUMiE4rtrQF~Ypd8tQr##qgp>k-!Qf#Lh4`EI#Tu%@f zBm<3DD&#v;_=;htQqUJjSnnNP@5)izXmsu7NS{Y0fqqdE?W7ct_)F3=jYpI4N`)`+ z6CXepIyI3YiUn6J^Xg{DPPt_iS@3zp+nI*47PPjYDYgafq0>-VWz2DC>T{+E7q@(| zmXZAR$Ra^~G9&3b>wvBe@Xl7<?v?vG|G`55Sy zlY%zMJ`8Rwrl*H1h5*H+`7Lvr&6l|@M4gdpS*Uxy)hp-XvYmu%4)-9G9Cf|(PBZjC zNaF*#t8ya!wSYCs!HTZqs$yvfZer69d=etyOdT|>s8=${i0uD}qJg4-2^2!RR@QKr zXjhE}vn^my-H=+YL3og&2En`Fpn+;iIC4sHSJIZ6zZ0E+Yf?mmznPE;WjMA%mW~eB zgZM7Fby_n*<&z*p(Gzs>3jjiq38B5b2VcDcFvFCuH=cS@1TcnRDXqugE~+nr#_I_Z zBXyX6RSlsWVoPGb-s_dNhgNOFRD?5A8tDYabqfV*>LBHg1;xhYhQSMX^1%bEMG?4} zp=kmrYEdy9V(qO$VXhpw&H*l=_NkL$sl^v#XwwrD@I8Vd`H&k=;2BX1G_(=aQBBf* z{kp~4-cZ|+3@(5xT7gQ&RR1fxkrV?JQzfSq&{X~dX%DK*Y{3(Ua>eYyKL|JD=JG}Z z`hzd@htT^&OKd64*y=e@+78UomC6;~qorli*$BO7lG#NzWPK&4uy0u{fQ(2jg_QFO}mSP}yD?#5pA6!u^_j9Lu?h1+Bd;}(2 zSXNe~5V(`ODDJ%XG!3bmbF_s8+COQ_hO+`GYUIrmR}~S^EeCwXW4NGU<>&dAyoTus zoJt{m!gG~1{izYKe?XODSO3ETNVbIRCAX@$*CvUv>UKnmSYZ2_tD_}}9@DI$P0pn^ zLZ`pbbeV9>Wq}Bv2wBk(kiyBy8d9YV2YH+6%ZF&BqjX(E$Z#Wl!;_*r zC&UOd@_dcQf3+zSqUjQDXyO=-hBWIzcwSSjO@Wfc^+y;|o3&wjq7_tO`(};{)p595 zOpj9L0_Fvy7PkN?MVdonEg!LtFq}s+g^a}`HqT)|Rb8M*8S%qkY9cg6#u`X_4n8NPPNd9IZD=p!9?uxECd_MWz1QHS09W%aXdjc z``4`Bue-nh8~FZjvXn-s7>h`&*#$5CF-o3mXC&nDZl%Tl_tauH&0!cMD^Z#{Ma43l zx$NoEWF206>bbKngxKMAOpB<5MWTej!t3YuUkpANk+lePm3u&1^^G5Ano_&WtJ&P@ zIv`7OkA;zo*&(W$gyPP<=lNbx5r^CSWjW`E6xgpad1gOGWvdq}ERL}CZMe6qspuiu1S5s_;!Jb=WGcAyH7d1XsQ1pdCN}ta0!?$h$(}Lc~bZrn?%|9awrg{5uq-seW`3B$qLyj1cPuoeXwcIQ?hL=i`GG$T8a zbJGlY^Na{YA!sXzeBi)N4NXJZ)1MdSZ){SL77|VWe(-#0hr*HdKHbdg8k^nJp zfATHEmehE3{1^BM1@LSYMQVp0tR;Ui|LmK#p#Ia&_gAnMH~~*~3P9+#!3dz9XrO(`!8qifD-47Q;qDPC5DxSO`KL zY;)D3SXpIi;mDUE`66M}0YnM}M;DaE9{7NcTeRPah5}z9yeNdq4s=PoR%I|_22uI> zcg>G)G~a`pA44C-LAcIRlH%=>@79a97tg!gx)c2%;I1-QNY=8J5|`W}Xfj&4mB!B? zA0s0UZ}srUBPoV7QG~O*19UnQu*?B~#?Oc?D0Vn6->^fjzzC1HM-RYw6@Ni3fET~R zxokc=Gsw?CNJT?0Pfj-_0Il@Vg6cY$QE=9Qp+nI{0gHF;vy_arr1@112eUGkE>a+q$7(alJ2q5^)}R#lz4PF`RX+a91iFn2-G>0y zu!r`wXM0$RN})WrS!GFGZ|<+t17dNF+u}dExa)hyBuXbF>nEf-C%$`n0`X&+f@K|s z#*tNGJZ@AKbf!i;*t#IYkqukEMt5X_1ONc{sYs&??mJk9VOcs?3W@+^j7z4hQS0x& zBGz+Yot{??_QL!oT$hO|yLETJIc@SVx2G`mxskuGP-^b_6 z0+c^U_?C$)?n~KgX-NnG1sd$MbLYz947uti{V#J%=xYV{TN&eD zsh{SS?Ap!7{09!6m~8X%is z98Zv5_*+6|5rO+_%4KhsFW$=Y{6?Qx(x2b^wDNCuWna0luS@+M zf?dP*1H_|l2}Cv9vWwX_nlF{ECWl`kMuFwC`W2!8k8`=h4ED1Y0eDy`qM&yIK1hmc ze%A6?KjKqC#PAlcR2LoGHEUQ1&$*9?8vWhTp0k?cx%MPS1|L4Uy!3ZATJ~zVsLf*g zGd{5!;i7S36qtk{X+-hi((AcD%j~@3#?`O3eD&MP5W7XeNEuZ;uM93tdJwVA3?J|0 zTbyLdHvY0_2Zm#N-BP8pMU=|WMl2Zu9OEm81SgAg!dC- zSM0<7+AjV`&#m$NdzY~AWBkv%g8Y7a{~+wdS96m3=W`C-t2Y4g<@ju`jK7`@hBd<^ zS&xgaTIa<(qlAK`Ld7qw0P{5xerNG9f5ozi@(VvTcqheH>p!v6Nh{9{uI)V{Oe;SZYs=U9WjQp1w5*kB;}J#O^!wY&zTg}GtZ}0w zH0NF3K>+k6;^unZ=2kv@dv7B=ml^%XJi3Uo20T=+sNbqL&z#~cN9#Z12^oohduelv zRVFN+z5i{q|4aDlyWCiOcrk@80ko! zrrD(1b}<#C*c-u%llq8CE7ID9sHI3L0KQOV_$TARxe$efA_Ip~-&bU5N6AY+aXMycK*8D>Gi2B7$l^)7TfY4HzLt5Ph-hL-moAi`}c2 ztr~Ry>J20*5pv!>YpFnA>t!>)bn#`kIF%r>!n5K1n*SC#pZAx3?JsZc{|(HHdju$= zbgi{=GOvA@jFd7c8AT#94GWj;U#79EM!brq;IBop7s0K7yyQl|jrldEv82ge8 z;ulQITSvIf5$@jz zw*D!1=Ab5a|4x$yrNBpJwoY#Q9@3CJ>ecSTgi4A?=IpIqcu&gag`e{JO>whEe&f&= zay3)U|Ltt7OucVQ#dG%eIS`3Ta>9~T9|nf7Oaty3#q{xbxlAw+lF1_jO4eS(G=y>T z2n{B!UQI{CL|6z>KZKC8sUGnIO~`ml!5)cgK@*U^G9a=d6)~A<>b=+XUXD*>;#CH` zoq+Viw2)qK8LShKl6*h`8lceoYtUk(KS*hY2+Cf<9cUlG^S2Ug>B2&zeOQ=Gw6p1o zgI?vWxXEh`hw8Y)u3QjL`~D(B*V_}x9lenEEzx}Tr3&O%ELc(;#S^>%S*@?eVW z`}p;+)q$9p!4Vsbc+9yEFokgx{C!=YhLdV-?g&VtSN9IzYdK z4F>Oyv~(^_5z%HBs;n{1#yD_|bJY)gbfw;?&gR*!bIPq_=xX3#`<|Pl`(NPG94^;>e zgnuW$k9h9Y^AaRIR{#Rm<73_k8hes@t!)R#ekteMWdFAhg&a`67|j3(L!!_Vr2Z{-FmfW z9k4ubh3 zkkGhG_XoH!d>pAgLUALCkxF(t3!Cf7-9yRMK50;VeO7_@>|C#S?*TIN&HLQ*A4-x> zOo08js4Ay|YFq;ez%KJG&(Y!Q3K&bkW#^^lXb4D2hNzADJ`C$6A4)7}<~5Q{T%xnC}zcB#fLQe=+*atwN==`+0fg}DXa?a(GSt*MFHsDH&PSi^sqs0QcZ=)bL z_g%Qr{gCu5FRY^U??F3DorLEIn!x@a$}!vwS02$y=`az*KDo#Xi+7jU_oIqQOhOEC zLodvUAaEdH;fSCkddc~`S_EGB9uv#fR{FoXl@&l!gAy1TB7(4TtPH;@7!WuJn+G>? zzKQF&qz6e^a0i(7g65U;$7ESRxi#pxeiJ1644EV{Wh`D?hcDT#o&r`=Ay( z2^Pm?xz%p`6z?b+hmhr8Np#wWU;bk+miV>fqiN%;lh^wF<#eyT4iBEn^f)AUZO{%&4O(qI{i?@d zg^a)HBPtaCbW~K^^WL7f5`O#1spZIux?PhkYv{Wv*mqZY%dE)c#+#yYy*jms-%bI> z|6L!~YcN^*?MyqMVaOe6a*CLDt1~rMy*`;}pKI2avMJ$}1GXC5>exxmF zX~7p_GS(}ne>Xc~F+kDe%aD)$y&Fr5Ayy_|N6Yme+>TfZ3o!ZibzJ}9exGGQL`F@N^+!C27j!=gzpn^WCMDR1UgAJa*A9nt}&fa^)-5Z zc6s$`pXsblh0)uv$h8|&roW7T8of_iUaNqZ%~{GDk7P%#*C?9(cJwv=@5b_agO%C5 zYlZR0+mU~72be9K`Dy(5@$%m`n%Sbiyvdi>ksJ4F%$Cmkntc1Vyz#KlY&oXFreB|$1DFEa@w)7KmoDgyK z6FoB_>hC9ZenKq9Pdsr#oa!f$H6bzUd%ds<<=Vs1wmwF_<%jYg#d`w%38OOaCMHJ| zWc9~oKTVAJS;+7B$tNkBRFe))O%;&7!nEuiN6Y8ok^?uA@aMj^` zh{pV+#;m{Q>ZGPnfVR|>HYPwvbxKDkK-YLm*D^rQaZ1lM;K-S&BmM#U=cn{z0t^zT z45$HySyP5Z0Y=xSjH&~So2QIB0!+H6OnL)Mho($N1I)fonN0?m`@Gbew^5(<*V?Fd z1F+s(Q-|jjfAQCPVFTUSQx;M`EoWgWo-aAz?{I75>B+Yg*DWjjJ`L*f(pELidelzc zD{%Siq@!&wG)oQ2SS{utWUPG9WH5G&I0T4A#Jhewh1MPSGoumRS zq?9ybEJgPEZ1o9*ch%NBb>=TDtxB=uFaQ~jJ-$yvF{|C@Y4)m0N6ldlJazU(Scj~% z(>pcx`_t|_lPAWjT{bW(AFvwL6iKaKymc?Y^gp=|ac~S&x34?hJ#%u|TcnGOv9{E; z?zQD2TWny&2ATLlKxz&m1!V>gk)7mbgZ3dR;laSz%t>4?UdvL{eHNb+3|vrF86*Uz zE1yiS<$DnvQWSKs?*bRpbI$B2ighVR`u9ZID*N?gqy`BhwY9tm3sU-wN568kKgAoY z?7u84Vrb*ItaMRoT4w7&1YiN^kuk}=wxxiWd(cS%GOr#D8P5dU6YQD-MaHJ_rb_3B zsx?dN!52i31+(hcE$|1tS3My3OfYvX*4~i`CV`1DmJq!@6&w>hH=}~HOzN0c?O<;@WF!t|cLb8D52)aNXN`M{#H%QlQOx79f$2eRB}{Yv-}om@7@1yt z7lC`dsX(=t5gBMFIIki@l^pzSu9`;N4-~DfjW%uIdl90GBLL_IS9DLcKN-r#R`E>H z_8~&7z?$;u!u>|;4wd8G%tEMHK}$)6U}1Ns)-`e=&b9WPevq@jGNb<&{(HD*4AqB&c(XzG38=uD$DA8Tvz>9_i+nx$r5EpCOap$({;!Lbigc~bdeO}3TN9pR&LAWu< z?OE{2^gCnKKRzZhe_QsPOC}mDI2NV0N zAL?7lF_lw=aKT(aYD``7exHi^Y*o54m!3_h<8Qaf>6v|+q)1VbQC; zt|*3zl7NRLl21(@Qde%nzp<#iR8lH6U(wwBVY1~+>B8TgnvbJ*ic1&q?Y}Em8(m#$ zPnNHI`L|e1t*z0oLwZFn=&!h$;_PI>)$_E1)gVQBz4z?-)JuzVr{-h9QR*5rjb!jO zjCzI7Z`-0nVR^yf#=pPq)85;*!qw6wnUGDMh4A26@L&`+r;!6D&bGIp<*KH==&j}( zUjEsvYVX==>+=V$GS`rWbz3Ea$D%Zq+gzV4bd~FTnW@%<&xB_MKTrkhbI#>&%oSoN z2lvJK-Ey7)TcO~Wzb&|WbkVKkwwqpasd=4X5&^Gg#ksQ@%Q4JeOLbDDL#5bDMbb?&_vqa7@@eAZU3$=f8&vnKjISG_eR5|$mNu{`tf-NkP+)!|(FN~d6Mu2^?=gj+m$ zi3jUGjS=-o2%Z5cc~`1so8L|IysVBmxAy8!1s5$8Q5HOO!NJ=;njKx z&^b2~oeg@2&boR>_(NAkr&m9r`5 zm5*Iz%ClbiCF%=m8hJ7e3M}={4&P4!;yK|_weHt#%B;2&O3mnG%wS@c zyhnrT#b?wzZeu)+3SMIeKOIhZuB35F>#g5<7R_|>jVE?&%gacrw%SLSK&y8t4{)3WS5Y(z4A_pj1c?rjf%<1`=vm~ z>vIE_l*Mkg20aV8avdaPjX9Ti|G=uZ(r@{A>bwY!3byVEvh3+dB8bp01vful>aT{| zlX)9&KaK^bol+Jn1JU}yX;Q{cijO&NFTi5c7SAV>yjqhwt9yP|Q`FAZ|F}-kLhr`I z$@c?H8S|arG-&Ylg-QKnms7Kyn*M;y6KfySdo*06ZfIzED_^4tEyi*{4D#wzGB^9l zVJZCTw0v5ojku$f77w4{g?P% z&h{()W?v10f7`aefbmyfoq&KIc|P{t@u-ALA}L%1s!v!*qM8jC8Dmclc4gymA#|1E%7(}TgvTqVD5bQ4PI1I?qB3rjtL1xO16(t?}HpYEDfU=XNM(AQxYcg+I3GV+3m{$1o9Pc7F_uth5f17M^?cfhx zg#mW?@)qeLMn!=R#VRN2-5(VNIbGHC>n|}X4nB6nAbR%0BjH-}B5_YvI!^{jJZySj9q)9}_LMT~l!tIet>)N@*i97v7<>e$8U2 ziSoR`*Qql4t`?L0+;U{^h8ygd=)IkN^`m1gbaQe4w_=|?{yGCMZddK;=J#jh!$KVa zKGn>~+m7w+9jngTjd?t3npo4aIqjjv9TihKpT~~!lFd9UExAuc%nrbmVGWX8UA1EX zwP$mMZ8y#oG)SIn8R?gfesf|#HeqpOK%T(6w)N(1C+=y?+*3N&*)ZVs3)jO>=pC-W?absN zi^9jJUiaZ~YiHE}v6HWz5O=E`?YYdBc3xyY1X-_J9G5PdXD%e<0;Gzan zy`4}^>Dy}p^NNc!`csCG9H|!~l)gp8oSLa7KFL%p5tyi{A*_KW8A?mzpZE}o&Dz}{Q=QPvGUD~0* z!eev8?U==kjF!thrNu_aq5QeKwH z^W1*sYv0ELH2)wcgO7FyTlDQv^MmY1G>-z81o5n-7rUXNFsyjBJu!$d**dhB5Oq@T z>n*XRg2Jtg3{d6SCwvg?n)2xr(H!!i%)f%6gkhJ5tk(!$NO~k9fore zj>tdOIK1_W&xT9+=cU^AVF2}!+a>yX{&|F}o`N;Ta^L?ab^20EYVweI^lj0kUbp+4 z?Ho+Ff+QDMSWKa^$N8;rb_yv@;t{s?^tsblTiK$ra(ZOJI!Q0jve?F9bvqAPnVYA( zr>L9pN=6eSAH5qz$oBCID!lFQt%Kv6^8fPlOY;y)wNR~t{~!?B)e6%{XH=ByY+nIP!Uh628n%ErNq=BJFGsV`B;O+3T10kVw_ z)|u5qJf96gu+*an?r}?qVoQmrjXg^X63Tq@9qw>zxun7D?{8;{)Q4;BIgPQrye>ik z3fm9nQjBAH8umm>owq6_%_YRty-_1=sK1Bg@8#ed&sRN}QxiLRt$~BtXScpu4=6wH zm4&aTRzi)>3s`^zp9%RN@}JN!b>#N>is`Ph-0rIqnmJh4+Fnzde0j?etSmL_emj%k zcXa>jsLOs8!p0h>S-f3VhgrRQ|8Dq^bnH+W!sOmZY^@%DQ+APzs|`1{)NSKLNQvWm zN2R-9&Ee~V-RmG&%>g1|_Rqjj^#gME4o$EE_W{2%fvl_}0V%?gj$g1KY>BXgInnKB zXOMy|VJ^|~$V$S<4WGZQSDy;fR8O&S8c4R1!-Yo-YXPgD*)92Q+rqC;U^7IYiNsi~ z|1EMBI3lPSl;?h$niWwsd&IP9C38cTCk6TUcuOTJPB_7-P=_NU+QzQ)bL)r-o%64_ z{ba_4e}eA8aC%lVt*QE2K~!PM?WGB&nF(3GntQDSILyy*!^PfgPadrU+_hi6p2*G0 z4_E6ki|(;Xs19wviSj#^sUz`j)a9l<@wh3kQ^t_|+D%5?-cqiC=j6nJ&&S8;{k3-& zJJ)Xg;kz<6bNu}gu~?f+V}2QjL$o107fSsyf)=V;Fn868D#e$Ms5^7lWKXPCi>Ca< zTAZmyzKOB&KY?|!yYBld#^XQzADWlMuD|b$xjQhF6#66KjH8f+b_0J?=w-j|lupMZ z6~u@q5=r4sS0DVf7EriaK@N@)Vz-t2JUwpeeBI=Ir;0mLu?<4{ul{~rF6yeNUECZW z`TpPd-v{}(R#G;1e}d%y$I^KQHPMD^cvDFrKnh(T3B4P7m(Y9f)ldZir78+)=v_dH zh=8FNK>-D6YA7Nq@P#798W0X_C} z4gS)sd=hlY4D#;EA-9ws6Cc0%Xzvj>gn+8?AGkGWQgu9f$NJX4jgxwR=BXQk2X&l2 zTu7W0lbW{pfsgqbCVOs~B~#1E1Np0Ek1wYpXJ`;J3UrMEr7}SQRHV?@KZQ*&k(+an z4y@Q8Qh+ylwM1b$5{(3vgFs4RoQ>Ra85F26g;Qq}PhkLqRAdhqB$~tqDM0$5ftE=T zY83zB5VDQ=F_iV8$N>!-II|-p2KOOxRWkYZj}y-%^HdVJP;~ZkGFx8<$DgZK7dP?i zL!#Re{9_D}c`A<%O>7+hBQYQ8 zB(710NLr!v`jChaMq->H%2y;Y!4UBo#vW6Y@N46;F+!dK!)}12N(u$gboT92<9haD z0d)8ZldqBv5(eNpboSn}P!x@qwah0>gU8-QU)th-Ek89@h|&h*l%pl73`}?c|5ZoS zNiafp)Axkf@i#*_gJGeQM#yFKG2a#FLgCm6d){wR{2>55gE}1m;-u1%-x(kjfpeb4 zE$}f~^!#&9qB5~USyEV8(0CZT<0x^cEIC0EGF*`c)40}$pynyZOtzAZ4D@T4!3{%pGXlr_H6D8gxoB4O6_&(O zRT7C2Qw761sS>I6jwGg04YQdRncoOIYjyRjRKVQ$I6e*K3C@2x!8sH4d1fZ^tJYO} zq2kwGJe=iB71b0r5eokbg){h``K9|!V+`)n9ncJmz$r@LpiBd6Oqei@`#%SSr6K#- zZN7Q3*05cdum9*%?iPM=&-=H>)& zV>oy)8vfAPCy*q6a#&w`THFB*6$L=AnJ%+bOAJNkWvt<3vEa4oK-p3roq4Ud$%0)p z8^c}A+tZ@L6vUxFSk&K1vdD?ITM-hk?yyUeUXjf}y{LdVpObMDX_K>fj_L@SkolnE z!oi^jJno@?kKO>2kU_yOnn+UG&y?s;VzTqD+LABSiJWfke)^NL?nq&cv| z0BtvN`B&m2SN0izQz04JNB}D*!;i;+QFM?)4VMmpD2%f)2jBz}#~|R{qUzH?gOnec zPL#PE{GsskdZ$=)fI;)yt$|n&V-?-?GSRrB%j`X>PQy-A6As=8z}J9iU0R&sObqve z=u?O92QUX+G59Nh_Z+}0!C*fsfSXZJhs!Y0A&?)H@(n=vkT~G{maOGCd(CqV6ix~m z)Bx~(qamKoimp+>nKUjm6SG)m9_Z$D_LqzFSYwDC+=X4H#5lBD%F87qxP&ue`>Em2 z8t8B>yYOmE5+%4XAm^Z_;c!LHp-nxd_VRXsEH+fGyg|_IbcouK=Zn^*1@bPDHY!_r zSpVI_ve?YPLC2MJ#!)L>c}%3)gdG}#|^I=%#CajGH5he#1=i>rsT#Xd4%;r8->qNl;_OoqJCO)ZB(95FAHAN0c@8N@xDTIS->zj-6#;Cr^(8tWcRLUHb1*uT?iEF$mG zfmat0W3l|rF52S1E5kQI5fm_W5s09~HuORO3}*)ORv?jcu?*=q1OzbsM3|s*I=1yc zj?rE(MIE>s1}?S9dx8Nt4%^4Oi=T+Ph!YDe*5qK-Kq4rdnY0*O6nOYSUL*xUDd&;m z6aS+H?_y?u>-LJIVS?yQjy0Um1$cb~IHd@6?R2DtzY^%4i>&ymr_#iC>@ot&HC=(q zX-sYg9hGw<;!~=M)QSur?YIRLvQ0;kFUSp=fWR*xt71TkR+Xd3a@O7bYJL_y=l&5x$u9Zyv~=$=l5&J(x>30dhho0E&x(m>12SHaRuwxi2O!D|jJB4<6t`B~R->H7hqa>pGI zFW$Jf-Ag<50)CE<89}2%JW5^lsdtM4%A&snHa@xDnu#0#WOsRmy8>jAK+Ev60l)DA z>v=dG4zVRroWV?GK5_OFPl#|PX^OS+Xl&yVyCQ9eQ75natTf3?!cpb}g{_gI6FmTF zBtLxn3zp>q{`xce$_m#4-LD-0omtjAMc_zS0KT}vBj`P`#0SX!2f6@ghLF2d$#$%X zbC7}XAZNe6ijpWo$7;B<(_Zlu{Kfl} z6^0KycnUoH#^lu>fQ0xLoz#NoY=T4q+?l_@xAoxEayvW)rM9cMu+W;AX8-0vDwxXV zC$08qUu)1b+)sK{AjlpL7=j7L-%fS)2UjPx+`S~?dCoMs#TdaQt{0kD%EsiT)nV35 zWym37wE!*Y&Epw?Bmb4sl+>irAm!Y3y>}lk3Holq#;8|MF*)^KRX*TlKPiA1d|f31 zTLGG7kN9X|(;(|K642*maGBmPuosNS5FvsN16IDA&{#dHB8cV zO2C~v;!nlviEEOwQ%2wlqL)&jTq{)xPGAp(G`@md?>|AVZt(j_bUP)rWc&isXf&RD zb&*FL{>F{}A&c@(k+tm^fI3A_PhC8^hkJgW#ufS+i=rUDcmKTiH+t9bQOi%8okdXV zCf~&Gi3NJ*?q4yOP!7jMek!34v>(t!gHHojJ9**c6L1qhhW1;mFtz7qsnnZ$^{Oiv zh2eX%076R0Ie6>dZJ*zG(E)?E>;n8T$}{i|W>uILr_Ta==%w14ML6Oi1O*`4=v+)E z(!J_S#IXx9BW{{df>6@-=ey7*50=Ei>;e-nbjcAes4qgvUPtQ^z2bT4$a)%QhD`|Af$AD&lPKe+RDAYo_i?TZI@ z-#?~8I7DrFJC;YXaN_TR|9e-Vqk@hRIZAM3u~nAmmG5FWE3O#V$1$Nn`HNQ~^$L39 zbLUV3%CB5B3ipXP0o4fF1ttaD#1$S|H{E=}tP*2WzF0nOi2tF53rIjJON^yy+0D>~ zY`x8HRSI*pU~n;!3#~_nocn3u*3KtdG{8F2Ib$N(SpGz(97994iF z0r4AOrj0dgFm#*!aYCS*%9<9hv~ElnHLo%XY-*!PjKk%Ai+)*`=kXOsWfMgSyf|g} zC#w#{f%+2Y>KYvHjN(@N!mO~F_)Isj(_##nOU#FTu1fgS^0_+c*VoUtsBpP2v~2ZH zi{kJ+1_=E*+dMBVUVsUp#PbSaC{L}eVZ`w^!{k*~oAI&JJzq_O2YNH! zJjFa!*qKmUh}fCb`rNiNl_Yffzm}#uTlO#Nc^+moJ!r%HoVI?y{a(r8`dW+rcQR); z&J5pvf8Nd5_W6H4INOPrb`tGsvaaTl@h{sR(R`1!yp_1G`|BXR{X%pkqE_3Tu1HOrf z=oC|HEQ*YAv#Y+$zji88)|jvDJB8kGE#T?5aAlI={^ltE*@LZdY1Z9?Z8djW_2sW& z-@9LivIaTA^ZQ0#EyRV}vxn#XJFtKGo#&tad(#Jem-q6MTmS6kJv308(+r#X{qNEb zqr65py{O_IyW6i$R`LLmLmy*>_y0o~q4T&30slWEp z>jV13e0K-*;&?35ha*dLOmC!eR9?0fdrPjCTPlvgRV|i2Zxvi%KS_Zq)3R@PS&WJa zZDm;;;U=$_mw(GX8@YN<^wpVZfso$7%LadW0>3o&d6yhdtVk4{V@T^KCOBTs6THQn z`APNjR=%LY2>yLD-=nt3c9*X;6>ra^Jm`xudB?|8>#jGuIwop%&!^+I+BmV_`lVeFVSoB=Jtq{JDaO|Aq8=$oH%T#0P4xcG z*73aA2v1AsorKBTe!ri)OH`Yf$LhS8w{vx=86wz3*C6=@12g!2>~1fc__&`(gJopI zxGCF!kRF=qaeo{o(ZPlQOU~-7r`@{L;E7tm&CT`y>h8#Ik2vLt`7z<96zU;TeyE(H zQ)#XUAIw%XV!-WCG(i#E3P+%0I^KcZ;q%gUSCMniUjKS_NA3Qda}Qp;{XVrTXI%2a zf{*O?Fh$zj;1Y*46e`8%|MlT!{_(O2ARXHw&CY|Q2e5((5QQi)cFw}PR5lwX_}Jb< z%^~cCFp1jyiwo(?>KqA@J_~H#d&2@#B;(t+7rF@dyEPr#3Q`Q;VQ=n@O7X$P%Zlo+ zlu-m-Ns!CL6&;?}dt+KtomZ^~dA8xHk4L6S{@=Yyf3{jkd1iMMUY}T%(iOBPn7y!E zE0SRQT-tiOT_Ew7?g{`E7x07cTpwBgh*P8-J$=kDJN%X`;O-9^VPe^kIsBB^zwF309m@% zMZz+24M3UMt~uT8pKBIKN2{fzW6OsoMaQ4WoQY?xdA;7BKO#W1ynjWzVWB=_tTF2w z7P`9I;kM`q@9DZex&CAOm#vZaHp*c(tT!RpPfJh8r{oh98#nx@GSu-x9b?ATbl~`_ zcQySB|F|PL_|)`HYXk&@maf*^G*aTTIvODg>Ni*UnN$PfwwrU!JXFtW!i9QV)b3>q7m*2AK?u|hO2OmiVf41~s zwy0w`J2x7~mD)>>d&wJ^cjt;w@J*zuS_(Aqw)RP(d;D9ThBYcbUT{pKA(8%>>MT-e zOC_2O;*tE(k$YhA=?OiBIm1xihf#ZXEOO|qF__t7kz0Gr8G(SjSRR^yskE74u3g%E zj_pP+X{)v`)ceLd_U~;}RA9w9jxzU(Z`6{m+`Z@ChuaR{r+wD=UeGy0>>N&6D+CpO z?M2Uim$1-Bj`dyidG#@;`g8F5N9Cum+(kku&lvJ&9Q}4qMk-?1bz;V(Lqul<{ z_H}%D>_9_H<;mLa+LPrY#S~{7PN0emnCbsT+Mk zeh2e0yf%$-C61yOtwI)h^&ji-FKfet1g_o=HN@~Qn)COR=nJ1R)%<-?^c0`XQ+}G5 zBL4zGo9Jo*EZuQ#BIjFsh)+xa7R7YAj=5+iSa~&d(;pA24m& zQ=)N6_3~7p^{|Us-Vo`mk?A6j!Mr$mYsAba≫^W%bmcoP`+kd0y}6MDOTKj~bub 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Ⓢ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%0Dd*Q@IfXn z;G|^%;QK?oD-!~1fFcFTBBQ|%Z@oHNXYSSaKIt&i69~OmJ@;MhhhU*=6vZapta5`J zSEOHjL5Qh|kP)HC?iMn`+m|wGSjpqBhO_Ls`#1BT6)_Q(Q~oz?{P3Cv{U0wrcCSW| z1iIaAH!H7n+AoN#UKAW0I||Gcc5Fqwb%Qvf7^g}ZVHvEXLC(P|K%nIwajR& zf(U-B2Y3VLACeBuKJeZ1?@L2xlhhA|s>wYg=^wS}RhslZ)4&gAJ6=Z;oxPqTPtJ;F z9`tK8Z3V$y3cT*I3F5->*=+^iRz3OUwe&a4cj~V+kF~f(K0DJenwqBY)sIqt4`Z5x3d()5ejCl+w;i!q zas+C)vTRE@$PpoNMU2rKAKHpYRw0$rZ)e+&Ieohk8udIruuPxum@(oqv|QvI7n00b z5g(Mv!MO82C#jpWiH0!@k0kA|U(TZKuWH}EuxpWWw!1UFOvHCoGQEln{=TYY-PuKZ zmiFIm+rCn(Lnq8fe+<0ITy1Nz!*sX2uLkVQ+S~B@LPKUmMtXCq@t)0{rx)%2HDjEd z*mFMkr28S0z1v=1j=r<+pUFPnn_F97*Bvt5+kJiax_)u+$_rc4r>Wof+H=A?6h|x$ zJpR4BsO!whoXd!uTKdD(NzLBU%P&IHzXV>~zSvV!e=% ziccmr;T0H1JjwnmeDvA<;cW+&d1)_7KLnB7htG#xQ5@cwRPz>@vzw(5&rolU9jT|#z|Lq(SR;4;VlIxo`v_YD&JtB!Z|=`~VKVL&Uq zN4yH0z{4kG54bBy_`#8cjr02Oi}iZ~4AvF*EHOW%|D0oe=11Kprk8L@X7{9%RiOuA zM>g9>^u_U7$jb9ayBPGN_ewk+o?R+Wca)y<^cjek(!SflSDmxL>E?=c*nj!M)YUj#?BzR`p1JaZnXiEJ?WuafCkg4})z(O=XLmx# zz3_y|u-b;wRyFkvqj00s%g}AT*L22?uF5LfUUj|>J#LGH#TRS=hjQQHzUuv?YpChJ zriRF=(|5D6&db!TD?@(vpZ@mn->j)dfv_m!cTTnE=B40k(O>E|FuGm3^+2M};4cre zTlpzW^*Ki$uUL!7zWbkFh=yzB_xGJ|%swvPkpjgr!dtd@d<|`|Jd!b1KN#q&ZC8zE zMEz-fGuL+>z%1~YDA&<;wVX#!_M{1h&IQQ%1Lw?>Z_prmzna%Ne&@PTzL}QK%eRP3 zY_rO8taQxLSvMPJW%b*EQJp5{4jJB~HOg58?Nk8Xy|=80kJ?3y*3C`JvSRS#$f1qd z#2Da+W0cxJr{KA_V2<2KE_q>ioTSJ~-*hzrcZv@foK-w9ojMlensHK!+oPU?Sv5lQH11xE{vfumI_xSSLc|H-8cW-+qmz`y22> z!m)66F9e-KlIUXnfXo>k1f8Ea|I${7^%7UzMy|g(GHFp5P_8q{Y&4nGvH|diztJw> z!h*tZoM#z$(ksf^G({m^6A3~vRTAAP$dQ_UD~m=F0)keDAj;KiW%@7KF*884OYN=7srN?|FmYjHw2O40#RLg~LqT@jWVgh|;xZ;)7ynt4wET>=Bdlr4QS6L-qrQFS_3;^#Vlnp(LVJL@}_Rgfx$rIeU8l zgqK!j24PC2sZ;)Bv2~((D2jc!(nl;nx%DutOwi-HVZT1np0TgPJcOKg^*Iq(%m^5giHaYG07mNb{Rlb z6hKf_YN|h9sDDij!|TuKVm#PR^d4eb8HoI?Y;<()8Cq-Ah`cx6WQ*5e4Y@SkKdG69 zrDdbcde)OQfCy$Y2DK1)z^-?*ps@;sK{Ei;9~Rofg_*I_S%&6`5QvK)b8WW*h^~j~ z@tBh1o4M#onb6XuXUMd9Bhh>6hhxm#q78W*ZtR(aJ?D*SC8I%3N#R)=k|aiQKkD+7 zmgj33hG~f+qk?1iBub$;tP8MmkKb9cL=5P_4638ILA7tMmt~@{PUqWps{Rj&1=S!;V^u7*`5R;$I6F z%h_wK@9tho)*XNg23^+3#W06L;~lG^IPS6l{O;hzgVo^A^SW^2G=EF_4NHq@jSzBH zfQl|yN#d|zNV~&AItU>eGX+d@2F^Qn)*>`<3qER^=nc2j!^?Cc)EFig=lAEy8)E(+)%4Hv5b-~&2lGT3JUjscR|Kp1GpdnnW0CqTus$SEKO%R)FPke)0= z+BK+W49_ zz&v+Wg(^{LECf_(R0rf}@dA`aLFwE{etaE(4&ZnK?6x_XED4hv+9sh*Jn1p((lvjv z!rc5LzrJ;X55-L7;9}G|DgeU-VUNdtc;>qvu6pd&glzumqhImoM5ilSK(O568v2dE z>}tYRAT;3Wi$Pd2s8=V`%~K=0$6RhIAc<-$Qdk*sX-{t0uQA{!zY%GvgqSH%NTH$U z^^z)Xdx-yRw zhY2uk=#xQrp<(~Cohd;CrrLP`!0~#ZDG(fwi_+V?r(f|>#KXm~2vs$D5p$0Sk#+uv zwJg1BTo?gtGwc4v4~D(_UJSI)%NWzS2IdTB<6LCah2Netmcf#O2|m{l1#0S$knq?= zx8O7Uy9_p>(CJSk_X#|<%MuxpAPDm6TXi>nm)ELZm~3nBN_AeaK| zV4_$0JfsV&=cWQEkl8N>bQ4)v?-BUno|=>a4{JB73M8g+DX$6xv`c#fmg@&D@7+_} zHXX6;BzEvbNF!-L0pJxVxbnyB03|^0i3hBIcE0P#wzWS#h_LZwzNLj$30Z21nTF}vJty$!9JHZAD-*cTJSUGtn)F{QP~m#ppyll$5`v)3q<3x!Lyv3X#!k0 z%O#!nWLAk}DGgHqi(Un3yFTf=nlQb`_=XHBm%+4I3Z3V{eNk+^B7gGE@UW*Ju$=9L zc#t@kGVTCob$b_9KY>Qn=#8xSZ@@&{)eu_b)1?Ux%3>yntAR~&WYF&bK4y#RV(@yepXhq- zYFxQa=@3;?4wKxZ3=ino?IFrKK(4BLs^7g@G)M|GRq> zo5*v+{=~LnTzBFvy)Hq$vXM8B8ET)kS-8V|s()CBmb=!3kfM}2vn|uuiV~fjYn2h9 zzBh3Z;Te)_?9|dk&+KWr%>G;5q0mo()8rk&Rz&Pgs9UbLTRGJED_PaG2jJPgs{^wH zhP_+R%LMTCc^0aV_UE5d*D6qr8;R)))5nl{%&+JhthJGA+*Vzn_ua(rz?$iN;sdXu zu>(kVn(K1Vf<8cKyS0-`VvMdJ`IPsjus6MIITUp(l+fvQLq>e1rtV%DQsd_SRZtVI zd#nmrzt(-1mrSqVsq5*Y&U?pk6$@gQ?^*bpi)L`io=exA%tyX`3Ej-rOMji<6Sw}$ zYJ!K`hDSv;SFqPz09{X(M0*z?Lo|H%u4sE}?ft2B zf$u(IF_|crA^KSdGYlouM}7XYJ$KlSw|=EwuK=f!!GHmH6lA?h#_Dv{Ym@;#%XA$E z2uKL-JD0c*gs^tQ@&#DrQB>>{pb0GKq5WQSSG-(YPfUhzpN;s^{~6v$UBvP;PR zfbGn0q2zEGVm!}cOfVS|p6Xe5rbrO!3gYDe{u&rU<`OilgqPec>w}7AqB@zRrJ<)Mp7Q5QL>MdsX7#$C`{@I6DFv*a1TqFt)R6Fg-WauDwW;o(8Z z;r5p)GRh$}Sp_1qxG0lyKto26)dX=JEO+jh+}>LcXy{7xY5}r{g%6&)y`?F*-I<#+ z=R-Q$kq<%AK0r5yh4?H(hzj9ZHx^4)Vs-TEc>>@7ANyN<8sqNTW3=jhw_Y_!9asK0 zwJce!_Ws6B{i~{7ZhCu_>Ft)zhaB$m$tJ$)?w;x8ZfQ>V1^~=l?&sJI;eT?P*M_j! zvb;Q*oW=dLPY3M@Bl3sf-Q3Yx8kr}6Gc_*jUm;!{tJGXvXXiA3tF7+LBsF&O@rj+E z5(dJPDs~2m(^ZOPWB|u~eqi&}XB=QZ<5!YZp#?aA@T!_Cp2>||T(|wYqdSwwuF^rm zH;oX5{wq>_HQ)iq`p)Z>WY)^t$K!d{vuvt@kDB(^lW!Zg`w6%1B-^@)UhBYy%Xw;vRGO5P7gSC)K#Sr zpy~w}evsRHR>+Qdu9xtGhi{4-Szqb^w5$)}MnaeYdjf9`aO0?eS;5)|TA;J@KsCQPB5s8ufF-$D?Za?v<7i z6kWXfi=NEmXI@vV0&+1Ih&uW?Ug1FiV>T*~oWrPB%U;LeheN$#XC8Cd)R<>BYwYppKEkE#r zg@VftX)NU^(3D1ta4zaI%c8>kI#zK(z@iS(e9PXQo!_KBb%^^Tj^fZ?)pldC&1hv} zOkXgFyfU?;PVr#ao>*vgJ>>D5am8RB%Yr+8ItE8cD8F6gZ&J9i#9 zT*`@|OUt;_$BRGy2C8i0``WkRqRTCwQ7eWwPab^wIa8^>Q%(J)LH-iNd;t*10lor< z{tnsEor&8g8!QB7G}};UESjEU$a`8LU>PNc1i2|K7}b}GF9Vh8l2D~ix7>(jtob3F z%wtjAgu3S`76*2q!!tY%sRNIh&ophAX?;{sk)3?aa{F@s(7u+VIqO{YzlVu9G%<`- z_hB&w8d#tJiqy!C9ftwG0@)lu9Bo>-{G1P4J3FwQ!>nMZA53#|Yy5Urmd?W-Ds3TJ z_=*~a{~aj_-=Ou$M1Om?@z3(Oj+2CMo%dhMFNT%Dqx%_C%y|D3)5Gg>24qFDBKSJb zy<2aNv>%+pQ|ZzInSbUqe|TogWL#6W%YE#D>H_+s+)3oVJkD*$-c+}kZfVMi&k-kg zYlB0!zqlHE+11dc_`kZ*j*Ed^l-n^sFZ!p&?ZPHM`FW|ccs`-dy!m|hvWJO3TLO6Q zw8p~3)VD)VZaVm?mY>0frrdJabmI3&G7yoyy7yXS>Z*&S&ud3tT)m6ExBF5{VaW37 zTJ9}9+B~7i?T@-~Gj$%_$+Kgl!H4%b*T??5pF#9}IP>Snm;WB+`#zfeH}m(emdF)A zbvRrhk}Bnju+G{xbw~Oc)xQYlMsWLA*$n@T*yy!&f#qgah05Sq zz`m_95zAIk$VaxvL{_p_{oGW#W3pFIOyosHS7sTz|E5Gz>Z0F2XrtFH8&(De79UE<6n3S~@DlyUF$Fa?enw!?FZO}lMplCMwqtw7NvZvuE+|fH~ zpD$awVq9m?YqlXKBu)Mj9nICvV zC!enPH63hvYtcaBDJx^w$9~s?PgkIJp{Gl4Q%`=9_$=j=Nv6_QkDh(>^yR1L9}dsl zK0ZI%ENunCAi?Uj$Lp+9rG76OT8n%)SucoidM9>kvkTg{-%$o3N)>Piz7Wro-Nt_^ ziY#x*u-2 z-YIkGOy#qS;=aPMlPB_N`n9TVMQgL3Pj=g5~s>fj%$q?eSL16FHH{8 z_htf?b2gSDwAJDuCJRq5G!LFbY7v5_|5ps`DXV#NlNr`LeG0G?4<;~aSaf@@p#f08)U~cmu;eQ;RXHXMu+lF`36M_j<1cU_X zO+Zwd5UMmaAP6cdAff^)A|hfTp*JxUrAz1?LXlnqA{`Bgh+qjesy?BLw0wEL>`Z27 z@?&Qw_ujK}mg6dS4Tbt}U|snc@Uvq+U0p?EVByD4!f9>M{n|M>h7H zqelnJLinyfJI;x~Oic^~)Yny1+_)86q0*=jfzg5-8%Vv05Lwoe>04KHDf`gdQ2GtZJva0;}Y&0^-$NNqB}Y6F(mE)Z`18 z@gVS3{x`cwq7Qh$q7T@6k_nZrbHEegszBGADI$3qrVwaqurYE8`YA8#{zRAjIwc$% z71AlQeH__{hn`^vbjzw&N1uxOCMm$0+uk13AhG|vKOFOUf~{gbHrfQ z6@*TJf=jc2j5|v}nyee~k^$X221GybXCjWHOvHOrQ3Rh(#93a`Uy%3|+em-Q69ApL z2~x`3DCgJ7m30LNpUl~MHw=xRMtOb6jC7i z^=>sOUch=eV&Z5$HJkT7pbQ4byNg-0888F-3Ig-MI>qKKt_p+pV^ z&4XUzc1sh?JeYuMBgAmbm9pm(6gBVv6ODI+BE{%%1iw1s4-t{RV+VIJa825$&lJH-j5@`*s%yE66cx-# zIK~4T^LJ|E_B?(X$dD1pP_!T}_#$~4mw5<-^1MGz=pu`Xz@C5^UGo7VjlmO< zdY?Ai21q4}g$c*mBFQWXl$7r~@LQ^@iIm>YWEurUz1Y*5Bi($%a_?>eqz@2xy`3?`0-*aEyKeoPhqTTd6MFn{$!HUZ{f!F2I83|}iFgqy zv`B}aZ46mb89~Y}=0FuV$bKM2zlc;gyae%QFzElhzJXk0KiO+!-o(8+Z;5S1XU)$-4sxZo=_gG zu!epzlz?)f!IbF`5eh1sg7atL9T>)+kB6CG3p*YaX0;)rtRc9~nM z1LQFtxilRAG@wp{-L6yL@P%8jAZ~a>8Xlp}!C7eF9Cg4yIRY6BxH>5kO#-&@xI{LP zMg!c~zyl`Cz!$ck4%z1$kw%GdVK{E!c?@94c?z7y^ip$$61oK$DS+@x#0C=sJVOg{ zFblG{5DE;zhVZBZrgZZ!31`GTxR0z+vDJ#PwU)7U=C`R@I9CGZNSHjz4aOy-MOcnr zmtmH4gf=JkGEr#S3E(mimKq1VH>izydR-cPJY8BU%I~NfOrHXWxx!jKF}!Jl(PSi# z=mlp$y$P5uj_`g5@8_ z%(9Tt?ZX>PzGJIOTFLu9-8PlC+xtN~Toj#btdwkOmAts5J{lqlOHycD5>%Wf;;DH1 zk$vJa&#bQNoj2niI?ykBbwuz<=wYQC#cEBJPQj#0cFJZ;;-vyAU4jD2e{nM(WXzRP z?pUSV?SEuqsWrpV{)$jAsB)5;di=7e?_TY7|7W_ zpCgUQB`W70u+Ek9%2kNTRVvL@8OT+e&pn9A(^SqoWSw`|EAMDbo^ENL{y^Tb`8*>` zzOiz?sdc`&SN`#se5=xYn}Pfj^ZBPR1$N2>r>zSdy$YOS3eJ`m@IZMN<_j)i3f+_o zFIyL0@hZF;Q+U0!(0icp#(d!|Own!SqC3__cfE@4#T4ByEqX9e^k}{)7*kADE)KOW z4)-dKj46&TEsh;1ellPD6jPF*T#{s6^31CwC8i{;v?ODoBx}AT8&jI2T$*QHTHsY$ z6jNGKT3R;1Ev=X@t-_R5E0@(;m%a2VYltapDlKanC~KQ9>%f$EDwn^qE`RM+&WlO* zmzEC>ln>9Bzr|FHC|A6*u6XZN@gb(-V`;_IK*i_zim#Z;Y30iA)|EfKDraIU=SnLV z1}cBgSN?~oT2iiBv94P4s`?vK^{=#QYoKapzKV-sfV>*L4Fm4YK*loAWemPS2LA#B z$5$<&QY~atE#h6hH@13TS+&Gq_5OuwX}%hwO3eYA8aeM8h1eRUvKp1a8nuO*gM77` zDz%4fY7cwY9*wQlEvwZZtUb0+Ys6P)tWsxcQ)lj7cRaSvs;tgtu@hM+Zf=W}8P17^) zrj*#Gw6dm*!KSQ*rfk0E9F^ugo8|)V=Azie zg>&g}IeI%(5}3>ol5*|%ogs9C4H7wR-@OT&5`eB9WOVEdGB1JPj(11LRs+a_ zN)doy8>W~~yA&P1NbNMe+sWm0fUa(!6T#Rz>9e}0a7;+kHFL6sBK&oO(?JzkfZRL?U1^^7;#ef=Q4tuD@1HNVsZg~ zsuehxDa6OY2$3FKQf2Zd+;eEf;eF9&DmGG0)!`z!lj;M3FaVEjk#KJ` zmvWCw!JK0Po)h@zY;cR!jpamCvEj!vbBF-s1|5D`mHSGH0YH2p;=WxF4NxA>)D-~m z92|ioQp^UcScpYx4{8+3b?rIhizd(pQWyg~o9xNd0D<0FceS0%f}SIH@^LzJiNJtr zj}RN=vIYsPR?@RJE*?@_4u9F&{adAx06-vgxH!G9m@@ce8z)2uiIn~-04FYq$dAi0 zRBgRML(7vPL|O+P7~~QLy@#Z3Fkdg`4E`1vLP8)ZoYx=?{az9w&cTU1Y>yg}O2NJk z=IfO6MbB>GxSyoN*&xUU2UJIm;DagK5n_u-&!IPcd{`py!jwU?At1)3QJmF*rM)dC zz4i2Y102h7abez|4@G2h-*i9h;7pq0fzS?Dul~Y9Kb|27T;&+<=@0IK0>?-G(b~>%prr zkC9n_+}eeXahcCGMvPw%L1-WEmk-VkzLDOEAmV{rimWP5rzSs$UxZ(LgpS|O9{)_Q zL-v52w^5Bi+YT;;`C6RJ>evwx_&rS^57r%5TioAQ#Tnk`0}0P;+i1aAtG(^=e$7v1 zUKx6=u=rX1#rGKr#QhI_fmF2m#E7jr!fv5qH+>_~gu`~?9z!zWac8KgpVxEw+N9blliAzzXRi27 zYeJ^bcY`;d-CO^-&2M!6{-o}(wr6N;&(Q42+?Ck*H&aK}D;F}3v~RZmw;j(xS8@2> za(L=B4!0z5a7pOYlE|&4y-%0!2LVXmM+az2LJP32eB=qvf6`w|^9i=60gn9JWwrm7 z8#DM;Im_4#zBP>%K9!ZDxQZqY&fpZLiG(%yD!qnZ;gWEgr*NxeoE8IengG?Jty)%b zS8WgS=x}TH*(+;gob{>I^TDfD+||?URn3ky%~R{vw~n5q@fn<2Km6Z1?+wDUYE|pt zUkmA#S1i2a(`DW46_Z;l{0S=o+%=P`73Fidd=jRO$1G>VJY5mH#+bOTYik-1Z&G@66MU zf~vJUZ&%EWuveaLT32B*FRf&Aai_kn*k8hVRjrpA{XPHR+VM*p%FXL-_~io(5UK&} zf>5L{#w>U>;UM%T9`gA=UW#nHiOoYDbO!qZXV?huQ#i$r_0jB2ucsSrG%lYO4FXiV znF=VZ`Tdl67W={^v}yNPn3&x+vltPzi{(1>fet0DpkuPn7*cIPYY{}%v;RpCgymyo zhJOC|O5x{bh8d*VBjSQJJTwf7IoZZR=5ual=?-)Dg(tEM!^Iuv9ZDT5F1}88TsTvC zq3tnT;>@CR&6VL7<{9g%$5OO*f7i;$caI62Dg7a1QJR8PFh3HegCFa6RnQC$vs}5_ zZHQ@_Uz2gs@vLmq{JZ=)?Hh0@EiCd_Jld{sGM`8}{BI;-#Wg7b*(+QAp}<=q@+j); z@MM1sAJjrsU}utTnV0`W`uGc%e}2D)vy398E^PYGzpprLKKtXXkqS&cgc@3MX?a@n3t*SH#Pt0p0Q=*{6PLmuG!vvhKLBx*sy14IA6O;f&Fqy0afHu|mCva$Y`8w2L_pAw8MLp1!!sm?tZmU8@ zPeVQ_P9VjiMx#zf$S9_|g&R%RxKp45Vno>5xVH(P!)WHKXf8k7L~dOF#+GRmpRC^k z(bY?D2-BF(`d*kA-&Ny$`KkGlvsY5C)StbY{ZdiC!GwPOK#8Z=e+eS1lNDolKgJqM z*ApcYAz4m;cT(XKKIIemxN!}9QBG$+)&8YN8VUa4^^KZ_=p%l`Zx@_IxLXLjAHevL z-6`_Ufy^-n3o$lJvT;T0$-9&J>wxI^=|!TX%$swc-JB*x#W-J}UVSVBeeLIl+FO>7JeK_ZX@}J84TP>=mU^#< z6lw2Kg;F5G&;0gOGkN>P?un=d?$YJT;3MMf9R4HXrg6cZglGEcyC0cPWOj-D$)cR+ zkG5ag=bO4hL>ftmBP=RQSD;YdK1CTDA*_*=CJ$A z@k-Rr-;WdAg;ytkA!DrOACHx|Z6N??>#^V9F8AB{FTWUJ0>F2Z+0Z_~lLGZ`dX2Fr zN9`M;$CM14`@MZ zyUc9%K1$}Lp@9Ai8e*?1dOWHgVO{qKDmqSjY^3O-+<>vtJ+Bco2-?Be?#{J|j|c(+ z-8c{y+k`iR?Cl61JB}z2d=Hkg5sDnoOS+8DSoM19p&wzg8Tyyi?>5<7Tpvy8@UedJ z=0`!I2Lo*&EU(O7&d_za5f(U_q?IEN)g`OKOodO0hmlW+mHrMo6?^W*FG0%OVyNcY ztj&o}tLkPEl%ys-0mVCRYFBnm(YI?%xI()GYQygXXMWx90|Fdz$6zOHDNSe~93lq_ zGbpz}Pcu0^yO=X$xk6T8jB*X+*fj(~ch1Iw%h*elB%u%ZCSZ4cDbkDGr2JG9tFu3H z+k~e9p^#4Sp@|HtL=kTIuMb=W;Bp2O{QIR-PZg7i(4WO-+TnHr0lDw^Dv>fPN^?d- z8o5Gp&!lcDv6LKg>Vy@EdB^ooR#A8D>g(TE+zR)0dFM|1uxdi&t9Bi-I3)H|I6_Rt z7?mhv8b_D(IH;Zzr|inhKS*|?^-G+EN-rC`yU1%jIc90;`oT#73(Y(-z2Fl;bsAy& zX}n4u_8tv#av6C4vMT(B&lT>%Q+A%ruY@i8ZX$E`Nl3^6ik`uRlw&13o-j@ z5_81zU#H!;;qR9y2$sF<0P}rK&tRD%U+o(WZdOzOQ~stra*UNrRUV zcT!&){E8VDZSc5WQPtP#$vx8Warjn1d;v@Y^CI<%R(R)~bFJ8`hJQc44Mu1?n2-&w z6%c%{23@0zv|Y0}nm$zQoC82eZ#>~70KYFe?{M4ollRiwXpdirW){HhOuI9q*ZoT! z+q}-qXuV52^IWSOBk%x^e_zpaxAJb=Le|-sa0QHg&CPRCP`%ahR*Qg|XKg;p;Ux48 zNwu?N{d4wYiQyGLq1u;iH*VhB(%maYQ+6lbyx!|B#sf&Gx*I=VOcxjHT@PsedF)n@ zQ-PGH<=@)z{R!6Zr@nF#flP(m*TIV|XMY_DtcSPzMjXxj5SngtZ0v$>q1d*HXs>m< zqkwhfy-(kz|E_|v7dg=fxbW|1KmOHFmx{gO^KhIHd4K527f&#s^le`KzWvEJ`TnQr zV~3DItnf9d8z#3leLy4$`sB3x;PDV>=SBgHe(*xs&BuoIR7%yef8j%XhB&1clDkP-BKFWJr)R+2{RKJWIt#g zK88KCxPN*sqJ7_U;*NiCaRGPsx#64RHal+l`rFfQTV^nUB!{a~%Ui6jg17eng3f)( zET(nLtaSv>VJY&)10||OBFsC%`r(txHOY)N5x<@qusx@B`7tEN(1l2 z8s9lU%bxG-GHtkf*?1({AWEx#sH`=Z1=P(pxYr7A2?_1icBy#81J{Jq0s$FF1SY8b zy>A>WHqJ|&qMiCQ?_VTe=#viwxR!s299yNYvAl01?gIhan}}5-V#mBq`NZQqYj8EW z32$`N#zLNmIKbVxoY)yOur`qcCQz}qM;}U5h?Oz#JTP<@t3c)>r)Z@ohr*Z3B1Om< zA``g@OunEAeT3diydqVQ1+l4yfKeU6DBunT#0PfOq5vEUsOJOK6sZ9Iu!d1LsgeZUX;EI0w!XN%DSVlag2hO(ZqsGyADXexyiho}}ge zJtZL`F8VVG_dm z8Me?|$|I%L0NJ-2U^HW7o1#bj)xK}ER}Z{%6eN0JWI zC_Pi2NDe?hlMV!^Lo^W+;U;oOqk-^zLaG^Yb02(-;u( zB=w$dn&mzonk#)DA#cwSJ|t~JLbJdQ6ce+zOP)=8(NLW&fDcty%8@LlBDot~E*sQ8nx^LGGV1RG$DV}- zJ7@ji2t>^qD{W$#pK{{a@zJ-%mZ{=0?pVj-5QWJn^VhS36+@IsJhle#gPI{GPTdJa z4OC}#D;ezno$28LAUGkxz9&Hn#iQFCMNq(L*w?yJA~_*aiUhpQFnI2%XWOXH`!mtx zEP4}7Mmb$>1H?Yb22m7^mt(if@smyHl)!hAG~UV&l?(i!b2xKfAkgC*qB$#OHb9;c z5P1wC6B+yGmpXPnQiL~z5OOm9w;_l2MR`HU=Xc~A_PrDF7>m@Q98Cm&PfJNwr*wXj zST-(}S>EqE4_~trHezQxsmW4PvxSSZH@L>KJ8qS`|D+GBI=+~;J4h%p7I+De&p@qv zuDm`|?h)nB(suduW6tWY@}z@eD#X^joO zko>8{SzKIthK%;J&a1v*Css^FTuVkOJ|j$uE07@vV&EL2&=*R^^he;3v!oo|P>~Yi z>`a~62cq#}$0lUPht;zRP9OkKjS(URQ1Ke$-##JzWQqhWfjUKSdkcwkom?Y@!>`$^ z=}aoUoSb*;LDI@4D){W&z&+f5NXdz)J5MrB_T#Agz)uvc`)rU%utt>I?mZS*rq zOZb7!$i`!orYulYz>9(EN+KWyXfpazb z9X5n-ZDCFukxsNTAO|x22<0b8xv0%2{Wz+Lf;3`y>Jh8UNt~9f_xrBYBzs_O8)<`E-{TuxTWb_8u1q2g3$FZI zQ6N6EKVSCE7mK4e;C7G0b;AdWBB?u7( zvXqrx{!|hm;$QxrxNn;fuM-a42yO49#j7bnl_01Q0pcQDY+q@vUg-?ENt%M2uC+Ww z1CLR}98#&`VxfB;0fG?%*_L?4z6=MA5_GlF(I-wxCbL&&CqzD~7wiLTgN)}^4wX9o zdj6%OizMF3^$U3)i)Hzt(r8tDvHW=`w4Os0#-BeuAmqH4Q@4p~7B5Tmusp2KwA1-m zx8Bi-CNxPkD)CxuL4VPVSi>Tw>dv9m_zJ2dDI5SOCyS|r6`;GNMqUCKM2Ik=rUyI& z!_UB-<;{bboy|5;)>y)rxB06(b4=02zb0s2r!bPCiRxB^jH%H{s`-57U|3~dAG+tc z#xu*rISiUzQW46yuG8r^%bO8dpzls2O@*8*{ zAWEYsF&pMp&>bQT?R*{VGr!wabP)M%+K2}Z9u(9ZQdZwy?w;|h3ExPo(TQm|q?@(>s9_&fJCNefmilsmNJfJuG~f`s zdtRc!ZKB<|-Eir&?uv@hO2&!(Qmq%m^`&p!ME5SMUh0WFm$SFlu#na+-grU;-X1;s81t#k(B{OmL%IZmhE_RqzdY+$?;RP zXcURX)vDQ5h2xFTK(oT`)$_e~ci&-)qIv}af%6k5j-n~2{{q(a5F8^MX$jtl>vbJe ztVGoZ2d*y@6uu0vdH1fTWoXNoj~7I}c3$Mc?7(300EeUZPyqFo(_iO@Q8&3UxsOnW z!|V5p?mazlu_(3fA(D!wjc*({Y@-PZDfT>6*f2NbJ74~nw`~Lub`+3CBae>)0M*v@ zV(>g@a|m=zu8ZIzqxSN}OOJ-{{g?3J$bBb_Ec~M3OY`Ut0FDC~eP>$a*R zuj=b)0`4cy{CjcfrF8?w{#^*5L3IrWzKYyCFT8otkgxFXzoN*XApNAAr{*?OfsVJ6 zi$82uG<-3R76}fibNpANH?vuDbgQsD`SF9JSAt&F-rH)3+-gkOYAV`lZrEz+-D>@? z)fQZa{Pb*lcH_I9_^!!xEmukUU5MsD||Z1)#!4>W8K_HGY-*dCtQ zeseJIh@xD>@`JYuJAKGUMcKt82Y22(ZOh-4u9tZ*p7N+KJ9Z*_XR3E+)?w$<%+8m; zJ71BHuT1T*6&^3}qX6PR7#s?KfGWWIfV_k9zY~Dx%GiSc|04|G0;(tg27HByK_YDq z!M=R?6zKzB8nqI=Q=3}=IQD2Ymq~{1@A0A{Iye4lD5*((H2wM`eSE1;M;ck`1bF1xS5%y+||sA zWEJ>>_2W-i9r*%dFAwqAC7w0MK5SX}HUA?w#ta*^gz#MbRS!$99ZwEKKYyMUM0p4o zJk(bvhE3V{)hlgpE$i3*$3C=ah=x*(__zm$ERRLjoP=p$VOZM6)~ML#JC&u)t;0`N z`K~tzM0`}Y_m6o|_pcw8_+{J85`L#?_2cKs2ff?FIq=Y`PkRi74QsZc;Tv0 zh@dTMsUOl()`mP^jM8R`)-&~FwAYteQKBSOWwRHvtRKrmqZ_Qn5E4d~pf1bwYh{0# zBxJtmW`?->Jd`A048}s3xz?_J4`(B62~kYe`Z&Ah7pwgbDfthbkvledhQz61{up1) zd@*~?ulVF1(jOU;eZWL!H$9|}gf}1!6^}9f31*q8bpsBWJuD9vyL~{IJ?VO~o)y3x zQWm>5sm<)ekQ#r`g}*V?3rQNv1odwuvwHeud-wb@X?GO6`38%KUxhs1hCE;0-Cc#m z^S-wc@!Pv^u#oue%~9;`8yF;U6_Ut1hwYBSHs8Q_j|GYg=H9M1q1(yEj3g}8`Blt*oBHyPwb$O2 zUKm`zTyQeWr89i0zVdTR;L7~x!G@}@9TX^^lx-tp`c;(B_aA=0e!DPY4%ob~ZL0Y> zn7Y*NE7>5FIYc*&l{(SP%SP|hjAp}}dQ`?3mj^AJc^c}+#ybnoo9CjO7~uhY(uVu` znF8;XOnGsq3`zmM6LJNH*NaUQXkOkT-WN{roSt*@5(N{ZExH9%lST- zeX65)6TQZ!qU4L&A=o3lLN4AyaXL)+%(dxoG0)=Z2+4ri z=}1C^;PesNy%8Lzn$ zp)RF!g_!~Kb4BzB<@w_L=U($A#ihd6OUvtm(O6^*}27b;uV=NGD& z2$e-fx2X4Gb)S6MV$INzg~eKyh05=`u`}MkUrulgmCZ2b(CYh4|m8gE_yRrX&F9Vg#|9Nyw3bP43%c3l16k7TEt|9+-kt^D^Z^WF>9=Q}~_df5pw%0Fj|xoIQvs7IXHR4V3PzRyuQ<6*}zok!V}tw?jh0hfV+ByFChQCmO<*|DnnH zCUPH=Um1P3@i;ze*xV)rEDv|?Jbov1c$Z%Yo{+XBqnWU_wLP`B*C?OTw-#tZ4fCB2 zF1j5isOr(Nd*vEc_bgo$R%;Z>dMhLH$taD8_(X}u*aO;zjt zrF)Z>_rt>ZWn)nN3gr+(P2(sNDeKLpW12GE()l|3^R>R?9+%6-90>Wo7wKV<1hbRb zjT&qH5iY0uX6fl@(`7r3<8hL>mR_rkqZD7XfbsLFgh+#7al6<0$Gu>Qgc=Xo{VB(d zZjQR8j#(O+{Oh+5=#!S!E>PZi1$&I2mMwyQRKA*)t(p!C=Q4?E_jI!#FVa$&*g}op zp3pV^l~hp1WQmrRdgNyJlYLarQp>YM70DcMn>EzY+C${DZ>Mm+u)$-?B;xV_ zN@>IR#J_7b2lKQAgmgGh@7xqp`%l}F{~PaR05!&rKVycH*6#|HWZRPzhh{F?|HH+> z-C_w|Gsm)XPfVX6qE7pIn(3V#iB#1jnV);@5l?`id|0N7nb*!?gX|+YBtB$T-v**l zAdY|bSxkv3owW&4@I4)(bgZ{{E_#G~v5;a+FG zI8P<$ROC@-Qvvb$v2dST1kpZYAzgR)>4dHlR9x}Vmzyc70LXv1v6D}c8G3r#k9bfR z-7P$?lyvcWqW|Yupb->f8=1ZjLlEOn>aHIp>J zY@Cy&UNE1giiwro40ALbJdY2~&wbTW`Xk~z{KVDVR65*o`lCsnv8t7upv})-(#d6OWfnW4-oH<*CpPAp?aw4_QmJvE-?IjT%!6Y2;L`V+ z)Np8Z2;eq!?aQzoid;4&Y_7#c-<+QIO zD@tm3_i@Io#d!z%N0_o-h~rr&ZS)crZTOwc=Lo?`n#-CO!aqZmqu~W+LLJ;%U343 zH|0Gduk&l9L2S_Op|?fNO5(WMn=bC5!$n6{vLXU)Rhf>STdwAv6m#y8uF`5dA-2JkKoBKBg5+B5&?E`8UwF^Tj`flo(NL?~{m>tzj>^b^a8T)WsqJLp$t^t3h z>FYwG>$B;9S1-Oh;4Uu!Ygoq>3Q?jh5Qk~@&=KSg3+amxjI_Yl6;U1_46a=kToFNv zP^j)lF5wyjMUBDWE8rhQh_!qOKMAuzzoI}@1Z4rG;t+|#D^QMexs%}iWK0<$=t!eG zFM%6C4nEKcz1fW;iG`77Z~=6fbYGZx3Qq4zkiD4y-@Ol(0k=~H7Y{K=}}vqrmF} z7Y@6fnz~0^(F%LOjgpvpciZ%c;DwYEv8#{6b-Z>`grZV~WGx9Eb*g?sUUmgLF(Lx3++`%=RtOvP>j?fTEI!BLnJgey4jnj89_-Kaj z(Gj(Xk`P)?`Q>n`>mDXiCnZkHNn;&npBwIc+jZn<)Np?E{V_Mi5BDNID*oQ<9(zrc zA#<=UO6={7o3Loi?7cJ@d%eX5WmfV@4~M|ELbtnMTHm$@;Kb+{PEm#y z_(*i*cq3W|>g+B*4JiZkV$KTbISR;jr@p#>6gwNkGjilKFMXL1RHrBL6HREMS(H4g zK6gUE>>p0b+5BgOz<1P(s|P~7`ZEOGLg3Vp#U>lo*$|D50ALlT?VMc}7OFQPc&s>V zSJ%eWIqV=cY_0AYeE!-tC(Lewo^j@|y;4r5{J|X{OH};Yg~lAI%^Z$aMDfVI8gwo( z9jA6RS9ubTL1e0I=4y!NY3b!@pUXQEl&6!Pr`MckFqvn#nMV@OH_^*CJC|<}ly8}y zZ{3`4JDGoSGoLJ8V6Ru;aIWA?P=RxL!MWxFm&t;Qn+2}oh35dT~s1aU6HD zIDWI3CSH=LSCV|LR($NY1pg+Zmo>7}L3rR9^Qm7Apu z@v<7dvbu9+^+9Eg>1EB$Wv!EC?VDvx@$xRc^6qoxJwfGt>E#2>fvhY<)6(;j(F9wUe)Tk zs`a3%jr6L`=Bn+BWh#5Os%7+RWY5>gKd4d6s8MdIQJtz$->T7&sMXT1)jnT)g!`aYC!Vru1hGa;xSfJ^?v#d{^uJ49yA1IGz7IYJe+EHywyOF zXq<ltUN)$V7nB3wRy4?G31XoJ z9>s?8pz$&wM2Z(&X0(fjz{Bu@1Yb~`*~+PIvdyW!Jynn7;P^;{JdNfJ2_du#p?->K z><2{RJ1qqOAMYmTDL9wh2zAF`RXdISa9>rrNXu<m4eADgY8!&$!-&aZZnr|i-+Bo<@ikvJcrhOa=W|KA63ZNlQGr4!eH|G z;00Qn{%T|UD;@FEau8KZi$4y*V+wr>$%t3 zi|Xvz4@m-jJ^{9L{9_bPeNXI?eUVtZ2@RHttY@>AT+aglaASR9mG)w z+Em4bTVBnixA3t$g#Z+R(LCDHe9;zJcpmrHwb@kzMQn$+)b=y?brmAV5qU9z4ktt7wQ_ zEIN*>0rHV>+H}y0gxkyWY*_;rU2siUG!6eI{vq#rO-)z~T?4ntdaZCwB3u$!o&^6c zfFV4WhK}CLf(ro%G_zBV0=>mS=r9pT7F>=7F#_P?WQY(8X7_n-cKIkAL@VM!Z2;;> z0ce~t6dkgcgHz&x^ccWiI^-6MM@&N5vw<($2m)oC%LYPdfDUKEFbk3N1RBD@Me@BC zTtdXO;BNW0r_<5**w7PfP{S5SW<$qF5HcOjTf#=PHpXYTG_5Nnp)O~rn+xEsQy`8c zs1+UpV+{VKz`sqw*Wv&nIz*NRq_8JfDX6_Xw3!Bi%q91gR)F^?sB{31WMP!?n8~s) zxyJ;4W&l{;98@}5oCdi?0b@xJA`?Pp00J8LPq9z|($v}x!j-e6+92kag+g9E5iP$pyq z=!&qQ18^3IBlPaJ;#}$N8XBM?Ym$dTmc&ANvJD?&(jXqS2S6)xzD06Ci^tz_RJbAG zi#-RFqo9m-L6pJ761N;AvRkA{$c6`??Vhd`;3o`hf!*#1xLw_O?9+8R&ryWvlM&i9 zP?d=>p#ueYs0Dd~&Vr$60GbU=X8?f|z@H9@(m)t$Okhb!oB=+EjVxuL>UVHx#>~Sn zcqcsKIjK6(w^i8}j%ELPe*?AFGJAX%%p=SaKmSOI$0O;`W_>)G{p+sg8;S;oL&v;0 z2{9tUuhL*qg#Wb37@Z2VDgz!#0Vr(Hh>5iF1+VRyY1%VtdlD(dD?Bp4r?UYL9deIH z>E}R0vljP&&>RBXiLkK$;RKn0jwZLqoP=;GKME-jq%UYihM*|`Dju)wItSwtJMI#H z&R1d-c@6;yhtYuGUwqcauBzfeB_8*Z4dfCg_-GJ&VD5%*JF)|)9{wI)j=A^ceVv-X zP4ypK0vtWkZSb&K#~1F5?>HC_4drjWN1r9e|4^-f&hf+LShK%l@iFJ|+FwP5A0Vv& zlw}3x1OvXG1dU?DwSAE%>A*fZfWZR=Oo#~`t-Z*JqeGAG)bI5LKJ(9^*|UCMzH@mb zw*OeZ3xL3M^%k>{%lrbT4sz+e>WhFOYk7?`&%?33{PU4Q>h_`*7a> z=gUGa4Wmf-3lwO;bamhFzpqXp6&X+-oOzXw)?~v@a!KKilXB;_tLA_)k>9K6_Spf7$su{XvXA$rmoW~uc9 zOntDmO3h7@Khb9Qmt-6wjB^mz^Y_MM+3F5&-EwFPD#YRnxN2KpT0hohnZ$YdI*bmQYQ8%(`}%HI zAPw*HQHUa?LiEbARq*&0`lXHjZRF#JN74pWrK?MD#~13dwflV}Gt+PWNMF$T;+oJe_ve-S zRJUo$W_5bXM9wIwGfbeBt^gcNq!ZDewghI9HhbicK8I}wH+b~TuHacT|diy8VxhxeC3zc~iFMMwl}xJ4cK6UBc7m@D9m zdjP^NlQ4Qw-(r;hi2a})-*ff{?W(dH@q~5q#+B5|&+mJtdy8s7Gw;0lN6d_!Jv)>6 zXm{V$H`d18Co_`H1YIx82-uv96s85ub4&P3Hwp0FoFMPYl3%t-q#V%)J~e|!wtPIG zBLo_N$C&-DhteM0Y+k5u`5nQrcyOzIYklh$(`iknCp=N?lTH^d=Jrx2|D{j9ub?Rp z{RUJTw*6GEvmV}gqu;xIhh@6=k^iV;ZceiOAD#Vo-=96Wb9dr$%A)2(T zq)5@UAxYDQghnY#lZG^Q#uCz`!5D*KerMn7y6aX1``Kj)Z} z*X#Xxzi+Qx(>K3;#(&_7ZCK#o4gdMT;ky}OK_d@K=7R*!TEc=yUro&i_ax%NL&iTC zhx-KW-W(1SUH@AimT3XuVKd)LZuK6#SsETbKRX4#0|gVCn;U7nf(s>TZegSr##pkQ5X%VpE&UdLZ-B+3o%_QK_nee>lvrHHp#OcH zi29`yR{{%wax?-NSG*71J1Y$i3yG_j-lL;ydS>+vNh7bJQ+fR^F0SjdCs)OMaeh7# zcMjk46urT4lW&LgNWM_@(%{-F;;ZEoSa(sSoU! zDIXI$wK%-v@)zl&#+kVI*oQ)?fTMq8^MVmBg;Fks?#!amnD>vj91dk&IE-HJUsYCF zz9+M7h0bc<j0R zZ!HQ zI2`PynY6TYpC=RY8MD0hPU+|0V87@0QtZVV7#tkH#0#1}H~%tSv6A-ocGz*j8gsl! zQ-LAq8ypxHPq%k>Vp9Y>9;dsnbACqJIn3V|Y33#2OS*}~1Tw$7*4tgvMVBoem$cRj zy#|=iY2@W*@ST*0Ad9`PpjO1^Qwz=dYO8be2V6E$sc8&zBR87?_8oI}_c+;!s>#qK z*9(}2PDvsWmp{x&bED=nZl>)dzmIq8Gp7p@h=MGtq0?|ymV>S?JCo04HF4F<-1uT{ z6R*~3fJ}88uFe`TS0Ep@yQii?trv0e3~ndCIj57{#C^Wpa)S%pQF^DEkiyInF{Pqm z?E$((Ak0h{pgzx>8J7qIOi?X6g*gz*=Vvx>#red;e(|J~OqPgiLp7ThNt$ZYrP5&@ zhYM@KrX~(739)HX?=pc{4F9uwW=1+bE`=qbcd-Cgh%;g-78ZsH@CW?=BG{9|BGIo* z087Q08IfPHpu2lOEdG;bgnwA{C!Hu$ClQ5J+oEL3{}r9MbnkL?36;40=0DVld#^8# z{S@t)>)uuW;$h2U>fh+Z;zu1NwEp_+Jtbc6aO(uWbmI9ow5iMTu|2E?%XEXc= z(#rUM)rsp9;rp#bi}Ea3C;m_s#+Tna^w8;J*^BQjuuja``>Oay2dopjKfWsY*~5;K z*V$KII@Vu%WzC6(@|S|=q7!3R z5B}1LgV)`1AN-w89Lf$Dd@z&)>%^g3bgbSmtP|abZ^!Ev{L+ad!*>}w^}gNvr4#RG zy8Hv3m|HLc>%@_fhlA^6i0_5Z3%&pJ0Zqs-D zeecZwUMG4U0FDWNln%_FMgd>{MJLkqs8!KLKY8bVR!E!@ED3t~jGwPB7ts-Hw5o@& z3cs>Y_(s84Abd-((jTi{Wa}~ZPR+G&?7gPHV6281r$1i1JOkE=tMUqAome6m|8PqV zIl(znZ!__cG8jM6V53|$@kv_+DdL)sZWlEgYb1-BNX2Z?=j^N{yhVd5D<{J>IrtY3 zHaESRY@x<=<)ID`BaS{-GBsc>@QR<)#_48iDXVNR_4E(FsL7n@3h9>x`u5OWU1PZs zf6<9n)BgR83D=2jE@olMY3Wu)n=h`>Bvo%)QOHdr?mq8j>h1o@=Y?us3D|?sEj8S7 zA^4NmY(U{k=U86J)O2&*~`G-^XfKK9-JijDJcexK?ZDM9sG6=O$ZSAJ2(9 zpKY!g=!*Mkw}hW~KFmEbJ$!y9OR-^oR#>xECKa`um(59r9?RyXQ$Jy$t-u6u)^I_) zkdC*3{}`=>TZV-Zgd`?r(MMmGxI1iW56za!xE^1Ji;c{`;~o+M8$bo|B-cul17 zFZytLmI!NKnbn`iyRh$~28XRA*Lw*uHusjQ*46Gb9ly*-y0?7guDacJ<7t_kd%DJT zb^C(GuP_zvud>=ze=uu2J>TZOo^4(I(X#QYtfc$;uGd%e_R>~txwoResg-d3>-aLa z<})7xUJ@S6DKB>+pa-L`8(A7zx}#>TboL+I;*uo*R$9lujwI|oXEBPtIhOk^M0el2 zMy~P-yz^#t)kmMS&TrGC4Vu2Nq?gS_t$*+eQXbzd`(!Zv;l%6(w#LlM`gM_eEh3n3b&{AjfR*Nzqjy|>W9|%rs5}zEBTR!>zmay^rSdpq6K6Xpy z*%5wC)XGj+`DVURYhcA1b9%vG$y*}$B;LxVPx*$Vdey!s3AUU*l~&Gm@*-&b17$L-v3{{=H5TDbXh$H`}ASfy{_ zWP}`(*KkXAV8rUNHSi$iMd2&|-s2rJywZjjMK2t_JKDN@9B0&IwK!aHnhi3#3yO(p zj)K$nHLVTBmtyW3XqnsGSen4}qcx9#zWHz4l_QF`<*Xa^zB1c6*o`Y|@f`KLW#2WL zV*F~z;C#U6+0J(D1k=GMso|ETOT|Q#b}ct0q9lrsw31XQ773$uLV6Wl1FDwo8;jeb z*{l4z^xYD#3sLOG-Ct~Ws#0(rx20{P?Iw<| z*Tw4-HwU+5Y~}_#P266)Wyr!-jH6QMmwTLhqFdSc@<(9Yv153727UAU1JK3h)0$Jj ztCkvV@l*eb@6`RXCZ(0)7vb4IJY_*`pTkn0_=k?3DS5S7XefS`x)ol34^kx)5Sk_x zx+6@~s-4V8^?)0Y!V{tS1|mdCiqgvPpKV_!6MuNEHQ|8Ux}_4F`Q%@zorw$G+~+j& z@om>c(f-iEwk5&sC!ECDI=E%<3V@qV<%-#T=>Em8p|HbSm#FLuSvc@yvUy9mxcKqh z4_9bzxW{Rx;c>;}*~g(Hr+a3-R4ZhofsYA2GVK+YWN(FwQ^EcT)Hp+Cr8CeN!-+Z} z?U98EemoBUc1Si4WQG@(_XfjdA?4ZJu(_tS>$&HTxQ5INp&#rJL_h>GGeWI2 zLL)vjKQHi#3%DQxS|CxDkRZ4dPB7(JGldH!;b&VSG)vkjIIJBD zu;XIvO@f}PhH-~N=U0Y)WrI|krseyN`=mH8z6~^8@2FY>J zaEI>|NuZZMG)4lc^q`KK&?i$74Yu?pWSkEvZjy^JHohnmdQXvE&g;Uz6^2ZZAtVV! zV*q+=lo`m2`0>-OV9zm(l#Rj=0I7_HR-&ailJLJx z`{tP>Rl!?PuAqw>&SEtrmOu-Mh_58~5AS{DDS!zXK_r2W!|oPw-A_z(MaK>!0<5^piT|gz(*eD zq82;>=uF@=195f%QeKGGU<1wsqy`10M8BrQ#5&TEVmjb@7BYwf5ERTp79dZC8w8Pf z!ewUy_AJ~p$iOMX)58pe27t0ty(G(E^b@YF@N*9nqO64YRNBeIM073|g8q2pItgrKKnf(du;H)nw$)IQIYsY7qg*^K;+B@D3pW zc(}LyB^1I0DGY=T0bxeZ+DJs6WrS!jG4MvT!fv=S9j;*Uq)-470kY3aG$~D_S>sM^ zKDB`btRiA8h*)z5K_7l=R6^*J)l;e7G!k@@jao}UneuO?G6~_E@pshdQFOqJjR=_8J3@?3_Jx93=szKtZ1+BbB-6XRA^6 z!n=BQ01VgVevGSuq$9WDdh+?K*qi)V_h!NRsWes2q9o&+>(7L=fbD6XN>VA0$@T1h}0V= zm|5BYCVv6aj*AMR6~O&IhD@dz8LLA^gfI}3+=2ihLY{ETf{Ct>OR)~Zss&>e$e8z8 zC=KE*6Z#Vw6)i`?ds>H{XiMznp46ehFHbQ48$x~-+Q{``$$B&3)(dG}_Ovh!5g#~4 zd4?b&<(Zd58TS^+-}8V+sEMqCtot%LphE&iNI*a3VM*4*SM3kC0W1^^qB4-H8Ms60 zz-c->goC=hs(6qe;Z=J3OV-H%X0C-05ddIfZP5!3+<7z>)`j)_sga4V^HpXdOqdVx zWJD|uVMxTp)?k*io%0b zv=$3^X$Nc|A(jiFrSu!F03tQu=~LIdfU=Vcrnd?8K4$@pHoa(RhDL}GKh{E+B|V7z z5DQnNqX3M`CeMBV?=23KQXU%;ZWYMt3n)U?lPttI5!1B#B+Qj{=)kbB(2$5e%eXnh zKt$p0hmetzLTqgYL4oKYsfleKIf)`;Hxdz3M8rlWB9ui41sE@SGuD>gMV6*2(*YFy z+GBMnkcm0LM4*@mTgtutY(R;hu!@VjF@u&dfk1A-2RpX22?CO$ey<0XBmwdO^n3fY zRn!|K;LWQANT-@toAKBDM@~i&pgGc6hm6Y#>n;~p#g7yGv|2GwCEg!+7)LtZp%4y2 z;HKEA4mIz*TySSvuS5Y5IE&Ds;vDHI>y1Gt<8+^6;2Z!=5v~pj)6LtiPTM9_eM{6T zPFZVwcAF$>N=AcZjM@?-kEy)1Kgz*$0?PB z)Cq!ayM`W&54^JJteYCUWEDM$i#a)centF3!^pSifYc*SJZMJl5-Wl4w-LcL>%b)xabY|jW*|&`y8{wPW z1xt|GVn~AqDu#e!))#wE$f*l=Qj0f4;W>Ens6W2Ae&o5$eQ~Pbol|Ua)@t#q_!3HO zp?N}q*}Ned4{oqZfxB;rjf2KtOfH}jDq0iwszg(>L%(^(XD=F{v|XKp`pDq*F8p=J zwrtNf=3HBjXWJdc_T13+{LuFMp>1FzKANVGIs?rEURSghCDJ-XWc&=HV@3#-Rp3P| z{0tdiRnhV0V~2><@jAP+%(3&s*3MUoU7SaqO8%jj zkS|H*OGA4QmHY*xe8n8T*s}*{Kw(FFFgf0$>_xNOUJ4)nO`}(99&CRJ>1g*6!9IAZ zO+x6?O6eP>_RSOfboTYHABBvx`!|O58+rAw?C#xc*r%TY8qfDGRU-WP0_2~Zhy0o6 z$^%uuc&=Mse|%z6-?Wt3Hme!Zf(;x)?qnt~pRdx=blR=Snvm)}mENrryFQ;tDW6{N zTJ(GJr?viXn^_iT+&nkgg&YkkG^gFHoswpi4ZQ1-DxQ3vLeo&po<%F{HZU~Oi)wCt zh^~#t&o$z*vT`hP#71dj@%2)A&8(e;LTPDfO-;?Y1Qret<}mNQ;7K+ZY_dxzX=(lP zTg-sMjCXrpQoiR*E*lq^d2voI#?n-cuxf1cPyaX39J;$`+RI_`}yEe#leGze@=)s zBb)Ma9~2)%kHTcu>1JAft&2rjQP^M=3UDMlV4S@O&Vkbh59zQ$AtXyGX)o;=rh}p|Np( zW_olKMw5c3rsk1RQBav+kuqnHn_2vvlMryM{XNHzKo$*iEE9x-du25Mg?ce&}|luoXQ+e&pFc*-XW^vT|ZW=?(Vd)-`% z^qVT5F*|a*j9i z?jw&d3)PfEKzDL=H@AI|^OVPIFeOtDGIy^cA1zED9S{|nQrpGcW-foZDZzqFN*NHA zf@ED4%5yOnX3!)bVQ$KRNWwL<8zwWWIr{9rrq-uo=4dN{%dH+A6~JWn*Kx-T{8`l0 z(EJP9&i^8_Bk;E(r7+cn=`DN}0^?d_tQ4E@>mCFd34i?y+IkoL8Q{WTcXUM1)W8`T z5x{sC=IPi3k@r)91k@h3B5@=Dd71^yy#E zL-PL{c&=>cl0VKvF3W2FI1hPz3HakYgn0(3{m;)s@S1octN||lh3AsquR4AF1Tp$; z(%+ni48T11kMofKX`ah^FVlm0?q8pWJWO0dTvYwITII$8{86=kIS=W3LgG@n|NeQ1 z@co*f@Oj8Do(rFcR7%D0c?f{h7yd_h?y+n5@!BQ2)<$^?eC+z`^j)n_e2|wL`*ecT z;xX~jWT^02ATq0b;u9HXAmUo8dWssYzu#nj+GT9u6uDuGfp5Ulc(chb-9L!yc@F+R ze(_ubajP?Y9@6HP_ek9CQS#$&&qEZ~d=8qDJyP!p!#Sz*BUM55-q?TpJY;lwh#6-% zGkh<@Yvx;iUeU}*Vae#scUFzztYFe$@9Yolwv^dXjZ1WspX_aiYkpSMgk7_Ew^GJk zFB34O6N=ftn~7fekAD(1|G{(pf6h(ut8;Xgsi&;K@_n{->j)%vYQ zyD-*-a~t%peXBhq{7>>+g}Z7s*6)q7#**A@?rOBuzTZ?fmP|{!t2ty{W7hKG?O7Un}L@H}tRj;50M-$9YKHF3u^9iOgD? zT%(LSj*IEUb#7AbhP+)L-R&l_S~>7^X5B}xpotrNg*=m*T@Bt@6E}x#@=ROm8vM#8 zvV}=`W<$F^1+`D)NH}@sQ+2XWVKWoA0L6SVZZ|hlL&U`I&9_jk=f;|fZWEI8Em!Vt zOt2H(QTv#`)40AdB}jCasQAFzYIjrGe}v~2_STru_3l_IT>T&Bx!+qaB%RjkJr;NN z?Yb12z9n=oX0Q8OC2*aLwdqAafU}qprtYXN-uR#^O2LZ|p-GP_mL0=cI}1}UNQ;g5 z0B-RHYJ^cIQFB}pXExJ&S%Zi`{^b6+xUwIv8V9iID z*2Qm^^EwcvfhJ=%)}9X^>&4w&>a1;*9luqyE?!#sj<8PcUFeplG3OPQ0qfkX03-vs z6W%KAAq&kUV~~=qrKVU?qjI!7CXpq1wnynS7&0WCn=fMFr8%kEdIChOo-){K?vtZ$nXYuK-G>4Z9aTbZrQ4xOOfozP1Qh^g~5eLEhA@y0$XX`+J`7b#Qwgv ztZ_cThvC=eMY+>!M~ zzzC4O)f!zz$Lg|UK)3Dc>!{UB05gxB_lR;bQo$wMM*>=&j!?3W+cMCb5^(QrduwHJ z@gsxOfa<#)-D1BNk74q8&R%(E4T;v7(5qNw}Y=#vg)Y;3*df6r>hB;%j^1J=L$)oR67k8y5 zb`Ge^h63u=J9#HR?CjUl*<5>iew^|6=D?=7IPDxpv^+kjXUfsQy{0h^iNA~a%G|kV zJ_-6g1f?^RX|Ytz3yPP&&K&_POr?7}ctKj4C!j5!HQg5;_wWR#tY+I>JKAqQn=3BZ z=-Ih9*p63pZPd$n*0h=$_3(4qORB7A@|HHIy>!-jkJt~6dUFAcEZrK;#-TL#i@!Zn) zx1*G-96si2m7P691=cnLRbpECxKb|;+;Vd~UA4v-eHpwGTq%AIZ5^rUwrg#v{Bcev zRMv7j+@AY7Ox$0xwRO_G<93vz*bj$u_vL~Yr1L+WGpZKyxKTSeJG2fk<&)#^dIan` zHdMbea78S^;y#o)bpEbt(BR6jmX@HdDc_g2!Go$H1yiBwabb&FBRq|RoLud``};kL zvlqF7Q~oE~GVEkjdkrq)G8=jui;pLG93UYOT)Y?;dUPc?17N=i18Gx!s%{ZOR$rIu>D3;#crB)MI7D%NHP@iHhTb5wYRVRYM|Ov3t3QBYd3L6*{GcN3=RfKJ;ohunI5`uFwdd#S5@Uncn zJ64x`<3gX5fTncpHi`ejD$tb{OJU#-v0e4JD7a{U!=|_$N1c7upfmo_UNv?>Lfkk5 zwVZ((;F;1Vl)BNlo$8EFLgcf=)s zj=xm+F6IV4ws%zu{ESZ&qW6+edugcsOoRpn5Xwvf$5(+8Y8*Q=8qR`-a4{Fjr__Z| z9}TgG#0VDRc-Y{s*mEPr;J6SsB8HVISZv~1D#mRf0xGLfhc}<^<%2NQL-GMM2|Ptj z>@E&;^!NW-5?F8_C1xe)FHp*R2ZqqF@PeKz8ShE~j7UHjF|JUOFrXR~v=ZKtNmU0> zN&o^yLu{gAL)b~CG~}MM*yUV+xeK?Cgxx?z>XKnl38zBA4FKAd59tt~UBI;!WI%@t zm{O4d75kkFY@}h-xxgthuz`j&<)aDI3vX=wHHUr2`N?|MGnACV3MZjpZfg7k`m&>O zqd*evdJvxv5@ZyVjEF}ahm*i47z1iDfn|P}o$xjkA3)MDwrnVjj6Fm;g#>^QevbcY zFpP=9kWq)ImzDTPTRJt2k2d1^ONrnn06ek!oQ#Ym@WJ`mn9i2KRdtsPR%O$t0v~-L zjK>Eg1V)^z2^=G%Y?K13^a+xMDx)y24W2jpp>CW0LE4b!3)Q7G|T}C!fG=BxA2bE+$_pS@>9=V zs-e`kB7nF0!VXNdl4-PmKx#)#&=>&Nl5i_%Slv?4Y5LA`3g9Y)Y-J2g0PVh#kZB75 zHhcgj2g$J^G6hg#1D}eKxGWf$;|(czkemZjbI(o#F~YlQRGfkkiVVWq1Vl4!Gu-GI z7j`QZt+*h+E-vBt!#A1sd?Iw>EE*sKK}3{`@E2XPv_oQ8xJ^V56y_UJF36EE00qz` zK|TPuiH{3lKTs2TY$ahfaWR|dgdIXSrHfW1;M7?Kk;Gr=YB}JsIRix>_7zTrt_sXJ zS^99%ZCvXvH-hacrS>bV;m|m||F{t0Ec9sH2?Q|iZsp=tsSEbguyRcBIRCCX0TIl4 z976#>HsnKpz^i}o#2vW?c)XcZv{EJn``HLhB36g;7-SdV5s0_>&xG9QdwHQ=K^aTj zS&A33p(m{E@3V{IBAGZ4O~lJ;fen0MCk?TZb{CI;Ux8?K?p-A1De=Q2y$_Hn0QI}0 z1Lz3hb@cj&fDsWtEe9x)(B^PVKd5+v5U~jkNdvf*B=lKgcuYXNo?Qm|RhrE!!oG8N zrb@C!YKgSK(7Z{UF74LRow!pJ;71)K2}JB7AVkNXt_;SASjDC+u)iI@<10>=0sth8 zDg~(oD=Iy(kBRz8e}d%WvoiAy-)fE_NHS4?U;ls;|m9E$;6$QN1)9_>Apep;U z8@o{DZ8%q%5b+a(Ud}DNbsg=(#O(&K%W2rmqR}lBEl(1DnH4Hc7qI{ zyFY+)uh9FL=ujexz(?!SZ`N;)R9eGwti6O;TmeO}RG(yTeVG@P88kGMI8OKKYJ-Bv z_+V~&IPJ|#95_eA{-mD^X5v0?0_Dg>7z!{d1cQa3jy|@Z?D@gIu%C$&5TJq;*w49M zP4UsgEuks$6^jIf&wHFF2!$PL5&V+C6*%ZSKXIwQgMjklK}=8(!7&*3c$W~DG90g( z0WT1F&#^&UNtoPb|Gam(L78@0nGY9As}+>qEj;0Htd7E=VJMjr+T=QxUng z_WigpXDfRl)joGBEF|CWWQg5(M!Z)^ZbIkHi*w8I4aPNMIg#0E>3s9StTi&tRRH_)N=U9;qEbL%_E zpmC8_j)s=whdqs|290WpO{!XrOIxxVt>2GxZzRz{F|7e#p@i234-u#eGKv#?b3&zm zHqHKQR`J=q>oa-ovxQc(<<@57&}Qo&XezULR|RBK0gYl#OtG7?B~A5a@5FQv;ezj` z4)W(8I3whjZ-($?XM>9YvlUcSAeM3_6M)!J-y3!-Uv#9aUPLY=h3K zkL|f#9X+fTYQ9HKw$f6S+i@g}nAX)2if>EqYWIY~E>oc{#qREkuAWC-J&N5!THSpW zU7cOsqjOy&T#)|={5IFMY7jS)+|~Nym7!KwQ#S2T68+v5zQsoVB|hzwRaqYcuLQR% zkMiZb!a-a9Li1Bf?!EVB`IsX9Ax(JYm@nVWCwBAkhWxOh9$Dxey~;lQ?mj~=-&GAt zYt8#NIQ1K7_kZ)~H?8d7=%tMKQ;E;N-|({%fJe~LNMziF^Ul=J?6kL&EwfSwYn7Gp zJeSnc(vlMFR=+gg1#5%fZ@D{ZXt-|i$;^|5-wIe|s*xSVQ&L{ISvqcX(5-k-nrnzo`uHnp?RTh85DpE32mb-YF>-Fsh* zh9`{&q{+$A$$8aDFQp2 z?mOtP*Y^&$$ofqJ`dGR2MazWW+nHNAcR;^#f#BPrTfF;Urgxr7(n#nK%}G5=gc|2w z;^ooiF&|F8mUdU_=jY#Bd3iEC>*d{=?=}2smu6|iyBYoTzOi>`bnq8ckf=Z+U3BnX zR=ZSNo2ZZ^j*N|t%6+e4uc7Ftj5F$z7F<{ zPfWJ+IP)_iIJ_HFJmCF8jE$aBNE3Kh!oXGpBg#I3Ks+vj>F!`(Ck&1K%0%r=oaUzI za7y*&O_IJYM>xtfVr06o%!9*`x=A7q&}q8W z6xPlB0>M2o(-JlIVojWYy@rpi5e6K{?4(*s3Pa4L!gv2&$CAg!Wfg5Bxbn%HvgI;bI>+ zeOoDlv&(R%8BXZJbXPns=<6F0j}P#gs$r-LCwJjIE=+@ANDj9E1y%kzlB+IVT+8IM z{|gO26V4ftCW^d&*zoghcN8W2&ka9+i*Wz7;iuT(z2RvZ=+O7q4L=Xf@cMOi!22G! z;pfi?*Iqp-;!h1f>;HEk-2ZpO555C~#{bdqgHK=h+p0e`{G?%2tp8~E$t1*R{B6U} z-yq!nUyI%@xnLj^*F+}hNcQ* z)vI^g{DVktr&645UU|=Nw)t=*_iF+h#o6#Dgv(K{|JCsG7ld12rt|2zx7?anqR+L* z`5T%KLoMUm794&w`5!~L|G9>rzeBh=i(_^@`~%^F!I-np4QIb%oM^!#S2mWu`gYu2 zx@EWuIxqbvk=(x^+^M>m=C8PhvW4HEhBD!giMg=C2w?iwAd{QeM)he)l0>!OSYY+I`Nz>SfpK z_iuW7?QY0dL)+tT_--iG_f^T-%ha?s1LMZ6!Tl;$rLs4Mu}^P&)f~dNs5hL?d6qp9 z;<~l}dIQ|>!%Wm1T5^7xd*tZjpozv<bMX8#=EaZa9KUO{*mN7Q4tTm9 zm{o7A&V3s7L21x-l3#$rO0e z?X77$i*8i-R%`Cq4s$jF{C$7x=V|=Qpx3=I7D@Jv8nRDT2op-oLJEKJBWz9dE;d4) zLPhACAVRJRx_vrlt2{<=n0<_h9hwM@gHOQE&>V0{Np^)l^(~T1jM~Va15cX21?IQMm{QbwdQGZ; z=j4csHhcy1wN{Hq+2V608U1ZuJIpyibhsrQ9ptvI<9>H{^;BDXc*EG@T2jixyyc6J z#|hcn6u`A~Kx<*9MFft3!_cUJ_A0t+I|HN@F4O!jL}FTL7yNzh5;R+_eoHR^`aY$bq!CASHLV*nwI95E7w z(otPoqtVV!@m;h{Q_IyoZjIgmVc9k|1qv=&%s` z4M1p1uuJd=8UeM7igDtjjGI1p^8}b27r8<$Fvw z=$=1)WfiT!*0YC4hcXdCbm&_PmP|reGeHy`k7eKj@`6^HW-iWyfmlcalo&{uiCM0~ zEM%at6ksm_;X?on=;+mC1d?*xKo!~VhFqEn`tvbsrl3|ei1LqpmT z5OzZ7#4coiCZdakbD>~H7)S~m+e7lQqNOVnkQ4$Ukc@U=qqhN9XIZH|d00CVu%4T~ z0=W8Q2%$?smuv>M(K5@X85;S(8RoCXiQk1c2xR=?)k(MV&fKX{47i@5Qx*G)=j1{| zt|kH)2F8SXxm68UnvtkY2l=ugz~mBmgb)%#!SIJMKc*C?NmLXAm9GZBcn~IR^zk|b zmKA#FCAP69U9uTCLI9NM=!F!t%5|KE2@=V@v41r{V5T47GPT)g7c%a(HPVT4cHbu4 zUDY)10_6oJw5&~maH22f8=y(fbYKE|$x(2Gxpy^SNyuTZ0^ro+LR)+XHT5SIv*S3p zQ~j12A9KVNsX<^!Bv%hz2Z_R~8q{PZ8WNs^NW){anQcox*`C&{;_FwOvWp%!LOnEvN4PVPtd#(j1dRakuS)?RI$E8AS5{4k zt;e>@{Lr135HW;=Swj8=7}c_GX%g_O3E&bE#=jswj*TrgMl`u%e`nlY+jd_@1lYT7 z*-SgO97CQ^PfC1$#@8>yOYhEuma}|69C9#%mc#OA zpzRvCh#wKh0zAkkV_ASXAE1zMRs`fO2I2@AU1o*+6m)T3i1epC>bEOW@VmH|57-1C zQ>honTF@(D`pQMilR}Ib=;bVcCt%?!@a48?XDGKkAX40SyfWzj+bt z1mKia!5!1~di$9#k(bVMq3v-tpQU=e_gW$MGE?_-!cpfBSRbb?XGb3ddSCO&=m@-`;yu*j z)V1mC#STxzCfr2|UXhPnLqf^{xP^;7EQ@n>5=u4KdB$IJ)!@b6Dk%+laMp0ssf~kF z4V)_>*XL2O&v|j_$8#?Oa-BE2obK9m@qs%1Cd=-8Y%$Avah zfrUh@79CLJ0(c5a%NikH=)|X?qo~MmVioDag}v(_!*`02G&v;S+n*M?PyZ?9W{J6f z=s{`qVf}ZiH$DZXMj;7L*fySR%!T{?J4f`b9I<0Y&cjPMgXYm=mSH=vFot-b6}mlRTWRln|f zd0m!GU3OtDv#>Tvv;K}veQrqoZL|6~D)^IIzXWaw;UZS>aclUvTLkn75dl|EA!sr4 zK>ZORN|}V7Av#^EI<0>--kO9CqvC{Y=oAsxq>qylKYr2t_{HI4vp%lXnEc4CrI0glIh?Vmk}Hoq!J);uez7)-3!&KJEk! zF3V{Uk~ra{2a6&&U$+qa%b*z|eg_vnKn7Jp8#O{3)hik`e>7@$HR@C}E=_J+vbTxo z*`!*5Tk6?pkleKRW77Z&7bYX2#Wxjan8?K}=#Iqpr4+M)i%(|bgUR5=AJ`dw;%`eD z3G2}N=9>3a5DsK73MU?FBfBJ$ArTR8pZx`nv)d{194hdqKYls07jjPK*;nw+hVmQ~ zc_%7(7e0Qm^W@n%wghCiobzl64s8k9+v1b`#Tx+j)4>TMVwi~7K*T2QMZGLXcoXqn zMEvO=H)r{_i*DOGldr*h$X;Y2Jvh!(Y!^bin2Jxfc0ApR ze;(RVY|v4**S@5p<5hOY6UENgTRX}ujZ*5x1k5|CsBsUemh{cF^y$y{8SZl+f&FS*`VG7LHkv!EG3+;K=-WKsza^}H z^E@=l#xA0u;NBU!HL4}MtIZR=k&k(ep?k2gHd}zNbE+OBf-WN->LQqS#5-|;T}APe z-$3Q#l72AZv z3r-#i6hfDX4!um3-HzWtgo9rgfzOWzQ;@3w)TSilMlKGp{$6u`gnUX> z&Xd4f?k`4(N^?V)P&#HK9dnHJqq_+A{x^rpnqgPW%EQKMFhfqH zpoLF_TDMeQzW|9k6GpFL6ZQ>t`6D%sg$py_?dhkVW{OjlN*@cae3D%4nfk*WW;LPC|8!MylF+_HacP|M|5(#gV-Fu znLXE)N{_jTGN2=}=Aq6nirOiV=){~jHGJwdd>1I2hX`G7eC^}TYi*CfFI2HSCghXj zyA=HHnlNtfxTL7MPho0*-|KLV>VfUb_<_G^_-VLz{PW=6o11+{2iiUl?PqR}0aw^H z4#E_I_U3Pg@(m&J z+qOvgRVXyng%vzN$ZwR<%8IpVo*hjb>zbu_*A-Co^*A&yZAlfX{RC;#@VRD*M zP1vrvu6p5K5$&Dw5s%B3p@Z8mzayM+zEHhzY8S0aK3FtnMT}bHZM`&cLz*6g`T2s` zSoLC?Y~35t-a4xuh8*0z@=5f;-D@6tr0q6%ce?4r>Mvu;HhK>fsySMB`^T(J`qMA& zGyVR2VxL(=q}P7)SsS(jzaV?(e1dd!?s5lER+-P|ck2j!fU@ zosM*3X&X5xFs9yA4#Y;&H9|N?ncV!c>gt-BvZi5!$WN-V1AU_sQ$4isJvxEaYJr{ma!DP)SE zy}i@D5^i<*6=JWiuN@p2gbh)9dvo6)9}fQ`v!w0?1NHCAv&4Kp2i`{zjK5*i8#n?g z8K1%}=5v=8v*F17XqvvEHnCwOlUB^vODVs0_;3TedSIYgTu+tG40o1Q4|a>H<;bKk z@>2K~pqoh52r*(-=MOLkM4VP`Yke*2l$&OCT6KMK_0r|F=*-~&)8^r{!sysx!X5q_ zx_)adx1C#iFS2@cgqg$V=9j0>izWA%!%c6}X>30HeDW%k@J9zu6<0Tis$m1wP~B>j zmFb>qMyc^mL7oPR{ebzS_c8@;HYys!M(<<{J43hDSPi-Q|?hOl7+Po++Ex zP&+VAb}#G{i@1h{3e_Ykta#ju2E5<=YH5M}5vm5)SCHpYtQFos(UUeGA}Jtt|( z^|VP|Wu0{Ydxw7~^Z#dIWNddpW?a+)dw zE5uhHhbih)akDLNpR(9#Hkyu`}HbXNIBR)pL_MveN+lGIumh5q8vRTMa{6j?8&61~};yLIg&!w>iB z3}m@iKr!8GmxpO;;G(J0;bGhv5jQpv zZCk!<$>XKFY0(i>Tcd3hU~xO)xa7UR*4O)Me{W!Pg*PA7Zr!`qs(ChT0JN-ViDB(r z#E3O1ZF#-y@>{b(`xEh^eg$iClzA4J9zL)`XZRS}w7xesn!BlDZaB_Vt^9H~h*-96 zXN~+)60k93`@6cUaY<+NQ`JvcYHf4FYPSQb@a4ZgRITX6GE&ZBd`nT|>$p|c=E|rTBw@SaTCUY* zoA21r5Q#$WyZ9U&9k-sdteid{AA4U@2`(62pnNP&WfLg^p)i0z#8+)g3T3#!)w@gF zEYR-4vnl@%dv6~O^}e@%f9E@o7&Ai>d730i(j-fgGSrGnmL8TQYDkilAt6tV=ZDZJ z38|)%#H2|=n)IcKNzx=ql7^(Iq)B2hHTTC_Ywx}Gb?@uC*53Dh?cctR-*z}09rKSl z(D6Or=lguW&TcD6>rld+GkPcs#2dy%j6wyoQYm~ybym&Y^9#=J{x&-P=;lBwXQ{5* zL4Lia!o3L+G08tDkj`ND1&%FL{8E$2*$dgw(#=e^wk)m1~S$2*z3+H7kcP zXrLXbTd;z1cJYJ(p5@T66U3Uubc_xS^<*v_VthC1y_Q<2iL=X_!+degPP=%@_iJBn zAMhnu)9cZ6b!b*9<8xEbGUe~*;#E5x;Lt4)NXwGv%X)8nxnov!Jxnf%(v`-Yb<`nz zV#m7Af?HyQD!7WECW9g+FIkGNK!mZR3oz5@_4UhOxDEJc&0A0!tQf4mG_LJuS{%Xk zr`O3)->X?OtQCWc3{#lWnT8S>8s+ef4Ru>8*BLlX`|hfy+=37X-wJUgC|JWN290sW zXd$SzoM;D@U$B&n0p!>L%1_TC4VT1T+kJ3zGR}*4kb**&onUctDR%V38rOpTT+s&C z4twKc7BL~n1SZgM8yTqPaO^GyPB|~K3?CaiH||<^?B-GQdR`QHgU^F7JUVzMVUZu0 zyW^R72MGl&4a{v+TPWJ4MuB&%h88kZra{mg7Q9A^TEoC>q~L#~_^8!KZWs%@3ECr82aVzc0B;ob|?_Bx+CZakf|kBy6>!fL#zP^-Met$E3Z@>28j zDu2#9az7{Gd0tvt-jOx1r5Ka@6h{Cq1z2G4NHlS7C@xKJg;X=3J}&Zc zo^>$lGCp>kY{-GxV)923spj&joB5||4&iIo;OdqZ-gWI={xre>y$v*0q&!e?7_gyMMzePr#LMd_Dvefo`JWlkCawv^MHII~m2sdjsE>!hw~^Ni+`128-z;pgcHmGY6+kCPZ@3?>Q zTI4xpWwOo$XOr}tt_MLm08e0`eiHct?``06zC8`Qj0IuWo>K|H+f#6ZOwwKsAxB18 zzE$%kvN65`w^w}f5R2f=CV7KKxq>2Rj|=a3MXp^%8z+jK(~CAlUfh^|(XHU3XX!=f znK;Hw9DxZFc%*a?&vqrONr#q8F)pPSL)rLbHcs>T1!6sp985aExfES{DK?T6X|pAS zPI_|>AaL;C@`2S&J_0HsGA2s0W?p7T60+A`K5lwBPx*3z$L0L4%LOyZpP2-XO=%j7 zz@S0|3JI>pg}9y%V_d#4vy4-Vk745`vD-CKK{{^R@r%eK;xc5StU;Ok@CR<=Os+7J z+nmnToyA>n5htouVnX;ngn(mQ>5RP6RdA)d_DWCJ74gKCzM19yHsu59SDpqyFF99U z(orB-v6)BOB1J8rVP~_UQ@rxd^l}^>mEnq3e;YpjoPz#<|0KraPVw-!c*-w$#7Q3M z1y5=IHHykLLKIK!2yf;CUaXXi|FAKUQZddXkGoE_LYS;0nEYA^vA4p!tYYCWl@Rk4 zQ5ADfkxiq>wq*b^59#yJbHyku8?Db)^SUijl9bU(P*K^2zQ8)6EZzw3JMN4k5y*+{`)j?wLe+)O~N-AsgDfROxbvy3< zB4YmoEweBRFkOBwt1ep&zE&xC{$Vp~BD||qu2mDft0Es%r`@W)QXFt}14)^6)<#mG z1RmnoZkmPNOn(uOw(a=Qb5P{c*o<{G_{RYXPR;JUH3g@tvo|nJzT)<6NIAZYQnbtC z(mKA|UO*17ow*3F)v0;rgC~34w7pVNA{2iQ7GHC|`Dm)_Z$&9a%Q1J}_B#^u?Xoy>*hwn{c=K z*AJS#QHa^OJIa9wk*luQhRAj5=h-9svguECZq?E}Yp#{0{K#pr4pd*6p%%UOMqX}} zbBmfF>ef2jd(UoB9N5Pl&D0~MWGx=_Ggs}3cH{a%oKJVbqH}j|L{X+|B3nJxf&naM zjGRDE)Y*Xk0aE&bMhN#r`!bp$xJ?lmO{T$32W%;;`~wd$aLY!z8g=VWPBICp4DdL^ z$*K2qJnzdXxZDg;0{yQl-l}(r)Mj3t}oc4KZ%yT>|l9bE@$fTC0Xi^lb<)EnLAcOF@yXCFx!)MVg zoy3xsjF#r;mPgSKU+T7s%vxKCC196ypZ{7{S( zoJYe}TlK2zwpV||e(P~RuTAG&aKN)aCnpF?x+TrBXM0~+y;iC z*9+Nw!FPsy0urn0g--@1ckK=`)t}Yzr>zu|TPyE)_S87F-6fJsKJuBA^l{0erMbs4y2Rb;$=xAmT7bPc@@*o%O`cUN z$ANJ9@W^NbrlY;3ucsZC3H-5_K4;n|zE1)y#Z-0c#F$@kH}L*&>4SddQy^!b(*DLq zL3z9NaF1?Vr_hv6vkDz-Y#nr>1)3TO^@)KUZ8bt3QWt9i%3QmK_{|N%7NnC%rG*Of zc*8An=}2g;ZI`T5{JyiVP1tFL@DR2W(aE0lx+=X^8b zTP&e_^n>SGq^J9^Xmfh9t!W=?Aibo!1{tZa7S%{)QgOUh`}sV+ewdh7F*tC>q`+k} zh=UK;h^!;%G+IQw)@EL0#z0ozi&_mzTO-)=wqx;njBl?G} z6W?=&hXjEPEnc3l5aAlRdkO{ox;&1+m&!};7i?x&yX&sV%W=-D(dURuhI9OjWgQ}G z-}gvBvTkFaV68`ykEgAWF9^tS7a@Y4ezvTCu%{*!c(TCt8wPNYUz%b8@);P2z%Km7 zBJB4o?FYspa9aIJ2Z4ECfvz$12pQR5rE#@IO=> z%bsEMSWEb&_-_`+ZffgXO7YGt`OjkIel_f{)2ewZqby?ifDG~X6C?_b#^ z{8MqP#fdoLJ>&U-SZ$L(6~|tC>bjD0a>Fmhv8N;|d)+?(((_*z$No1i;qOS#ay^Xt zmT04Un!C;VkIW3`Ucl-92h#J-i67G!G?{&wij^-uJj0#&CDw&|?a#4tJgV`>UtPkF zBTrl%7aXk9n!Wt%(=NTtuN}|51JTbITdFf#z5jDE$X~_ESsvv5);p(MLPpxcA=&m! zyZ=xe``@^PlOJo|mQN1x$A%_9A^3%IsbI#xUBds1$RK{%O?r&APfpyttM|kI1nGHu ze{tApl8fTnGyaO*R~?{-coz{Xf8uB3A@NH8k>DgHIZHJqDU0;|F-y3yiI@9x8pV?} z^N_FGoJg9gy1w-J$<%X|4>vUI?s!a2>U^zV@}rXPqQ0Y%3hFt1<@%3y9uL%d$}viW z{J`ZCy+;pgR2v9ieq7B4H^qWcqhWUk$6@KwgBeiud-s&J%m>f2KuUHW#8PL!=!)cC z(3dQ~8g}AHc4*=2n{%?8qU3rwu{#3>zH8vjI>hNvp2 z@TN-Efbm_i!DoFAb|exL2$e*Ly@LXFx7Ig2#9?mK|9{$mhqNUKMA z(c~fMO)-H3;-alz88c+2M8C=Sm@TDl1;YnbE4sM(q410*;6e zb?Mwp@mbUMGJkdcte)>pJD*d1^JoBR%0iXcvssu>lq!(`L8-ifxr!Mb)3dGW7H#}+ z%!G<3+>bjwBR;XOV-b492T>BP#S76vc^>OpflXR(~8Jn%@>&&0UG?*pZ@c!e*iK#AFp| z!*VBaLRcyXr$j&qsq3<%f?gVW1+DA6GelMf@fh72dxA)WvKmY<2q&!4%3wfx8I0Ro z4JKadg**vRAlOU0j@Zc;jj3S}$e)p*1k94~%Gbq1H3`c`p!mieGlnTj_5JfhHg$ea zxE|zx<^IzU@q7XcGsL>3(F_1YnY6lXxe-8*@hb?va;8`3a@S0M27 zFc_PnX^WsC1oW9fa~ZG}6&@Co-m+s%MjN{@wFB!*`UP#{n!rv)1kw5h@kh7qL3 zE%*=?UID4${%J=YXceS%V4^rTgkdi_2#8eT!g1Nd-8XKI!Ll&or{9kWi$ zaZk%N!5v3Qg9yG?mr%i{4dC(FXCPR{znMcVq!5?&uW{S5ax~D2Q zL8Az4hL8`^@OOmd1Jn$Gbw;CmhA<+dIWGgT#<$9jJd$KQ)XHqP&U{M9d_u_VtjT=n zj?bguj1cS)9&hT3j-$i7dBiU?{D+dv2f`z>*nrd#RZUPc00NbT9Zv<(E4+e2j-`+x zki(zH#vNi4^4ZEa@z|wo(l{HdosC(Vt-dr{^Bo&|6YowT6PJd#i}8!3L^KOEj|RB` z^Z^a4b2(e#&qlq&&%BABHUs20$yM%0)xHN~ZJzr?WaDF`huoMLl=RR>3S^Uy-$M6N zJ$L;0sIRrQHXsyiVFPCgw+q=DBf^JLeP(x1^fg0He9d8J<8=nSb&5$k#y&cu6kRtT zrR+qX@fo`=lXo4;4V~xX`z}`{I9KU2^pUkSc%GL3WsPA{#HOO{2|7zgPG$ zO>Ko#GX^3M>hbrMo{rnVyg@jr{u@d2kDOsoku<@)ykYZ3Fv?5(&oq`^v*}Hm2cK<8A$hAuv+d58~bXtEDPkWEZ&B)(Y3Zl z-mG&fL}iOrn@^q2Z>w6x*zOKfY>o9ytPhm)>u%oYngVVbCbfMS8NORzmt4}a!Wg4_ zMt1SyxyDhsOBR0$Wa$#ExiNa6(F_zHG57m-ewQ0Zwp3oP$j!|lW_-$Rlfwagmt*~} zUOtDDK8F>zTq);*F}ZVKWcymn?dg@UTV==7M_J`9n(7!EbK6&P`PZ*sXKv4dXRdNM zGw85!v)leeQ*)X~ChwHWzYGr&b4HDHF~(W_@>UF(%i=3KSA}p_#BU-U7 zzQ6G6)m0-O-bzz_{6nG+M^0j1q= z`uO(=nMoh3b41j_Vwjt69vrp>19CHmx^bhma+tI#o>~~@S%(bPoM9x7h}(rC3lF-p zuXB%BsH|)x5NJeKA;Ti#pb!0gso=a%jlLD#(x}Cd6rEwj68JFOC`JPUwybZk(aJX@ z-a2D{PA!M(>yy(+q7RwS2fN(Q^Es?Ox_nq_RUz&YNLN*GoIOI@#O*Vcozl}QlS{2f z1noAuy5_ph44$}fqxEQyZk@C+qMSY2Vghc$iLU*9t%6#CtN09~rkStdPOa;#InR+e zcxXkW_jl(}T}nm1eTaV*QYXxCGhz<+wO9gJN{(cIIxBX&t4(BvV9>VF$tYyIR#&Z{ z(*{w_5LsA68+r8C)V8#@R>t>;{VT=8qoN{_Xkf6A;GCxsL1%5wS?z(inHU+n7P;`n zJ@HiYV!CD_XH~?YO-^26vQbVSXXF^&A(GyC42kfWI^mu=-p&GFM?feC%-X-r%lA^% zj2#jWE8PAulIG03_=}u+g54h`Y0gPHyyCjE&c?qqBbC3r6|qutGG&){qShg_ioWwy zGt!^Wu>Xl9&8SoJdZy;(@1IDcUp~Bg^s4gIcL--9W@UbJ6vq*a{|l0)zpACQH`OTj zuSl9(9>%#U(f;?GVV~T?5jP&D7-^EkSNK+)u?bQv+etC}vE8G7ENt#4Xs(uRp zT%6%a&vO~Zmvp_OP01y9?aV8GotM8neEQAN;D@{@xpHTNO9?rKLD-?XtWeKV zU@*xTWYRz!rLfoF#EC&>Iyk9Kq!SCKXQ@;A;tqF<4MJ3}1R369Tgzt650<51Rl>Ij&q3{bHeS@{W@aKCWS%<@ljI3FQ^?#wozXSliE*tQ$Cns(gd&UC&M&tngEvWdesTbWN0&_o9fd$iY3dcpE1`ycA!F z+VXnqf|e~Rvv@3`fQ84>&fz^IsFj_QN9#y3%h`muxC>?2IqobKd}o8w3Mw?u-=)NX-vZ5eTT)<{rVk=v_dd&V4` z=<&1p5ERsT5L<-=>q8u@HAlAA6bh~t_8Pb;I?)bXYRYV&1(xux=teNn`V?>S+}$@< z6^IhET59`4-W{6OBRzWV&N-#U5h$1`{yg11fnaML`D4V(>=&?}d7R8~CY+7Cg7?vd z-63M5KE|5&9KV&E*fpom^JwAd`|x0(-VlOX=V>(;-mPiHB(eg^TKDf-{piAIza zN|BaC;AKh=Gvcwc!v@AXk+rDlZ!`etYP>d?cLt0<>V65naZ zM|Q028M*w(`Q0po?6#)5#n~U_D`CaNivx`Y=TeqCKtWNjbQCh-Pj$m5AIS%nDaJ)d z>qaj9^zHpN#YE?$y3zSfZ6AMHZE*E#EY7#q;1~<~JJR^|nAfP3z1QA(7K)ygVg?3Y zCHr6iE6F96+w<}{NgV_9wNq9*0424yw)n&sRu0I4NN*dKr`;I`f_=CF0~9(K3&3)t zi%%PGn|tH=xXl7gdlkL$)lJcyEDGdxrK|4Tx#O`~ zBWfr9d@|8=rWp)lR_re+ZXImv87VCv5G$!=}FTp6+4Axl;>Cuwwerg3kC$fnt}8@q-A5OWO$^- zdM&len(DBY5#8R6VM``PWzj<0Qfo$4SNBMdZfzpNA%Nc4A~DkynpsdW1(HZNN(rBD zMl`D`l_U>|Tg-4vF3{Xqv>Y3^s0u`tU`X(aE`TZXs19LQYZ+F?%!`gAK~hzYtRQ;oUHVT z?-S`PMCg=Jl2_i{-9R)nAu8vJ*wILfrN3rq4kB=lTusI0%D}zA_f|?_D1}-e4jAHV zI#W{{@+@N|BNGx?H+biaB05#py1A-ZqP&7Z4V5Z~wiC511DrI>ToG0@wR1qkZLa~l zHGp_BH@5`4HFI+_Fd2Mr!%U3`zb5m)PqCiN&26WqhgOV*x!Ly)%&&7pK1k#Lq|XPJ zNPl;us&VsAo5eThb*?(|@a*4eRILhZ>o>4Hi@*4L0{>s|O@G?6RhzHII7Uv$Q;_mk zcUXU#8+I%aA$!@)YD&LrR6TmJ!r_0K!2jRu*=plhZ~|qu$*jaJ#L9YCJ2|a4SvRb6 zhaP%8O~Y;^;+MI>DO+7$0vc5Tf&YIazG?m-PoTN?Pjkbc@l6NKX|AYtzxiAUoz3}J zEl!?4^pEe^{?e#gxG;6j4cXDAnJK!ngoY>0eAA3C5sU1MlV}u_=`VY>>zBMAS~o?+ z;gq~Nt4K?y=7vROoVW*sS?fpIR2rqm01~_4VB)k?>#tAU$!7GVt-lfY!;!H9{lW^Uh|C3D`R1sn2K9tuR3~ZB6ZeZ8dc|>aCpteH!W5<>bQS=|MUXp_&{O! zpZ9F@pBXk?{A&XLzu?^PzBojS_G_c6pArUr?v%>E3H<+j0{L^S?2>>#-XiqNgIHVehVjh^Kl*YaG-yr0_gN~RnGkuWgD>x~dWKmD4ii8~gDGfISUj8u~QsZA7C%NxwdcR+ zgjMXN>lh!@A>0I|XH~sn@+Ain?CSxPj>Dfjt^j zNw6)6%1S5U4?OLrY)-gGiLAUm-Zs1ZSJ)`{bJOEkHE#Byy0(0=9Hj z*GOL_rgd0O%#i_&XAvnNWelE)#5C4bHa81^2drN(qE5sBW%#{A7YM@P(ZP;(5ikpf z>ZYFlX69zVDsB_Cj5cFBiZN~A+B8Q#(MlPr#eftKP>Db-d~YS%X65A671Galc2sE1 zjFg(Xa%@v23}%k0FMoJQVqzp@MDm%%lI`1#Mz~t5h(=B(PVD!b_C%_sr>|2gKg)xz zd`zTIwDig8%xV>L9jKPXKqorQ?>%DT+0UghO!`?So+d+y^kb2HwoIHsqZ2g(Im+~* zIwODeRV~JJxA>eKIB#8!|X3JtGjedQdIRHwOs$z=iFs ztBj4LW<+}OM!WTk#1-8wK3pWAD5twqDr*OwNr`^(iH)Nz{077QbUrWfNw#fEL~25T0(Tzi z(JHT!)DEy^tYDN>g*oDR~L7qTu|q1N{A1j<#aJU@|;Bbrw1m@@m6Ov|_+u0-WjJ z+-N0T_eYKY02K7lF|gyc3TQ8Lyng9#rnfHqM<}SFj{N%Pp_j@^nnP;Z}L2c zvcQ+jIP$|=?yonV5%}Gp_Wsvir(e=r^Kbvuu-;Ks-)_0nzJuZNZ<~;(o;$-?^f{sb zb+6N((_6O(AelH{$wk(iW1lJO%hGO@y=FW9JH7Qe-M!_!X0`C1dF1CKjDPn!{WrZ% zW%6Ef{`S;jtN)4gR@c|^Yj@{uzk^{N&R|@9aKDM@#6uws0s~@ai!Jei`;TuD^zb(w zccv{S3rYQ?;XJbtqq66%k)zi+s#p9S*LhHt7>09&j(fIDi-!u`4CnF&1J>;XMJWU$ zNc}U5?z`;8<95wi1cbE`y2k1`Zw$k08Zh7Ex>I;!OyiI1mlf-%&5$QlKc4>3wrduJ z6~bDEtRBOtSGWp3LwG^P6}Bn(hwAdfy!g~5?D`X=N+i-ACV7Z)?p z3?8H!I2^{sVoEa(*I_zJ0cIWpvgzQ#Yie#b^(bz|RJ;dXj%CHbl&NEEZVTw$&bDU2 z8|&g~nMaD(X7Sqds8+Vb{Z(9R_szv?shYK7m-FI*3azyP9A%D(r$L|cx=g6Yjv1{b znvK@cqL1aYR+X%clpwB@+^Uugsd%`RBC?=5lyl5z!hm=q;gFcL(W!z#%?e30+US(g z#~G|bxcyR6fs|>@aNvu9L;|`Ah#F^Oy0n%s z)Ii8_qAM3mVFE$SrI|%qbJ7!uhJpH#8GMN}D?Sm2(`x2Z-*Xv2xK#q&`Gi!noHJ-i z=M`6em&uSk8qvzAuAM$mO!2H5Ol=djCDOzKqK!V?`nM9s~3x>@`jjHktXMGK%N)l~N&E@2*GSe94QvFgBqpQSBPdY1A%%sruEv+}35vnAz z_C$nfiI_FhO^I~L0LQPY#l+H#RmB9{eY1X~JddgzFQIZoBc0-kb}>&X6?aj)iYQh@ zjS>s0dHTrOM3%r3F%M`59w%jg`%y2=p3| zazMlZO$UUVu>~*%M}9K}TZ!M>h`%bh-Etl4Pc8qDFF4@jWu@GlSN-H~=kGVXhd&4P z)F*8Ct7gvsw=WoeetFcvFYjMIsJ{A(FW6H{MR35{1-Fy#xLy+LCyww%h}XFQw*AEo2w6?x7gj=W|&8UG75bN(rRKc(O< zJJ3-TEv+6X%){05KThQdu534rX4BzkVN(jOI4usdkWU%9DJd=+svWHQFm&sW=kKR{ z!Iavc?rB|@{M4v>LE_RxJ??KWG&&hLeBa~}cevTC8erWw@8_ZZgmsU8i7}JdzQU`^ z%zkU;Jlnex4JaMI=I_6@Z{D)tLz_ap^J|Cb<8k;IWAUZ0cBsUCRv{3V`8S$5|E%Cx zcypOJ@fTlkcT&T>v?Z-GR5O;DFZGhGS~316=wreUzxM_IMlJ5?VMY7smZt>MdNUT^*O&&a9wQ$VN7K$p{h%ij(RAA`U4Hx zyZ3mU+EQvFYG&SoeH1b4FhOi^^Xa}o3bng$=Cg3SDoQ7PR6(xaKlzGeLwE5?H{plcR3H{GpqAkNGCd2fyK#^{o1{j^=L-{>&plW^5(blsK$wm0eKRCWW`$N2yVYSB8R8hohhvxK(u~3)8!M-&3++2T0b6tV+8c6 z7Y@kNI^=!g_B(IoE7ApXj`q|b!qg%Gh=5MZ{-kwwVp`tUiw~qs;beMU_sj3{;V)mJ z`Ck{MKXC*4t7yUyJj}OOx)pajB#ZjL%k|lvRju-Q$3ClMk0;)nuuX5@#~*fUl^goy zoNw$`Pwzg6jM*4lo~dmI#pk566U6L6<=n~Ux=K>+WI(Y1cWhF*Kt@WJ19aEKgp5=$ zF)<202GLoAxU5Osc{!Xr7+O1`4E}L`gjpvJpwQDxI6!d_@94RZ!purM46 zC?luja2Of3M2^IY=p^W-k2JR<5{~WwD=%GWL34J=Wd~R@0zKRZhv{5@x}-U0(YfK9irM!Q8yyUM9O(PJ_OGPY?1K%b*HuqN zH-9I!{?A1>e=*BIbh9p|TzLpYH}BXz()o^^l3J084!=e>6}m$4)C%@L0iu}>u+Vdg zr%oOJVwSDFA)s$)|JMhi&3Duyh9c$2vG;ec*8gUfnR!`?SZLCN-=x<62eT|tT2J`h zspDT(uw0|`nc=!;6F_vcC)4m`^!8ZellXmR^QNR0t;y^F10QeuO9}d)fM^Tfa~|5y z$UK!`q;q9tp9zyc@}zQs8Vsb?KCpt_{a;5nRn;DcJo~8mGVJYX%^pyKzFrfQp#NEF z{X4q(In6cWyv8M`d!`=$Hp~9H1bw0=Dly>#M!Ct+{tuR*|6Nk+Vj5_ZcRQA0$-TRD zzQ-kXQb=n1m3=W~o-a&uZZ>=^4?8j6p}n>vPa-CTxTe_17j-tMkMfe&oB7NrbHBT> z=vqc*pbxf;6jriR|KxNtzaQpzB9U%-XI1wx=FN9^>g3=sqLn*#Z3I<$cW(?x90PaH z-xjIJyIWOrd%^Os2QPXiMyqedTw!{x>+Y?~t*(8!FC_SgXMbIX{s1k-ws`)_cOGN4 zoezgXC%ws$p<}mhEw@KQoUW(ktBMpf6nZc?>wy2*ZRzPDo0e;&Ll_7BFIPUrd^)mY ze4_debY}mu@@0$R!{b0Cd?svE6tW6ADD3vK}xPGc*ZqY&_KdG zCdE{u^@iz9X`8wkhb$wIg<-+byPaQSnq>EAb)Pf6xP90!ubb#33-*_KhM`Wrfupg7 z-R2A*jl1spqp}3jif(navv&pa!mh3G&3FSx9jY}ZUAL`r9$0khW{dxd>jl*r3~e22 zMSW26wRCOyPW;;odf~fn>oZ+<`Uc#cgc_OpiYbVb} zi)U_|sNGf^n&H*$qkHT5eTRWBXA~Lzb53>%Bh0@Z{lxE6C%YRYcc2V4GLJdP6CQ5~ zJD7XA`;8M>>)y8g!v!g)2Q14D)$+evq`!>z);?O$y233aJ9}`a|Cg=p2lw;RZ**sw zJSgaxd+n>;%-ehSk9FPe-v8y|?iRlf75Qym-)~es+2><7mj7sNR#@qAevrZBvIp3z z6lyVX|M8Z{?wc-SS8sH`3YW$`yw{N;NL%ighKC>K_cV|^c}aE{9q~4?Y?)Fxdr6NCiksi&TE?nA z#{bBlg|_GITP8;BimKeHm(aQ>@6wB&B_@Ux>qflIU@+E%=#5)yjpyCXU>UYBRF<2> zV`gR?Tytk7CE2OTaP3DztgVmA;*xs3awKW_U_B*@BCu}E&Wa$M|8&UhV5K%UG-||~ zno3QqIbwe7LP~yH*x|d=1CaQ(qhi$38V8&{HBOg%_qJASlg<06tb?{O!~;!11``y5 zJ;htqtb~65#fQFwqMf+CTK1$N9?no)ef#U1S}G@4Ztr}~N5EZgjF3j$4cd^g}y6H}JHQhRh^^6|o|Ce30ZW)?)%^=6=TAiNzF_Lbtk z>>|%)Y>N?Lw})?=%Y=7I$r~9Y_!(<1180Vy$*f(qbG$~VkdKtSZ;b3hCEvP4NN2(W zw3tyU`5l7&B#QSF;V0&zc7VH6Uf?i;^pQ=9La>|PCQPpm2(60!V#UZ!Ih5#18hLhT z3y!(w8QBwolf)<;2G)fVt;&G+B4{QR<%>Y!Qt~D$v`mTvwFOo*%ycQV0KnQ@QQADx zVJVJC0TnUHdLn2g2faH2JC_R4>G3~G$u?~7SVAg{;OrGNyp0SGdJfdt1a)chavIK2 z1j;$EWE#driY2nqF)S!tjG0b_R_(PvL|l+Tou{)Ryr`W0yiratQF7b2;NI4j6s-{baI>&w-UniGRb>g zG3ya@=?_^unJ_5OHWY=8i81N4?X5C0okou0#W}ksCAp%XL=d(!&~^-1g#jz186Z(X z6k%L0TmxuUA4xBJg4wOlP3g=}@l-knUhxF={7`ja97*@s@Xn^OTR&T`;86=k_Xe%+6avxgp?x>nI zrk4h9li~;_gfJS~jEV_nqs>53I1>)$z}`}f3g^Ur*Ap%fc{UGs<(-m)l>8GLKPJX9 zDL6V6CR1TMD*8txmp6{l6JZrpoW2;V5W#v(m`Nw7jpIJk_K9-$XpfWg6}yil%u`FE zlF+?}IF5S`^RT|)FjNHTyJGD)XkA{RAp*^%q6pb13zkwwMA*))q}d2INQ57{hg*zz ztGXuHLa4bMoG}H*l){^yhq>LvE2Nyhr?|aR%vLJS!4>Nuf-xc(edw&62*zrk3J{@m zIT(Ease{nLJnT-|32iD-V@<%;C4Q_mM_k;`Xay4_Y0Nd3_D=Ay>KrtUj+;wClfmzf zir%{i))V9O!s5y7lLYbcl?+l4>vSX)yNyGL=aDAF@Fq~W%_;Cc1nWVNw<~C|$+@9T z+QcR?_Mpoz!*4n<5Eb{V1Oy?_Gz5ilVw)<&r=;&tH)yC}cWkf}r#has4I;00&-TFQ zy~ey_ zSx^v@^pQr`G=WxST&6=g+aZjZ2u(q9=0u!8Z@@ZAxn@*UfC$$_!0)HRNpuJnp?;#V zEkq?uaG4DLTxqD~2#m~y9mivWIG3Mw1ki1cB=HV$)~c71x}!C5lkNzN~+2HU;;&WoUoyjRjHWP zn#^z}yiAI5RE$G&Ip{d~O+L?(DcTF*G z#QU+PIyJnQ*kC692UoOz4VJ(m?R$aFi6EIHP>3sfB^$Se0m=&?vZy+l3fe?ao-9aR z3N1#!XQUnv#@&S0Fo{YGj3o!9aOK2Pd|k`-_O3aiv-QTb;2VzN-st({k0(f9-emT4 z;)583Aj-D(r{s$1UK0#boRoCqQeyQk@+S^?)@5?@i>MC>K{%b@#UR8f7$lyt*GDEP zjLni1_d%eP#J7ed&lkSOVQf$jU~RGvPPL zA#(c+^0Sj9doetR2BDcK1q-X@N|;GU;ZX!|0$!FIKpZ`EDspeG`H}p z$$``GfpfzA9^lUW6c*?^x?i<8%-W9|dg15vB=+AFCt`2hXOEOx^Ca=I-(>F7g}jhr;i< zdHPLru3umrY{K7d!oB=abow(RCW}p&Pe=7a0vv1mQ|pZk9=udqd9`zI8kJxlUX{QYn;V!`xL??~XB&RU$K*YWt9Gi4?b;UT)m9a|I+y%TN}A7Bfp`=RT2rqW6~hf7 zb?i0ICA@mM(7f2_6damSp;dYO->CGWHz z-RVV#*B}%%I!cp=G7@18PkW8*n&J*<-s6d;pM%?%lG%t_IENHYBQO8<#9p<1g;)E^ znD*7D+h;5yJHKpqdD+gU;jCP7q~2Ob8t$hBc*2IQgbmlM_Ng6+o{pn+_<|Dj zWREtGq9QXpm9KSXd?RZzpQkX?5}b=*DzxYEbIKw}K}9P>&pDZtOW<2<-LAPIHS}8- zPY=}Ryx6yjEd1?a{f`me>M_9fte_El#C=+vF}Lf(+$-D;u2JvZRU3}g-+wR1FR?Ft z@QF|^C#~JR<#55SXL9)?d@yq_ZC|cqJa?h_BBj70zw8_D-VOM1-#8q5Y?A%l&E4%# zF87{Xo^cYB7v%2I4S0;)xDD!uOU!9cu-5z#! zcII}D{)|lMv%5QnCO=G0+7?MG-^y#NxJpV&_qsk>u5#ASdEZrM`%*5ScXblnw5bEdiRHZWk}=}YM}H4j-7cKdAK z41Cd<>D>u8N0kdFtYQUWRqZMlCL=2bqwdQ{rzdQxcVlXRg&1xmUIF%NdRTMBIg<`8lDX>6EA#}H@Jc%j2SWvi8!`Ym+d836h zFiW?4a{B%08*LMT6U!PEuRugJ_o8%v&k7=4xm+Ze5CIPpc$+IKrcBWl6~OZZj_6b# z!J%r(BXy_%MH*8sDDXU|jL_T>2k--&a!}=n8T> z14f7yum1tqFdKV_cVs4pEjgmU-lKd6a&c4H_J_4MK0M>?d~jy{t*VbNY7Ttpd3dY( z(<>xF#lVGM^ZB*#`1~EM{F`6iiY}}>>vFsH>xa(kdtbHQzBTqqeD{dL;HNtN_!r5O zvK^1=ZvWZ#oXQAJ*`8Aw!KsV&UpCCWST#&MajFO6M{SntZhLL&tVAuplHTMw%UP~7 z9hQq{rTlWS?wpqTSGMQ>o{M$<==MYJHp%Pkf-~b7L0X=KHC?bN>~sx z))PIZ_&D}zYQyYKBk!*{VEfEf)|)YV?krK}?=yloqxG|HkH6)lm`_NG{#7^3oz)G8 zvJ$Aoa|B2KV(hn-(~bVUVP4Z3Qt+iv;(W>G**|N;JW_1^2Qq?-CLfb8dwdPpe7n@` zAJ{OnRJja1*f9Tx;_yta@7#5dN@J5s^X?6Uo1ppg4Tf zk<^azjvH5!_62U3-_@n~KD+YFf^^afPU?#O3*-c0Q&5tQXRrFRnz{w$L30)n)N{l>A{j)y}B^OtqMBKcr~2v;NSs`M<$Imv&${OX~mTd88VvD~gto*P1b4aa~*SaME9}tb)pl5NO?jWk}j3;xw&LD%!8pA`idb-$7-90*e|}^qd=5 zy=>y~p4gP4SJ#f}wSzl(tAypFQk0|gkTH#OSB0i0aX3}`ApT5n=?%G0lu^NBU%yK3 zw?%tAUPN}()ZMu7uElpo(4i*=t__!V_NBV+W<2G(RB<+)ezR+G;(2p&)%6SO_w9M0 z^;||_741}gw`8TqLtgR?I~gZwx!JZSQ6=%blyB;DsB~p*7QQ0L_S2>p+Zqc7nn?cN z20YK^x7{SwT)}VmTcZLs$~r5R%#fjzBQQ?7+B)-d+)>SEaoPuYi_5SJKKTa8?`edG z965V?mo6VvJ19EuHhGz`j=#R!Z!N6I{T%1NzqSXtzBr{s zJv>p>lzaF#ej4{y?*e;P$@qo<_DUW7gVuuORU9lz@=QO1ho3o8e{`km8+w^b!PXEo2cr8DloWZLiH% zBp&}LPjxhMP>!dekGu{}b<}krD8wvu6??Msf;VI%OMr?v=vmx^doJa7l{(p2E1J)6 z&+fa58f~>CowXyO_I&2#=GH=$w3&}et zsF1OUyod$SL}VKgUQL8z(9qf}oO3bRpGp4giif2H!(`k>D%k+?Ip~UyqA1Pfz>8>* z4DuOc;bv%&AI(57reF1a)FUtf7Sp@SZ4WQ!!o-iXW50 zOp}!PRP=Egyq-c>CWef~@LVx$%p=U8la~T2V;n!2pt`OFSik(i+JcGlgvv9_)nH`<5 z4VC;)G!GuYE)1}^p1*(;~i&2kdx=# z@2T3g_xZ5veA-p{no6px>)%(e>$lblksyu?z!;-g;zT-Utuxo6M<;`N{n_~H!l|PlxQYB?@OccUZW$M9!Qp9LHZ>hY> zkpV|yl)I(GI0k{EAV5-rMKpqB_dkzN?r^|>UDPf~HZz+{vkxE=$4!SBq z2ONnC+B1(@7pADTCB zi>1&KTqLPMVHT7tL);aRg%tW%hVX6GU`%c6MP!v6nv#NQV#tt7aK?bI5-3=V3T`5K zQrPBK{eHs+e|4RAIhk2EC~nF8<;V9MMw9Hvk|sD;VzVeUYxANlH(km_MOb3on=4yz z(iSe|DIY7C{IP3W5k57zqHZ-wKPVG-bj9$0<@L^8sY=d7_c1!iZDuqLbW?X zf~Azol)^uFp>S043Ge@r@l zqJ&bitYi0M^!y{#NQ3vv642(Nvt^Jo7c~5UE|MTq66C4`SS8zBX?eNXzwJ#~7du`9B z%kAfB8%r7s@?`n1;_r?G+|5&{QjWmnkA( zQo{)scT=M=cs3VYMujS<4@6lIF+X24%^~Gu{RcpK0D;h%47w=yREsIQSOdEl1HS7A zd@2Y0mJBS;9|&$8;7koH{WK79a3J6ye5GbWa1NS0$ zaF%k=n1z0nX?6OkRm(wp-lK=L29NS0l8oT%@sJ+}G1ML^T0T@_JY>rsDpFGTOVG;Y z$o5Y|MR$h$FhH{o(Z>Kg3=uth(%Y_m=;!U$kA<H49zHhw!KZesYhCMuC3Pr#UteO5%rxTcc&=X#()!*oI5j{?(Ut+~U!MPa zkox|UcBCHs*51I3r7@jvWQG&r0tKonMO~#ZAAp zxM$_?b?=UP+O6K}&#vgs%Idv%#QDSRc?~-kKNxuUc6`FsmYf-hygiR>8kyYt&!kz& z@Tr|@VGEG^?zwVx9X5Ri>lS}+HxVYor$z(s|Qk{029s2#g-4D6O+%uEeTw=l5e>Vmp zqgT}BE8 zZ*Q-XUPo_5-oLWAq_IQIGtr{{o8E=V>&+gju+Yf?x@X0G8VQ*iwkwQ6(i53p(%;&; z8tbnqvrZ|ttwt{Fx7XbDYti8m`nE5wCx6?iBXuIJmKz^bCV76k!|QvSa@I0KLV{m) z`giRo44-GpnwHdkn8b9DrJa+$PQB!7t8$5gtp)_Do>(Ad}W zvh5+<)XTN5-i(r1)*Aut+9tm{k|ysIt3rJG$0SKfvJwH;(^95^vMSDFeV5xCj(e=t z!Cc$MR(i8WI@{$tV!F!LGAd z+}bg0JI2t^;m&H4dp2P;8(4>&WS;M_H{a#6$gGxbJFR1Kg%d8zV6>g_xI1K5epjxt z@BDqF;dbV`+nN6agsS9Lm9s~s#H!5v6ROVx)dx{I$^IkN-bGaIpZ}r6T20M#wHC_$ z|6~9iyBS2Vs=S{g|NmBE|2MZb*N0s9aDD&XgNYCSXSepRRq)wW^E4X5|J&>He*u8{ zKP$0r&VK(xiS^VIDE_0wN&^0R{1<>a6k7aWN~}@l*b5QkfARYKH-Kv46Q|)Tt8jhO zv}#pcn)KCwygs91U;QbFq=SZUF6lDahyz{jq z_}}R}VMRHV?kxXs(sqs){_3D|*xB~u>1U$N3#p2f11+0<#J8(2MQ(F{c40VU>!Pnc zq7U`=+;#t0WZbIRap$`XwtDtu>~z(nn~%=i=i~30>UPrGaAoi&W!9f>cl&V1hX2^4BGE4_)y(7XHu8hyZNcxgCY?W*UOw{@3kC{x#J$S9nIucPLexTX=A5 zX}{#><)`V=B5g+5M7d0@Bx)XdMnXoEBJdFJ`u#8X>a11K52zxK7x@4|XNaUvNV!-T zuaR!fB`XtziEWsNkZelP2!bFz}ftvZ8WH>$yidRHj1h z()-*cwIe?@qPj$tE!(|M)OUUl!)LSuYU_F4CIDtK7b2%97s95gE9cyDUnC zQAB+$M+ouK1%J@}ULl-fv+-A2&UmM1!~F6s<~wo=?Ow?GWUc1Z;M%`648r23X*cvp z7;GTvbh)zc-r({;Zt26f?ve95_@9J3^@d24NfmeCnkb0F*sun-R9C_!0HtH2-_-yc z48#e~o|+c>v(sHNxCD(@xn)gT{zwOqIKrniDf+6_>}n?vQxH}3p(m>~5cy%`-$xV& zsSH3;h0~?)Zm0NH?a!*WblOrAd1CFk^ySaq|30~PaCJ!4s)T2C&cA79HX4YQ`w-vc zDF;MpiNpgnW29R-cQZcMLl6@p)QTz0eg^ti(UJJ)K3Th*OQHfDI5GUYXQr@^pm6WSsf}e#9D%Qese~7)GS> z5=N>5_8972_}?c&zzd{oV0O%jMK84vjGthJtSbv|U#WNaV#~T#T2~2IFhAq=sjbG| z3(sGH3&-o?V5&FO9~T-bxk$LIL%&-=(nLCl#HJ3lmmJ(>d==3E04*;26+by60V`5v zK!TX?FhrY-Vz`&TcF_zecbfEv(E&`d$|=ATQW6!`iIM{woa=xC*_~t}i!iIS4#0rd zo*`TTH1?_tGWG_W?1)h5Z%uE2t(hAPx@Fu(;^=&;p&CUy*sNjC=O}oSk^+|I0L&(m z3GqL{GBPz{bcdIrG3?f!NTx~@?&mp#*y{>SViN#4siYgKf?%MCf!V|E!v$pq<9iA0xH zHsOp^KzEgCgtKIDGyqKfd_f@Kn=~gJ5Na);Zpa1q-@)G*RM(;Tt{qyQzyp%2jAS`o z`qH=vBX|wq1f6UWpdks-uaRjGQoXg27XZ~Gkwh4S^^6pF_%beuh<3xnQemV2peZxE z6OCpO^d%}}PNw?WX;?FY4XkD?05TbTOM3g5Grfc4!~tAs0EyZpn~}%e1S=RQC7Ms^ zm%`c}b*L6qRr3}Lnli6yT8MqlZmo4wRraE@#$8bc4$z96(9Kzx!EtdKlq!>3Wp~0z zB6z;*RW0D!T>5bNhDV3vp0$dmKCD`?GSmHiFLoCPd;!6H3kkGm2Dspk8g5n1CudPX z52_gUN4XCW9McI^;x@ICyRUsQ%{&H(pbWU6FJ;=xNt~$<@PRek?U3(v_no6a!hZt%3u26Xr_5k&plU*$$Kx5fl+J^RZwZanvG7;v66 z)0shGE=b( zMFBQ977#CAR0JerYU>yfzyTnopq|Sbiy+#`NlS3}NNM;V>K2Luwquc9=EEpesH(54 zZlrYng7U>sz64BtRQ|q57)=fN$A_4%6rwEHQVHH1TfZ1xbT=^TQ!4BzhE`xZTsf=% zGVsJ|2gRe}72`W%>Ed`)+!0~2o>g+14|**My)fGSEO#(Rfb@ zK%5k2a)FsVia7(KxvUOd29sm(<_nZ1Db-5}fE^3+ivd)!x&sg5`~Vm@|5h<cTuDg?B1{znrVOOIF@7e8GEfTqt4#B{xQfUTh7k!HhRSbUSZE)yJ=Fz%bb+E5 z2@(|kA>*JY3;E;o$0#8SkejIxB!k_#sxxv&=nsIy z1@gJT5hYaUzbxSbF_E-1=@;a)j2KEK$Ke250o&qGDv_Wm&7z2X*?3J1i~KJKU~oZ! z5}3;&%q)Q{XYXdp;@#yGs_LrAg$2BtchNZ?YYIb}{8d=#1}BJtLmnbHoU?jdxtHi1 zc{FIhKY4$E&3;0R$rADY<7VLib)Uk~A%v3#D~Si*P)u0_9~L?6yxLz5g1Hc0_rOLX zXsLB-Acr^?hjIrf|2!d?a*37^?TRbJ+D%D6IZSvfpcvCL1_WPl^B5{e!p z)s8{@i&F^7wFY7s6%(p1gftG?8&GR!-bj1j4Zpes(E!R^8JaAiV3MlrQa%xfFcPvr z1_wqHMA9NEo+q$IGrEhga+)z30vjf05+Q?y4Gq18jxddL@N?jxuAH zL&a^s>#H0dF~h@;y50X#ALW1f_^T36C6Y7^_?&pW_|B}T#2>E7&QbBJSKi3D7BhBj zbZeCGX>M^GlkBrFakj@S*hizvodbt%*TtrWy#G2d(THm#z;9 zJ?83mgwJ*m(}dPl{u`561G9;GQngJzaBjpRs5Vmj;Wo zd$cX8DWhxoYf9xBbR3^oy4max6|v(0FUK58pI*a8SBkzx-u~YGep}Rhr=Hg{m%N)9 zymWG(@+terx{FJ?b^v?2W&}6Pq!bY3s?4ccJ?HjHT~Tk^N{^LyA<8s#I*3x-V`*j88aGnj<5Ip zT&2BGIDdw=v)kq<>du~S3+=l_?kkT5FSlc!(e0{^Sk$z&qe<7P*T*OEqvu?YKIb3D zy4`Qw9KBwDmbxHsk>2S3oU?v<{nz#Kdb`ecT^G8~hOc(}^yZIrqqkYQ1WJ>mhj`r$ zUz=;kR=KP7ICZ`9>J{EG@4B^o_k5E9hkvVdj-}ly8S&9i?CB1UEPi+k_incf#|lS7 z`SFw_md_8I{kX~rAO^8~?oL)WWqZgcZ5@EA0K+c7L8JTBQP&ptqq;)&wm8oA6TP%9 zfmXGL=;`%+)$CV}w=*N$c{GH8c|+6jPOBzQ673xZUwOwV+;;>MZG8QIr`-$Gz2_LV z;K#__ro4Ga`|pW6`?6N~8p`|^jRvA-PFY$Mau2mIr?~1M_6WrkBj_*|8f65n zideX<%0E1xl+FbR+;d&4++!LR2d`%7I?vv*0Ydn3;K7d9t0SfNWHeXnuAEt(;4l5*2P=#D7;re0H?THF1CiPgp<{aR8_3LMt`KRxH%bh}m~8 zW}zjdBdg7HMq1@W4+-eNf==iq1`QG?criLkN?RmS`}$xU5ZgX`w3UiV?g8xzz4hAK>abEFmaP-rUgl{%0>Q~1SsPVtgt(c13 zSZ~4gKS0pK_e@M*hT~+ld}nyQoNO-k)+;&Zry$Szb8r#u6#d#eeY0oVVBiiBxAR+t z>F+k>LO!yB0zKHpKUD`y^0!=@^)|v#3cBMV31vG@-asq3tDHF$o`RHbnH(K3nzAR^ z1EAddnVjyDl9-#aI2p~mVSipfRcMKn>>-r-7gxMV6~7_v@?W#w1+W#b31x-(Dc44_ zlEQK5*4u2RRIS+sxKIwPQ?C7-fNW$WGsJ`tWf;sM1j^oD*H0rlru94mR2#!Ttn9mw zQm$Tu27YGN>|YOKgxB^}R-V4K&%cn(wnN`G&@kv*)W%3eO_!yjT;O?0jwfDH`!?+`sriT%>LAOE z$R;)a>Nhc+P-iz>d~AQ$3bIyg)sqEw{@Q5o1x0Z80VsI)Lec%V@S=!(AJ;roiMSR6 zC&i#Ci;UugFc+wRL-=xm62sWL=rH(iZ`zl=@OLY}HOt_`%e*EV58a=p|8b5EON~0M z-n31tl9CloM@tHcFnCFkRn21_DpkJSNGvso`&^s-m0xV?K_rj* zoQ6o{GYlAv8nYt7wY^zus}mD3?`vTPL&qGc_5It8^$@q_>92g8ILl&fOW;l@fDD9) zyUpau162o1LF~x|7{Kk<`vSNU6ZVp-A1MLc7gt07Ob+TUzY%)a@@n{q89>1*NuJRk zSB0%6LMA^ZJ8nZJUORLX#$b`B2ELLe*2-%l+6^4(GoAM`+q)hL?&~=0-qa)kb`2|D zz^2Kl`Sy|Inj<@C*JO3T-nFbdrunyarTZJMYy0AFw0R&sz+~(9F98f8ZP)SgiROUA zxxmG)vV3u#RjFn45XdLz0a(%1;t(R2xE3B_ ziQR1^$^Z@hp>-BP`u^fJoK7t5p#C%gUKHj3)CNn%hlbjA7x+^7qWloWL(wkJnj^FF zeTO86{<_?5#AiGT)-hAn+wERds`%Y|xM1>9YGKVJ z?o+c5=YA#ReH+YLQSj%-uN62PwMbz3!QnwT^LtqJQ$sAe3nWL4%MMe<1u1o!%bGes z$74#f()>-?_2u@*I`SS694#ozLGxym|Lt)C2bYn3igTX*SL= zO~Sw*m{d^Bz+mB1lIM~00&|9fP?3#$4m9lS%Hx_E0y5O~%;kxuB44+&D~N^w+d<5R zmkvMsGBWP(dLwN6=7v?qpDxyuYmS<*srx&&4^T`ZxI|h_hgNLe4u%Fuo?-?T*l>yD zmO5yBEWk^`EioIb*Cc4O2?!PO3-d(~S!Whgi3dhW797&S0Vb;`YNXyohrzaA_pWGz z!vhU9#|K)07)Xwg=&{rUsJJ?CmFF3No!T>I*+4PT07=FRd_l%EhIi6GnuIVKbZe=I z$@r^XvOH`i^Crxs0_62gNwya+m0YZV)UUKOczMJeG}B-+@@Rpcu?|I{=3l{WX$_td zC16M0OhU9l&&i#A+9(E>P}mgFw2{&~XO_E}Wy znMmlBCGuVSMLQo_kVt6 z=eB%JqIkf*`D?~pg6eNelK{<{W}u!P>emumlRt*ECOIz+IlEx6pux{0JpaQ^?A4Cg zcfKBO4ktR#pSyDAa%AJ`*L!v<-xpcpIM7NDZEcA?I&D}gF}FUNw%UGcOn-9JS?kxf ziwD;>od1k85FZA`FWY~+)4W+q%i&y@#evnBExUfC_NZZ}iw`dC<}SN>JazMeow-r- z8h?1Gui4={yl5q#5QwHMREeby5faGGan};toaHZ8UWns;`V^TGH+=s6+sn&}*X6Lc zE`N4o>~f@Ybj*(`0<9J>^*i2h<-%)m>n=pNhT^eFDYN_ub2 ziYEu{IOT0m|ADeRXlff%w+WuB&A8aL@cxd-yC-57ZkQgr5!k#j(v?PCRL}TpWiR3LOc345ndSf4*J+`HF{lW)s|HMAN@@C7a{Hb*_uNn+> zS!SND%uid@W%%TFa^~5CQ)#IIal;RfWu9xzU!Rr|_w?zT%nMhi*7HPhBd;v8F5SuB zkkJ_T>_c+am1k2MvU}s6e>;|S^;7=Fyti@x{CSggeQIhWPKsAd!&ccHngzTftN0h{ zDcN1de|e<=@h^27vwQ3d(koKpU#ZH5dl&vq7mMOYEv#~GE-Bcg5_ewPrsUjS{&!PN zZ~Pm_#+*Cr3pUrjjeqO@Hs@ac-^~)z@-ZK)-20UU84Xs;-z`qbeR%M1MpMA@_u-AX zgRKQyT2hvOh#nfjY0BPA$>R(UTp3$wee625Fp$$Moyo!u9Z@U^Nj@3nnlPJc?mw*znU z-Y%TZk&6<(*IVVkTT+-i(3tS!L`wdL<RJB&7aEcnq{nEx?l#h<5d3w~Xl&R2?7Oun)z z{C%ge;CthWsShfo=-G6^c<+k8-x>?2J{1;DzFjf>=WXHi)N~=Bfq_OCWQV~X7!r&T z;xS?xM#{s`3QVmQBe!7c?U+VCra6LXeZ(k}7*&IVPh__C^m|Yag_F*P=HK zPrewQvn1mzoo|WhoNRtC&R)N4`)4WyW_uFASXmyIsO|!zX!*AehiHO#_u8I zH>)lH6CN)|XB*x2OGi%ryVj9Wbz|Yv?t}>6vo@-1`wIEmxzi_>`ablww~cG9S$dZ5 zbaLXBe{x#utJpwpOXI;aXNuW=7ar`0YQIt7p;IUe@THj$X10)KQf@-6NL6!DQSZJ^ z+gUqXymF!`M*}>9_ohk{@-lD8DVW;(zmt8N(K>tVmK&Fplvq<1df~}ZR_I?+_WDOWYLe-BexE0|ewd0JApVy{SX~T<84>b1}9bGBd z+3s}WppET3?&9oz>$58xG?~(aQ0t|LUh5C~IRf7eYF33Z()5ZTTR-i&H*;B?fqPy$ zwH!)fEq<}+m7T-Ewo>Fu;O*|?t43}om}!`OBbf{dR(!EpNdvRxBKtnw=eKUQnEUS| z-+dKZGq1&F;}b#rOY8PrR_Z2eZCUHUOa7#jgfBo{y&yCjQgd~DJpmwGzNJL3 zI>J_)i6(%pZ5+R#jJaI`5u*vz9OumGv^4q=WJebi4WB$wbm+&K-4AdziZh_rVSiJ{ z;Y)m(Aw!RWLR;)YHmaReddy+j;f9i?gq#5RXvj4E_Z$;UAapHtMG2oi_N0}cICExB zh0&3fFYjH}Aiy#xbyMSmi!k5{TJ@3gI6?V+B((>pa?jl8Y7tE~+3Ya7yCZ@wY+ej7 zsoF9Df6=X%i0?}>!H*Z=b-ZyKgOFX}zrk8Ftj_1qalk88Fc-jmSoc#e3+HC@&71IC z{N#2+>YKI2Rv!KLF64TTB=d(9*Q>p;F0U0_^uw>rb(##B649qh5~J`j_{|=1GVoq1NpN3lqn8?LJmBEAysTh7v!<-+W}Cb^ZkM* z+<9mjb!;$~RaE(U$i8M9#M$<TGTDDt`<5o@lNdak~V#$UzIvdOuwY_XE zz;LrBh{h^|R3jr(V8tyWj%)1pyZP+Qy#hJ`z%-E3esU9}=~~y+Hg{q&5)xA#T+dFV znYP);kH;EPxkYq(tbTM@^HpM#zdU7Dx!MO9)B z$Nz1&4PI`@aOJyOUT!G@m&IH3&t75YwVAmsq=INRY?{`yu+F@zMcf10{Nss z+xc*VZXXUR!Fils4{HG!&DT}%^8)v5Xa?XhpPO$^f@gilDIrPxJ(Oc=g+%n=^0s9z3_#;^FcTM&SbQ55VA+>s_*|eO zye|54d{Y+Ptb86e}#5~Ics&Ha)3m|?HKsVTu~S< z@EJm!<_MzBCuxfTN8VApA;d(cx?v$N8N?LhB$jYp$Sl6=gZ?xjM~>U$u#XZ{*%gMU zLf&yehbdSl5G{FGr9BS3R8@=~!OdC1Y2)lBzMyRRSCPG3p1S{)UQU@|@iqe-085`P z&BfU|z-KePYj~wGFDmWlvlxB74V_J8o)65hqt4N@tg;0KpSBqX?qe`l%#wj#bg=$B z_>9xC7f*I%3YIL`y-y!6K?N%d$`}_@QvKf<(^DMrhKIPoS;maqB>1qPIO8|qPc8O@ zw`U75 z7Je{(zs-rDw^J&-27WTWuJX@n4qSY0MqXcc3GEf*{Xoj|FAcLmEqCc4`B! z=;vn^r{WViuvs=>w>{B_S!8!ncn6O)#rU)PKy@~LxMc6+I~Bw}T&Doi9Wyk^-axB~ zHTb8(h*eKa6+l$Lh>jDLe0w@*%46vKHS;fhLC4f~WZyp(qvnIdy2izN`vqW=X{7-; zJ*(*}F;I_|itF_O`+C4gw>T=VR5(O(#qrY)YJ0zuY?LO74MI&8ek6G;|77g@HGqBY zE7CaX@YhV2cVAb@HQnyBF9uqbQ@glnLuJ&=mZ zo#~ox*@)+h56uU_KWu)11h?dVWotpRwMQ608CkWvQi5I>BqjhhATWIspbpU-h5&~h zTaau4F&qC@C$N+WM9M=pO@N(}?=v5UsGI*Z^K)^)fBgG0hb%8#@N*dS$_C?1@fi%@ zU8;dVx9JWWl zlIgRbexm8jX)#yR?XC&x;gnIMY0}^mP4T6%9D((#ZCU6wsPe;>7Y*dhg#59m8v~mTnKEmmAFgulg#|ku)19t&X zHybCT5RCCJ57lbdY_nDhZysG{cNZX~l4#Ls2oqW)!Hw~+dNTNlD>yCTd0~K>l5Z$) zu#@rW48C&>fA<2A3Y5~d`fGsG7NvYc3(r*Q3#5-m(&9K-v+BtR!X$dIc}H$hO#qFG z>?3BVAdLCEoB2(0tJ=kJe-f2*BeY7_WfI4}H27=Ia`#N;hhtr3+C-i!H3Ie(Ya1pE zRe(qEN^?u*&`^LZpfZ2`89Gz>pqE6&(&!NWx=WqBIuOr3eYEqzF+P^IukHmbFk?2g zHQ%33SzN-4ZiXV=Pr@Ezod8xY&vzuUdg zePs(n+GR>X+{udUGtCJnj8}HIec78?k}=OBOX&)B2I$SDg|WSU_g(Or`9o0^N(iL` zCLUH1MRGOwfmfjm|0tEddV2H#fEpAA;^^Oxjw-N1V&$LlcjTe}Osf`gPg!IOw#YO; zj{$l9X#W;c_AiwK2SaJ*&pcz$ojXyFHZxF5SZ(HS;932cNb$gacWX@zOm7Zdh`Kru z0FQoYO^HXtY#9-YxZgb^A7BHJir1v*8%h*)UU78U>=OF>hdVYG8|E^Pl-XQn)>pbs zFdKF*aJt+=Exdk7u#NislB10sasq-Y^JN8lXI zl??~FbQUyi187XT{2o)O0qR4hH4OWh0*0i83O7x+L+Ta)E=0jXR*yy;fc2nusTdKl zOez9EBA~?VOanQeb>pPiQn}p_?rTJqb-?5b55^v|&14Qi9sE<)>HSjcCA^e0wMKY1 z|6ITgeMwO?kqmqkVjyv>sEA0A?QCd$d|t0xE#1}O)&mzRfayEarCm&qqFs=_V-2TE zpPh%pIxc-~i|$eL?9;sBr1>Pk{p03DFLrc7@$+ok3ltsNxyK8*(AkM0QcF;c5g+S;ZwLOl;tvvf$|RZvxdOU? zDx%nla{tN?6Sof#p;Vl(8UTRziP!9c>s*grlAt@jsb&zWA8>J7qFBt(SYE11w3E>= z9%MHTN5%kP<(Y0cpOy%mKi&!0bi#HYaY9~mXxSv22q!7lrcB@&$5x+Xv@0~%QNeNz zjHpq@_I`MUf!dEAU3&U-<%T>9qgTw{1rJVd&uq6adDcWhCQqQeCYjc_1re=&jWC%w zdQ2*yHAvJL++fW!!qY21y;=nX>YrnB%Z;l+(h>!Du7x1dtzJ!v`_rjDBESt*lw0BG ztV`1mcJHjes!%ti;&j1J#C2p{DE*IWcH^9=Py(6nZ?R)4j({FRfS7~(Jp8VAt2_}| zb>{0*FHV(x&$|yRmb-5!+A(&LFn%;q`mF6Z3)ZH~C<`2A`lXxf5A5uwFmai#r?N=b zqhk#Z?6`eRSwvPcc3A{QJwp{U(2w=$5lZ&m3}*qk-)gZ|E~W{n;J2G)JD;UP=mp(2 zitI(!SzE;l!z}1RcZp>2OupG6YLVf`cTT6(pa8x+P(=(@5E(L(8?C71ORuX|yTPk$ zS;t(b7lgSCoF4y}IP`*{UTJ&hQ$|U#3zvWF8hl8X!-0zo0X4n8CeO~{X_B84+j$B- zyy?;Wrnjy^8lmHYO?zNmYk``YD>h5_ti0$!%stnTnnlz(NsdMUNU9qP(85^4{O@J+ z7sT-a%Ur<>+FPWehfhTDg;k}plS|}9FcTNjUHQ3>pUP<_QsbZWmAV>E+T{(-MSWO6 zjP*sBmdz?B`w~suUG4NFa`HTrSOoxWRy~rB7XZoA>5=Nzh^a{+wukVh#O-%8;Cu)@dgYn}lQvvE;lo35y0^Jq` zVe4_zycUS-pLnF8eU-X_-Ulryr}*P{A0(+yC$ng`!;0ycdE64_I+_2z3#w_e#x4A= zq)!R@kKdwL(gh`oFn;t>TXj_kor-&d{3|3INUy+aMd#px-zRz=8}I-({#oFc`AO8A4@<9aY_1cFeI_E;p@b+}8ap)+Ay?@2$(Lz&k)#`;k zX1(p{j9uF|pJ^MN%e(h*A{#<$d99RD%Z1Eb!S8Ib8FR#pkd)n991{64yh95yrK*#> z6!SD`n@u@NaNpx!6!#x9$XYMigwK*QyD2hY)_l_r0?!_8zyZxpu+fX7Ytp?ENKQ2Z zc|4N9KL9dyb%Chfgqbw_>;bG(&6hQwc3S3Ct1H+c%I>%oG<4GSUVv9^Hu^3;5OJ2= zI#)8gO-HZICtAjS*KKa*c9rn_kG!|f4^O7NIM`7z?XH05j(6x@Q)U|_>aA2I+SMeY z=6xbhmlNH25)558O)UZdo`4^;E1Icv)#7nVj1{e@7O&Uc~L@G?p z+_!Q8i*M>`ZF}Y)_@=E~rZ3HCyLX|3sv=9b(Vm-9(SKBVkl~v0lD}jCM6{Y7sE<`5 z!E87QQP%)a8H@yjL0@osKcEHNSk#87MSxm;zRNu@g8@tz1BQb^b5|hA6{K-1z!n?~ z1fUUhG?hUB01&SpVJ<%Ldk~LU>Rn1Br;ey5l$13x@(6!mAv?ah!*HNSpEDhhRw+}z zB`;}_sUv)Pg&?to57)|Qc;^<^ie6R30NUxRoM{xO_Yv(NVI8@7Kug0N^8T5d5O(y! zj*$q1uLBtS_djU2Y^D_Rs@B%xg^INSO7uOiv|f_52=ynvmH!jpWFS11yijL_)S%svR*)QA0 zz>xtQ8C$MCp>^A6X0;SA<~)kI%6GlgNoCz9eV+zR&`!hee7CQ-X*{eXqk$byPxdtgLd_G)#NT08$%o5YijNj0_+ zQvs-y&1}I3(*RUjoAgBm^2&e+Z`g?)!3cw$FujF_sA7m3iRneKd&Xll+dD#t+@R{>8>#O$yl|Y+^OP1U0zr%(vljG-V((Dx*c;rq;;FxF$IjNWj|Rr9+7eGh*fTMWVTEdrd$?E&yQ0KAl{nE!23M>ms(z?juqrty z_P2~SX3^Fn10>VS^=q(`nlkbL;3**no{SfLyiMkntt58Pn)+u-a4%QBd>r;L>LK}3 zbu{lm>-(7%-m(2!$Cq=cr7~vH!$pi^R22M`258AF%Va`N48MpS^1|5nnu9a*?&RQ0 ziK++s$A;(PSWqD>xXSl#xbcOxFM(a1(j$@g?-^(87^w|PNtVsT?v*%o6W;~xjlV~{ z`sUVEwsv2GX?uq{>uv_ZEkN-Dj&{D41z>r6R{V-HBQ&Igd4H6yflo*RL>)qr{}|bK z`d}>^1I+<~25y>BPi+U$c0Q%3=%$}p_r4u~?9DA2W?KsA4J6%8WWP$%SZXe5a|$!1 zVcA1BiHRXIE8>0cS|5DWeDJyTA)SOZ82IxNq$b9|G&Y6Z0V5rZ_d&LDgzcs1vSe24mddDNnW0$qz=sO^Mm1X4KPxS6-2sp!(?ZOKHWK2+?Vtv#_=*k< zv2}VYNN{D_jtIRX0Evs-(#{5{c&;<}zO=jp9xI~{ZAWQ<+Qm*o?mwwbcc~rkPuInR zL$$hrvL7R5bmonZ8awxoR$fIwef;2$8h=6!NN8abMtwX>r}6h`g7=cxnXVm2cF8R5 zLf?yZZ=e`22sgmkl)B!A%t3~$?8w>`d&6XK+lQRK4;qurjW;ZEUHR|3pTtE1CtcnX zjG?0mRFKQI{Vx1}XnXIcrlP-5cc+J*&_zlpA|NG5Zy|IPL{OxQ0TF2;y+}(S6akT5 z6eWNn3L+h(h9X_12`H#R5D-w24kEevzGvpnz3-ek?@woD{{d@0d(GN=eaiEc@DjJ* zo-3TU;F{9|vHl0^z`Nmn#;2RrlE@hTfcjivB>G@99~cdSW3?^Lg$G$v->R;LPOkmj zV1#28vcArV2JTZ#VBAFLI>4Rk1GVxxz^_UYKp;0R5R`PwRnH%X#|*d!-CKod18HMR zT$2XvdeoSu&!U!<&osM!u2Wef0b!3K9Q9l8@efw@F3I#RQ6%te$klJ~$MZ>coVp&G zn*7>6kFREY`72bj5QsiTZO{A}>}ox;DVSO2~!96JxiQ&S49 za=q<2M8O-Bpo*XQ#-4oxSq4DS)Dgp12ZXnq-@dx-thjM7R37PIco{#axOHbJU)3v zs_@-&3|^P)$r^-ZxyFIMKJO;fUzpBUTv-D4ev~AM9lY@e7oGPSKma{`lS)cd6*5>SMQ&v_kpxvTW-n;w$7#(fKZBR<@lDaH)m7FUPd*&(W9aRHhY0Oy*MBA+I{-DE!s@&(<*P zb*$4hwkv*55^8n%Em3nN)z%I=?B-@6;Y^~%(5Kc{5mB&Z-WIexQ zS#Pist}{?RuOME7^$zP0N_vCIdZ39LKMC6&@bn8xpEGx?OWNgA`})gJD|m795C8Jk zIdNvbQVabD$$vkcl|SR>xuT-{KG2{?QMR*&Uuoxb$|me{m87nch6BGP%_3E=XN_L38q1wl0=YwQ69LNCCz8C*%CXd4f3J#At3P8< zrCVC>lvOXwx9dbw7U@)BldDIUDhKlK8khuGga#)*2vEGcDLWgWe7dgpPpzYfs>t6u zuKtERr90MuZdAnzRFu%8pUDN!V96dbekdX>*coUmDCFGOX_^eJUt4OQmS!>HHt=1-bYip-gTYqcY zd#(2A*7mPj9m}m9zqLB|T07}lR74w5iXYale*3e*MP%-s|{H z$88`wH#l_v@OAzX(cL`Vxv8MLrPjHntGjK|xqVT0$F_6ln(pq+&fVL(d!e0sF}nMS zo%{E75Ar$>igXX3bsoOb{oB;}w^R41zw_w5?!W2Ie_wTvmphMt>(ci+>5yJs5`>9Y zISl2ZAJ1|^HE18@YIv7R+NM4XeckxpNsW;0eYBfthWNQ$<#5g$=X1{3HwGPWx|dw}k4^-6jFq0tQ;iY`_WDp^-xTssAjIcmo#%98)X7la z&#mEmyZ=sx`OWv-qu+2}amskZdo>c>$A6R7(AEJ zFC2A*9>By4W)6tm)8-tM$Z^UXlzbG)IVAP8Fmp)eWgF+PY{OjUuzdRw=Lq(VVAjal zx7u89l|MLTy;c1j$@NbCdtuf)&7W;t@3nX4vfktV9dV7~VM5uX`fNJfV}?9ev&W2u zqPWLRPd&;WKQGtLJz=i$IeWrF=O6c^rIApMwZ;$or<2ypPZEW%T#e$Hvb*spXUgGL zJI}OJ@aLRq=cs=?GlY1d+!@zy=hI@@ zaQyRR9_Re|1fgjDZ%L;f=YLC<>)>BVRr!*?kfw9YznE?$T(FpV0axH;W959}m5qJ$ zL8RX{sz<}<`*-+MA3!zY4IYDMflx+eA{1WC6uJlzdyYBo zp~q3v^q6)C1xQrGTVVBspVQ*B`DgG594Z!_O@m6?>9OFjJP|}agwJ%*m1Me^LrM9uyH@0H+(mXq(heEPwv(>Buak^$Pf8Hj8Oj(CB*RK{iHaC7V47ZT-cbau z$VV1O>ig+_`Ro@HzFsUGIA8*1e{~;gD#ppPZz!#5B^+pKMCZyG7!X(G%uLO8lMvT9 zXNb!rE4n5E!uq$vN$%~3Y1%}a=0t;ARjQfwXhr@b84B6;=u8%WSCt2Cb)!|d@MFr{>RUa zyR_vZj5mw)I8y2)K3OEy708p{APSXWOkzi6pX@Q|X|FvWHXDfL3Qs3vCpMbR{PZ~+ z@N+BLl{At@~6PgUKQRVVB+o##ew)u$sr9| zU;5rnR-02jW%5U3W4N23SJOR%JzMbff?uI!*HR^U?hil{eU&&{8txBuyvE5%fCkX`5 zLOf`RK!J-7FftW1h@ckri_pogr^>32wL?b88rUwRCq)*rgy|FK3dw-``b$0>cyBJy z4552KPwdnsn<|HKnD`BlrRRiM=#4LH%Z&t9LK2voNzKZBJ)mPW3|>z}`q~lKIB6v9 zY$8aRMiqDSBl4f6KtKG{XVN5sSOtrrcT53D)hJ2xNf$C0dA3A6Bk9n$WrD>6B&&{x zOkGm#JR8;vma2%iO{KqNzrO;oaZ(Yd0}s)`ra?E0$_-1Mr=~rTO13<0G*gc*7*{nJ z{7IIg_IvC}d!U{GcQrG7@|(Z^Q_@pgbUdt_7(%?>1C|&AQG@xT`EL->kt2ZW$aUdm z!={$@3n`k0-{66xU>!{$j*|=o-*oS0<|2?|!e-}v)QP;u{&7mECp~m261v;T;*Jyr zDo2nZod~Om)kIUZdKj)BIO9MeVy5SjoL9+0#&74@gNh-x?+@8L`~X$_p@`m6kM4Ru zQA&{ZjSjDg)58gGK7P#mdn8bemw!ICo)FGr8tS9wKfE9kUU$Fegpl_9$4^s& z?}9lDO=C||H{wn<3$t>+f5dX0;N*qS*m`K&v#I+ynOD29gGDMT+Exl;k^ifZpg?PT z*N3Ij*Vjb&X{_4o@Z)(vA0Kk82ebSI{$_zmqKPyE2hb82fe3%s{|i1ySz%d6rM{&v zL9Vb9?sY%+ZM?5rb!*A33$jEFo;=OUN!hlhA-<#`cd29iG)_+7Sl#E#B()eP&o)kA zcY6WbR)9L|u~oj?wR``ba1pdb>|v+!a$`8H?=zoZL@Ws-e*reRF7l27;$oaWRlf}7 zpYQ${&X)U5ID>1xiz&f?rurd~?|hkEqn$Q%+}EtiwSRc^HFZg*Xvw|XLhx|G>VYL2N)HwV1ae3xd zfYmi)pI?kwUIF?#DTCE~B>ycAjK94NhaBUhoCu%5&*B#oe*ua*%nES2N+r7oBHLyj z&S2Rz%WzaG3zjGCj2JB*$PulQ?mo_7-u z|4f8CJ!21fH_Ckx4#{5lzg!sha{n zvEB0HZ)cJp?PAsus_4-g)LP-#>U{HrxV~v6`jQQ&$G7)?ZOr;XcJIsT7tw z=ZBG7uc)S}$6nZ0BFUpNT;P1`vCFS!Dkiy@%Yn*!_FQq_4_9YSbk0=3vhhr#n4j$3%+8`*hTfEtfvnwMqHA$iR?8q$D{yp`tnHR;6w7Sn zkB#WlYH>GJBM|U$g3|LJwTCQa!e{O}uRguQT<1GfBV0lH^{f2sxff?WpDzKt1Uxe| z7Im!0kBF_XTVa%3p20mIn5K}v6|>ZO9*!pK?z#ulxoLlD(;i~at9($>cBs1_B%Opr z-zT0nPJG6zF3P4Z{rsDr$zI(H?g5j7t(2s5)ZK}qBhQR#&Nu>|NuF}0jUxNonB@tT zt<>YiBIsfLIlRU9IJ?A0*2aEz$~rTYv?N-$-@wa5WKwj}(=W+tD%=&>G8P%kx{r_+ zKkD;^2a5#Hi5}pY8GYbvVqke1YY#06yqbPVFIDE2`;z{5b_2gYF391=ZRkbwu>~-* z9ETUOC+zOyPxY!PN$tit)@C29>9lA-BvCcF#K6b%Jl#}Yr=0eD{2yPS zYpHvL)4=bW2fsptj{6{}CgZ73ooZfin9qbg-9NCUq@lR%ibF+?!z-1u&nm(zuQ-Ya zIzId0Si!>O$|EWu%7g{o=~i)kQ_hb3ATRs@d-lAMZMI#%IH$WbAWuU&pY}fdaE;z@ z?SO|+V@v=w5?(C@*Aqb8Hok(fJTHu0#6w)3CxBc}1LTYf!5rs*-8aA{Mv7I=!wb&$ zcEDm(H|cJ-%QiP`b8k3K-MGfJ(AUok#Wj zayRYwc@K_VOg!ybh*-1R$npY#5Jh)$Ax+=BmvAO}WGGI{_|mCOf6H?-$-_C4RETmI z$Tr{2;YRFzO19v#&{fH<V%vg^jMl3(&)Uo=TH0PgJ)KD|(np`%iz6Hffl`!?ARsV5Lmf@7!iU3$Y}?~TEd zFke<@(lp$a@8hGWz&!K*eJgimqX8K5b z+!^l|-_{4uSUy>tdvnXXYxC~}UuGDx?TJFj(01(uLw9#KMK-8H=1k_`&i){br{PHJ z)n5j>)4u4lVaYtyxB8A7@?Gmish5A%a<;M6e?PRTp;62WM4jZ7fOd2wvn(ON7(W#hqGJd1E_tW_#_GSv-O?h__|d~}>lo!gzk z)UVh$VbTLAZ39%C?+SN1g+b|rzF0}#poER!qj~Yzs+CU+qxX|_28~m-YWqJx&Ua7- zoRh)o{9jB?)vBZaU_9S3n0Ww_4$zqdO{*zgaY!y1r-AC?oA0-Mq?Fb3|5uZwbt9>r>uIJ{5|5O<5mV#K+5gfcIi|0|nPt{3pAP>o zIAxRVDd(EPzzyG62;;=WS{QUkOP13Ih(#904J)4oIvD6Mj zlk}c$A%?Br|Bogq@8iPPBvQ}xaM8tU6-k>-D%1a6lZ2Ek|1UTv?f+nh&-M6rSL(mn z;r}mdk^&y1b+Vc6k^*8q%oTi(`tJVI`J)R6Di_L%AEm)qm!YCpFp zEKTHg{zp6fzjfSRvs_cot|8B!?x9r9-dtoJy}9Xf=g;j3aiCd?@KC17wa#6d8B0wW+vCZ#2WDZS?wLP?v5ymo*tLb+mxrdS?5TmzzaScMM8oRo3UP&{jxi z7U%D`L_gIfgZX%iseQUjT5e=K55}+;`s>#1i_7AK>2%0%EmMJG5NOx_H&JuU$v|@h zEjFo#*{}Po+lz>cQ3lDF5kz)X14xK&msrj*L9h%~>n=1MGiE?x?i?p^Tl9i>uk^t=d9_CT4Rm{DG}UgFh}g-i14D5bM* z-112PgsmI`W+$_;67h&IJJcUV@_n$U9+aEY7`xt+40#S5!#Ud}#oXe+cdzU7@88GD zOWfh#h{da##$w565ErV5#r!TBimC*k9u+6^+x5f*QErM?f0JUiN5Pzl!WACfNLN&f z7#;)0LZPhV)%U*^6Eb;!oRFlGfCW=uUK_vnNEypyE{99m2zxNUvA^Mc*)(_hinHFf z3z@&oBvXii4Alhaaag!0nA4|=PX(MLwX#W3uzv)8jU`FX5u=K^Oy|XBbyv3zRsf_kjM zj3YLcaQ~6OyzoC$2q1}SBY7>x8mo)yKO4$uJFvvWRutm5$9h2y?}Uq5A1;okHw_)2 zd<8xt=9^`j8&?-zKIJOJQJK}eBzr+}>)%a&`G1I+D}9-tGABdZ)#(1P^GfW5u-x+@ zyA-<|Oj2vVBS*lM4&UII+i%yu%Fa%|ST(2(t9a<9yJz=kPVTmi&||&bUE6n?D!vr9 zL8-}^nNRd_a<${NpG5z5nEDx3%ZKdh<_C&y^)>{@A9r|9j;%x#hWh z%yi=n&)ut{W)2Z;If2pfKX3j?$jDahtqnf&QcsrUV*%BsWZ=WP_t)f0gR7+?526Nj zjzDwkhkW8WAJ%2QtX^H{;Pw4?FX_8%6KXeMS~M%?oTu*J&##4Nge&snukHAQxMyg> znOPo&YOauztQ(zDyr#<=D`p8!l)G&^zlc_UKV@sqh{dl1Oag_3gwb5l*foEHwiKHa zTf4#n7CjDDC^Bz$Z0Xs50}N*5H}0F$iHGIl(8>Xgi>^FynBV|TqW|^3yFuKA-Y?V7 zoSh+!?$CS94gE|f1%_@3L;cAOg*G*Z_ph+d2rK){=@^3`ob?k!Noj-2-Ke-2^%7*7 zcKyS107;J74GB;Z(Y}5lw$SZRp@ce<)b#E?5dJAWKbF6l$Pr0~0-TkUr)-=z?C1+X zJp|A70F!_kDM9M+$MT1mctImwv+i2#ni>w<^7j&1N|WB;E-?dA`{t=wzf*dB;UtJP z02ZhM!17eMP!Pa%>H7fe8($&;dB$xZuv0#aRR)s)NfHJ3at}yJ-I`Fh2G|h{2?=W| zKt$Fv+LI{tmu?I6t2v}&tdqb{pTi6Yl=Bf>^psvKW;@M%B1+07OWmz__sb+(8(eIwf#1gg1$wnik7@SPNm~PY_NUzcMH~--S$@ z*^;ZSlBpEPO9N9*rn96&v?%W(e>_^=kEFkrHLeaKdeu~!EjsXm846$+$P%i%NQD_8 zi}a8P(u?a28(a*T24Mv(v_fE(+eVD)j_;n5I17fq)#E0lKiBwry&pFAFU<@w7~_L| z>h%cNO{!)VSH~dT2S^wY$`ENPAo-+J`^rJ`6n~{JcX%t6K9honK32*YFQX&S`anno zo|-GwtcO5Z;&m4TBxIWO(60DcmVI$H!1T6Iu`OeS?(`Bs%{vE18={~v(G6oM3{w>Y zFlPegaf|+xN8*~l${wQaXp2JAOw8R(MNuHsC{*%h&<5Pt4+uaIeB~9vnxh;96gZOt zJLw+<@rV9UyR11H0S6)8ghKXh)Oga*1NfkdiSwHKXlvyNfqYj_6BJa6YZ}gJMj;OJ zaHSS=Nl$`A`Qii6myF_km}=tBx>zaBgVpek9y5GaZ!V08Cj|Om*IT%OASGHTx+3NQ z_T@+kOc1%wJyKD_%{0+p&);Y(!SMrcDqTHxAAlR-%|d4QrO7r)NItemXsr)}DaK75nB6?UJU(`Ej9^8U>IV@2Cz{&cWLI@CTL9-fXY zNN0YX&iXN({U9B6B7;*SgWEoXH#~#CAVc7F2E)NFe2{@TktwE;DPey$Wx_DWE>nhy z_ghxxnS)HH`An=vmSz{+HqTL+UZCiXH}dYjukjp4*Y_aT z??hgJMqZG8UPyReSV7*M*Ljg2^P&&(h$r%6HS)vB>TO2(E!JvxX1KW%a+v*{q;EJU z6_{w{67BT}xaX*W#JkX%{49HQ^_lF88DS9#=*gVSw1Wcg9spC%6O4gZl%advInJq| z9zx-smL@Me)5AxVM0y!Y`HS??oYr&cTz=}OUGml!H1ZbjIE=X}nS>9?H#M_5~xUi`lHELqz zkMBU?n#2o`F|czO@Yx#0YWa97ABCV69z8dCVvPE-^H3dKBt)=;`kQ&|{u@rcEN%N_-!&93(PwgH&b!d6I2`+VNNlAX~ z^`{ig;)Pn|1G6_(nqQ9dE#v;fgy3yKzpz7XEdUP;q4)Y; zn%5Z_Szb5?DiIq(pE{44ybkpqs?t@`IHtV%m2@|Nnb%**Irw_=v4HZs;L^0>H0e{% zxkIXFlAdwGYPcP1cq3}~AJz!8)(Fnl2>-3YoU9eos+Dl8m5ivBYOUzVsg<3rmH(US z#8cdT+vqa#R{mmnYSB)!odWxIkFA*wZ1= zc(?phuM4vpI{;B5K7@)gU9Q$t-{zQxjXLJPS`-PSTNEL z7-e>b*D&izs26J8$r88S@I05Jbc@38hEZ)+9BYIrGC%4GWu6DDEJ0lij5ZNW*Mc!W z=~A$|fkJ~FQ0C!vp?ZGML{x0OmnL z$(>xa%zz(s)Ey%9CctkL?8)sq90)ul;~wsEyo~eb@CT`3y@M?~y`e7vEYx6BxD@Cc z-Q{?2hYO%cwJU+-2?;Kg4&*$N9SFG%MGi**4k(y0K)!v1?s|br0|vnKA-J6~h?NRQ zpJ(GZ3-#EueJ*#L@S zK$TIr(YvUv(&DpY9_EF~n?Yy+ce7mpjx}_&l5Ajcxku7My_0ZfFTOarRVYNeQm*DG zmc;Rw3R`0a6lvg}J}4Be%h8DJ+Zb&H+=<;Xm!fzoXZKz`iKC7RcRi`5 zY=^SMp8ME}lIVq{Tps}|vJm`0Jk?c*(b$X1EEU)r{54bXKRyCN{D#C9&9{0d5g=89 zFY9QCydT9cG|Wkeg-{Je(hzFZk%psTXgzX{F_#qqQh3$XjvIW}5L`of`Qsdl&x5Pw zb=bvQXhqbW@>WBLB24dxhCQ2p;!#|95A5>HkZVE<0cm2M9TvX~WaeDDe#k*CxrMd@ zvAs3KDT7MW;f6V0e;8Gt-GCTJs0|%k#b4ZUk$dK=B9u-rMp>H5qoA#M5cldp7^$Un z!A!JTHvx*?=K{5yHtxQF;wVQ`u7a|-VekfMXuWA)lO4ENswEtaml}qQf$V2!TwPiS z(0Qi4PcQGH|9YY{P;Uu_s6@ucq)r_vhti+{?+w6{(5VN#76@$i)a2`}9@qs8uB!(| z80{flK}o5w(6ymkdmQ}O)V|9gZXq;T2?o|gSrRK3FYuWWx=-kxcaf@+Pya6D_YL6> z+1@kOevEpFnsQEa>D-VWtrj&xYaU zUEx%^3-lj~#T5lbVplL|(33|Y)kCh>^mppKq8 z3g;L&23*g7{N0%Iw=VeSy#s z_$I*BH`2fov2+0)&st3Twd@`Vy==L+U#)9|vX=UUmhUy~4|G+vR7*j?ublp9rUK%F z0%R^ocpB<&wdZf&UuJS>W($VcDG&DV+Kw&1`*pJSRa!%x=Wg|VCY0wd zwxgRDi`rx8#;4q7Mn!w#cGrI@Rto)x6CjJpoKjzh?Q+5f#t z7}OT}Y9#wtd?KcXH{hPmU$M(kbv9ZeS0ldrF0vJ%a@Dvq4)I)EBY?Ei~8a zw=A@`CIc_x{%&tw#6x(3EcIDbwk_#~Tvvjuj86t{TbYXI1YJ6RreXV%xzdNA%NANY z+m|g3c!I4jnW^kpTVK8se8t8wc;|}U^_*ZE2k(X*8>hez!M4s3J3F?7IGzwY*A$gq zJGZPWA@=SMgLmycN^?RSyeb-Y9enCOggE-P?(91H_3(r`1q`d~IR#Bz3B4LJ8@zWl zY#}Gq`ObfbbMl4}Vp&x831lvtFqedrA^R>#;<;h2$!8k(T~n2&!mg)j?e1SsH{cC- z%QRCxaLc}I6MiGtG34Mz{`K5&_XpmM2kwP|Q{gusN9-Qlq{Q*w@hC}AJ@j~zWpl@~ z>|w~EXL)Jv9WVNeipE2)%DSmL-c_x;hu+mayb(UN!>WIM>L+X>ZZ*z^{Jqt@kQ?FK zvex+5w{2@G;-M_b~5WYyiZWgs8zg{leNdLZ*p-27$;(3t)LuZ$(@~-Se>i8@VwP=m_|n7B zw^u3-!n{~yUa5FjGGI~)qQ>bKFb89CoXKa!VCnLEEBaBT{xol8Que{Bm)Uo z^t~`c2}!HFW^S%rkM<3vjIEL{KXK)G8D=EwZk6J==*ri=Z-lK%Co4+3@Ly?0To{o6 z1hC@FdzjdKR7vVBZ5Ob|S+Hiy28^i~FC2wrX5Ftzj5sn8fejjH317<4{sR)>E9e1H zzGY~v({5vv(ig(dTbEtRk&~Sle8%wRrLl8U2Kr^a zJ%{bb&*n8vo|2DZN{#`xj00rta7hKI>zSi*L#a<6^yQ~>Ji$LG!@l8vK|lA_%OQ|; zcBD-8_3I0_6Y3r=Ku>FQhFkdOUVgNqd{gt|Yl~2?32u8!D#x*?iCy1X!H9$?F7LTH zajCAr^{l%-zZICAOGQ1igc_XqWSRI_jM2kYZYZibmf~JtBG9m6tn4I2TDvq7hnXE-ul>6$f*e>5zE-q&?{{B%8gDZ-?1)b+!-6H zjZXV?O_r$cJh!;vb-Mighcf4#=k||QZC-x*@WM-_lJMQjy5DQ6)^(@C<7&l~dk>Ht zPpFR%&b#BH(_>*M{43~wqVs2Jtk6+hk+x2jV5lV{xusJ6$`2+qMdhFm80U&qrLVi4 z8RpQmR;|nUTN0{ACC(W_T&1h4HVcd_a7Ltu^oZqKnyAxf{$Z0Ee1}R zB5$J|h_Ik}20 zEpC9!JMvI;k2vmQD?nNn0|W09VK{u8ylF9X`znBR-Y}=<(xqWH8Ssh24JRp){hEoK z%3%AHt0NZ8tq#s|y7lY!92HYTG^3xMU6D&;=NpB&a;sDJ)|~I4T{)C7fIbtEEHYqU zEnK)If+Sv78&Mg&dES?ajQI%F&8vkb$OnnYy2=&pj}<(^CVm`oA36VNnD*9>tnkmp z$xdLh1m|C_<>Yngrp5=MzABWeDAAD`?yOL~T=WzlC)7shi|ANpm-S1~<)WZkgp~`x z>9M`wozV|$bza_j2#$ebuBxYT^*=B!(~tA(oP2v5G=9z?!l-QCROQ63pP=Y4%$$JD zt#TprA9pI}yS@G5TBfNqotNsPFekin8>%{cY56QQg$vz80f`RXcj}n0pGa_Q~ z^~`n6kbt7}B*oJX4UJebO1(PiGB%I>?kGf#6YV^$x%b-J)Nr8gDB1gT2@9jkoO$uH zOZc$M5}k%XjHbu-;X>Z(ze*&XZi5G8%|ZlG0Gkcrsl}~qdG^v0~U7d0mO#N zor5@y?FJTI^?(y85AO@{w?SFT^$Dki%aYX&7Lf^>Bl9l+;l+QDYkqMj)i+@5mBq6` zGlp^kW4EGBTe-$9dYSn%Q27({Jo>0^ziDz9Ga!&1hyxE6V919Cz#IfHyCqT45`fVFmVrdQ{B8?V=xMo$eAIi($ z&5Z)nEg0j2>44z?f`z83Pa{bOK|mW6Zab3UK0?wj?&mDYdIR{_9V_&AAZ7;a?gSFp zz=)b6^DA+}`(URhAa)ulrkZG5P2?*F`%9SU(QpE&{`v*LrxJXbfDG$x;v7~cE@`g!AsK*_pan5Nw!3cwYn*bC6Pi^g)uT9Nl})AS0{M#Ht|M>M z%E|77g#EPYCo@kt4Ufh)BJxS+@cI$8#1kl@|2kNQqR+CA5FS9tuEb_Q%~eJrFvj#O zWAz(E#r;IR6|jn*IeXH`(-G5Q>z=FEk%vCb0%0UzpCkf+gaK38e2_9f6eZRFK9Z<3 zKokgjD?}h6>~uFOhq%||@5~K-F-PjQD!Do~Cm@HvZ*w+in;Nw?d2JCDs)1l-GT7t2 zp88w=NI-O^%i68eecNnPJHD$>dn6OmD@cAbsi!{>dm33UgoiKz?-T5x{UfpD4RZl( zpU@1+FUVX>+47g!TiHh>0aKzGKx$Pc-y!$k+EPZQ7}8$_qRD5;R`VqJ{lo??z&_}y zqQE=!=S)()I#+ykU#u?6MuP%{B*G762_q`!0R2e=3K@e zakH*Bh?C*(U_T`B03dyewGoZz35CH%A&$Vf;b+ppdMtqNb5kZW)+tOiCyYY|4f_=> zq0Mt79pXrcPalGEIe?XzFid2{w9-#thzgdILd2O*Z5Nck>r@SAFm$>XYvc|#l}s^O z+6^`eALDe?8)I2zMAOegy(?7>!G?ly^3@kO{Mw`=iQIlv1#G;69fX|$?+BA=mT{n% zlP{!0oEWIkeQ;KgfwVb@!=p_R*;ewMc)_pd+&u$EuGc#jR>`JqhniJbi7o%9522Yc zQJ|+bNVpdu4hP8WdOdhn7Cx&98nqOV2GI_=HEID}$JV11lbY4ql&b{Q@PKBP!W@tqxf5{$M`Jikvf)7GkCHgZI`jz_-iQK&u0tINU|UnD z5h`{{?(@gbJ6@-uJ*Z8bupPZgVKtwV9pso`pKjkeOJh#_2E)EFefF zotcRWd1q$fTB`_gnFteZe?N zfYWetQ(tnEj3d?w-*SGTssEN-z?qi8OEni-&$1X=EeDvP<7!pH;!Cn{w*qAY0^^Oa zP)Hb*eqjTo#h?mNo!4(6A^d9n-Dhp$de{Crk{QPFTHMvG({9Yen-}IpaGAMRYj;k$ z!UN+Cow1Q8>sT8#KYL@@&Ds z>YrY{@)fS|6y<6CdRzRBtbs&pERpMET?nK(C~DyhdQoHW`=5UcSC_s^gGj0~asqSE zu(ah1ri8GvnXaE};Ck2v9#h}>l*U_KLwmkWb*XD!pi zb0Lvmpv_{|oliLfa8ZisC1xPOacQpE|Ky74LGg*?BkmdN)OTH>Y{4W_q_&dAC-r#n`Q7 zs`pFmBRmOfZ3*59{6t_B9;tW}WwcyBmC0rCz3(^?gdz_-_8I(@1ZrLfjY3Bfd=kUf z_x2OWqr|rz$hS*Ax71A@hva!(S&wH~ePf&nc&yJP*u9hVnN9ndmj81WH&5^1T_4%_ znceI&7mb`RyEPg8D$v5`d-PA)kKkpCB)R-^%a4DpbRbvDevOs?$_@K}7<=<@sNVSh z|I9wt8T-!Ii5Rl4V;^f1Lbe8#B{YO=WyTC9S%!qlPPSAdly{595|TR^-pD>YQ1#`m^^e zY`w8sD)`J!dyON%f#WK8ck-?}J4?RY`5$68$DG zdL~Zd$w|rTIO#iaGEd@UU&YCNij)5nr~Y0&>gm9j&6Sz|-mW-&n2?WGx+AA@UGHkE z=@E3+bZgN}>{RyN}b5?VhEY|_#LGQvCnbv@g^4gqLb>)ok-Jaq> z<(VM~B8XV8o1XZ^X=`n6AoCC-!O_HVel+LoKqjL3kfsK7{zt;$Ctg2i?5$lvl|SeS z-iXK;Z(qc<1)t*iy&MFdj+>dg#O%?=_6FQ+2>Nq1*tl5v@DMTlp&5)v_%1nTCX*JB zG_KfFKYCN?b5{XF+2q|#_sPxi|K4UaXFf^=&boc`H*0&8NlQ1}iuv?8Hpk@d^HVe2 z_61`L-E?m3NTVEKOV|XWJk#>~%T_!h`E7`rI4kk?@;gmsU1d}0J_T0GbZByU3&k=* zH~+V~t;w9Yw^hwV^5lDnsY^<9$sN{}WG&;Jw=K6$)Tx4M*65!T%0FF|7=ykpEf!pD znwEy*O}Mz?TE&@d8n6q(Z|qL%)?4qsj#RyR=ODOLR=dK}CNxvJ52yWC{r8?z^uu$N4_^KCJs#8Z=P!hl7R!VD zUwku^+X&OEdzYZ|i4fOxP&s@G4$-T$^AHI3wvBUiQoToL^#?E%Y4|lBndPU%G+j~9vu_YUp6AkZp(0{u~F!#ag z0rKlNw|LHl3D!>RI$!_Pc-e_BZq`^G_I7uVzhRqIFRF!r4YXOws;mB+L7K%f=U4|} z5GXObDbXKh({&{A#dd01`qqT2-bq_aYn!F#`W>!1(PaaouJ%`{+OL=zP|AAD?H|Vu zLCaGSeSh|Jb#%uHBw_UJg6Tc9nCQD>ULEhZpVh)Y^*aAoi(VSyJ>Iz%P&@zn+h1WM z>~)uU$Ihk3g;O?5?h^&2;G`vG;0oP)3E%XmL9C%5`df?14218?U574Ma7ywb$Ml zhlGZyH5yd-cyl4$ODCXjp3)ZH(4zx1E}w$luMZLTp)K}GYO1PUw6gfSySx8RqVaC$ z(V{0K4?I>!G^bt$@)hpP4IbKkD+Mmt>FjRPk<`0a>NauPo69t-IeK^JLaC=T8*>gE zy0^Exzvpr){cdX>SkM4ou)F(G%+o_fL*K&e&fls6S!nU@@9A_M6RcV5cjMMA!5^$( zZ6dN@taY^pTD+JmjZ>S_7VN1p`@!NJ(00+rnskm4qGc`6L^PwOZ9rRgAR5akZ*E*< zyU>^Ku{4%(Uq4{f9-*rYSQU#nv!0r$zM8yyIFcK&IKHMhlg$<)nFZ}~wc3p>Kz+g+p;V7Q$0_WIcV1pog)%oEW4H~%l(%mtnQ zH{#4?ow>yG8z}cB`2Wo}FHO}pJiDynbxro!-5dWW-~8cON7Jin9F?Ir~~!GvUj13NC_hER&;nf%A*7M{WNE{O(SZT~iW`8v&K@4wDSdcDKV zo~1Iw(~m0-Kff@Yvb;275_36rO6vZf53PTr_TBdmefvz=$QF-%*nPJ0MYZeJwrkv< ztVzzv>X(lnZhap$)#acb{e8H@<(m~6EYO0oPKFnbPG~=H%+KIizN7HL*!|jH$on$K zgdbuNY|8QcZ`VjX_U-;8q@%_htwZ27kNT#mr`&1xJx@DP@PH>l6arJP4m$(|fuKb= zz+RxWVPzso^ndu~qQvIPFmb!=eyjuE9Zq5>g_x!8A$XY_b*n_-T)x zFL=qS%Zo1i}j57bykC?LFn-us|(wxa#2}P2Z8gI<%9eg|0AJbh_vcH2c+ZFubie9zgQv-BF|GV-1&G?tVM* z&OwoDOqUczxP8F^L~Cu%ydDKUWOn-ZeenIRE>Ue9waZy(b3;w$p)!Ou6kyy`jZb|Qm0M0WLC$aaL z{y<{XJl^Kd$AG)VR+45pj|v{&e11n$CU6y^iTlm0!rLS>X9{OCo{6?*d z06H*T59P5Nz46Yf#Z_PBr}#J-rJ6vnL#Pe}Y+B2WpN@Z~!dG$+bOGnN>a7+Qvo(AF zpsazcy%R@>B7#>J_}U1KFuwZM!T#Vziv>`m@sZ)AQw&lGCfrjtt+8BwU^V^*2R zzd0$9fU7Icx;y)aH6X3M^ON~@gJpeGhZ&Y=_=rItfVamxvkEJDK&U3cf$q=k>UYu| zB*v8pEM?;{n~|&ni=>gAcLD#db4K0T9=$duG*3J)J7eY3fm-o9Lv^Z1u>I6};5LpQ z$KKu9zOK9fl{Zn)c@s{Uur@mfB1y7?5@hf%-;_Rqn-MfRWQH#z8@r-y2E6A(z4qjX zdnZ*}pr2gnQZ6jR6tMw>YDeIA`6kvCJth^K7vk1{VOR>eVeV}s*dOmRL|^~O;gHDy z=Oo^~%CMFj$6IZSQ3UQA5{(gVGLzT@hF}Sk?l(H`sIro;I_GRv`1+~!HKdU04@#7@ zOr7}TRGXSTC6GT7tuEVdyZl%a!NU-d*&22#r0bo9UhE_B>X+}OYav^QQA4}K!;WUF zMfxAyF974spvv!hF0=+U<7dx2`aJY%MvDqZK0oukwp!AhFj0A7fZ-p~=-iTbLp$90 zx&QQPY4_+2opX`pPx7+M{ACXpku{6hIR4Xp2}g%KA+Ci3Ut>|%h)z|`qi1*SUVWE< zBsQdUP3);&XY)6i3^~7yzqVGf$o11zVZ2OwuvXbLK*4phFCS*noI_ZsO%kNIM z#&w>VXt5STeyjH#+pHGfh-rY{!xJeYa={Mx!13lQ)7U6!{uR67;;1uo_ zDgS2RHJVLgJzrUjQq9}>aOoc z{5S8Gzi2yU{QUjP)Xk0>fm;zyuG4R>ZFV-h$Jl*uM+bg@Xtf=sTYJ0COmnW?RQQXb zd&WGU`MA4zpLOL+ETVXZExmO&YDrKB8P9t`bgO$TQJY7YnYDCv2y#XhFS#T%`&+*h z8bG&|d+hpgHR|Mpd56Pb69VHP@aoYrOgnj_{^RybVbFHhpK~8?9)B`jg4y|XC!z6@ z6NqETg4i%A7Z1%IR5{msHs*j6hi~p1n)P_%7BeWTbxtsCTh%)`iz^416TV)qBwv#$ zl8u`edAR))TW|$ES~e#+V^XoPJ!Ivv;)6?F5CEC`ZVH%Z*ttVC81P9?|Dppa)-f; zGS;aN6JB;yZH<1j`n&UrEZA9ta9^~Q*&U;Mbk<3{SoC|kgX#Xl6Z@q?=*I8QZ+O}h z8kO@eyVn2ry5`<=gFxok16D*SIO zb*lfrq6<2fKK4&wY{T2XicyW- zPbfVB1(Vdzey@yPZV6>yWJ$C6j+snyR$djDLl^n1Z(5GvD7QbEem(7*^75R=R`uvC zi2oT&aK9*rt7e5jI60R3m~2XNEq`*4>9dW>Gd|XnP!&l#%UmnQu|G*r^To7JEvzUx zuYJrV1&FehRkrS)^3eVwm7jO3P^h5>bwmx1)3gCpn7^ODyd1`n`v?Bkg=-t=V3NaZnk7a`!i}AdVDr1?8gMD`0wW zcgVCSc2ie&^6FYnCG5|SV_~!Mp9<5UAF-KgO*LY8^$Zy3eCD~tj-#l~Z}8c0RNJ@1 z+{g`;Wt0>)D69X%b`IKiD9CRs4mA|CF?M*LO*!R@QUTy181#W@o& zg#%6TF&OXI!JsF`;32j17AB(Y4(NI(A=h^Zdpcht3u%jia7fU4G|ij@<>0{Id{MSI z2(*?A?&T&VqVkwL@&x#K91J|B>PtX%JcXICU}`wXAs<8-8M3N^;0iIS(a01c6tj#v z&&u*$M#T~ke+gL-8%X>z>W~pSU>nuVLdqJULpX%wV@NoM1;Y?7VwhQp%RF0TNIVA8 z$o+jWI-KQ)4&6e95z{zCP-+A!41G#`%=;pqJ06s+I>;OYiDf3xBhW$jb8Js$fHn89I(g#ch- zCNzBDFd-q!NG|1-S_ZDh2Iyh{Ay)nw0^&RtykuCQi-RSWBff=0Zn06f&~Vur z>INGytvRWN#+qU;g%gg-GT^3Y5SI{iFNG{6z%_x3R42G55v7cS-^zj5UIB-5qtM7s z+lw%6D0w^sFlCqqanyk>W7J6|AhZbLY=hN^5Ch_6Q#6HxJqfod-frhcN<;9*rz=>X zJqNHYP_mVLo;aa$gQIzYz+AGotNJfdp|7LN^M^1Pn-r57E(% zq{B-pXefz0MZucO5DpXi7XaK7V2xWSBlIaSkd?LVqsHLo^1^`{@NqWi9}Wy=LbI7r zWh{Ij2N20w9P}yaiwI6l5r+XjgaeoS2S72<)5os08>2hEz*4#aHOxg02?b?<3YTH# zgfb~Cq)h_kxQt4|qSuBInoK|+0EhFy%OZJsYQO*nYO9Xe>V)`cLOYN^HHUy+R7(Jp zU6SHr1G4p%tX8XMoH!(B=&A8jGCuIV$3Pwe4$iXX6=g++|}aP~cb&L@%tX z=^Tv_=DrCh65wlNysx%V8H~^lJleFhJeUay!kq>4-Da@e3XBE+et>go>o1P*Kt zaOZ>@2?TN?UB}>ni_YkyH_A=b&_-Ca-~-K0I*$|qW{xcp!NCcdg@G&&Ykzns6N({J zH{!t>@8MZn5O;C-p;p>00zBv(^sqD9))@ZB6l8>^H0+?B+>edEQ672?WZIbd%kQZ5 z0kr%wLTZ_318C$B!Qd61O(s+*BB@z5WM4`vc}u8_Lp~RBFGtu99kfLQ*PaC1coVt{ zAbMc$R?oMpXeVWe5eo*c$%TX9Aq2!Ntm7FNJb4?*Jb+$>Hgjs=KboOX#l!b@s;)Cz z!ADT%aZR6hP%ew0eL2GEDZHGXImQkNt z%U=(k2iKC_-|?ytOf(q?aAdXWE`qZRA#C6JG!jx9(VTQL|IiB09;5lW60g6MP+=*- zX9oo=-gG|&u|-o3XOU;h5Kp2&LKukYpocsFr1_%N7~J^>+l!wnjY7*~tMqHCz(*Ks zWvQ+N69HuV2N&;Uvntw1nbmYEnq!WF^3^*sO!aZxMFj>XavR9pFV~HW@0sd1!BIqr z8nf)U3+QhRd|(%~&IXY%m%$;KM(9E?sIYUJvdOq*&OFb-!R@$1Vt_Mh;2X$h8l#D; z&Jki=_hyuDjFGF$e0uyvVps+HBZmT+_fv<@J!w6&$%Z}po}7p+ON<2ZV8OSD;KTS# zSH?Z+v1?$(6dyD;1OqK@rurMf!%6VMWz_MpTyPxpGzK9HRHzXv0CM{YHfV==E(!hc zy%e&Wdu;;V$6oipS0Qt;DN`a>1z(>x#+`YtOJ`6q9a4gYln}w3VgE)a$PdZuVJy() z$g=qdkRZ-H+=vaA#a=p%s|;#t;9yajT>l?3A|o=@GWS9r4t$)L^_KyXV#95}!RBR} zZc1N2(3N(ptTuxIj&}to6A@WWp6w2$DKp33?%ubsgPb!%<91Lc*nl%mKnfXhxhZTP z3o>Wr2aqn@!h+v*qf)S?b51qF#JWv35P$<8Fo$@P5xO`)u{%s23z1?2Comx0n!-I3 z?m_?P%5+99HX62h=0Bz^w7h2aM4nTMqfE4RWD6?r313kgK z9Q~jm1c&;|K+VkL+sj_xAcBq%YP^ZG^K955EciStNOQT^bQ$bJu2XZpq{11?7h-|T zfxZ+Ra3TeD;0kb&2+>7@05m!vG)0K$=*c$62r&POw4-NcSpytJ(7f zVmR(zz**m8`S@O*jz%a5u#pT8!GiLDbNKRHw`AV^v0PtPZe7_RKm-|(A?xUShq57m zS;$y6==qJ2)uE_FHpmwT5hj9Ojb`t#;n_GKkOdRRA)6SezgV~d8(5cpVSoTKhNEmT zye%eS-DtQd0lvpd?^#0G0)QqOo<~5Wu%DPFK|`4Uw{9$tfrMdEI{^JU9->c%*kV#| zk;caIAh#1=_+sI_-KZ@VY885F_8e@RKklf;|Ck-*_%cT8worRyKCUrU*cj@T32)$i z9=>02#BN%hFZ}q_`7kVq8#A174xWbvjRnF)NU-o4_;Czl+}Q8XsaC}zaC7r>c`wA$ zxw2bEXQR|eeBtE3#0kZzI7K8qL@VQKQsl_FjBkzUx5V!ylAuDQVIxe&-ePYEtEu2V ziW-DiHSV1DL6Dm#4m3@OoI5T14aN9{dVU>zY7uo3OEJfQxL#g>No2@%N_qa|DakW# z=fZC##ok&z&u)r)B2BnFnZP$RK54Y6F@w4ZZzC{*pPQRB!GS0)4F_8DEsPHj_Ee2Z19E*N{qKr*CAwIs3 ziS7H9qB0bJaW?M#!Q^T2IiXmeV5>NwFJPkTM(O zVVoi1F>4VlQZ)Y4EzZck*NlF*ORjeXY<-A-P|8eqF4WE~t7#2mSf+Qh&kM zt#dO|rJwQy5|lg=j|In-yo_=8{mOXpd-UV?D7h;SU&Q?C`P!nhprNzSedD)TDaCj4 z!nIRTA=poSmfxJ57LPkEUCxemaX^KzL80Kq^xuE(ibsZ^=WZ4RP*_Q80_oC2K{9`) zrwWd#KlvpT|8=%9ps;Gbr0U55&T`#_GSKCMII>2DGU+OE@dNhL?8B2216h+ICZK)H zqDJssM9)%nWl9Rb)s=xPn@;Ke`4w3?RVWXyQ~&Tny>4?1VZelP{gZBQA-f6Rlikzk zIkWO*aXf|rl{t|+=RZ!IkKM-(3*lgSMBY>WQENGKuJ=(w%ZM4(r0c<5vN*x}2Q$hi z(xpf!gQnGDlrSI}k9@Xhhx+dPJ~fyL^&U%TpZz{BQQ(O$MP5uSOJY#i=fB)T-Is$4 zF(7JVyit`OEb|CpYZL{?{gH$GZ8{%JD8B2S;dY<0lb;bAi{gpM{)YpK(-T9M$tpEZ zM4R(4z9=B#LStdZCr(*F)C6iYBfRNV6f$z+Yxdr(97SOlsp$t-h?w^&oBYcLfh>QO z2gMrV6Ou9#4_$yO1LzWq^dI;Ce6peOi0N?o<~cjMkg7+6-|KmYJSoH2g{jw{ofwJ^ z1uFj+->fUW8~&r(Qqe$u`sdb}PcmY__WJk!=9kur`U`t!`xmQu^ns-#{_~B&9;V`M zug{)6;Zm-oIZhM>lUssjN4Yh#D6Gz+r;Y7`L&oj}T}B&c_BRLarU zqPr#Rl|a7U-`#b~sXxKxqUi_SwrS7%3tXN0(s`8!p|^eVSW5uVXNUxZkRSeX)=@by zsYbl_NnXs)iQ7e-oi%LjXbX?HHn8pcs>DM&3Tz3kkwr|2a=aIz7@I79in#?6d^jsTv#BI>sa|h}7$cP47L=q4q!&_jU%T8T!Nl`HT~uBpbL)!m-D2%4h9M)#$D8xl%i0PCc|^E1256hJdQtFniNv|w!>*w z{&7S;JOBUma%7VIzTUX6krtD`g%2pz@i{Iq!&}l7&e4xx$Q> zl6KFbDs?{cv!!2{K9m+an1f zLo{4e$dK+v;8_=l&1A`4v5gKBf8!ZE|+|8%*amp>E!X22jc1b0&52E{}jY0c;<$R$fb~ zX6^{;1YzzHzxOEni>?|Ir17iTpjIpudgvom55DUp02*iJ&?JWa@@Y#a7`Xh@RqTa} zHvLHD!pxTK(3;d_5dU?i%@Y!#&??ymQ>_6}(Ob`A^twIr!c>&;{GN^mjYslN zpQz6~MMkGutmN~(ccKg4rMa3Ab%0@S${Q7$F`>ewF^7U6x2-s9X{x zQ(bt(J%t4ldlyfGEyTn5wujW06mh7)j(nLf5kFGnZyyR(X^=ZQhCg(|v$#<-Umma% zl)YC-HlnGA2ZANtLX$n4wB&Nxj;&KFphg($Pfd_tJA*Im6($M9{oYVwTq{Ax95*#wAKduZRVl#Qii4ZMh z&E;E2C~SA`rN^7k3Z!Jad?d?G#-QE4Fd|fLu+t|k5Y*;eLKgG45mU5izhopy;YHej zbTVL$ZsScBER3+rXtrc2Z*_GyI*l*ZcnEh=RBduv7YA72vw0I76<|$01=(HKA4_ zVemZ0O!33{Kejy&iw;@sD&{588-hI1e*_VVoDVtHgKM+)X{m2>#bt$t)(Q*72h>0O zGO%4bl5_Yk^zFyWu2#z!#)WO_TYGPO-G5q9)zH6~CJ%b+vo%!e_=Bm7*#_D2F=!VV zvq0V9*Mb&GIkJ+Wx0GIYB_o*-sr;q_lPORE$-7Pnqk_V>=kP=~)n9qv4>HB{9)UW- zEC_$qELT`E4@GXsK344EfQd(-5B#!;j|18_=uMKTZLf|0*#Si(ENhFc=^)h_9B=PM zC=yLif!3L7*$+3cRp94O^LoHJH0xa~7*ai_kcg+0#)iXW@Q?ICF-J<##rHEB8ovf0 zzwiaKWc9FFZHQ;4%lnFOwaPWZDNnwxct$q$MAJyb-OkR(`-$`g|92wauY~piWy!fs zf_g6!?c7qM3&z7{m@+|_fmy9bYXfhqsv>Qc=TE=iv7c=IjhOCuhtfW9SN(A-V#qun zL!;I5&wqEqB+qO0`F@=2dD(TxA}9w}{^0G!0_`DdGx?yxPO-mJuNt3GUtCzW%gEw{ z|6Edx_q~KzS`6hBc-RX6%0+?{n+AIqvd;4=%JzbJc*5LJnIc~?s)_&$WM|a7^gy0= z?YT95`49}Qvln)#d)o=4wv4JYVS!9o8!Ur-(IX^|Lf)7{E4SXdrmO-x#j7EViicW1 zHW~TSix<+cy!|lHGdp8r*Kd`J(NP^Hr()^B6vJGy zksOV#1(5kIDg*l)JGoTwFyw$N<=M^p=OTvNnYu~`3Y{M2Xd$Uu%Z7oHAR99}c@<3~ zK{%DREik{U0-}Y_=Xr`c9%gVef?DeP__|ic%um(l@K@A}JOV2}x;^BIEE2iz5Czer z1IHsD9&#}*G(%ov_m)iGyFEiUPq#XDy36rq-t`)D@BT(QQDWGx>-x5J)bsyB%+-p` zi`?4iW});#eckiUp#T2nXiaG=+G$UmB~`IVc4_ z?yI->?`MB1xg5Dn_R@GX_|s8Dq)?^PK8~9k&_I`2B^ym4zDEs$Qjn`y-A8Nm^EPxJ zY^8@eRh110OM-O$GPwlt@!tM((T;unwrPHk@kJDy_U6OMCAk4=ssyB2EF-hS~?LZzf7Lyp`&MW zRo`~{B^YEOd+Vd0(8!mB2-JFRwl0C0kxVK_x^0bO>&`la)tadp* zH)NFHs6#|tb^))DuL?WVrH}rYhU!_sE|DO%BnS=9`n`tU%5*a>&w&ahW ziBRKm0M)EaWoI5?=gi=tI_S&~eIRc2bNwNY@iG`hhe^fdinR)G4&WbT(aCFT?pv>qMLH|K@`?ple96$#D?93P$*!LcB(Ha{;%N_~qcKUl;M}<&; zBQz#FZ2DjTxiQw>@HpgiS5-s(V}2(myN6+)yAF?b{?k5E2fcL;d`p6PnL3P#ibMi_ z&yaq6$^^RtrW_4VhT=^VQXr{#jMmykvqep;A6dT~VJrfmu_80h0ADlY=Id@*Mal&R zMd}M#Xj=n}XJ9d8!V#pb9~iu-NlOOtkgj`4LO48R5%n%gIuu}T*MO7(@%Nd!=u9KL ziC}k!;TNdH_nfa6uRQgCOC{!APd3$fCM38_ex71Cmxevqa{v5+@s0S(WoVUXd8?KF z5q+0IhK3<^>LIhglhJ43UeYOG;llHR-n-Q0*)@_g^$-+v@3H7>h-FvU2ZNx1M^Dym zoLomj+>Rm~3{hXa!+tea%z(O7sDVtHp(My4@_=$Va&8To?2MFgFGCKK6(m6|KZaBZ zRI6d2J+ste7(nCizWCmwyQqi8f>oEv3JfZj2k%y4P$OUm{95-ckf(1xplz!JB|xwk zh&c;lj|L=FAUtpK^?r#+10X(+EA3*xTVhEb6$^S6 zN1rf3qMCiul}JK3N2#V^nj3-BUW<0S=oEtv}YTeQyg);5|qW zyz$ga`G`Y;qrbsDHyQuRu6K>m4=XJRL-us!jV|vQ!d1Bd+smMnT_Amur)`@Pss`$O zfqyzT25bggUWlDC+g-S0+W=@jBhrN>H(~O_sf#7ZEk%|EmE8~YZbdKKY^pxp3 zc7}K#qw0ZX8N4}GW#IEPxt`inxJ{2fYPW)=%nQD;Q2J0k4E!MzR z5l9r{Lm@LWgAnK;D+eZk8igRhHmF83*K9dc4lC*6XC_$F+~mdA)M4V1EY49B&A^Uk zG4Gj4g8W#J1Kq?++%IamhAJVmLuyj491!XDD)k3Pm;ZMdlYc=7T>G{iNrqhd2@$>i z1W<#Z9O?H3prBn!?pc)ZGB_;)uM_HMFn>gO(Rb@{sP@aygCFO!{GN3{7 z_zxlE#nF)Tqs+>V@spzf+X67c_TgMb%jcqMGdq&4QX~uPF&Oa!Si4pk5eauPn~k) z`AY8*IOa@4muL7<<+v&%q%seF65$Mh>fPcl0-bu$TrhB?#;P8jX@Li@8b$n~z*i>F zqoM{}`Fj*(& zV47sDoFBx3d@X}bm2m@Ial@g$LvB5MWkjsW06tQQp}Kg+5>u68ntRc_jKBOH_Kh-) zMHxGNs_J)S_5SxFW~J0Sh8%Ej5iFL#lNTBzCnKnkD9y?Gga_Qpmv!5QKk=x`h!7vLXPGrlDG^EBg(TWE{+=T zk)~V&+As%;tmb%OFS&Okh;~TDW(yRZzkHSKzD-+d0HM&8oJhLTDdgvx9LOGOKe(Mlw^cs&WlT9zOEcqcb{16oRH24u> zn@f2w%Y^lTq?RAYNx|~$zt&%g5%@$B{6o4*)_sI@ezYv+cgU8Ge0-ky0`XMM&t2l^ z&(4L!-q^IE*LDVlqvlGf1IIoekJ`@^BK%sK{&@7EVK2q-)L(-qpZgF06q^pv3YvM> zvDEiexvr~tr79wi@&O?{Oz}$|N*;AUq0Z_loYnth!|9c&BZ_oM6yC!xA=S^Uyh&LL zQhoR9mcu)3`uIabMb4`$9>H13v_q_{$M#5xJlF22;Fr_^4_Tw7vo1oj<`F-i!LF>H zm$5u-{`hH_#K)So?Clsvu1ovVX?=x6Pu-0v4>y&eHE(7AbK~zX;aA@ZnYOPPj>!~A zm#qQ)z*G;tnN}Q0L-&PkF09deAxTXL#KAlB>_Tqr`J7?vNp6ghil21?I`~q+{nA zsuDMbo9G}5)Ni*KGKI<3SgA5l*!%Sb6NOqr4gMIEB&DvMryl~VaBrRvWP zeRqCxzskgtC`e30- zjkjArA@rW99R8Eqc{r`>c-ldqS}NmqM>rR5PJ3`C&29!Xb<*MCr?j3wX;1!W2r|n` z{-yQlruSR#C1@H8vV;cCqz`4J4;L~PE`vY?>Cc~}kG@KO@hSb~pY&J8We{;tE_|c;%!z6;+ z<_&(s&=(s=PV>ADF)}%BU>v?4Znv(}d45CHzaaeluTK{)<3H6I`sXe>$6bD&$F!Jz zYi?+KE@PyOAJTtG-S=+vccBIAjLjdN?Y_EotPA_# zU#I;V^9RiKRqjpuo;vZ0DiEX}^J86eyxFtK^H$Wxfr&Q%`|-biY-mj}Lx+kFp5AQp zNsB5gZSW&RIb@67n)vzOnc%B>*GuXW@Jwa@R>gOl(c7FOi!GwW{kSQc`a<|;Id`?+vlH7{sjw^&We0zC*=(6saeT&`oACO6_>7+!< zmXjw0Ke~&3wMJz;s_2bDcR8IbX|J*^daC-`byGzggb*hv_KJ%)pHxUGj94h-39v^G z(j-z!-};M8KrXv)jK3bIMLk;>BW@(qD?;=gPN8DzoW1?pdT1+Br>1-(R(hW34);c|uLW1vX98QPptsds(l#{X%e4Rk100&9-v(T@C+P9AZ8toQC=3`4V*~Lx3%q6C@qXcCxBH9eo!O>NOzygdQ)66PCI35HgS8sh2g^tKqH9?ycN0+c#M#aXw8 znY3~qaZJ#WO!BON^XQ%8wO)9=fRfrfl+Ax)*q!0FKKk~LG@xx3Y_(sZ*C*k70%OCw zv)2JZhG?@ufUkDDA1P@sj0R{TZJtRan>awIjR39>oS0XX!+Uy)LI*;ke-sKhA<28z z!S)!4viBYYkUyx+xxKhoU41M&yr~;B_4Mc?bFd0$G0NL(A_(P`b;XOno z+9Z$ncN8zElz@^cXY+*+K3PvQc|^2v0^J%^$JSFwkx~j!g0_{rz3d>u2m$LeSiKse zjjE3ZDs0EN> zn%AuLHcM2vZBC)R%|&aRg%Q?1fV!bV;c+93h6=M40xj^${Hw^{=_2{i2$-@ylWMFV z0dgVqfjvou1yeYI+i3xqM+^kojm>w6h?ey$6Z48b3H=n6D6%F|DM8%5cL$$0Y#VNOxEayfrY~EnJ1P? z55CYOQMEqI2~WnI8S#4TKWAm?riNa};=!B$8Ph6k%G_Iqpc9A*Ar%bR7B2xhMa(oL z<0vlpNeF874t4P*1}$>awwd6AP1gzVn(N=fFGC950e%(025zzpRt%g|2#~a~B#VL& zWEL38E|+)&fWOto@$3`rW%{vjEieEb-C%{zKD5%|sN_MSSRmDX3gTbfZHvwGTt7KL z(~j^=FgD)qu;i+OBN|9KjqT$fUp^%GsFrs&4*+dT2;Gx~wmm(sUsA9AMe~wVxNfPh zq&z5F3zkiRr}WA=7Bj4fmo;OX5w*c+c#Ilj7)5*MrY;pm$d3Sht!Z(kuoD5T$i+y+OE~+W6pof-pP?p!Z!Hv^eQB>qn*3Yiit_m>TS*VB%WhIh~)|{ z=}~Z;SA?G8_5p3som`+V_$TJd0`J3Fqw#v3jTW!Ru0Q6WFZ|JY7oDx zQTrG)yjF{+#>3vRVIcT)0%x{k>NuaUpx1ELub}GaMcTT1)+XqqGX@`_{nYbOP`;mn z%{V=8l#PrJL76#-3foJ(8Qkr~2c=iL6^Zko{Fo7#wb>Q29#p-%QT6QwY#hhYNo%#hOjqExN568nb zRkj0fgrjXOlL6HwoV@lRb%TOlXOJ2IYvfaFH(uFsLQP^(Wxf&?UXK-2))TM48}rd- zxR=i!XG!ZtYWE_?gb*hHsW_If3G3aS-S52;8+(=nk!rKh+bgPUT3T;frEKOS2Wx)H zTRDIlVud!0u*MgmI*`ynRFI9skZs6r# zb9ZJoMZHME73*X&Pv?nrG#OelY0WKWbiM4Y$V_~HBg{(egkz)nZHlBlOA-rKCR2cJ z%5y``XRtkaUmGWH(I=L!h9u+KemR6VtDU~rc)I7*4^`HaC93a1GVd{aYiwU_Ut#yENPc(rhks{pVL!pj!OV8N#wE~3ZCFj9~c?aTFY;IkxDaH=>y zyD7OqJ;kLUXaM#;a=b${*mWH8r`*%WXwF9Xc*+Eq*a(RBhIUpoUC@~il(m;TLFU;D zjfEKG5hQT_Ne`R=^_*3-%+> zS80~WSH=5HIfE?~F0hEsrneg z-uxrO_-4G)el?z7L4Wg#f1bF`fj3n~n(Hf7)(cO?h8-~7*&gJ(<2@rmAyb1tunfox?2i6SGeze&lY$86WXw^24f8 zN|wX+Q5EW!m|Wt)X1j+%i3vu*JXbLCYo5gbihQdrwl zOcFb6wE}5Z9u%nJfEn+#Jh4DpVue1sf$$p?_86w{J4Q3%lKT+lg+>{_1{*Z)tn>lf zb&Ok{h6BqUmBPBI=G0OOs@&_hkR6D^D#W`fc`$2v{Df5ZKqI)D^G^|XigP?hD}5Gh zDe zhnEJ3Nx!4KuiboK^(#*rHmg_aK8!f;hJX8JnE5W!*`6#UJ5V)if3dq%z>h)*<#%4x zB2VNz^S%suYD;_E$4!JilF)`9Mh>bCl;)9*j`=sfW@*{8_(+^y_wg4m-q0QVZc@_0 zVhbR67VX8zKygIq1jx~{v+r%|Q#x+IiUC}aq)9Z8@8`n3fd-rL(;v8LciJBVus2;L zdxf=oWeB}i-T07BTg!@?OHBBqX_nJCRRRwPKKlJ<9yt1CUYu+LKLL2h!#qs}er69Z z_1ViwW&!}t5}T>0O`Z^Fp^VNkLv@Kw(r_xqGJSeZLqR=-dEFl;<`sKpMSmltudD8vvf*V|1>{bvVXrZ}2Nr+1+){o|8T zC6i78$ZF!cX$ zbT8gaKmH%U-@9*&&3*1;?w8zexy>c_`#q$&CaH!}P0FX_6ostHYGicz8`l8$6AG))k2zLi0gU^V}V1AP5 zqfA|1GG_8?FqzWD(s#Ng+0N$11@?!gEJu5h(ON0eRz6mTzA~38G^k<<-*M0@xC*eO zBOvB+SAa!@jLw`cJFUDh_w3&f<*K1{@vNXU7|_*??kWKsC@M%R94-UJvJ#;YWsp?K z_BfHMjQ!H8$yr3EcourE7da|6Ab0f%Y1|;t{nfurCXZqM)xEP--EOM3yic){E7z=> zfLEH`%eYh43h#(;N2@B0aDuJXLU-PCKtA9ta)gr`oJs8T=w8~pXSLkMSKwzI{J;wt zgvUmOdFO1PZb5c;$i7EaGl0X! zntFr8J*?CJw!e|K0og|}AG0dVMqB|9_U=t&#Gj#}1+*m+63-nWcZxT{Fx-JlkJBxZ7Q zFDG|fybZL}Jrao%@$FYVt0b&tE83kSO5h9`Q%E=6-B*n@~>OaP@`M}v| z2QgY`<1|FyNvA0u}J{lf!c) zrw>(wUtfhvdHhyJz5(~49-5neUV7>WU@r;yT0`Gir1p4JLKk>OIzH~nq&{(hf>*pU zK4eDnj0UTt-AwIsUYc_RP+g$rkHqPv?%2Q3o{cBw%gJ9nuE;I__v+Hi2-OkGDL^*h zuK=Z+_>6k+iT|_^Mc{`g_lbn7cm?Kjunii;{dEviL|fhQBqmUw1e7w7k>(oIY2fYp z<--P{8HlQGL6vTtb~%N1Z{92;pM z`lIpslcO-JM@T(H^xn`Jx6X!pFUCIbSnO z{4E^A4G}c^JxmedoS5Wx4aL3tT~>D$8K3(5Ym;4++W{$i?dj;qViA)zO=s&fpEzv!D=weC%(w0umg;UYij3BiL_sAMaq?9;nl+U{W#;EAWE&hPf|S=YzF{X(f#}pwmW|w(bIf1VFxzGSgN|ysANB6giBYyw$-qJ;a06JzG0K^Ti!%&^L>s>{P_ce?~%YCN2| z{8BYxPdVejwa0S;<%YWbIaR-pI})&g&ApjbJv;dYPzQjjcnRFv$Zr#p+$)Fv7Dh1^h?^Np2e-lqCch2BvFBLvx z1G&=BJbbPuQ{`&`+Io)QR@kxESm3U*cZ}C&QUQ{+g-w$yaQE5^%d&{w^Mp%|{9SsP z4sM;TPS>6ohyHx#GK&`PtKxYp^?9nXI?Z7!1AhK*b8nVP#}M~cHYW(5?fq9=4$QHR zHJ0aY)28zTs`^wQw*wcNY~Ub`CgmEp6KUOAQme_~xj9<`(Yz+pQ*yb7P*b73s3Bap zj8+mL2UGlgvVSIhV2F@uuiN?aEflZu^Zd(Z^+jpcT|L!0>kU+1j)dXLF;^+u zxZawy^_5Is-mt-JfycKF3{%-BrxCwLvgu9ya=_k=+uwpJ2dmXP$-Od0>c%l5AVdXm7H+77W@8*6JJ5u*-PUDSx z#Fl&VP=D|7718gLfPRft+PFR9Pnz~$|3D@OcR2qk22>ZP< z^S2=(De(eADz)Jpny|U`A%KTgFLHQ99`ncZDY5pnY+^JF1ZhSpl<7-jm&P|ShxQWA7txj&Vu&@xq zL@V9L%Y*7TCwR`w3>=?Di8)g#_1!_>+@bi8%hS2|w|n-sGVviCcAfbI9`tX5fb}u{ zV3~x6T*PmwQg!DAZ~L1$iWKLXMntL#oO28n)h#?JRgVidfDA?IcqB5X`5t|6J$*r_ zYF2p3xV6XeCexF4J9xp?j!sBnf6Y56ck`fsvw(a|UkX?#xsc5n{3<>)~h ziwCKfcjN@L9trf{YORi$c93xNdYW(NqkIFdjXgSq6o4kYiS|<{3h4}v-u2hOE3u!-g^qh)=L3W9<`jKXQ zG3qH1TTYWJY%n*v?2%V_sQ#?NmzePn#c$-#+`sisgJkmH!=>`?#~q)}SGt|>sx5!p z-Yl%D9;g1s!0N#z*Jc^(mtwE-U7-2G?_xc#nSMMcQ+DSEo+NIedjEoOaYvHK_v9Br zA=}kr8o9ojamQay8-RuCDB1I#{i`1GqF1l{LC(iteL2jLQ<{jL{qZ90?4KiR8~L?I zf2jPTJ3D+%5hylyX;$}*ajzQj_Od8wjJ%ROQy%!>vaVu;nh&udk8L9K3EeL)Sn+fdzly^c3eGzwAlB^tc#KV zHYig4sQAmn_Z|pn9e?VmbEiIiUg*gxHb-}2_R${)?~{}Hw}+$%C0ntypPF> z6)hx``JOO$<$s$ZscNGhAN`cizg#)0=zz?virHyV|Cc4@JN2qZjyoTf827kV)7%N< zh}$xurz*Z#fQ@pD$N;|t^`oVBV^-nl=Ce1S7HuE4H{fG9wx@qq{IJB86x-WP%0wv= zaRtfTh~w;d4)%u{YBPuaAr_^hD&oG{Edy?kL6GRy7W&rrT+$_HW<`H?zBqD9@)-aa z0!&_cEF9cLLj4$x#d8DW2M@DEI6$xXYBwy2pwiMGseIgrHCoukdUYpQ@dI=2`{?q# ziO^fUTOC-c&J2z{ zL6p>AC^}- zlK8*pm&|6qzuA#UB3!6_jwiIq#=HokasS?yz*+GTONrB9$qFLS-d%ac$+U!Tzm8=F zgYbD>QF2&4Z)rWSRB8F}V~W`c=$n$DrgBQAut(^Y<|b2R|82|D_4?Nmzn~(4BFROi z)MuBj?(Z}oO))RZtnYILXaqBg?0&Q>cZ1_a!RS(e>_~(7j99lr=pG_HUOsSZ z_JB;c#spsR0(THcNz@NR$XF4oU7=q+_?Kw>YveH(me5`;|ME$pQX=3Iy1qY)5hbDn zqX~vh+bKnG8LE*W-+-|-pi31FBoeZKe8D2f&pHfBQ8}65@>$_rh8v*(pJ3604eI6? z9=dKv_pP3fAu^$&Oz21k`g5|D27BHnn&J-SFN-jB(IbF0#0=@>Ls>TMkA0h_P(B~DgQp5P^~ zeA#lpS2l|X4xw|uKMRxb*aIt%R$0QtIbI@(kGtfV!Mhq$;FBai-L=jsZ7(GzNIygH zUEg7}j{01mU|JX-Qwf|!ku@i#MRRwZfIuoEI>wq`6sl<6C}U`=EYzpiKlduekzm`6 zF!dztx)HjFAu3)PgO@d4j%g&`^mAas(X;;8{<&r9O|uuWcPJ1+3Phf$Fzrs@=#rK3 zu3(8)8F@zgok1+KCy+AdJU|Bv;UT~AU}fOKZvfqa2X(Mu(WLy{ZjMAK0WAj-1ZMZU z`EJHL;=jInhV{9~5V`qXBWT>M7FJ!z-(N&K)P2d?6bO#{@SUfn;GG?cY#uF~ zV@IXxkc6ujv^i+Mn-|SCuf1cfC2XTt+J#)c>JoG3+3@rAW@f`kCnxz*&*j^br<`_W zj%!P{^i>z-F7q~iYfjCJdGG*bW#ChNrqurYg#C%=?uJVZEl%~i3AC630`t|-g6 z5TFSvlNVj(?y92Owa&^nH?%XQ&{k9)XW7kmrQ0fgw;yS%)hjp^T057M!MZDPHK#Jj5mA4t-Y}2F&-@S4SF{da>6tH=4;?Y zd&^wY@0Y!K8Mma47mP&T+Ku)3T2S)3iRsk*GGI6*SifZ+{VQtSm79fU{H{e00Kf4s zQ-*RWIeD%>`|eAv6unky_Z!cfifp34u{@3(+nNi$4j;4|X|zN01dWv07BoqzHf;5b z%==!>0Y74|n;sD%K@7*qmlV)^DiQcZY`b5hd}C>B=gs3s{^(vfm^<)TE#R~cX1541 zqaVSmTdK<67)X3Jkw07gBlxaCfs|^#j~m*IE`lv!tdfMR7gqPFvI=GH?Bx=Nn*+Ms zVGc!bA2@cwu~2PJuzTglbY9N4MorLTP&CLM1KJST0waRMx_P@;B7n{3 z3yyQa7rW1dnU4-A??jxiR1aE+mMwQTit34WUqNqe?6fNu={weI^vLtL!aA5pk6zv; zrvGMB?34VM6_vzWISJ;8!MvKeO7hxkvH2EP6E7Vr$XOPaiP)$0$O{i1?ki8eyFHLj?(Ur=Y*%z}l8zbr=}1xxoe4whm*sFKmylTiLW6~zznY^2h_y7PdD^>P zQSq7oiL5@GcIp^m!k&AZh<#1>e@(|czAA9aQzfJ`dR;D|&_DmGF@G<`sDtHyIXtjO z0aQSumdOX{&*|B0lQ?)-Qyk?ti;w-FSPgQPiI@4hA)qS|fDBcu?ZF0eo7z|hY6IXe z`!Ah~R5xJ;yWsU*>FAL;1HIxF6muNB=4R4gPIh`TnSHVrz7|@Jc1;w%QVmG zafzpEzb(zry;fn#Ffg2(eC@5;5l`UU!>NdpBFjlA2|XAw6LXK^KqP8N0hpnigi3G1 z1=eK!91odNly1WxHiyRc8H34uYzh=gLK7*%o9JCT0jLxSA<7cyA#qPZ_$OI>@^v!Y zSg!8eX%1C}Yr~US+X^hC7xT(<6ySpgRgPUhnFq*N!R6^(AYADxXW#tsirs*0y2)|gn>c;feYpM zzq1h}B@FOQD?SVr*bmRKgYDl_^8$b*3iQD;k1-tDL;()<@w#aptM?$3U(FxOTImW$ z?a@63dIRHu4bFp&OU)E?6J4YnI1DIN$#fU1)O+T66NAbBZ=h&(~W-Q(caaA)sx;hfI15Zy0eCU6Dks*%GV&c1dA<&HU3Tx>T zk~NHh^X+=dNfh`6QtBU;P@o)FeBjl^V}=1l9|^=!#xgzU`kJB>w3!BAR=aEl&{~z~{P|C{?*#+?RV-N`f=#JWK+*f-O5b0OAmt z8ZHzqgD`7DYvKj@hlj8C2c;gLhzGNadYYkrgj0uq%_lHXu;%W_`#O1 zCc?I+oxP^1-eyBz`3`jRKh98}Bmkcv7W0`F>kv!7F6C#$+17}_brUzf+FFhkUlQ|L z=n$_N*roEadPwN9yb;7DP{-}nPcsQj5eeiJkM0A|_kP~8>VdQn(V`@Bi1ho^9?-LY zvWvB{Gd%CpWtL0koIMVxuFA0miJrp#PD2s8tqZa)v+5U`ME)wwCS~}|Y$0Rmo-&8} zwy9nkFmL@^@(24Fx!_M@wqT!Z-%9QOt(KW|{`g3qbCCqj1;qgCTLDG=C0FTw@sz_= zu)w+VwzN@6gRr1#tPQu4uBU(HMgQA#@|XkrPL~&CD^5l4Q!%SdUMREHn{*&%IRg3- ziB$xV_>0Nis0LjKH=ScqKR44`t4S0k zTukEn?;n41ZAvB6|E&L*4eJI2!3FpJn&#_9a)uSp`8-ZV={1a8D>xt%C$#)U$u998 zId1#(Y{NC%OA_WW`e=T;-7I6ID%78Tfx4bH%wDL^PVZbcxFrVxictQ6k3b|UoIkjx zr{K|+>ZlUNcv$Mg#rP`{2a;23|DJh!3sIlND``<+%uSCLNSa?6*QK}yFtiYsg z@m1Ba>9zmfe0iQmHGT3o_H9jcQOkz!#@UDmPj!{gnzb}u24LrZtUru-_wnrW{Cmx> zti^x-zG;5ej~J_emn(C(+HzOBu_j{8_1&9e3yB=Ww68!iJO9ip5kzH-=oq3h;cxSz zlv83mnCYm5qk6@|s`J7ws@)q3yL8|gGQ2?db<>A<4x>CQSLNi@v4qV+;x$ACH%mz9 zyakANd7MG?D|r~1+FZ!b?j-{0ruRvLU(J$ijh;0YmGWfs{~wIyIC zl;G3sZ=dkyn(89?s)5?=w!T)AnRwLjU_;I3;TDPHl0cW{9v8ovsyi=o{NgGbt6F=I)U$?qi@xJ`Tf#Un+{)~sQr-D@Ni{NvyHI^84^81i9&3x?5 zIqaVC_nr5^SwnPQ6?uOmPT@o4>DT9$s?+&XmTwkwPEELTQlSHAfeIGr3sH7A# zZcJ6Ve-i1`2@~zKx6Sv9wo;8hCOkmy$=KiN17~mf_a!>j5?Kvj>@75dl^nY4U0SX_`g|)&#yBJvmI!)*wonUc6 z64jp@`#jc!5ZklQE~Piv{=u#a#j-JxES&$;WKY3Ws3T#ZHS_E6co!LFe z0_O7+DJviXM-}U$fzDTTXDHCQo44qCMOzjh_wC?cQC^>dT3o(M>`fs8fto%=feLW1 z_lXRMF0;tRuLLAMkMB?CHa;09b25QW(to9;12WsjFOUxSr|C=$#m?@^XgdZ)xR8n| z#nyTTj^+9ZpGJfY(WS)S=2}!y;aAxid=U(Y1bY^JOk0qD>}Q@V67;_bi*z{=jP=+; zC#2p~bL!fa|8iiYFd+a>(A?4wM6%=!S<5Wu6=c zoPc^JgmL1Q`S<)csjCS!e-)gdhTX5`U)jL9M^LBK4m+lpWk8Rr*r>;nx{Ri{4R2VA zoO{Nl(kl77cCVwJoGc>B^V~e2K%S%QOcKvp0Sj$7M1)2GhWV2>g1t%9&v5+agruUu;5S1k7#fKHwq1mW0u0xryrHQ7$IJ>M5M8C24vJ4ZacG#*4?uY`56iUlZkMA6Ifi{11>dV zWE&P7FWt9vM96`3)#zJW4F|nU+*U^f;i>umv5R^9H-$cWUNgVL&Jg01m+Jf%?-+yj zY>`IR$~>h;%XBdj>B!kvLG43I?#b2%`UW9jZVa{HSMmKA<1rGhg?_qlEqE>E{q=k# z|9+RRSY57Uf zLH5zR`_)dgUbST&Yq2XGnGY{&BK5rwqwgNk!N;?h;^e*wm(cRz{35o(y&{#^jbW=4)yS>A`X56v)DI%b zGZU@pq(b(|^s*5tMJ-JO`+I*n2S>Xerc6Fjwc1(EtyARGr`%du`-j>~snkEKdRQ}N zH3iqh89(pP@3f`z!oC~#riwqY>3Z~0iL+5J{bnx}ZW?suE2IA} zRkmfUeARe*b|-CgELMN(H2;ZZ8;Pb3$HG{(@g*(MGr{2(O#b6&EBfnyw@=pG)*KQv zE`Ffq;-xLxDYQg4Q*VnM!{(=6ZHcws%W*pOy0RY(oBEhGwV9 z%Oy?m0J7>JrCLXqTC4v2L7HJB*)$B}&jN*d=u2lA6vZd0fv6wCv=he!c(#=8Z5y_L zl$v$UL<~yPgwFR{$x-8!soaz_lj}Eue65U3{1eixWnQ+P1$iNa2)bwIG`y{)sJ#*` zv$AuuQuk*SO66t2KDv?YY?}eetW23&E0Y)@xIY)UvC;Ao$X%7kM?6S6ep#+<78JfL zdE6^aaa-=sC|sDkPm=flDhdz9pX)y>Xq~Kkz%%ZiCkJl0C5@6Z@~Xhzr5pOz%FW3c z1vSZ?m6wVfg-gG6{V~dO;-@&3nBh}_m)(|--PWYGVe+F@1jOJ}dM?%De89H&Nk)OI zG5)T0VNtI{KMpzGFM$%w@5w7@({Xmu%?+I^q_PfNslZc5;fw^6s}Pg6KBa{r$?iky z?~uA|ox}stGz3ap#zUW!k+bQk7b_+U_ByWZ86_pJbhSq(gzj=c2kgXs%ze#N(=j+< zoaU-)pzMi}VL-W(W+@v6rPGf8%mi4fymboilvC~^6gpX!8js8+@+E+1j0_PK!mtU$ z!U?#G>+j}KM=K(3{@bRH?^AO&=9I* z=Vs4SA%IT~1ri%}y;%<;PB&DU64@U`*wYYt46cj{-Q`Lz0GvcaXg!kT;E=zx;iu_P zUKZ^ABIXz#nnUFHPlF_Wu#xe^%A+LE`)rYM8*_5dOm)W6Zz_}YjXCs}kAUhV!nV}*^Eno_qNV0*eZpwVq%`OWUQ5_XbrGdeCklSOZ z5*Gf)@W?I^GdT~#1Lj=OFsDN1#!?|FLz2^6A&7_eM>md@$mI7PuYHSfW`ah~*~~f0 z_3DT`mBTBHXN@b$reZB3CT`6L$#vongITAP2SDL?8OF9;Dn$glrSm*YosA@W#2c1$ zativ8O4x^i1tf?c9o|AW3m20c81%1Vl3N(l& z{VJFOF{D5&=RvR45P{b~Qf#l%Bx)UDb3hngGYWsoWd+}XMWOKPId`(`Akbl@92&%q2z%`W*`>pccB}