From c2a864ab38a881a20e6e02dbf76bb9e51309a0c7 Mon Sep 17 00:00:00 2001 From: Patrick Stewart Date: Mon, 25 Nov 2024 20:35:42 -0700 Subject: [PATCH] refactor(zero): beginning feature branch --- 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/test/dispatcher_test.dart | 197 --- packages/{bus => config}/.gitignore | 0 packages/{bus => config}/CHANGELOG.md | 0 packages/{bus => config}/LICENSE.md | 0 packages/{bus => config}/README.md | 0 .../{bus => config}/analysis_options.yaml | 0 packages/config/doc/.gitkeep | 0 packages/config/example/.gitkeep | 0 packages/config/lib/src/.gitkeep | 0 packages/{pipeline => config}/pubspec.yaml | 10 +- packages/config/test/.gitkeep | 0 packages/container/container/.gitignore | 71 - packages/container/container/AUTHORS.md | 12 - packages/container/container/CHANGELOG.md | 151 -- packages/container/container/LICENSE | 29 - packages/container/container/README.md | 45 - .../container/container/analysis_options.yaml | 1 - .../container/container/example/main.dart | 75 - .../container/container/example/throwing.dart | 6 - .../container/container/lib/container.dart | 18 - packages/container/container/lib/mirrors.dart | 10 - .../container/lib/src/container.dart | 396 ----- .../container/lib/src/container_const.dart | 31 - .../container/lib/src/empty/empty.dart | 377 ----- .../container/lib/src/exception.dart | 34 - .../container/lib/src/mirrors/mirrors.dart | 10 - .../container/lib/src/mirrors/reflector.dart | 904 ---------- .../lib/src/reflectable/reflectable.dart | 8 - .../container/lib/src/reflector.dart | 298 ---- .../container/lib/src/static/static.dart | 179 -- .../container/container/lib/src/throwing.dart | 93 -- packages/container/container/pubspec.yaml | 14 - packages/container/container/test/common.dart | 122 -- .../container/test/empty_reflector_test.dart | 138 -- .../container/container/test/has_test.dart | 51 - .../container/container/test/lazy_test.dart | 18 - .../container/test/mirrors_test.dart | 26 - .../container/container/test/named_test.dart | 34 - .../test/throwing_reflector_test.dart | 36 - .../container/container_generator/.gitignore | 16 - .../container_generator/CHANGELOG.md | 58 - .../container/container_generator/LICENSE | 29 - .../container/container_generator/README.md | 32 - .../container_generator/analysis_options.yaml | 1 - .../container_generator/example/main.dart | 75 - .../container_generator/lib/generator.dart | 255 --- .../container_generator/pubspec.yaml | 19 - .../test/reflector_test.dart | 179 -- packages/contracts/lib/contracts.dart | 71 - packages/contracts/lib/src/bus/bus.dart | 2 - .../contracts/lib/src/bus/bus_contract.dart | 196 --- .../lib/src/container/container.dart | 3 - .../lib/src/container/container_contract.dart | 134 -- .../contextual_binding_contract.dart | 42 - .../src/events/event_dispatcher_contract.dart | 199 --- packages/contracts/lib/src/events/events.dart | 2 - packages/contracts/lib/src/http/http.dart | 2 - .../contracts/lib/src/http/http_contract.dart | 299 ---- packages/contracts/lib/src/model/model.dart | 2 - .../lib/src/model/model_contract.dart | 148 -- .../contracts/lib/src/pipeline/pipeline.dart | 2 - .../lib/src/pipeline/pipeline_contract.dart | 127 -- .../contracts/lib/src/process/process.dart | 2 - .../lib/src/process/process_contract.dart | 251 --- packages/contracts/lib/src/queue/queue.dart | 2 - .../lib/src/queue/queue_contract.dart | 284 ---- .../lib/src/reflection/reflection.dart | 2 - .../src/reflection/reflector_contract.dart | 148 -- .../contracts/lib/src/routing/routing.dart | 2 - .../lib/src/routing/routing_contract.dart | 260 --- .../contracts/lib/src/support/support.dart | 2 - .../lib/src/support/support_contract.dart | 263 --- .../contracts/lib/src/testing/testing.dart | 2 - .../lib/src/testing/testing_contract.dart | 302 ---- packages/contracts/pubspec.lock | 402 ----- packages/contracts/pubspec.yaml | 13 - packages/{events => cookie}/.gitignore | 0 packages/{events => cookie}/CHANGELOG.md | 0 packages/{events => cookie}/LICENSE.md | 0 packages/cookie/README.md | 39 + .../{events => cookie}/analysis_options.yaml | 0 packages/cookie/doc/.gitkeep | 0 packages/cookie/example/.gitkeep | 0 packages/cookie/lib/src/.gitkeep | 0 packages/{events => cookie}/pubspec.yaml | 10 +- packages/cookie/test/.gitkeep | 0 packages/core/.gitignore | 71 - packages/core/AUTHORS.md | 12 - packages/core/CHANGELOG.md | 452 ----- packages/core/LICENSE | 29 - packages/core/README.md | 32 - packages/core/analysis_options.yaml | 1 - packages/core/dev.key | 29 - packages/core/dev.pem | 57 - packages/core/example/controller.dart | 60 - packages/core/example/handle_error.dart | 25 - packages/core/example/hostname.dart | 46 - packages/core/example/http2/body_parsing.dart | 46 - packages/core/example/http2/common.dart | 7 - packages/core/example/http2/dev.key | 29 - packages/core/example/http2/dev.pem | 57 - packages/core/example/http2/main.dart | 43 - packages/core/example/http2/public/app.js | 27 - .../example/http2/public/body_parsing.html | 21 - packages/core/example/http2/public/index.html | 12 - packages/core/example/http2/public/style.css | 20 - packages/core/example/http2/server_push.dart | 62 - packages/core/example/json.dart | 53 - packages/core/example/main.dart | 58 - packages/core/example/map_service.dart | 22 - packages/core/example/status.dart | 14 - packages/core/example/view.dart | 18 - packages/core/example/views/index.jl | 9 - packages/core/lib/core.dart | 7 - packages/core/lib/http.dart | 1 - packages/core/lib/http2.dart | 3 - .../core/lib/src/core/anonymous_service.dart | 61 - packages/core/lib/src/core/controller.dart | 242 --- packages/core/lib/src/core/core.dart | 14 - packages/core/lib/src/core/driver.dart | 401 ----- packages/core/lib/src/core/env.dart | 27 - .../core/lib/src/core/hooked_service.dart | 605 ------- .../core/lib/src/core/hostname_parser.dart | 81 - .../core/lib/src/core/hostname_router.dart | 117 -- packages/core/lib/src/core/injection.dart | 208 --- packages/core/lib/src/core/map_service.dart | 172 -- packages/core/lib/src/core/metadata.dart | 166 -- .../core/lib/src/core/request_context.dart | 382 ----- .../core/lib/src/core/response_context.dart | 456 ----- packages/core/lib/src/core/routable.dart | 140 -- packages/core/lib/src/core/server.dart | 423 ----- packages/core/lib/src/core/service.dart | 380 ----- .../core/lib/src/fast_name_from_symbol.dart | 10 - packages/core/lib/src/http/http.dart | 19 - .../lib/src/http/http_request_context.dart | 110 -- .../lib/src/http/http_response_context.dart | 220 --- packages/core/lib/src/http/protevus_http.dart | 144 -- .../lib/src/http2/http2_request_context.dart | 186 --- .../lib/src/http2/http2_response_context.dart | 233 --- .../core/lib/src/http2/protevus_http2.dart | 243 --- .../core/lib/src/safe_stream_controller.dart | 123 -- packages/core/lib/src/util.dart | 27 - packages/core/performance/hello/angel.md | 65 - packages/core/performance/hello/main.dart | 23 - packages/core/performance/hello/raw.dart | 18 - packages/core/performance/hello/raw.md | 63 - packages/core/pubspec.lock | 685 -------- packages/core/pubspec.yaml | 52 - packages/core/test/accepts_test.dart | 70 - packages/core/test/all.dart | 64 - .../core/test/anonymous_service_test.dart | 44 - packages/core/test/body_test.dart | 139 -- packages/core/test/common.dart | 60 - packages/core/test/controller_test.dart | 206 --- packages/core/test/detach_test.dart | 35 - packages/core/test/di_test.dart | 141 -- packages/core/test/encoders_buffer_test.dart | 112 -- packages/core/test/env_test.dart | 19 - packages/core/test/exception_test.dart | 70 - packages/core/test/extension_test.dart | 32 - packages/core/test/find_one_test.dart | 25 - packages/core/test/general_test.dart | 36 - packages/core/test/hm.dart | 14 - packages/core/test/hooked_test.dart | 148 -- packages/core/test/http2/adapter_test.dart | 305 ---- packages/core/test/http2/http2_client.dart | 105 -- packages/core/test/http_404_hole_test.dart | 80 - packages/core/test/jsonp_test.dart | 57 - packages/core/test/parameter_meta_test.dart | 150 -- packages/core/test/parse_id_test.dart | 33 - packages/core/test/precontained_test.dart | 33 - packages/core/test/pretty_log.dart | 38 - packages/core/test/primitives_test.dart | 75 - packages/core/test/repeat_request_test.dart | 33 - packages/core/test/req_shutdown_test.dart | 46 - packages/core/test/response_header_test.dart | 58 - packages/core/test/routing_test.dart | 223 --- packages/core/test/serialize_test.dart | 43 - packages/core/test/server_test.dart | 226 --- packages/core/test/service_map_test.dart | 84 - packages/core/test/services_test.dart | 131 -- packages/core/test/streaming_test.dart | 119 -- packages/core/test/view_generator_test.dart | 10 - packages/{pipeline => database}/.gitignore | 0 packages/{pipeline => database}/CHANGELOG.md | 0 packages/{pipeline => database}/LICENSE.md | 0 packages/{events => database}/README.md | 0 .../analysis_options.yaml | 0 packages/database/doc/.gitkeep | 0 packages/database/example/.gitkeep | 0 packages/database/lib/src/.gitkeep | 0 packages/database/pubspec.yaml | 17 + packages/database/test/.gitkeep | 0 packages/events/lib/dispatcher.dart | 3 - packages/events/lib/src/dispatcher.dart | 499 ------ packages/events/test/event_test.dart | 430 ----- packages/{process => filesystem}/.gitignore | 0 packages/{process => filesystem}/CHANGELOG.md | 0 packages/{process => filesystem}/LICENSE.md | 0 packages/filesystem/README.md | 39 + .../analysis_options.yaml | 0 packages/filesystem/doc/.gitkeep | 0 packages/filesystem/example/.gitkeep | 0 packages/filesystem/lib/src/.gitkeep | 0 packages/{bus => filesystem}/pubspec.yaml | 11 +- packages/filesystem/test/.gitkeep | 0 .../mqueue => packages/foundation}/.gitignore | 0 packages/{queue => foundation}/CHANGELOG.md | 0 packages/{queue => foundation}/LICENSE.md | 0 packages/foundation/README.md | 39 + .../analysis_options.yaml | 0 packages/foundation/doc/.gitkeep | 0 packages/foundation/example/.gitkeep | 0 packages/foundation/lib/src/.gitkeep | 0 packages/foundation/pubspec.yaml | 17 + packages/foundation/test/.gitkeep | 0 packages/{queue => http}/.gitignore | 3 - packages/http/CHANGELOG.md | 3 + packages/http/LICENSE.md | 10 + packages/http/README.md | 39 + packages/http/analysis_options.yaml | 30 + packages/http/doc/.gitkeep | 0 packages/http/example/.gitkeep | 0 packages/http/pubspec.yaml | 21 + packages/http/test/.gitkeep | 0 packages/lucifer | 1 + packages/model/.gitignore | 71 - packages/model/AUTHORS.md | 12 - packages/model/CHANGELOG.md | 77 - packages/model/LICENSE | 29 - packages/model/README.md | 19 - packages/model/analysis_options.yaml | 2 - packages/model/example/main.dart | 19 - packages/model/lib/model.dart | 35 - packages/model/pubspec.yaml | 11 - packages/pipeline/README.md | 380 ----- .../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 - .../pipeline/test/laravel_pipeline_test.dart | 258 --- packages/pipeline/test/pipeline_test.dart | 106 -- packages/process/README.md | 1 - .../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/README.md | 1 - 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 ---- packages/reflection/LICENSE | 21 - packages/reflection/README.md | 167 -- .../example/reflection_example.dart | 172 -- packages/reflection/lib/reflection.dart | 8 - packages/reflection/lib/src/annotations.dart | 216 --- packages/reflection/lib/src/exceptions.dart | 32 - packages/reflection/lib/src/metadata.dart | 258 --- packages/reflection/lib/src/reflector.dart | 258 --- packages/reflection/lib/src/types.dart | 19 - packages/reflection/pubspec.lock | 402 ----- packages/reflection/pubspec.yaml | 12 - packages/reflection/test/reflection_test.dart | 236 --- packages/route/.gitignore | 71 - packages/route/AUTHORS.md | 12 - packages/route/CHANGELOG.md | 98 -- packages/route/LICENSE | 29 - packages/route/README.md | 136 -- packages/route/analysis_options.yaml | 1 - packages/route/example/main.dart | 58 - packages/route/lib/browser.dart | 225 --- packages/route/lib/route.dart | 5 - packages/route/lib/src/grammar.dart | 327 ---- .../route/lib/src/middleware_pipeline.dart | 50 - packages/route/lib/src/route.dart | 99 -- packages/route/lib/src/router.dart | 493 ------ packages/route/lib/src/routing_exception.dart | 21 - packages/route/lib/src/routing_result.dart | 95 -- packages/route/lib/src/symlink_route.dart | 8 - packages/route/lib/string_util.dart | 43 - packages/route/pubspec.yaml | 18 - packages/route/repubspec.yaml | 2 - packages/route/test/chain_nest_test.dart | 19 - packages/route/test/navigate_test.dart | 44 - packages/route/test/params_test.dart | 45 - packages/route/test/parse_test.dart | 20 - packages/route/test/root_test.dart | 15 - packages/route/test/server_test.dart | 205 --- packages/route/test/strip_test.dart | 46 - packages/route/test/uri_decode_test.dart | 18 - packages/route/test/wildcard_test.dart | 46 - packages/route/web/hash/basic.dart | 4 - packages/route/web/hash/basic.html | 30 - packages/route/web/index.html | 15 - packages/route/web/push_state/basic.dart | 4 - packages/route/web/push_state/basic.html | 31 - packages/route/web/shared/basic.dart | 42 - packages/routing/.gitignore | 7 + packages/routing/CHANGELOG.md | 3 + packages/routing/LICENSE.md | 10 + packages/routing/README.md | 39 + packages/routing/analysis_options.yaml | 30 + packages/routing/doc/.gitkeep | 0 packages/routing/example/.gitkeep | 0 packages/routing/lib/src/.gitkeep | 0 packages/routing/pubspec.yaml | 17 + packages/routing/test/.gitkeep | 0 packages/session/.gitignore | 7 + packages/session/CHANGELOG.md | 3 + packages/session/LICENSE.md | 10 + packages/session/README.md | 39 + packages/session/analysis_options.yaml | 30 + packages/session/doc/.gitkeep | 0 packages/session/example/.gitkeep | 0 packages/session/lib/src/.gitkeep | 0 packages/session/pubspec.yaml | 17 + packages/session/test/.gitkeep | 0 packages/support/LICENSE.md | 10 + packages/support/README.md | 6 +- packages/support/doc/.gitkeep | 0 packages/support/example/.gitkeep | 0 .../support/example/exception_example.dart | 4 - .../example/service_provider_example.dart | 67 - packages/support/lib/exceptions.dart | 8 - packages/support/lib/providers.dart | 6 - packages/support/lib/src/.gitkeep | 0 .../lib/src/exceptions/http_exception.dart | 123 -- .../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 | 17 +- packages/support/test/.gitkeep | 0 .../support/test/providers_http_test.dart | 129 -- packages/support/test/providers_test.dart | 236 --- packages/testing/AUTHORS.md | 12 - packages/testing/CHANGELOG.md | 79 +- packages/testing/LICENSE | 29 - packages/testing/LICENSE.md | 10 + packages/testing/README.md | 45 +- packages/testing/doc/.gitkeep | 0 packages/testing/example/main.dart | 8 - packages/testing/lib/http.dart | 6 - packages/testing/lib/src/.gitkeep | 0 .../testing/lib/src/http/connection_info.dart | 13 - packages/testing/lib/src/http/headers.dart | 174 -- .../lib/src/http/lockable_headers.dart | 67 - packages/testing/lib/src/http/request.dart | 323 ---- packages/testing/lib/src/http/response.dart | 151 -- packages/testing/lib/src/http/session.dart | 74 - packages/testing/pubspec.yaml | 14 +- packages/testing/test/.gitkeep | 0 packages/testing/test/all_test.dart | 69 - packages/validation/.gitignore | 7 + packages/validation/CHANGELOG.md | 3 + packages/validation/LICENSE.md | 10 + packages/validation/README.md | 39 + packages/validation/analysis_options.yaml | 30 + packages/validation/doc/.gitkeep | 0 packages/validation/example/.gitkeep | 0 packages/validation/lib/src/.gitkeep | 0 packages/validation/pubspec.yaml | 17 + packages/validation/test/.gitkeep | 0 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 16548 -> 0 bytes sandbox/eventbus/doc/video_presentation.gif | Bin 1887898 -> 0 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/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 94259 -> 0 bytes sandbox/mqueue/assets/components.png | Bin 30338 -> 0 bytes sandbox/mqueue/assets/default-exchange.png | Bin 24526 -> 0 bytes sandbox/mqueue/assets/detailed-view.png | Bin 138254 -> 0 bytes sandbox/mqueue/assets/direct-exchange.png | Bin 42545 -> 0 bytes sandbox/mqueue/assets/fanout-exchange.png | Bin 26191 -> 0 bytes sandbox/mqueue/assets/simple-view.png | Bin 36356 -> 0 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 54748 -> 0 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 --- 675 files changed, 651 insertions(+), 61127 deletions(-) delete mode 100644 packages/bus/lib/angel3_bus.dart delete mode 100644 packages/bus/lib/src/batch.dart delete mode 100644 packages/bus/lib/src/bus_service_provider.dart delete mode 100644 packages/bus/lib/src/chain.dart delete mode 100644 packages/bus/lib/src/command.dart delete mode 100644 packages/bus/lib/src/dispatcher.dart delete mode 100644 packages/bus/lib/src/handler.dart delete mode 100644 packages/bus/lib/src/queue.dart delete mode 100644 packages/bus/test/dispatcher_test.dart rename packages/{bus => config}/.gitignore (100%) rename packages/{bus => config}/CHANGELOG.md (100%) rename packages/{bus => config}/LICENSE.md (100%) rename packages/{bus => config}/README.md (100%) rename packages/{bus => config}/analysis_options.yaml (100%) create mode 100644 packages/config/doc/.gitkeep create mode 100644 packages/config/example/.gitkeep create mode 100644 packages/config/lib/src/.gitkeep rename packages/{pipeline => config}/pubspec.yaml (51%) create mode 100644 packages/config/test/.gitkeep delete mode 100644 packages/container/container/.gitignore delete mode 100644 packages/container/container/AUTHORS.md delete mode 100644 packages/container/container/CHANGELOG.md delete mode 100644 packages/container/container/LICENSE delete mode 100644 packages/container/container/README.md delete mode 100644 packages/container/container/analysis_options.yaml delete mode 100644 packages/container/container/example/main.dart delete mode 100644 packages/container/container/example/throwing.dart delete mode 100644 packages/container/container/lib/container.dart delete mode 100644 packages/container/container/lib/mirrors.dart delete mode 100644 packages/container/container/lib/src/container.dart delete mode 100644 packages/container/container/lib/src/container_const.dart delete mode 100644 packages/container/container/lib/src/empty/empty.dart delete mode 100644 packages/container/container/lib/src/exception.dart delete mode 100644 packages/container/container/lib/src/mirrors/mirrors.dart delete mode 100644 packages/container/container/lib/src/mirrors/reflector.dart delete mode 100644 packages/container/container/lib/src/reflectable/reflectable.dart delete mode 100644 packages/container/container/lib/src/reflector.dart delete mode 100644 packages/container/container/lib/src/static/static.dart delete mode 100644 packages/container/container/lib/src/throwing.dart delete mode 100644 packages/container/container/pubspec.yaml delete mode 100644 packages/container/container/test/common.dart delete mode 100644 packages/container/container/test/empty_reflector_test.dart delete mode 100644 packages/container/container/test/has_test.dart delete mode 100644 packages/container/container/test/lazy_test.dart delete mode 100644 packages/container/container/test/mirrors_test.dart delete mode 100644 packages/container/container/test/named_test.dart delete mode 100644 packages/container/container/test/throwing_reflector_test.dart delete mode 100644 packages/container/container_generator/.gitignore delete mode 100644 packages/container/container_generator/CHANGELOG.md delete mode 100644 packages/container/container_generator/LICENSE delete mode 100644 packages/container/container_generator/README.md delete mode 100644 packages/container/container_generator/analysis_options.yaml delete mode 100644 packages/container/container_generator/example/main.dart delete mode 100644 packages/container/container_generator/lib/generator.dart delete mode 100644 packages/container/container_generator/pubspec.yaml delete mode 100644 packages/container/container_generator/test/reflector_test.dart delete mode 100644 packages/contracts/lib/contracts.dart delete mode 100644 packages/contracts/lib/src/bus/bus.dart delete mode 100644 packages/contracts/lib/src/bus/bus_contract.dart delete mode 100644 packages/contracts/lib/src/container/container.dart delete mode 100644 packages/contracts/lib/src/container/container_contract.dart delete mode 100644 packages/contracts/lib/src/container/contextual_binding_contract.dart delete mode 100644 packages/contracts/lib/src/events/event_dispatcher_contract.dart delete mode 100644 packages/contracts/lib/src/events/events.dart delete mode 100644 packages/contracts/lib/src/http/http.dart delete mode 100644 packages/contracts/lib/src/http/http_contract.dart delete mode 100644 packages/contracts/lib/src/model/model.dart delete mode 100644 packages/contracts/lib/src/model/model_contract.dart delete mode 100644 packages/contracts/lib/src/pipeline/pipeline.dart delete mode 100644 packages/contracts/lib/src/pipeline/pipeline_contract.dart delete mode 100644 packages/contracts/lib/src/process/process.dart delete mode 100644 packages/contracts/lib/src/process/process_contract.dart delete mode 100644 packages/contracts/lib/src/queue/queue.dart delete mode 100644 packages/contracts/lib/src/queue/queue_contract.dart delete mode 100644 packages/contracts/lib/src/reflection/reflection.dart delete mode 100644 packages/contracts/lib/src/reflection/reflector_contract.dart delete mode 100644 packages/contracts/lib/src/routing/routing.dart delete mode 100644 packages/contracts/lib/src/routing/routing_contract.dart delete mode 100644 packages/contracts/lib/src/support/support.dart delete mode 100644 packages/contracts/lib/src/support/support_contract.dart delete mode 100644 packages/contracts/lib/src/testing/testing.dart delete mode 100644 packages/contracts/lib/src/testing/testing_contract.dart delete mode 100644 packages/contracts/pubspec.lock delete mode 100644 packages/contracts/pubspec.yaml rename packages/{events => cookie}/.gitignore (100%) rename packages/{events => cookie}/CHANGELOG.md (100%) rename packages/{events => cookie}/LICENSE.md (100%) create mode 100644 packages/cookie/README.md rename packages/{events => cookie}/analysis_options.yaml (100%) create mode 100644 packages/cookie/doc/.gitkeep create mode 100644 packages/cookie/example/.gitkeep create mode 100644 packages/cookie/lib/src/.gitkeep rename packages/{events => cookie}/pubspec.yaml (57%) create mode 100644 packages/cookie/test/.gitkeep delete mode 100644 packages/core/.gitignore delete mode 100644 packages/core/AUTHORS.md delete mode 100644 packages/core/CHANGELOG.md delete mode 100644 packages/core/LICENSE delete mode 100644 packages/core/README.md delete mode 100644 packages/core/analysis_options.yaml delete mode 100644 packages/core/dev.key delete mode 100644 packages/core/dev.pem delete mode 100644 packages/core/example/controller.dart delete mode 100644 packages/core/example/handle_error.dart delete mode 100644 packages/core/example/hostname.dart delete mode 100644 packages/core/example/http2/body_parsing.dart delete mode 100644 packages/core/example/http2/common.dart delete mode 100644 packages/core/example/http2/dev.key delete mode 100644 packages/core/example/http2/dev.pem delete mode 100644 packages/core/example/http2/main.dart delete mode 100644 packages/core/example/http2/public/app.js delete mode 100644 packages/core/example/http2/public/body_parsing.html delete mode 100644 packages/core/example/http2/public/index.html delete mode 100644 packages/core/example/http2/public/style.css delete mode 100644 packages/core/example/http2/server_push.dart delete mode 100644 packages/core/example/json.dart delete mode 100644 packages/core/example/main.dart delete mode 100644 packages/core/example/map_service.dart delete mode 100644 packages/core/example/status.dart delete mode 100644 packages/core/example/view.dart delete mode 100644 packages/core/example/views/index.jl delete mode 100644 packages/core/lib/core.dart delete mode 100644 packages/core/lib/http.dart delete mode 100644 packages/core/lib/http2.dart delete mode 100644 packages/core/lib/src/core/anonymous_service.dart delete mode 100644 packages/core/lib/src/core/controller.dart delete mode 100644 packages/core/lib/src/core/core.dart delete mode 100644 packages/core/lib/src/core/driver.dart delete mode 100644 packages/core/lib/src/core/env.dart delete mode 100644 packages/core/lib/src/core/hooked_service.dart delete mode 100644 packages/core/lib/src/core/hostname_parser.dart delete mode 100644 packages/core/lib/src/core/hostname_router.dart delete mode 100644 packages/core/lib/src/core/injection.dart delete mode 100644 packages/core/lib/src/core/map_service.dart delete mode 100644 packages/core/lib/src/core/metadata.dart delete mode 100644 packages/core/lib/src/core/request_context.dart delete mode 100644 packages/core/lib/src/core/response_context.dart delete mode 100644 packages/core/lib/src/core/routable.dart delete mode 100644 packages/core/lib/src/core/server.dart delete mode 100644 packages/core/lib/src/core/service.dart delete mode 100644 packages/core/lib/src/fast_name_from_symbol.dart delete mode 100644 packages/core/lib/src/http/http.dart delete mode 100644 packages/core/lib/src/http/http_request_context.dart delete mode 100644 packages/core/lib/src/http/http_response_context.dart delete mode 100644 packages/core/lib/src/http/protevus_http.dart delete mode 100644 packages/core/lib/src/http2/http2_request_context.dart delete mode 100644 packages/core/lib/src/http2/http2_response_context.dart delete mode 100644 packages/core/lib/src/http2/protevus_http2.dart delete mode 100644 packages/core/lib/src/safe_stream_controller.dart delete mode 100644 packages/core/lib/src/util.dart delete mode 100644 packages/core/performance/hello/angel.md delete mode 100644 packages/core/performance/hello/main.dart delete mode 100644 packages/core/performance/hello/raw.dart delete mode 100644 packages/core/performance/hello/raw.md delete mode 100644 packages/core/pubspec.lock delete mode 100644 packages/core/pubspec.yaml delete mode 100644 packages/core/test/accepts_test.dart delete mode 100644 packages/core/test/all.dart delete mode 100644 packages/core/test/anonymous_service_test.dart delete mode 100644 packages/core/test/body_test.dart delete mode 100644 packages/core/test/common.dart delete mode 100644 packages/core/test/controller_test.dart delete mode 100644 packages/core/test/detach_test.dart delete mode 100644 packages/core/test/di_test.dart delete mode 100644 packages/core/test/encoders_buffer_test.dart delete mode 100644 packages/core/test/env_test.dart delete mode 100644 packages/core/test/exception_test.dart delete mode 100644 packages/core/test/extension_test.dart delete mode 100644 packages/core/test/find_one_test.dart delete mode 100644 packages/core/test/general_test.dart delete mode 100644 packages/core/test/hm.dart delete mode 100644 packages/core/test/hooked_test.dart delete mode 100644 packages/core/test/http2/adapter_test.dart delete mode 100644 packages/core/test/http2/http2_client.dart delete mode 100644 packages/core/test/http_404_hole_test.dart delete mode 100644 packages/core/test/jsonp_test.dart delete mode 100644 packages/core/test/parameter_meta_test.dart delete mode 100644 packages/core/test/parse_id_test.dart delete mode 100644 packages/core/test/precontained_test.dart delete mode 100644 packages/core/test/pretty_log.dart delete mode 100644 packages/core/test/primitives_test.dart delete mode 100644 packages/core/test/repeat_request_test.dart delete mode 100644 packages/core/test/req_shutdown_test.dart delete mode 100644 packages/core/test/response_header_test.dart delete mode 100644 packages/core/test/routing_test.dart delete mode 100644 packages/core/test/serialize_test.dart delete mode 100644 packages/core/test/server_test.dart delete mode 100644 packages/core/test/service_map_test.dart delete mode 100644 packages/core/test/services_test.dart delete mode 100644 packages/core/test/streaming_test.dart delete mode 100644 packages/core/test/view_generator_test.dart rename packages/{pipeline => database}/.gitignore (100%) rename packages/{pipeline => database}/CHANGELOG.md (100%) rename packages/{pipeline => database}/LICENSE.md (100%) rename packages/{events => database}/README.md (100%) rename packages/{pipeline => database}/analysis_options.yaml (100%) create mode 100644 packages/database/doc/.gitkeep create mode 100644 packages/database/example/.gitkeep create mode 100644 packages/database/lib/src/.gitkeep create mode 100644 packages/database/pubspec.yaml create mode 100644 packages/database/test/.gitkeep delete mode 100644 packages/events/lib/dispatcher.dart delete mode 100644 packages/events/lib/src/dispatcher.dart delete mode 100644 packages/events/test/event_test.dart rename packages/{process => filesystem}/.gitignore (100%) rename packages/{process => filesystem}/CHANGELOG.md (100%) rename packages/{process => filesystem}/LICENSE.md (100%) create mode 100644 packages/filesystem/README.md rename packages/{process => filesystem}/analysis_options.yaml (100%) create mode 100644 packages/filesystem/doc/.gitkeep create mode 100644 packages/filesystem/example/.gitkeep create mode 100644 packages/filesystem/lib/src/.gitkeep rename packages/{bus => filesystem}/pubspec.yaml (53%) create mode 100644 packages/filesystem/test/.gitkeep rename {sandbox/mqueue => packages/foundation}/.gitignore (100%) rename packages/{queue => foundation}/CHANGELOG.md (100%) rename packages/{queue => foundation}/LICENSE.md (100%) create mode 100644 packages/foundation/README.md rename packages/{queue => foundation}/analysis_options.yaml (100%) create mode 100644 packages/foundation/doc/.gitkeep create mode 100644 packages/foundation/example/.gitkeep create mode 100644 packages/foundation/lib/src/.gitkeep create mode 100644 packages/foundation/pubspec.yaml create mode 100644 packages/foundation/test/.gitkeep rename packages/{queue => http}/.gitignore (87%) create mode 100644 packages/http/CHANGELOG.md create mode 100644 packages/http/LICENSE.md create mode 100644 packages/http/README.md create mode 100644 packages/http/analysis_options.yaml create mode 100644 packages/http/doc/.gitkeep create mode 100644 packages/http/example/.gitkeep create mode 100644 packages/http/pubspec.yaml create mode 100644 packages/http/test/.gitkeep create mode 160000 packages/lucifer delete mode 100644 packages/model/.gitignore delete mode 100644 packages/model/AUTHORS.md delete mode 100644 packages/model/CHANGELOG.md delete mode 100644 packages/model/LICENSE delete mode 100644 packages/model/README.md delete mode 100644 packages/model/analysis_options.yaml delete mode 100644 packages/model/example/main.dart delete mode 100644 packages/model/lib/model.dart delete mode 100644 packages/model/pubspec.yaml delete mode 100644 packages/pipeline/README.md delete mode 100644 packages/pipeline/examples/async_pipeline.dart delete mode 100644 packages/pipeline/examples/basic_usage.dart delete mode 100644 packages/pipeline/examples/error_handling.dart delete mode 100644 packages/pipeline/examples/mixed_pipes.dart delete mode 100644 packages/pipeline/lib/pipeline.dart delete mode 100644 packages/pipeline/lib/src/conditionable.dart delete mode 100644 packages/pipeline/lib/src/pipeline.dart delete mode 100644 packages/pipeline/lib/src/pipeline_contract.dart delete mode 100644 packages/pipeline/test/laravel_pipeline_test.dart delete mode 100644 packages/pipeline/test/pipeline_test.dart delete mode 100644 packages/process/README.md delete mode 100644 packages/process/examples/basic_process/main.dart delete mode 100644 packages/process/examples/process_pipeline/main.dart delete mode 100644 packages/process/examples/process_pool/main.dart delete mode 100644 packages/process/examples/web_server_with_processes/main.dart delete mode 100644 packages/process/examples/web_server_with_processes/views/index.mustache delete mode 100644 packages/process/lib/angel3_process.dart delete mode 100644 packages/process/lib/src/process.dart delete mode 100644 packages/process/lib/src/process_helper.dart delete mode 100644 packages/process/lib/src/process_manager.dart delete mode 100644 packages/process/lib/src/process_pipeline.dart delete mode 100644 packages/process/lib/src/process_pool.dart delete mode 100644 packages/process/lib/src/process_service_provider.dart delete mode 100644 packages/process/pubspec.yaml delete mode 100644 packages/process/test/process_test.dart delete mode 100644 packages/process/test/process_test_extended.dart delete mode 100644 packages/queue/README.md delete mode 100644 packages/queue/lib/queue.dart delete mode 100644 packages/queue/lib/src/job_queued_event.dart delete mode 100644 packages/queue/lib/src/job_queueing_event.dart delete mode 100644 packages/queue/lib/src/queue.dart delete mode 100644 packages/queue/lib/src/should_be_encrypted.dart delete mode 100644 packages/queue/lib/src/should_queue_after_commit.dart delete mode 100644 packages/queue/pubspec.yaml delete mode 100644 packages/queue/test/queue_test.dart delete mode 100644 packages/reflection/LICENSE delete mode 100644 packages/reflection/README.md delete mode 100644 packages/reflection/example/reflection_example.dart delete mode 100644 packages/reflection/lib/reflection.dart delete mode 100644 packages/reflection/lib/src/annotations.dart delete mode 100644 packages/reflection/lib/src/exceptions.dart delete mode 100644 packages/reflection/lib/src/metadata.dart delete mode 100644 packages/reflection/lib/src/reflector.dart delete mode 100644 packages/reflection/lib/src/types.dart delete mode 100644 packages/reflection/pubspec.lock delete mode 100644 packages/reflection/pubspec.yaml delete mode 100644 packages/reflection/test/reflection_test.dart delete mode 100644 packages/route/.gitignore delete mode 100644 packages/route/AUTHORS.md delete mode 100644 packages/route/CHANGELOG.md delete mode 100644 packages/route/LICENSE delete mode 100644 packages/route/README.md delete mode 100644 packages/route/analysis_options.yaml delete mode 100644 packages/route/example/main.dart delete mode 100644 packages/route/lib/browser.dart delete mode 100644 packages/route/lib/route.dart delete mode 100644 packages/route/lib/src/grammar.dart delete mode 100644 packages/route/lib/src/middleware_pipeline.dart delete mode 100644 packages/route/lib/src/route.dart delete mode 100644 packages/route/lib/src/router.dart delete mode 100644 packages/route/lib/src/routing_exception.dart delete mode 100644 packages/route/lib/src/routing_result.dart delete mode 100644 packages/route/lib/src/symlink_route.dart delete mode 100644 packages/route/lib/string_util.dart delete mode 100644 packages/route/pubspec.yaml delete mode 100644 packages/route/repubspec.yaml delete mode 100644 packages/route/test/chain_nest_test.dart delete mode 100644 packages/route/test/navigate_test.dart delete mode 100644 packages/route/test/params_test.dart delete mode 100644 packages/route/test/parse_test.dart delete mode 100644 packages/route/test/root_test.dart delete mode 100644 packages/route/test/server_test.dart delete mode 100644 packages/route/test/strip_test.dart delete mode 100644 packages/route/test/uri_decode_test.dart delete mode 100644 packages/route/test/wildcard_test.dart delete mode 100644 packages/route/web/hash/basic.dart delete mode 100644 packages/route/web/hash/basic.html delete mode 100644 packages/route/web/index.html delete mode 100644 packages/route/web/push_state/basic.dart delete mode 100644 packages/route/web/push_state/basic.html delete mode 100644 packages/route/web/shared/basic.dart create mode 100644 packages/routing/.gitignore create mode 100644 packages/routing/CHANGELOG.md create mode 100644 packages/routing/LICENSE.md create mode 100644 packages/routing/README.md create mode 100644 packages/routing/analysis_options.yaml create mode 100644 packages/routing/doc/.gitkeep create mode 100644 packages/routing/example/.gitkeep create mode 100644 packages/routing/lib/src/.gitkeep create mode 100644 packages/routing/pubspec.yaml create mode 100644 packages/routing/test/.gitkeep create mode 100644 packages/session/.gitignore create mode 100644 packages/session/CHANGELOG.md create mode 100644 packages/session/LICENSE.md create mode 100644 packages/session/README.md create mode 100644 packages/session/analysis_options.yaml create mode 100644 packages/session/doc/.gitkeep create mode 100644 packages/session/example/.gitkeep create mode 100644 packages/session/lib/src/.gitkeep create mode 100644 packages/session/pubspec.yaml create mode 100644 packages/session/test/.gitkeep create mode 100644 packages/support/LICENSE.md create mode 100644 packages/support/doc/.gitkeep create mode 100644 packages/support/example/.gitkeep delete mode 100644 packages/support/example/exception_example.dart delete mode 100644 packages/support/example/service_provider_example.dart delete mode 100644 packages/support/lib/exceptions.dart delete mode 100644 packages/support/lib/providers.dart create mode 100644 packages/support/lib/src/.gitkeep delete mode 100644 packages/support/lib/src/exceptions/http_exception.dart delete mode 100644 packages/support/lib/src/providers/contracts/service_provider.dart delete mode 100644 packages/support/lib/src/providers/deferred_service_provider.dart delete mode 100644 packages/support/lib/src/providers/providers.dart delete mode 100644 packages/support/lib/src/providers/service_provider.dart delete mode 100644 packages/support/lib/src/providers/service_provider_static.dart delete mode 100644 packages/support/lib/src/providers/service_provider_support.dart create mode 100644 packages/support/test/.gitkeep delete mode 100644 packages/support/test/providers_http_test.dart delete mode 100644 packages/support/test/providers_test.dart delete mode 100644 packages/testing/AUTHORS.md delete mode 100644 packages/testing/LICENSE create mode 100644 packages/testing/LICENSE.md create mode 100644 packages/testing/doc/.gitkeep delete mode 100644 packages/testing/example/main.dart delete mode 100644 packages/testing/lib/http.dart create mode 100644 packages/testing/lib/src/.gitkeep delete mode 100644 packages/testing/lib/src/http/connection_info.dart delete mode 100644 packages/testing/lib/src/http/headers.dart delete mode 100644 packages/testing/lib/src/http/lockable_headers.dart delete mode 100644 packages/testing/lib/src/http/request.dart delete mode 100644 packages/testing/lib/src/http/response.dart delete mode 100644 packages/testing/lib/src/http/session.dart create mode 100644 packages/testing/test/.gitkeep delete mode 100644 packages/testing/test/all_test.dart create mode 100644 packages/validation/.gitignore create mode 100644 packages/validation/CHANGELOG.md create mode 100644 packages/validation/LICENSE.md create mode 100644 packages/validation/README.md create mode 100644 packages/validation/analysis_options.yaml create mode 100644 packages/validation/doc/.gitkeep create mode 100644 packages/validation/example/.gitkeep create mode 100644 packages/validation/lib/src/.gitkeep create mode 100644 packages/validation/pubspec.yaml create mode 100644 packages/validation/test/.gitkeep delete mode 100644 sandbox/eventbus/.github/workflows/dart.yml delete mode 100644 sandbox/eventbus/.gitignore delete mode 100644 sandbox/eventbus/.metadata delete mode 100644 sandbox/eventbus/.vscode/settings.json delete mode 100644 sandbox/eventbus/CHANGELOG.md delete mode 100644 sandbox/eventbus/LICENSE delete mode 100644 sandbox/eventbus/README.md delete mode 100644 sandbox/eventbus/analysis_options.yaml delete mode 100644 sandbox/eventbus/doc/pub_sub.webp delete mode 100644 sandbox/eventbus/doc/video_presentation.gif delete mode 100644 sandbox/eventbus/lib/event_bus.dart delete mode 100644 sandbox/eventbus/lib/res/app_event.dart delete mode 100644 sandbox/eventbus/lib/res/event_bus.dart delete mode 100644 sandbox/eventbus/lib/res/history_entry.dart delete mode 100644 sandbox/eventbus/lib/res/res.dart delete mode 100644 sandbox/eventbus/lib/res/subscription.dart delete mode 100644 sandbox/eventbus/pubspec.yaml delete mode 100644 sandbox/eventbus/test/completion_test.dart delete mode 100644 sandbox/eventbus/test/distinct_test.dart delete mode 100644 sandbox/eventbus/test/empty_event_test.dart delete mode 100644 sandbox/eventbus/test/event_bus_test.dart delete mode 100644 sandbox/eventbus/test/history_test.dart delete mode 100644 sandbox/eventbus/test/mapping/map_ignore_test.dart delete mode 100644 sandbox/eventbus/test/mapping/map_test.dart delete mode 100644 sandbox/eventbus/test/models.dart delete mode 100644 sandbox/eventbus/test/respond_test.dart delete mode 100644 sandbox/eventbus/test/streams_test.dart delete mode 100644 sandbox/eventbus/test/timestamp_test.dart delete mode 100755 sandbox/eventbus/tool/coverage.sh delete mode 100644 sandbox/mqueue/.github/workflows/action.yaml delete mode 100644 sandbox/mqueue/CHANGELOG.md delete mode 100644 sandbox/mqueue/LICENSE delete mode 100644 sandbox/mqueue/README.md delete mode 100644 sandbox/mqueue/analysis_options.yaml delete mode 100644 sandbox/mqueue/assets/components-mq.png delete mode 100644 sandbox/mqueue/assets/components.png delete mode 100644 sandbox/mqueue/assets/default-exchange.png delete mode 100644 sandbox/mqueue/assets/detailed-view.png delete mode 100644 sandbox/mqueue/assets/direct-exchange.png delete mode 100644 sandbox/mqueue/assets/fanout-exchange.png delete mode 100644 sandbox/mqueue/assets/simple-view.png delete mode 100644 sandbox/mqueue/example/main.dart delete mode 100644 sandbox/mqueue/example/message_filtering/main.dart delete mode 100644 sandbox/mqueue/example/message_filtering/task_manager.dart delete mode 100644 sandbox/mqueue/example/message_filtering/worker_one.dart delete mode 100644 sandbox/mqueue/example/message_filtering/worker_two.dart delete mode 100644 sandbox/mqueue/example/receiver.dart delete mode 100644 sandbox/mqueue/example/routing/debug_logger.dart delete mode 100644 sandbox/mqueue/example/routing/logger.dart delete mode 100644 sandbox/mqueue/example/routing/main.dart delete mode 100644 sandbox/mqueue/example/routing/production_logger.dart delete mode 100644 sandbox/mqueue/example/rpc/main.dart delete mode 100644 sandbox/mqueue/example/rpc/service_one.dart delete mode 100644 sandbox/mqueue/example/rpc/service_two.dart delete mode 100644 sandbox/mqueue/example/sender.dart delete mode 100644 sandbox/mqueue/lib/mq.dart delete mode 100644 sandbox/mqueue/lib/src/binding/binding.dart delete mode 100644 sandbox/mqueue/lib/src/binding/binding.interface.dart delete mode 100644 sandbox/mqueue/lib/src/consumer/consumer.dart delete mode 100644 sandbox/mqueue/lib/src/consumer/consumer.interface.dart delete mode 100644 sandbox/mqueue/lib/src/consumer/consumer.mixin.dart delete mode 100644 sandbox/mqueue/lib/src/core/constants/enums.dart delete mode 100644 sandbox/mqueue/lib/src/core/constants/error_strings.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/binding_exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/consumer_exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/exchange_exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/mq_client_exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/queue_exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/registrar_exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/exceptions/routing_key_exceptions.dart delete mode 100644 sandbox/mqueue/lib/src/core/registrar/simple_registrar.dart delete mode 100644 sandbox/mqueue/lib/src/exchange/default_exchange.dart delete mode 100644 sandbox/mqueue/lib/src/exchange/direct_exchange.dart delete mode 100644 sandbox/mqueue/lib/src/exchange/exchange.base.dart delete mode 100644 sandbox/mqueue/lib/src/exchange/exchange_interface.dart delete mode 100644 sandbox/mqueue/lib/src/exchange/fanout_exchange.dart delete mode 100644 sandbox/mqueue/lib/src/message/message.base.dart delete mode 100644 sandbox/mqueue/lib/src/message/message.dart delete mode 100644 sandbox/mqueue/lib/src/mq/mq.base.dart delete mode 100644 sandbox/mqueue/lib/src/mq/mq.dart delete mode 100644 sandbox/mqueue/lib/src/mq/mq.interface.dart delete mode 100644 sandbox/mqueue/lib/src/producer/producer.dart delete mode 100644 sandbox/mqueue/lib/src/producer/producer.interface.dart delete mode 100644 sandbox/mqueue/lib/src/producer/producer.mixin.dart delete mode 100644 sandbox/mqueue/lib/src/queue/data_stream.base.dart delete mode 100644 sandbox/mqueue/lib/src/queue/queue.dart delete mode 100644 sandbox/mqueue/pubspec.yaml delete mode 100644 sandbox/mqueue/test/binding/binding_test.dart delete mode 100644 sandbox/mqueue/test/consumer/consumer_test.dart delete mode 100644 sandbox/mqueue/test/core/exceptions/binding_exceptions_test.dart delete mode 100644 sandbox/mqueue/test/core/exceptions/consumer_exceptions_test.dart delete mode 100644 sandbox/mqueue/test/core/exceptions/exchange_exceptions_test.dart delete mode 100644 sandbox/mqueue/test/core/exceptions/mq_client_exceptions_test.dart delete mode 100644 sandbox/mqueue/test/core/exceptions/queue_exceptions_test.dart delete mode 100644 sandbox/mqueue/test/core/exceptions/registrar_exceptions_test.dart delete mode 100644 sandbox/mqueue/test/core/exceptions/routing_key_exceptionss_test.dart delete mode 100644 sandbox/mqueue/test/core/registrar/simple_registrar_test.dart delete mode 100644 sandbox/mqueue/test/exchange/default_exchange_test.dart delete mode 100644 sandbox/mqueue/test/exchange/direct_exchange_test.dart delete mode 100644 sandbox/mqueue/test/exchange/fanout_exchange_test.dart delete mode 100644 sandbox/mqueue/test/message/message.base_test.dart delete mode 100644 sandbox/mqueue/test/mq/mq_test.dart delete mode 100644 sandbox/mqueue/test/producer/producer_test.dart delete mode 100644 sandbox/mqueue/test/queue/queue_test.dart delete mode 100644 sandbox/reactivex/.gitignore delete mode 100644 sandbox/reactivex/CHANGELOG.md delete mode 100644 sandbox/reactivex/LICENSE delete mode 100644 sandbox/reactivex/README.md delete mode 100644 sandbox/reactivex/analysis_options.yaml delete mode 100644 sandbox/reactivex/lib/angel3_reactivex.dart delete mode 100644 sandbox/reactivex/lib/src/rx.dart delete mode 100644 sandbox/reactivex/lib/src/streams/combine_latest.dart delete mode 100644 sandbox/reactivex/lib/src/streams/concat.dart delete mode 100644 sandbox/reactivex/lib/src/streams/concat_eager.dart delete mode 100644 sandbox/reactivex/lib/src/streams/connectable_stream.dart delete mode 100644 sandbox/reactivex/lib/src/streams/defer.dart delete mode 100644 sandbox/reactivex/lib/src/streams/fork_join.dart delete mode 100644 sandbox/reactivex/lib/src/streams/from_callable.dart delete mode 100644 sandbox/reactivex/lib/src/streams/merge.dart delete mode 100644 sandbox/reactivex/lib/src/streams/never.dart delete mode 100644 sandbox/reactivex/lib/src/streams/race.dart delete mode 100644 sandbox/reactivex/lib/src/streams/range.dart delete mode 100644 sandbox/reactivex/lib/src/streams/repeat.dart delete mode 100644 sandbox/reactivex/lib/src/streams/replay_stream.dart delete mode 100644 sandbox/reactivex/lib/src/streams/retry.dart delete mode 100644 sandbox/reactivex/lib/src/streams/retry_when.dart delete mode 100644 sandbox/reactivex/lib/src/streams/sequence_equal.dart delete mode 100644 sandbox/reactivex/lib/src/streams/switch_latest.dart delete mode 100644 sandbox/reactivex/lib/src/streams/timer.dart delete mode 100644 sandbox/reactivex/lib/src/streams/using.dart delete mode 100644 sandbox/reactivex/lib/src/streams/value_stream.dart delete mode 100644 sandbox/reactivex/lib/src/streams/zip.dart delete mode 100644 sandbox/reactivex/lib/src/subjects/behavior_subject.dart delete mode 100644 sandbox/reactivex/lib/src/subjects/publish_subject.dart delete mode 100644 sandbox/reactivex/lib/src/subjects/replay_subject.dart delete mode 100644 sandbox/reactivex/lib/src/subjects/subject.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/backpressure.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/buffer.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/debounce.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/pairwise.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/sample.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/throttle.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/backpressure/window.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/default_if_empty.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/delay.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/delay_when.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/dematerialize.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/distinct_unique.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/do.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/end_with.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/end_with_many.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/exhaust_map.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/flat_map.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/group_by.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/ignore_elements.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/interval.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/map_not_null.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/map_to.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/materialize.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/max.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/min.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/on_error_resume.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/scan.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/skip_last.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/skip_until.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/start_with.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/start_with_error.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/start_with_many.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/switch_if_empty.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/switch_map.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/take_last.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/take_until.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/take_while_inclusive.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/time_interval.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/timestamp.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/where_not_null.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/where_type.dart delete mode 100644 sandbox/reactivex/lib/src/transformers/with_latest_from.dart delete mode 100644 sandbox/reactivex/lib/src/utils/collection_extensions.dart delete mode 100644 sandbox/reactivex/lib/src/utils/composite_subscription.dart delete mode 100644 sandbox/reactivex/lib/src/utils/empty.dart delete mode 100644 sandbox/reactivex/lib/src/utils/error_and_stacktrace.dart delete mode 100644 sandbox/reactivex/lib/src/utils/forwarding_sink.dart delete mode 100644 sandbox/reactivex/lib/src/utils/forwarding_stream.dart delete mode 100644 sandbox/reactivex/lib/src/utils/future.dart delete mode 100644 sandbox/reactivex/lib/src/utils/min_max.dart delete mode 100644 sandbox/reactivex/lib/src/utils/notification.dart delete mode 100644 sandbox/reactivex/lib/src/utils/subscription.dart delete mode 100644 sandbox/reactivex/lib/streams.dart delete mode 100644 sandbox/reactivex/lib/subjects.dart delete mode 100644 sandbox/reactivex/lib/transformers.dart delete mode 100644 sandbox/reactivex/lib/utils.dart delete mode 100644 sandbox/reactivex/pubspec.yaml delete mode 100644 sandbox/reactivex/screenshots/logo.png delete mode 100644 sandbox/reactivex/test/rxdart_test.dart delete mode 100644 sandbox/reactivex/test/streams/combine_latest_test.dart delete mode 100644 sandbox/reactivex/test/streams/concat_eager_test.dart delete mode 100644 sandbox/reactivex/test/streams/concat_test.dart delete mode 100644 sandbox/reactivex/test/streams/defer_test.dart delete mode 100644 sandbox/reactivex/test/streams/fork_join_test.dart delete mode 100644 sandbox/reactivex/test/streams/from_callable_test.dart delete mode 100644 sandbox/reactivex/test/streams/merge_test.dart delete mode 100644 sandbox/reactivex/test/streams/never_test.dart delete mode 100644 sandbox/reactivex/test/streams/publish_connectable_stream_test.dart delete mode 100644 sandbox/reactivex/test/streams/race_test.dart delete mode 100644 sandbox/reactivex/test/streams/range_test.dart delete mode 100644 sandbox/reactivex/test/streams/repeat_test.dart delete mode 100644 sandbox/reactivex/test/streams/replay_connectable_stream_test.dart delete mode 100644 sandbox/reactivex/test/streams/retry_test.dart delete mode 100644 sandbox/reactivex/test/streams/retry_when_test.dart delete mode 100644 sandbox/reactivex/test/streams/sequence_equals_test.dart delete mode 100644 sandbox/reactivex/test/streams/switch_latest_test.dart delete mode 100644 sandbox/reactivex/test/streams/timer_test.dart delete mode 100644 sandbox/reactivex/test/streams/using_test.dart delete mode 100644 sandbox/reactivex/test/streams/value_connectable_stream_test.dart delete mode 100644 sandbox/reactivex/test/streams/zip_test.dart delete mode 100644 sandbox/reactivex/test/subject/behavior_subject_test.dart delete mode 100644 sandbox/reactivex/test/subject/publish_subject_test.dart delete mode 100644 sandbox/reactivex/test/subject/replay_subject_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_count_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_test_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/buffer_time_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/debounce_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/debounce_time_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/pairwise_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/sample_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/sample_time_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/throttle_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/throttle_time_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/window_count_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/window_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/window_test_test.dart delete mode 100644 sandbox/reactivex/test/transformers/backpressure/window_time_test.dart delete mode 100644 sandbox/reactivex/test/transformers/concat_with_test.dart delete mode 100644 sandbox/reactivex/test/transformers/default_if_empty_test.dart delete mode 100644 sandbox/reactivex/test/transformers/delay_test.dart delete mode 100644 sandbox/reactivex/test/transformers/delay_when_test.dart delete mode 100644 sandbox/reactivex/test/transformers/dematerialize_test.dart delete mode 100644 sandbox/reactivex/test/transformers/distinct_test.dart delete mode 100644 sandbox/reactivex/test/transformers/distinct_unique_test.dart delete mode 100644 sandbox/reactivex/test/transformers/do_test.dart delete mode 100644 sandbox/reactivex/test/transformers/end_with_many_test.dart delete mode 100644 sandbox/reactivex/test/transformers/end_with_test.dart delete mode 100644 sandbox/reactivex/test/transformers/exhaust_map_test.dart delete mode 100644 sandbox/reactivex/test/transformers/flat_map_iterable_test.dart delete mode 100644 sandbox/reactivex/test/transformers/flat_map_test.dart delete mode 100644 sandbox/reactivex/test/transformers/group_by_test.dart delete mode 100644 sandbox/reactivex/test/transformers/ignore_elements_test.dart delete mode 100644 sandbox/reactivex/test/transformers/interval_test.dart delete mode 100644 sandbox/reactivex/test/transformers/join_test.dart delete mode 100644 sandbox/reactivex/test/transformers/map_not_null_test.dart delete mode 100644 sandbox/reactivex/test/transformers/map_to_test.dart delete mode 100644 sandbox/reactivex/test/transformers/materialize_test.dart delete mode 100644 sandbox/reactivex/test/transformers/max_test.dart delete mode 100644 sandbox/reactivex/test/transformers/merge_with_test.dart delete mode 100644 sandbox/reactivex/test/transformers/min_test.dart delete mode 100644 sandbox/reactivex/test/transformers/on_error_resume_test.dart delete mode 100644 sandbox/reactivex/test/transformers/on_error_return_test.dart delete mode 100644 sandbox/reactivex/test/transformers/on_error_return_with_test.dart delete mode 100644 sandbox/reactivex/test/transformers/scan_test.dart delete mode 100644 sandbox/reactivex/test/transformers/skip_last_test.dart delete mode 100644 sandbox/reactivex/test/transformers/skip_until_test.dart delete mode 100644 sandbox/reactivex/test/transformers/start_with_error_test.dart delete mode 100644 sandbox/reactivex/test/transformers/start_with_many_test.dart delete mode 100644 sandbox/reactivex/test/transformers/start_with_test.dart delete mode 100644 sandbox/reactivex/test/transformers/switch_if_empty_test.dart delete mode 100644 sandbox/reactivex/test/transformers/switch_map_test.dart delete mode 100644 sandbox/reactivex/test/transformers/take_last_test.dart delete mode 100644 sandbox/reactivex/test/transformers/take_until_test.dart delete mode 100644 sandbox/reactivex/test/transformers/take_while_inclusive_test.dart delete mode 100644 sandbox/reactivex/test/transformers/time_interval_test.dart delete mode 100644 sandbox/reactivex/test/transformers/timeout_test.dart delete mode 100644 sandbox/reactivex/test/transformers/timestamp_test.dart delete mode 100644 sandbox/reactivex/test/transformers/where_not_null_test.dart delete mode 100644 sandbox/reactivex/test/transformers/where_type_test.dart delete mode 100644 sandbox/reactivex/test/transformers/with_latest_from_test.dart delete mode 100644 sandbox/reactivex/test/transformers/zip_with_test.dart delete mode 100644 sandbox/reactivex/test/utils.dart delete mode 100644 sandbox/reactivex/test/utils/composite_subscription_test.dart delete mode 100644 sandbox/reactivex/test/utils/notification_test.dart diff --git a/packages/bus/lib/angel3_bus.dart b/packages/bus/lib/angel3_bus.dart deleted file mode 100644 index 536519b..0000000 --- a/packages/bus/lib/angel3_bus.dart +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 5a2a24f..0000000 --- a/packages/bus/lib/src/batch.dart +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index d892653..0000000 --- a/packages/bus/lib/src/bus_service_provider.dart +++ /dev/null @@ -1,60 +0,0 @@ -// // 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 deleted file mode 100644 index f46dc4e..0000000 --- a/packages/bus/lib/src/chain.dart +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 81d5395..0000000 --- a/packages/bus/lib/src/command.dart +++ /dev/null @@ -1,5 +0,0 @@ -// 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 deleted file mode 100644 index fcf1ea6..0000000 --- a/packages/bus/lib/src/dispatcher.dart +++ /dev/null @@ -1,251 +0,0 @@ -// 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 deleted file mode 100644 index 1c8cdfe..0000000 --- a/packages/bus/lib/src/handler.dart +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 5d4b999..0000000 --- a/packages/bus/lib/src/queue.dart +++ /dev/null @@ -1,8 +0,0 @@ -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/test/dispatcher_test.dart b/packages/bus/test/dispatcher_test.dart deleted file mode 100644 index a931ffb..0000000 --- a/packages/bus/test/dispatcher_test.dart +++ /dev/null @@ -1,197 +0,0 @@ -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/bus/.gitignore b/packages/config/.gitignore similarity index 100% rename from packages/bus/.gitignore rename to packages/config/.gitignore diff --git a/packages/bus/CHANGELOG.md b/packages/config/CHANGELOG.md similarity index 100% rename from packages/bus/CHANGELOG.md rename to packages/config/CHANGELOG.md diff --git a/packages/bus/LICENSE.md b/packages/config/LICENSE.md similarity index 100% rename from packages/bus/LICENSE.md rename to packages/config/LICENSE.md diff --git a/packages/bus/README.md b/packages/config/README.md similarity index 100% rename from packages/bus/README.md rename to packages/config/README.md diff --git a/packages/bus/analysis_options.yaml b/packages/config/analysis_options.yaml similarity index 100% rename from packages/bus/analysis_options.yaml rename to packages/config/analysis_options.yaml diff --git a/packages/config/doc/.gitkeep b/packages/config/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/config/example/.gitkeep b/packages/config/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/config/lib/src/.gitkeep b/packages/config/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/pipeline/pubspec.yaml b/packages/config/pubspec.yaml similarity index 51% rename from packages/pipeline/pubspec.yaml rename to packages/config/pubspec.yaml index 92c1efb..dfe8308 100644 --- a/packages/pipeline/pubspec.yaml +++ b/packages/config/pubspec.yaml @@ -1,18 +1,16 @@ -name: platform_pipeline -description: The Pipeline Package for the Protevus Platform +name: platform_config +description: The Configuration Package for the Protevus Platform version: 0.0.1 homepage: https://protevus.com documentation: https://docs.protevus.com -repository: https://github.com/protevus/platform +repository: https://git.protevus.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 + #protevus_runtime: ^0.0.1 dev_dependencies: lints: ^3.0.0 diff --git a/packages/config/test/.gitkeep b/packages/config/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/container/container/.gitignore b/packages/container/container/.gitignore deleted file mode 100644 index 24d6831..0000000 --- a/packages/container/container/.gitignore +++ /dev/null @@ -1,71 +0,0 @@ -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub -.dart_tool -.packages -.pub/ -build/ - -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock - -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - -### Dart template -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub - -# SDK 1.20 and later (no longer creates packages directories) - -# Older SDK versions -# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20) -.project -.buildlog -**/packages/ - - -# Files created by dart2js -# (Most Dart developers will use pub build to compile Dart, use/modify these -# rules if you intend to use dart2js directly -# Convention is to use extension '.dart.js' for Dart compiled to Javascript to -# differentiate from explicit Javascript files) -*.dart.js -*.part.js -*.js.deps -*.js.map -*.info.json - -# Directory created by dartdoc - -# Don't commit pubspec lock file -# (Library packages only! Remove pattern if developing an application package) -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: - -## VsCode -.vscode/ - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -.idea/ -/out/ -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties diff --git a/packages/container/container/AUTHORS.md b/packages/container/container/AUTHORS.md deleted file mode 100644 index ac95ab5..0000000 --- a/packages/container/container/AUTHORS.md +++ /dev/null @@ -1,12 +0,0 @@ -Primary Authors -=============== - -* __[Thomas Hii](dukefirehawk.apps@gmail.com)__ - - Thomas is the current maintainer of the code base. He has refactored and migrated the - code base to support NNBD. - -* __[Tobe O](thosakwe@gmail.com)__ - - Tobe has written much of the original code prior to NNBD migration. He has moved on and - is no longer involved with the project. diff --git a/packages/container/container/CHANGELOG.md b/packages/container/container/CHANGELOG.md deleted file mode 100644 index 377e468..0000000 --- a/packages/container/container/CHANGELOG.md +++ /dev/null @@ -1,151 +0,0 @@ -# Change Log - -## 8.1.1 - -* Updated repository link - -## 8.1.0 - -* Updated `lints` to 3.0.0 -* Fixed analyser warnings - -## 8.0.0 - -* Require Dart >= 3.0 - -## 7.1.0-beta.2 - -* Require Dart >= 2.19 -* Refactored `EmptyReflector` - -## 7.1.0-beta.1 - -* Require Dart >= 2.18 -* Moved `defaultErrorMessage` to `ContainerConst` class to resolve reflectatable issue. -* Added `hashCode` - -## 7.0.0 - -* Require Dart >= 2.17 - -## 6.0.0 - -* Require Dart >= 2.16 -* Removed `error` - -## 5.0.0 - -* Skipped release - -## 4.0.0 - -* Skipped release - -## 3.1.1 - -* Updated `_ReflectedMethodMirror` to have optional `returnType` parameter -* Updated `Container` to handle non nullable type - -## 3.1.0 - -* Updated linter to `package:lints` - -## 3.0.2 - -* Resolved static analysis warnings - -## 3.0.1 - -* Updated README - -## 3.0.0 - -* Migrated to support Dart >= 2.12 NNBD - -## 2.0.0 - -* Migrated to work with Dart >= 2.12 Non NNBD - -## 1.1.0 - -* `pedantic` lints. -* Add `ThrowingReflector`, which throws on all operations. -* `EmptyReflector` uses `Object` instead of `dynamic` as its returned -type, as the `dynamic` type is (apparently?) no longer a valid constant value. -* `registerSingleton` now returns the provided `object`. -* `registerFactory` and `registerLazySingleton` now return the provided function `f`. - -## 1.0.4 - -* Slight patch to prevent annoying segfault. - -## 1.0.3 - -* Added `Future` support to `Reflector`. - -## 1.0.2 - -* Added `makeAsync`. - -## 1.0.1 - -* Added `hasNamed`. - -## 1.0.0 - -* Removed `@GenerateReflector`. - -## 1.0.0-alpha.12 - -* `StaticReflector` now defaults to empty arguments. - -## 1.0.0-alpha.11 - -* Added `StaticReflector`. - -## 1.0.0-alpha.10 - -* Added `Container.registerLazySingleton`. -* Added named singleton support. - -## 1.0.0-alpha.9 - -* Added `Container.has`. - -## 1.0.0-alpha.8 - -* Fixed a bug where `_ReflectedTypeInstance.isAssignableTo` always failed. -* Added `@GenerateReflector` annotation. - -## 1.0.0-alpha.7 - -* Add `EmptyReflector`. -* `ReflectedType.newInstance` now returns a `ReflectedInstance`. -* Moved `ReflectedInstance.invoke` to `ReflectedFunction.invoke`. - -## 1.0.0-alpha.6 - -* Add `getField` to `ReflectedInstance`. - -## 1.0.0-alpha.5 - -* Remove concrete type from `ReflectedTypeParameter`. - -## 1.0.0-alpha.4 - -* Safely handle `void` return types of methods. - -## 1.0.0-alpha.3 - -* Reflecting `void` in `MirrorsReflector` now forwards to `dynamic`. - -## 1.0.0-alpha.2 - -* Added `ReflectedInstance.reflectee`. - -## 1.0.0-alpha.1 - -* Allow omission of the first argument of `Container.make`, to use -a generic type argument instead. -* `singleton` -> `registerSingleton` -* Add `createChild`, and support hierarchical containers. diff --git a/packages/container/container/LICENSE b/packages/container/container/LICENSE deleted file mode 100644 index df5e063..0000000 --- a/packages/container/container/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2021, dukefirehawk.com -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/container/container/README.md b/packages/container/container/README.md deleted file mode 100644 index 2aaf571..0000000 --- a/packages/container/container/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Protevus Container - -![Pub Version (including pre-releases)](https://img.shields.io/pub/v/platform_container?include_prereleases) -[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety) -[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion) -[![License](https://img.shields.io/github/license/dart-backend/angel)](https://github.com/dart-backend/angel/tree/master/packages/container/angel_container/LICENSE) - -A better IoC container for Protevus, ultimately allowing Protevus to be used with or without `dart:mirrors` package. - -```dart - import 'package:platform_container/mirrors.dart'; - import 'package:platform_core/core.dart'; - import 'package:platform_core/http.dart'; - - @Expose('/sales', middleware: [process1]) - class SalesController extends Controller { - @Expose('/', middleware: [process2]) - Future route1(RequestContext req, ResponseContext res) async { - return "Sales route"; - } - } - - bool process1(RequestContext req, ResponseContext res) { - res.write('Hello, '); - return true; - } - - bool process2(RequestContext req, ResponseContext res) { - res.write('From Sales, '); - return true; - } - - void main() async { - // Using Mirror Reflector - var app = Protevus(reflector: MirrorsReflector()); - - // Sales Controller - app.container.registerSingleton(SalesController()); - await app.mountController(); - - var http = PlatformHttp(app); - var server = await http.startServer('localhost', 3000); - print("Protevus server listening at ${http.uri}"); - } -``` diff --git a/packages/container/container/analysis_options.yaml b/packages/container/container/analysis_options.yaml deleted file mode 100644 index ea2c9e9..0000000 --- a/packages/container/container/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:lints/recommended.yaml \ No newline at end of file diff --git a/packages/container/container/example/main.dart b/packages/container/container/example/main.dart deleted file mode 100644 index 35b1bd6..0000000 --- a/packages/container/container/example/main.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'dart:async'; - -import 'package:platform_container/container.dart'; -import 'package:platform_container/mirrors.dart'; - -Future main() async { - // Create a container instance. - var container = Container(const MirrorsReflector()); - - // Register a singleton. - container.registerSingleton(Engine(40)); - - // You can also omit the type annotation, in which the object's runtime type will be used. - // If you're injecting an abstract class, prefer the type annotation. - // - // container.registerSingleton(Engine(40)); - - // Register a factory that creates a truck. - container.registerFactory((container) { - return _TruckImpl(container.make()); - }); - - // Use `make` to create an instance. - var truck = container.make(); - - // You can also resolve injections asynchronously. - container.registerFactory>((_) async => 24); - print(await container.makeAsync()); - - // Asynchronous resolution also works for plain objects. - await container.makeAsync().then((t) => t.drive()); - - // Register a named singleton. - container.registerNamedSingleton('the_truck', truck); - - // Should print: 'Vroom! I have 40 horsepower in my engine.' - truck.drive(); - - // Should print the same. - container.findByName('the_truck').drive(); - - // We can make a child container with its own factory. - var childContainer = container.createChild(); - - childContainer.registerFactory((container) { - return _TruckImpl(Engine(5666)); - }); - - // Make a truck with 5666 HP. - childContainer.make().drive(); - - // However, calling `make` will return the Engine singleton we created above. - print(childContainer.make().horsePower); -} - -abstract class Truck { - void drive(); -} - -class Engine { - final int horsePower; - - Engine(this.horsePower); -} - -class _TruckImpl implements Truck { - final Engine engine; - - _TruckImpl(this.engine); - - @override - void drive() { - print('Vroom! I have ${engine.horsePower} horsepower in my engine.'); - } -} diff --git a/packages/container/container/example/throwing.dart b/packages/container/container/example/throwing.dart deleted file mode 100644 index cde5d33..0000000 --- a/packages/container/container/example/throwing.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:platform_container/container.dart'; - -void main() { - var reflector = const ThrowingReflector(); - reflector.reflectClass(StringBuffer); -} diff --git a/packages/container/container/lib/container.dart b/packages/container/container/lib/container.dart deleted file mode 100644 index db227c5..0000000 --- a/packages/container/container/lib/container.dart +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -library platform_container; - -export 'src/container.dart'; -export 'src/empty/empty.dart'; -export 'src/static/static.dart'; -export 'src/exception.dart'; -export 'src/reflector.dart'; -export 'src/throwing.dart'; -export 'src/container_const.dart'; diff --git a/packages/container/container/lib/mirrors.dart b/packages/container/container/lib/mirrors.dart deleted file mode 100644 index 848c298..0000000 --- a/packages/container/container/lib/mirrors.dart +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -export 'src/mirrors/mirrors.dart'; diff --git a/packages/container/container/lib/src/container.dart b/packages/container/container/lib/src/container.dart deleted file mode 100644 index e1c3743..0000000 --- a/packages/container/container/lib/src/container.dart +++ /dev/null @@ -1,396 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:async'; -import 'exception.dart'; -import 'reflector.dart'; - -class Container { - /// The [Reflector] instance used by this container for reflection-based operations. - /// - /// This reflector is used to instantiate objects and resolve dependencies - /// when no explicit factory or singleton is registered for a given type. - final Reflector reflector; - - /// A map that stores singleton instances, where the key is the Type and the value is the singleton object. - /// - /// This map is used internally by the Container to store and retrieve singleton objects - /// that have been registered using the [registerSingleton] method. - final Map _singletons = {}; - - /// A map that stores factory functions for creating instances of different types. - /// - /// The key is the Type for which the factory is registered, and the value is a function - /// that takes a Container as an argument and returns an instance of that Type. - /// - /// This map is used internally by the Container to store and retrieve factory functions - /// that have been registered using the [registerFactory] method. - final Map _factories = {}; - - /// A map that stores named singleton instances, where the key is a String name and the value is the singleton object. - /// - /// This map is used internally by the Container to store and retrieve named singleton objects - /// that have been registered using the [registerNamedSingleton] method. Named singletons allow - /// for multiple instances of the same type to be stored in the container with different names. - final Map _namedSingletons = {}; - - /// The parent container of this container, if any. - /// - /// This property is used to create a hierarchy of containers, where child containers - /// can access dependencies registered in their parent containers. If this container - /// is a root container (i.e., it has no parent), this property will be null. - /// - /// The parent-child relationship allows for scoped dependency injection, where - /// child containers can override or add to the dependencies defined in their parents. - final Container? _parent; - - /// Creates a new root [Container] instance with the given [Reflector]. - /// - /// This constructor initializes a new container without a parent, making it - /// a root container in the dependency injection hierarchy. The provided - /// [reflector] will be used for all reflection-based operations within this - /// container and its child containers. - /// - /// Parameters: - /// - [reflector]: The [Reflector] instance to be used by this container - /// for reflection-based dependency resolution and object instantiation. - /// - /// The [_parent] is set to null, indicating that this is a root container. - Container(this.reflector) : _parent = null; - - /// Creates a child [Container] instance with the given parent container. - /// - /// This constructor is used internally to create child containers in the - /// dependency injection hierarchy. It initializes a new container with a - /// reference to its parent container and uses the same [Reflector] instance - /// as the parent. - /// - /// Parameters: - /// - [_parent]: The parent [Container] instance for this child container. - /// - /// The [reflector] is initialized with the parent container's reflector, - /// ensuring consistency in reflection operations throughout the container - /// hierarchy. - Container._child(Container this._parent) : reflector = _parent.reflector; - - /// Checks if this container is a root container. - /// - /// Returns `true` if this container has no parent (i.e., it's a root container), - /// and `false` otherwise. - /// - /// This property is useful for determining the position of a container in the - /// dependency injection hierarchy. Root containers are typically used as the - /// top-level containers in an application, while non-root containers are child - /// containers that may have more specific or localized dependencies. - bool get isRoot => _parent == null; - - /// Creates a child [Container] that can define its own singletons and factories. - /// - /// This method creates a new [Container] instance that is a child of the current container. - /// The child container inherits access to all dependencies registered in its parent containers, - /// but can also define its own singletons and factories that override or extend the parent's dependencies. - /// - /// Child containers are useful for creating scoped dependency injection contexts, such as - /// for specific features, modules, or request-scoped dependencies in web applications. - /// - /// The child container uses the same [Reflector] instance as its parent. - /// - /// Returns: - /// A new [Container] instance that is a child of the current container. - /// - /// Example: - /// ```dart - /// var parentContainer = Container(MyReflector()); - /// var childContainer = parentContainer.createChild(); - /// ``` - Container createChild() { - return Container._child(this); - } - - /// Determines if the container or any of its parent containers has an injection of the given type. - /// - /// This method checks for both singleton and factory registrations of the specified type. - /// - /// Parameters: - /// - [T]: The type to check for. If [T] is dynamic, the [t] parameter must be provided. - /// - [t]: An optional Type parameter. If provided, it overrides the type specified by [T]. - /// - /// Returns: - /// - `true` if an injection (singleton or factory) for the specified type is found in this - /// container or any of its parent containers. - /// - `false` if no injection is found for the specified type in the entire container hierarchy. - /// - /// Note: - /// - If [T] is dynamic and [t] is null, the method returns `false` immediately. - /// - The method searches the current container first, then moves up the parent hierarchy - /// until an injection is found or the root container is reached. - bool has([Type? t]) { - var t2 = T; - if (t != null) { - t2 = t; - } else if (T == dynamic && t == null) { - return false; - } - - Container? search = this; - while (search != null) { - if (search._singletons.containsKey(t2)) { - return true; - } else if (search._factories.containsKey(t2)) { - return true; - } else { - search = search._parent; - } - } - - return false; - } - - /// Determines if the container or any of its parent containers has a named singleton with the given [name]. - /// - /// This method searches the current container and its parent hierarchy for a named singleton - /// registered with the specified [name]. - /// - /// Parameters: - /// - [name]: The name of the singleton to search for. - /// - /// Returns: - /// - `true` if a named singleton with the specified [name] is found in this container - /// or any of its parent containers. - /// - `false` if no named singleton with the specified [name] is found in the entire - /// container hierarchy. - /// - /// The method searches the current container first, then moves up the parent hierarchy - /// until a named singleton is found or the root container is reached. - bool hasNamed(String name) { - Container? search = this; - - while (search != null) { - if (search._namedSingletons.containsKey(name)) { - return true; - } else { - search = search._parent; - } - } - - return false; - } - - /// Asynchronously instantiates an instance of [T]. - /// - /// This method attempts to resolve and return a [Future] in the following order: - /// 1. If an injection of type [T] is registered, it wraps it in a [Future] and returns it. - /// 2. If an injection of type [Future] is registered, it returns it directly. - /// 3. If [T] is [dynamic] and a [Future] of the specified type is registered, it returns that. - /// 4. If none of the above conditions are met, it throws a [ReflectionException]. - /// - /// Parameters: - /// - [type]: An optional [Type] parameter that can be used to specify the type - /// when [T] is [dynamic] or when a different type than [T] needs to be used. - /// - /// Returns: - /// A [Future] representing the asynchronously resolved instance. - /// - /// Throws: - /// - [ReflectionException] if no suitable injection is found. - /// - /// This method is useful when you need to resolve dependencies that may be - /// registered as either synchronous ([T]) or asynchronous ([Future]) types. - Future makeAsync([Type? type]) { - var t2 = T; - if (type != null) { - t2 = type; - } - - Type? futureType; //.Future.value(null).runtimeType; - - if (T == dynamic) { - try { - futureType = reflector.reflectFutureOf(t2).reflectedType; - } on UnsupportedError { - // Ignore this. - } - } - - if (has(t2)) { - return Future.value(make(t2)); - } else if (has>()) { - return make>(); - } else if (futureType != null) { - return make(futureType); - } else { - throw ReflectionException( - 'No injection for Future<$t2> or $t2 was found.'); - } - } - - /// Instantiates an instance of [T]. - /// - /// This method attempts to resolve and return an instance of type [T] in the following order: - /// 1. If a singleton of type [T] is registered in this container or any parent container, it returns that instance. - /// 2. If a factory for type [T] is registered in this container or any parent container, it calls the factory and returns the result. - /// 3. If no singleton or factory is found, it uses reflection to instantiate a new instance of [T]. - /// - /// For reflection-based instantiation: - /// - It looks for a default constructor or a constructor with an empty name. - /// - It recursively resolves and injects dependencies for the constructor parameters. - /// - It supports both positional and named parameters. - /// - /// Parameters: - /// - [type]: An optional [Type] parameter that can be used to specify the type - /// when [T] is [dynamic] or when a different type than [T] needs to be used. - /// - /// Returns: - /// An instance of type [T]. - /// - /// Throws: - /// - [ReflectionException] if [T] is not a class or if it has no default constructor. - /// - Any exception that might occur during the instantiation process. - /// - /// This method is central to the dependency injection mechanism, allowing for - /// flexible object creation and dependency resolution within the container hierarchy. - T make([Type? type]) { - Type t2 = T; - if (type != null) { - t2 = type; - } - - Container? search = this; - - while (search != null) { - if (search._singletons.containsKey(t2)) { - // Find a singleton, if any. - return search._singletons[t2] as T; - } else if (search._factories.containsKey(t2)) { - // Find a factory, if any. - return search._factories[t2]!(this) as T; - } else { - search = search._parent; - } - } - - var reflectedType = reflector.reflectType(t2); - var positional = []; - var named = {}; - - if (reflectedType is ReflectedClass) { - bool isDefault(String name) { - return name.isEmpty || name == reflectedType.name; - } - - var constructor = reflectedType.constructors.firstWhere( - (c) => isDefault(c.name), - orElse: (() => throw ReflectionException( - '${reflectedType.name} has no default constructor, and therefore cannot be instantiated.'))); - - for (var param in constructor.parameters) { - var value = make(param.type.reflectedType); - - if (param.isNamed) { - named[param.name] = value; - } else { - positional.add(value); - } - } - - return reflectedType.newInstance( - isDefault(constructor.name) ? '' : constructor.name, - positional, - named, []).reflectee as T; - } else { - throw ReflectionException( - '$t2 is not a class, and therefore cannot be instantiated.'); - } - } - - /// Registers a lazy singleton factory. - /// - /// In many cases, you might prefer this to [registerFactory]. - /// - /// Returns [f]. - T Function(Container) registerLazySingleton(T Function(Container) f, - {Type? as}) { - return registerFactory( - (container) { - var r = f(container); - container.registerSingleton(r, as: as); - return r; - }, - as: as, - ); - } - - /// Registers a factory function for creating instances of type [T] in the container. - /// - /// Returns [f]. - T Function(Container) registerFactory(T Function(Container) f, - {Type? as}) { - Type t2 = T; - if (as != null) { - t2 = as; - } - - if (_factories.containsKey(t2)) { - throw StateError('This container already has a factory for $t2.'); - } - - _factories[t2] = f; - return f; - } - - /// Registers a singleton object in the container. - /// - /// Returns [object]. - T registerSingleton(T object, {Type? as}) { - Type t2 = T; - if (as != null) { - t2 = as; - } else if (T == dynamic) { - t2 = as ?? object.runtimeType; - } - //as ??= T == dynamic ? as : T; - - if (_singletons.containsKey(t2)) { - throw StateError('This container already has a singleton for $t2.'); - } - - _singletons[t2] = object; - return object; - } - - /// Retrieves a named singleton from the container or its parent containers. - /// - /// In general, prefer using [registerSingleton] and [registerFactory]. - /// - /// [findByName] is best reserved for internal logic that end users of code should - /// not see. - T findByName(String name) { - if (_namedSingletons.containsKey(name)) { - return _namedSingletons[name] as T; - } else if (_parent != null) { - return _parent.findByName(name); - } else { - throw StateError( - 'This container does not have a singleton named "$name".'); - } - } - - /// Registers a named singleton object in the container. - /// - /// Note that this is not related to type-based injections, and exists as a mechanism - /// to enable injecting multiple instances of a type within the same container hierarchy. - T registerNamedSingleton(String name, T object) { - if (_namedSingletons.containsKey(name)) { - throw StateError('This container already has a singleton named "$name".'); - } - - _namedSingletons[name] = object; - return object; - } -} diff --git a/packages/container/container/lib/src/container_const.dart b/packages/container/container/lib/src/container_const.dart deleted file mode 100644 index f9c3572..0000000 --- a/packages/container/container/lib/src/container_const.dart +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/// A utility class that contains constant values related to container functionality. -/// -/// This class is not meant to be instantiated and only provides static constants. -/// It includes a default error message for reflection-related issues. -class ContainerConst { - /// The default error message for reflection-related issues. - /// - /// This message is used when an attempt is made to perform a reflective action, - /// but the `ThrowingReflector` class is being used, which disables reflection. - /// Consider using the `MirrorsReflector` class if reflection is necessary. - static const String defaultErrorMessage = - 'You attempted to perform a reflective action, but you are using `ThrowingReflector`, ' - 'a class which disables reflection. Consider using the `MirrorsReflector` ' - 'class if you need reflection.'; - - /// Private constructor to prevent instantiation of this utility class. - /// - /// This constructor is marked as private (with the underscore prefix) to ensure - /// that the `ContainerConst` class cannot be instantiated. This is consistent - /// with the class's purpose of only providing static constants. - ContainerConst._(); -} diff --git a/packages/container/container/lib/src/empty/empty.dart b/packages/container/container/lib/src/empty/empty.dart deleted file mode 100644 index e0c4c43..0000000 --- a/packages/container/container/lib/src/empty/empty.dart +++ /dev/null @@ -1,377 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'package:platform_container/container.dart'; - -/// A cache to store symbol names. -/// -/// This map associates [Symbol] objects with their corresponding string representations. -/// It's used to avoid repeated parsing of symbol names, improving performance -/// when retrieving symbol names multiple times. -final Map _symbolNames = {}; - -/// A [Reflector] implementation that performs no actual reflection, -/// instead returning empty objects on every invocation. -/// -/// Use this in contexts where you know you won't need any reflective capabilities. -/// -/// This class provides a lightweight alternative to full reflection when reflection -/// functionality is not required. It returns empty or placeholder objects for all -/// reflection operations, which can be useful in scenarios where reflection is -/// expected but not actually used, or when you want to minimize the overhead of -/// reflection in certain parts of your application. -/// -/// The [EmptyReflector] includes: -/// - A static [RegExp] for extracting symbol names without reflection. -/// - Methods to return empty implementations of [ReflectedClass], [ReflectedInstance], -/// [ReflectedType], and [ReflectedFunction]. -/// - A [getName] method that uses a cache to store and retrieve symbol names. -/// -/// This implementation can be particularly useful in testing scenarios or in -/// production environments where reflection is not needed but the interface -/// expecting reflection capabilities needs to be satisfied. -class EmptyReflector extends Reflector { - /// A [RegExp] that can be used to extract the name of a symbol without reflection. - /// - /// This regular expression pattern matches the string representation of a Dart [Symbol], - /// which typically looks like 'Symbol("symbolName")'. It captures the symbol name - /// (the part between the quotes) in a capturing group. - /// - /// Usage: - /// ```dart - /// String symbolString = 'Symbol("exampleSymbol")'; - /// Match? match = symbolRegex.firstMatch(symbolString); - /// String? symbolName = match?.group(1); // Returns "exampleSymbol" - /// ``` - /// - /// This is particularly useful in contexts where reflection is not available - /// or desired, allowing for symbol name extraction through string manipulation. - static final RegExp symbolRegex = RegExp(r'Symbol\("([^"]+)"\)'); - - /// Creates an instance of [EmptyReflector]. - /// - /// This constructor doesn't take any parameters and creates a lightweight - /// reflector that provides empty implementations for all reflection operations. - /// It's useful in scenarios where reflection capabilities are expected but not - /// actually used, or when you want to minimize the overhead of reflection. - const EmptyReflector(); - - /// Retrieves the name of a given [Symbol]. - /// - /// This method attempts to extract the name of the provided [symbol] using - /// the [symbolRegex]. If the name hasn't been cached before, it will be - /// computed and stored in the [_symbolNames] cache for future use. - /// - /// The method works as follows: - /// 1. It checks if the symbol's name is already in the cache. - /// 2. If not found, it uses [putIfAbsent] to compute the name: - /// a. It converts the symbol to a string. - /// b. It applies the [symbolRegex] to extract the name. - /// c. If a match is found, it returns the first captured group (the name). - /// 3. The computed name (or null if not found) is stored in the cache and returned. - /// - /// @param symbol The [Symbol] whose name is to be retrieved. - /// @return The name of the symbol as a [String], or null if the name couldn't be extracted. - @override - String? getName(Symbol symbol) { - return _symbolNames.putIfAbsent( - symbol, () => symbolRegex.firstMatch(symbol.toString())?.group(1)); - } - - /// Returns an empty [ReflectedClass] instance for any given [Type]. - /// - /// This method is part of the [EmptyReflector] implementation and always - /// returns a constant instance of [_EmptyReflectedClass], regardless of - /// the input [clazz]. - /// - /// This behavior is consistent with the purpose of [EmptyReflector], - /// which provides non-functional placeholders for reflection operations. - /// - /// @param clazz The [Type] to reflect, which is ignored in this implementation. - /// @return A constant [_EmptyReflectedClass] instance. - @override - ReflectedClass reflectClass(Type clazz) { - return const _EmptyReflectedClass(); - } - - /// Returns an empty [ReflectedInstance] for any given object. - /// - /// This method is part of the [EmptyReflector] implementation and always - /// returns a constant instance of [_EmptyReflectedInstance], regardless of - /// the input [object]. - /// - /// This behavior is consistent with the purpose of [EmptyReflector], - /// which provides non-functional placeholders for reflection operations. - /// - /// @param object The object to reflect, which is ignored in this implementation. - /// @return A constant [_EmptyReflectedInstance]. - @override - ReflectedInstance reflectInstance(Object object) { - return const _EmptyReflectedInstance(); - } - - /// Returns an empty [ReflectedType] for any given [Type]. - /// - /// This method is part of the [EmptyReflector] implementation and always - /// returns a constant instance of [_EmptyReflectedType], regardless of - /// the input [type]. - /// - /// This behavior is consistent with the purpose of [EmptyReflector], - /// which provides non-functional placeholders for reflection operations. - /// - /// @param type The [Type] to reflect, which is ignored in this implementation. - /// @return A constant [_EmptyReflectedType] instance. - @override - ReflectedType reflectType(Type type) { - return const _EmptyReflectedType(); - } - - /// Returns an empty [ReflectedFunction] for any given [Function]. - /// - /// This method is part of the [EmptyReflector] implementation and always - /// returns a constant instance of [_EmptyReflectedFunction], regardless of - /// the input [function]. - /// - /// This behavior is consistent with the purpose of [EmptyReflector], - /// which provides non-functional placeholders for reflection operations. - /// - /// @param function The [Function] to reflect, which is ignored in this implementation. - /// @return A constant [_EmptyReflectedFunction] instance. - @override - ReflectedFunction reflectFunction(Function function) { - return const _EmptyReflectedFunction(); - } -} - -/// An empty implementation of [ReflectedClass] used by [EmptyReflector]. -/// -/// This class provides a non-functional placeholder for reflection operations -/// on classes. It is designed to be used in contexts where reflection capabilities -/// are expected but not actually needed or desired. -/// -/// Key features: -/// - Extends [ReflectedClass] with minimal implementation. -/// - Constructor initializes with empty or default values for all properties. -/// - [newInstance] method throws an [UnsupportedError] if called. -/// - [isAssignableTo] method only returns true if compared with itself. -/// -/// This implementation is consistent with the purpose of [EmptyReflector], -/// providing a lightweight alternative when full reflection capabilities are not required. -class _EmptyReflectedClass extends ReflectedClass { - /// Constructs an empty [_EmptyReflectedClass] instance. - /// - /// This constructor initializes the instance with empty or default values for all properties. - /// - /// @param name The name of the class, set to '(empty)'. - /// @param typeParameters The list of type parameters, set to an empty list. - /// @param instances The list of instances, set to an empty list. - /// @param functions The list of functions, set to an empty list. - /// @param declarations The list of declarations, set to an empty list. - /// @param type The underlying [Type] of the class, set to [Object]. - const _EmptyReflectedClass() - : super( - '(empty)', - const [], - const [], - const [], - const [], - Object); - - /// Creates a new instance of the reflected class. - /// - /// This method is part of the [_EmptyReflectedClass] implementation and always - /// throws an [UnsupportedError] when called. This behavior is consistent with - /// the purpose of [EmptyReflector], which provides non-functional placeholders - /// for reflection operations. - /// - /// @param constructorName The name of the constructor to invoke. - /// @param positionalArguments A list of positional arguments for the constructor. - /// @param namedArguments An optional map of named arguments for the constructor. - /// @param typeArguments An optional list of type arguments for generic classes. - /// @throws UnsupportedError Always thrown when this method is called. - /// @return This method never returns as it always throws an exception. - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map? namedArguments, List? typeArguments]) { - throw UnsupportedError( - 'Classes reflected via an EmptyReflector cannot be instantiated.'); - } - - /// Checks if this empty reflected class is assignable to another reflected type. - /// - /// This method is part of the [_EmptyReflectedClass] implementation and always - /// returns true only if the [other] type is the same instance as this one. - /// This behavior is consistent with the purpose of [EmptyReflector], - /// which provides minimal functionality for reflection operations. - /// - /// @param other The [ReflectedType] to check against. - /// @return true if [other] is the same instance as this, false otherwise. - @override - bool isAssignableTo(ReflectedType? other) { - return other == this; - } -} - -/// An empty implementation of [ReflectedType] used by [EmptyReflector]. -/// -/// This class provides a non-functional placeholder for reflection operations -/// on types. It is designed to be used in contexts where reflection capabilities -/// are expected but not actually needed or desired. -/// -/// Key features: -/// - Extends [ReflectedType] with minimal implementation. -/// - Constructor initializes with empty or default values for all properties. -/// - [newInstance] method throws an [UnsupportedError] if called. -/// - [isAssignableTo] method only returns true if compared with itself. -/// -/// This implementation is consistent with the purpose of [EmptyReflector], -/// providing a lightweight alternative when full reflection capabilities are not required. -class _EmptyReflectedType extends ReflectedType { - /// Constructs an empty [_EmptyReflectedType] instance. - /// - /// This constructor initializes the instance with empty or default values for all properties. - /// - /// @param name The name of the type, set to '(empty)'. - /// @param typeParameters The list of type parameters, set to an empty list. - /// @param type The underlying [Type], set to [Object]. - const _EmptyReflectedType() - : super('(empty)', const [], Object); - - /// Creates a new instance of the reflected type. - /// - /// This method is part of the [_EmptyReflectedType] implementation and always - /// throws an [UnsupportedError] when called. This behavior is consistent with - /// the purpose of [EmptyReflector], which provides non-functional placeholders - /// for reflection operations. - /// - /// @param constructorName The name of the constructor to invoke. - /// @param positionalArguments A list of positional arguments for the constructor. - /// @param namedArguments An optional map of named arguments for the constructor. - /// @param typeArguments An optional list of type arguments for generic types. - /// @throws UnsupportedError Always thrown when this method is called. - /// @return This method never returns as it always throws an exception. - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map namedArguments = const {}, - List typeArguments = const []]) { - throw UnsupportedError( - 'Types reflected via an EmptyReflector cannot be instantiated.'); - } - - /// Checks if this empty reflected type is assignable to another reflected type. - /// - /// This method is part of the [_EmptyReflectedType] implementation and always - /// returns true only if the [other] type is the same instance as this one. - /// This behavior is consistent with the purpose of [EmptyReflector], - /// which provides minimal functionality for reflection operations. - /// - /// @param other The [ReflectedType] to check against. - /// @return true if [other] is the same instance as this, false otherwise. - @override - bool isAssignableTo(ReflectedType? other) { - return other == this; - } -} - -/// An empty implementation of [ReflectedInstance] used by [EmptyReflector]. -/// -/// This class provides a non-functional placeholder for reflection operations -/// on instances. It is designed to be used in contexts where reflection capabilities -/// are expected but not actually needed or desired. -/// -/// Key features: -/// - Extends [ReflectedInstance] with minimal implementation. -/// - Constructor initializes with empty or default values for all properties. -/// - [getField] method throws an [UnsupportedError] if called. -/// -/// This implementation is consistent with the purpose of [EmptyReflector], -/// providing a lightweight alternative when full reflection capabilities are not required. -class _EmptyReflectedInstance extends ReflectedInstance { - /// Constructs an empty [_EmptyReflectedInstance] instance. - /// - /// This constructor initializes the instance with empty or default values for all properties. - /// - /// @param type The reflected type of the instance, set to an empty [_EmptyReflectedType]. - /// @param reflectedClass The reflected class of the instance, set to an empty [_EmptyReflectedClass]. - /// @param value The underlying value of the instance, set to null. - const _EmptyReflectedInstance() - : super(const _EmptyReflectedType(), const _EmptyReflectedClass(), null); - - /// Retrieves the value of a field on this empty reflected instance. - /// - /// This method is part of the [_EmptyReflectedInstance] implementation and always - /// throws an [UnsupportedError] when called. This behavior is consistent with - /// the purpose of [EmptyReflector], which provides non-functional placeholders - /// for reflection operations. - /// - /// @param name The name of the field to retrieve. - /// @throws UnsupportedError Always thrown when this method is called. - /// @return This method never returns as it always throws an exception. - @override - ReflectedInstance getField(String name) { - throw UnsupportedError( - 'Instances reflected via an EmptyReflector cannot call getField().'); - } -} - -/// An empty implementation of [ReflectedFunction] used by [EmptyReflector]. -/// -/// This class provides a non-functional placeholder for reflection operations -/// on functions. It is designed to be used in contexts where reflection capabilities -/// are expected but not actually needed or desired. -/// -/// Key features: -/// - Extends [ReflectedFunction] with minimal implementation. -/// - Constructor initializes with empty or default values for all properties. -/// - [invoke] method throws an [UnsupportedError] if called. -/// -/// This implementation is consistent with the purpose of [EmptyReflector], -/// providing a lightweight alternative when full reflection capabilities are not required. -class _EmptyReflectedFunction extends ReflectedFunction { - /// Constructs an empty [_EmptyReflectedFunction] instance. - /// - /// This constructor initializes the instance with empty or default values for all properties. - /// - /// @param name The name of the function, set to an empty string. - /// @param typeParameters A list of type parameters for the function, set to an empty list. - /// @param enclosingInstance A list of enclosing instances for the function, set to an empty list. - /// @param parameters A list of parameters for the function, set to an empty list. - /// @param isStatic Indicates whether the function is static, set to false. - /// @param isConst Indicates whether the function is constant, set to false. - /// @param returnType The return type of the function, set to an empty [_EmptyReflectedType]. - /// @param isOperator Indicates whether the function is an operator, set to false. - /// @param isExtensionMember Indicates whether the function is an extension member, set to false. - const _EmptyReflectedFunction() - : super( - '(empty)', - const [], - const [], - const [], - false, - false, - returnType: const _EmptyReflectedType()); - - /// Invokes this empty reflected function. - /// - /// This method is part of the [_EmptyReflectedFunction] implementation and always - /// throws an [UnsupportedError] when called. This behavior is consistent with - /// the purpose of [EmptyReflector], which provides non-functional placeholders - /// for reflection operations. - /// - /// @param invocation The invocation to execute. - /// @throws UnsupportedError Always thrown when this method is called. - /// @return This method never returns as it always throws an exception. - @override - ReflectedInstance invoke(Invocation invocation) { - throw UnsupportedError( - 'Instances reflected via an EmptyReflector cannot call invoke().'); - } -} diff --git a/packages/container/container/lib/src/exception.dart b/packages/container/container/lib/src/exception.dart deleted file mode 100644 index 9b790ef..0000000 --- a/packages/container/container/lib/src/exception.dart +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/// A custom exception class for reflection-related errors. -/// -/// This class extends the base [Exception] class and provides a way to -/// create exceptions specific to reflection operations. It includes a -/// message that describes the nature of the exception. -/// -/// Example usage: -/// ```dart -/// throw ReflectionException('Failed to reflect on class XYZ'); -/// ``` -class ReflectionException implements Exception { - /// Creates a new instance of [ReflectionException] with the specified message. - /// - /// The [message] parameter should describe the nature of the reflection error. - final String message; - - /// Creates a new instance of [ReflectionException] with the specified message. - /// - /// The [message] parameter should describe the nature of the reflection error. - ReflectionException(this.message); - - // Override the toString method to provide a custom string representation of the exception. - @override - String toString() => message; -} diff --git a/packages/container/container/lib/src/mirrors/mirrors.dart b/packages/container/container/lib/src/mirrors/mirrors.dart deleted file mode 100644 index 29c3c64..0000000 --- a/packages/container/container/lib/src/mirrors/mirrors.dart +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -export 'reflector.dart'; diff --git a/packages/container/container/lib/src/mirrors/reflector.dart b/packages/container/container/lib/src/mirrors/reflector.dart deleted file mode 100644 index 1c53546..0000000 --- a/packages/container/container/lib/src/mirrors/reflector.dart +++ /dev/null @@ -1,904 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'dart:async'; -import 'dart:mirrors' as dart; -import 'package:platform_container/container.dart'; -import 'package:quiver/core.dart'; - -/// A [Reflector] implementation that forwards to `dart:mirrors`. -/// -/// This class provides reflection capabilities by leveraging the `dart:mirrors` library. -/// It allows for runtime introspection of classes, functions, types, and instances. -/// -/// Key features: -/// - Reflects classes, functions, types, and instances -/// - Provides access to class and function metadata -/// - Supports reflection of generic types and futures -/// - Allows invocation of reflected functions -/// -/// Note: This reflector is primarily useful on the server-side where reflection is fully supported. -/// It may not be suitable for client-side Dart applications due to limitations in reflection support. -/// -/// Usage: -/// ```dart -/// final reflector = MirrorsReflector(); -/// final classReflection = reflector.reflectClass(MyClass); -/// final functionReflection = reflector.reflectFunction(myFunction); -/// final typeReflection = reflector.reflectType(int); -/// final instanceReflection = reflector.reflectInstance(myObject); -/// ``` -/// -/// Be aware of the performance implications when using reflection extensively, -/// as it can impact runtime performance and increase code size. -class MirrorsReflector extends Reflector { - /// Creates a new instance of [MirrorsReflector]. - /// - /// This constructor initializes the [MirrorsReflector] instance. - const MirrorsReflector(); - - /// Retrieves the name of a symbol as a string. - /// - /// This method overrides the base implementation to use the `dart:mirrors` library - /// for converting a [Symbol] to its corresponding string representation. - /// - /// Parameters: - /// - [symbol]: The [Symbol] whose name is to be retrieved. - /// - /// Returns: - /// A [String] representing the name of the given symbol. - /// - /// Example: - /// ```dart - /// final name = getName(#someSymbol); - /// print(name); // Outputs: "someSymbol" - /// ``` - @override - String getName(Symbol symbol) => dart.MirrorSystem.getName(symbol); - - /// Reflects a class and returns a [ReflectedClass] instance. - /// - /// This method takes a [Type] parameter [clazz] and uses dart:mirrors to create - /// a reflection of the class. It returns a [_ReflectedClassMirror] which - /// implements [ReflectedClass]. - /// - /// Parameters: - /// - [clazz]: The [Type] of the class to reflect. - /// - /// Returns: - /// A [ReflectedClass] instance representing the reflected class. - /// - /// Throws: - /// - [ArgumentError] if the provided [clazz] is not a class. - /// - /// Example: - /// ```dart - /// final reflector = MirrorsReflector(); - /// final classReflection = reflector.reflectClass(MyClass); - /// ``` - @override - ReflectedClass reflectClass(Type clazz) { - var mirror = dart.reflectType(clazz); - - if (mirror is dart.ClassMirror) { - return _ReflectedClassMirror(mirror); - } else { - throw ArgumentError('$clazz is not a class.'); - } - } - - /// Reflects a function and returns a [ReflectedFunction] instance. - /// - /// This method takes a [Function] parameter [function] and uses dart:mirrors to create - /// a reflection of the function. It returns a [_ReflectedMethodMirror] which - /// implements [ReflectedFunction]. - /// - /// Parameters: - /// - [function]: The [Function] to reflect. - /// - /// Returns: - /// A [ReflectedFunction] instance representing the reflected function. - /// - /// Example: - /// ```dart - /// final reflector = MirrorsReflector(); - /// final functionReflection = reflector.reflectFunction(myFunction); - /// ``` - @override - ReflectedFunction reflectFunction(Function function) { - var closure = dart.reflect(function) as dart.ClosureMirror; - return _ReflectedMethodMirror(closure.function, closure); - } - - /// Reflects a given type and returns a [ReflectedType] instance. - /// - /// This method takes a [Type] parameter and uses dart:mirrors to create - /// a reflection of the type. It returns either a [_ReflectedClassMirror] - /// or a [_ReflectedTypeMirror] depending on whether the reflected type - /// is a class or not. - /// - /// Parameters: - /// - [type]: The [Type] to reflect. - /// - /// Returns: - /// A [ReflectedType] instance representing the reflected type. - /// - /// If the reflected type doesn't have a reflected type (i.e., [hasReflectedType] is false), - /// it returns a reflection of the `dynamic` type instead. - /// - /// Example: - /// ```dart - /// final reflector = MirrorsReflector(); - /// final typeReflection = reflector.reflectType(int); - /// ``` - @override - ReflectedType reflectType(Type type) { - var mirror = dart.reflectType(type); - - if (!mirror.hasReflectedType) { - return reflectType(dynamic); - } else { - if (mirror is dart.ClassMirror) { - return _ReflectedClassMirror(mirror); - } else { - return _ReflectedTypeMirror(mirror); - } - } - } - - /// Reflects a Future of a given type and returns a [ReflectedType] instance. - /// - /// This method takes a [Type] parameter and creates a reflection of a Future - /// that wraps that type. It first reflects the inner type, then constructs - /// a Future type with that inner type as its type argument. - /// - /// Parameters: - /// - [type]: The [Type] to be wrapped in a Future. - /// - /// Returns: - /// A [ReflectedType] instance representing the reflected Future. - /// - /// Throws: - /// - [ArgumentError] if the provided [type] is not a class or type. - /// - /// Example: - /// ```dart - /// final reflector = MirrorsReflector(); - /// final futureIntReflection = reflector.reflectFutureOf(int); - /// // This will reflect Future - /// ``` - @override - ReflectedType reflectFutureOf(Type type) { - var inner = reflectType(type); - dart.TypeMirror localMirror; - if (inner is _ReflectedClassMirror) { - localMirror = inner.mirror; - } else if (inner is _ReflectedTypeMirror) { - localMirror = inner.mirror; - } else { - throw ArgumentError('$type is not a class or type.'); - } - - var future = dart.reflectType(Future, [localMirror.reflectedType]); - return _ReflectedClassMirror(future as dart.ClassMirror); - } - - /// Reflects an instance of an object and returns a [ReflectedInstance]. - /// - /// This method takes an [Object] parameter and uses dart:mirrors to create - /// a reflection of the object instance. It returns a [_ReflectedInstanceMirror] - /// which implements [ReflectedInstance]. - /// - /// Parameters: - /// - [object]: The object instance to reflect. - /// - /// Returns: - /// A [ReflectedInstance] representing the reflected object instance. - /// - /// Example: - /// ```dart - /// final reflector = MirrorsReflector(); - /// final instanceReflection = reflector.reflectInstance(myObject); - /// ``` - @override - ReflectedInstance reflectInstance(Object object) { - return _ReflectedInstanceMirror(dart.reflect(object)); - } -} - -/// Represents a reflected type parameter using dart:mirrors. -/// -/// This class extends [ReflectedTypeParameter] and wraps a [dart.TypeVariableMirror] -/// to provide reflection capabilities for type parameters in Dart. -/// -/// The class extracts the name of the type parameter from the mirror and passes -/// it to the superclass constructor. -/// -/// This is typically used internally by the reflection system to represent -/// type parameters of generic classes or methods. -class _ReflectedTypeParameter extends ReflectedTypeParameter { - /// The [dart.TypeVariableMirror] instance representing the reflected type parameter. - /// - /// This mirror provides access to the details of the type parameter, such as its name, - /// bounds, and other metadata. It is used internally by the [_ReflectedTypeParameter] - /// class to implement reflection capabilities for type parameters. - final dart.TypeVariableMirror mirror; - - /// Constructs a [_ReflectedTypeParameter] instance. - /// - /// This constructor takes a [dart.TypeVariableMirror] and initializes the - /// [_ReflectedTypeParameter] with the name of the type parameter extracted - /// from the mirror. - /// - /// Parameters: - /// - [mirror]: A [dart.TypeVariableMirror] representing the type parameter. - /// - /// The constructor uses [dart.MirrorSystem.getName] to extract the name of the - /// type parameter from the mirror's [simpleName] and passes it to the superclass - /// constructor. - _ReflectedTypeParameter(this.mirror) - : super(dart.MirrorSystem.getName(mirror.simpleName)); -} - -/// Represents a reflected type using dart:mirrors. -/// -/// This class extends [ReflectedType] and wraps a [dart.TypeMirror] -/// to provide reflection capabilities for types in Dart. -/// -/// The class extracts the name and type variables from the mirror and passes -/// them to the superclass constructor. It also implements type comparison -/// through the [isAssignableTo] method. -/// -/// Note that this class represents types that are not classes, and therefore -/// cannot be instantiated. Attempting to call [newInstance] will throw a -/// [ReflectionException]. -/// -/// This is typically used internally by the reflection system to represent -/// non-class types like interfaces, mixins, or type aliases. -class _ReflectedTypeMirror extends ReflectedType { - /// The [dart.TypeMirror] instance representing the reflected type. - /// - /// This mirror provides access to the details of the type, such as its name, - /// type variables, and other metadata. It is used internally by the - /// [_ReflectedTypeMirror] class to implement reflection capabilities for types. - final dart.TypeMirror mirror; - - /// Constructs a [_ReflectedTypeMirror] instance. - /// - /// This constructor takes a [dart.TypeMirror] and initializes the - /// [_ReflectedTypeMirror] with the following: - /// - The name of the type extracted from the mirror's [simpleName]. - /// - A list of [_ReflectedTypeParameter] objects created from the mirror's type variables. - /// - The reflected type of the mirror. - /// - /// Parameters: - /// - [mirror]: A [dart.TypeMirror] representing the type to be reflected. - /// - /// The constructor uses [dart.MirrorSystem.getName] to extract the name of the - /// type from the mirror's [simpleName]. It also maps the mirror's type variables - /// to [_ReflectedTypeParameter] objects and passes them along with the reflected - /// type to the superclass constructor. - _ReflectedTypeMirror(this.mirror) - : super( - dart.MirrorSystem.getName(mirror.simpleName), - mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(), - mirror.reflectedType, - ); - - /// Checks if this reflected class is assignable to another reflected type. - /// - /// This method determines whether an instance of this class can be assigned - /// to a variable of the type represented by [other]. - /// - /// Parameters: - /// - [other]: The [ReflectedType] to check against. - /// - /// Returns: - /// - `true` if this class is assignable to [other]. - /// - `false` otherwise, including when [other] is not a [_ReflectedClassMirror] - /// or [_ReflectedTypeMirror]. - /// - /// The method uses dart:mirrors' [isAssignableTo] to perform the actual check - /// when [other] is either a [_ReflectedClassMirror] or [_ReflectedTypeMirror]. - @override - bool isAssignableTo(ReflectedType? other) { - if (other is _ReflectedClassMirror) { - return mirror.isAssignableTo(other.mirror); - } else if (other is _ReflectedTypeMirror) { - return mirror.isAssignableTo(other.mirror); - } else { - return false; - } - } - - /// Throws a [ReflectionException] when attempting to create a new instance. - /// - /// This method is intended to be overridden by classes that represent - /// instantiable types. For non-instantiable types (like interfaces or - /// abstract classes), this method throws an exception. - /// - /// Parameters: - /// - [constructorName]: The name of the constructor to invoke. - /// - [positionalArguments]: A list of positional arguments for the constructor. - /// - [namedArguments]: An optional map of named arguments for the constructor. - /// - [typeArguments]: An optional list of type arguments for generic classes. - /// - /// Throws: - /// [ReflectionException]: Always thrown with a message indicating that - /// this type cannot be instantiated. - /// - /// Example: - /// ```dart - /// // This will always throw a ReflectionException - /// reflectedType.newInstance('defaultConstructor', []); - /// ``` - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map? namedArguments, List? typeArguments]) { - throw ReflectionException( - '$name is not a class, and therefore cannot be instantiated.'); - } -} - -/// Represents a reflected class using dart:mirrors. -/// -/// This class extends [ReflectedClass] and wraps a [dart.ClassMirror] -/// to provide reflection capabilities for Dart classes. -/// -/// Key features: -/// - Reflects class name, type parameters, constructors, and declarations -/// - Provides access to class metadata (annotations) -/// - Supports type comparison through [isAssignableTo] -/// - Allows creation of new instances of the reflected class -/// -/// This class is typically used internally by the reflection system to -/// represent classes and their members. -class _ReflectedClassMirror extends ReflectedClass { - /// The [dart.ClassMirror] representing the reflected class. - /// - /// This mirror is used to extract information about the class, such as - /// its name, type parameters, constructors, and declarations. - /// - /// See also: - /// - [dart.ClassMirror] for more details about the mirror system. - final dart.ClassMirror mirror; - - /// Constructs a [_ReflectedClassMirror] instance. - /// - /// This constructor takes a [dart.ClassMirror] and initializes the - /// [_ReflectedClassMirror] with the following: - /// - The name of the class extracted from the mirror's [simpleName]. - /// - A list of [_ReflectedTypeParameter] objects created from the mirror's type variables. - /// - Empty lists for constructors and annotations (these are populated elsewhere). - /// - A list of declarations obtained from the [_declarationsOf] method. - /// - The reflected type of the mirror. - /// - /// Parameters: - /// - [mirror]: A [dart.ClassMirror] representing the class to be reflected. - /// - /// The constructor uses [dart.MirrorSystem.getName] to extract the name of the - /// class from the mirror's [simpleName]. It also maps the mirror's type variables - /// to [_ReflectedTypeParameter] objects and uses [_declarationsOf] to get the - /// class declarations. These are then passed to the superclass constructor. - _ReflectedClassMirror(this.mirror) - : super( - dart.MirrorSystem.getName(mirror.simpleName), - mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(), - [], - [], - _declarationsOf(mirror), - mirror.reflectedType, - ); - - /// Retrieves a list of reflected constructors from a given [dart.ClassMirror]. - /// - /// This static method iterates through the declarations of the provided [mirror], - /// identifies the constructor methods, and creates [ReflectedFunction] instances - /// for each constructor found. - /// - /// Parameters: - /// - [mirror]: A [dart.ClassMirror] representing the class to examine. - /// - /// Returns: - /// A [List] of [ReflectedFunction] objects, each representing a constructor - /// of the class. - /// - /// The method specifically looks for [dart.MethodMirror] instances that are - /// marked as constructors (i.e., [isConstructor] is true). Each identified - /// constructor is wrapped in a [_ReflectedMethodMirror] and added to the - /// returned list. - static List _constructorsOf(dart.ClassMirror mirror) { - var out = []; - - for (var key in mirror.declarations.keys) { - var value = mirror.declarations[key]; - - if (value is dart.MethodMirror && value.isConstructor) { - out.add(_ReflectedMethodMirror(value)); - } - } - - return out; - } - - /// Retrieves a list of reflected declarations from a given [dart.ClassMirror]. - /// - /// This static method iterates through the declarations of the provided [mirror], - /// identifies non-constructor methods, and creates [ReflectedDeclaration] instances - /// for each method found. - /// - /// Parameters: - /// - [mirror]: A [dart.ClassMirror] representing the class to examine. - /// - /// Returns: - /// A [List] of [ReflectedDeclaration] objects, each representing a non-constructor - /// method of the class. - /// - /// The method specifically looks for [dart.MethodMirror] instances that are - /// not constructors (i.e., [isConstructor] is false). Each identified - /// method is wrapped in a [_ReflectedDeclarationMirror] and added to the - /// returned list. - static List _declarationsOf(dart.ClassMirror mirror) { - var out = []; - - for (var key in mirror.declarations.keys) { - var value = mirror.declarations[key]; - - if (value is dart.MethodMirror && !value.isConstructor) { - out.add( - _ReflectedDeclarationMirror(dart.MirrorSystem.getName(key), value)); - } - } - - return out; - } - - /// Retrieves the annotations (metadata) associated with this reflected class. - /// - /// This getter method overrides the base implementation to provide access to - /// the class-level annotations using dart:mirrors. It maps each metadata mirror - /// to a [_ReflectedInstanceMirror] and returns them as a list. - /// - /// Returns: - /// A [List] of [ReflectedInstance] objects, each representing an annotation - /// applied to this class. - /// - /// Example: - /// ```dart - /// @MyAnnotation() - /// class MyClass {} - /// - /// // Assuming we have a reflection of MyClass - /// final classReflection = reflector.reflectClass(MyClass); - /// final annotations = classReflection.annotations; - /// // annotations will contain a ReflectedInstance of MyAnnotation - /// ``` - /// - /// Note: This method relies on the [dart.ClassMirror]'s metadata property - /// and creates a new [_ReflectedInstanceMirror] for each annotation. - @override - List get annotations => - mirror.metadata.map((m) => _ReflectedInstanceMirror(m)).toList(); - - /// Retrieves a list of reflected constructors for this class. - /// - /// This getter method overrides the base implementation to provide access to - /// the constructors of the reflected class using dart:mirrors. It uses the - /// static [_constructorsOf] method to extract and wrap each constructor - /// in a [ReflectedFunction] object. - /// - /// Returns: - /// A [List] of [ReflectedFunction] objects, each representing a constructor - /// of this class. - /// - /// Example: - /// ```dart - /// final classReflection = reflector.reflectClass(MyClass); - /// final constructors = classReflection.constructors; - /// // constructors will contain ReflectedFunction objects for each - /// // constructor in MyClass - /// ``` - /// - /// Note: This method relies on the [dart.ClassMirror]'s declarations and - /// the [_constructorsOf] method to identify and create reflections of - /// the class constructors. - @override - List get constructors => _constructorsOf(mirror); - - /// Checks if this reflected type is assignable to another reflected type. - /// - /// This method determines whether an instance of this type can be assigned - /// to a variable of the type represented by [other]. - /// - /// Parameters: - /// - [other]: The [ReflectedType] to check against. - /// - /// Returns: - /// - `true` if this type is assignable to [other]. - /// - `false` otherwise, including when [other] is not a [_ReflectedClassMirror] - /// or [_ReflectedTypeMirror]. - /// - /// The method uses dart:mirrors' [isAssignableTo] to perform the actual check - /// when [other] is either a [_ReflectedClassMirror] or [_ReflectedTypeMirror]. - @override - bool isAssignableTo(ReflectedType? other) { - if (other is _ReflectedClassMirror) { - return mirror.isAssignableTo(other.mirror); - } else if (other is _ReflectedTypeMirror) { - return mirror.isAssignableTo(other.mirror); - } else { - return false; - } - } - - /// Creates a new instance of the reflected class. - /// - /// This method instantiates a new object of the class represented by this - /// [_ReflectedClassMirror] using the specified constructor and arguments. - /// - /// Parameters: - /// - [constructorName]: The name of the constructor to invoke. Use an empty - /// string for the default constructor. - /// - [positionalArguments]: A list of positional arguments to pass to the constructor. - /// - [namedArguments]: An optional map of named arguments to pass to the constructor. - /// - [typeArguments]: An optional list of type arguments for generic classes. - /// - /// Returns: - /// A [ReflectedInstance] representing the newly created instance. - /// - /// Throws: - /// May throw exceptions if the constructor invocation fails, e.g., due to - /// invalid arguments or if the class cannot be instantiated. - /// - /// Note: - /// This implementation currently does not use the [namedArguments] or - /// [typeArguments] parameters. They are included for API compatibility. - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map? namedArguments, List? typeArguments]) { - return _ReflectedInstanceMirror( - mirror.newInstance(Symbol(constructorName), positionalArguments)); - } - - /// Checks if this [_ReflectedClassMirror] is equal to another object. - /// - /// This method overrides the default equality operator to provide a custom - /// equality check for [_ReflectedClassMirror] instances. - /// - /// Parameters: - /// - [other]: The object to compare with this [_ReflectedClassMirror]. - /// - /// Returns: - /// - `true` if [other] is also a [_ReflectedClassMirror] and has the same - /// [mirror] as this instance. - /// - `false` otherwise. - /// - /// This implementation ensures that two [_ReflectedClassMirror] instances - /// are considered equal if and only if they reflect the same class (i.e., - /// their underlying [dart.ClassMirror]s are the same). - @override - bool operator ==(other) { - return other is _ReflectedClassMirror && other.mirror == mirror; - } - - /// Generates a hash code for this [_ReflectedClassMirror]. - /// - /// This method overrides the default [hashCode] implementation to provide - /// a consistent hash code for [_ReflectedClassMirror] instances. - /// - /// The hash code is generated using the [hash2] function from the Quiver - /// library, combining the [mirror] object and an empty string. The empty - /// string is used as a second parameter to maintain compatibility with - /// the [hash2] function, which requires two arguments. - /// - /// Returns: - /// An [int] representing the hash code of this [_ReflectedClassMirror]. - /// - /// Note: - /// This hash code implementation ensures that two [_ReflectedClassMirror] - /// instances with the same [mirror] will have the same hash code, which - /// is consistent with the equality check implemented in the [operator ==]. - @override - int get hashCode => hash2(mirror, " "); -} - -/// Represents a reflected declaration using dart:mirrors. -/// -/// This class extends [ReflectedDeclaration] and wraps a [dart.MethodMirror] -/// to provide reflection capabilities for method declarations in Dart. -/// -/// Key features: -/// - Reflects the name and static nature of the declaration -/// - Provides access to the underlying method as a [ReflectedFunction] -/// -/// This class is typically used internally by the reflection system to -/// represent method declarations within a class. -class _ReflectedDeclarationMirror extends ReflectedDeclaration { - /// The [dart.MethodMirror] instance representing the reflected method. - /// - /// This mirror provides access to the details of the method, such as its name, - /// parameters, return type, and other metadata. It is used internally by the - /// [_ReflectedDeclarationMirror] class to implement reflection capabilities - /// for method declarations. - final dart.MethodMirror mirror; - - /// Constructs a [_ReflectedDeclarationMirror] instance. - /// - /// This constructor initializes a new [_ReflectedDeclarationMirror] with the given [name] - /// and [mirror]. It uses the [dart.MethodMirror]'s [isStatic] property to determine - /// if the declaration is static, and passes `null` as the initial value for the function. - /// - /// Parameters: - /// - [name]: A [String] representing the name of the declaration. - /// - [mirror]: A [dart.MethodMirror] representing the reflected method. - /// - /// The constructor calls the superclass constructor with the provided [name], - /// the [isStatic] property from the [mirror], and `null` for the function parameter. - _ReflectedDeclarationMirror(String name, this.mirror) - : super(name, mirror.isStatic, null); - - /// Determines if this declaration is static. - /// - /// This getter overrides the base implementation to provide information - /// about whether the reflected declaration is static or not. It directly - /// accesses the [isStatic] property of the underlying [dart.MethodMirror]. - /// - /// Returns: - /// A [bool] value: - /// - `true` if the declaration is static. - /// - `false` if the declaration is not static (i.e., it's an instance method). - /// - /// This property is useful for determining the nature of the reflected - /// declaration, particularly when working with class methods and properties. - @override - bool get isStatic => mirror.isStatic; - - /// Retrieves a [ReflectedFunction] representation of this declaration. - /// - /// This getter overrides the base implementation to provide a [ReflectedFunction] - /// that represents the method associated with this declaration. It creates a new - /// [_ReflectedMethodMirror] instance using the underlying [dart.MethodMirror]. - /// - /// Returns: - /// A [ReflectedFunction] object that represents the method of this declaration. - /// - /// This property is useful for accessing detailed information about the method, - /// such as its parameters, return type, and other attributes, in a way that's - /// consistent with the reflection API. - @override - ReflectedFunction get function => _ReflectedMethodMirror(mirror); -} - -/// Represents a reflected instance of an object using dart:mirrors. -/// -/// This class extends [ReflectedInstance] and wraps a [dart.InstanceMirror] -/// to provide reflection capabilities for object instances in Dart. -/// -/// Key features: -/// - Reflects the type and runtime type of the instance -/// - Provides access to the underlying object (reflectee) -/// - Allows retrieval of field values through reflection -/// -/// This class is typically used internally by the reflection system to -/// represent instances of objects and provide reflective access to their fields. -class _ReflectedInstanceMirror extends ReflectedInstance { - /// The [dart.InstanceMirror] representing the reflected instance. - /// - /// This mirror provides access to the details of the object instance, such as its type, - /// fields, and methods. It is used internally by the [_ReflectedInstanceMirror] class - /// to implement reflection capabilities for object instances. - /// - /// The mirror allows for dynamic inspection and manipulation of the object's state - /// and behavior at runtime, enabling powerful reflection features. - final dart.InstanceMirror mirror; - - /// Constructs a [_ReflectedInstanceMirror] instance. - /// - /// This constructor initializes a new [_ReflectedInstanceMirror] with the given [mirror]. - /// It uses the [dart.InstanceMirror]'s [type] property to create [_ReflectedClassMirror] - /// instances for both the type and runtime type of the reflected instance. - /// - /// Parameters: - /// - [mirror]: A [dart.InstanceMirror] representing the reflected instance. - /// - /// The constructor calls the superclass constructor with: - /// - A [_ReflectedClassMirror] of the instance's type - /// - A [_ReflectedClassMirror] of the instance's runtime type - /// - The [reflectee] of the mirror, which is the actual object being reflected - /// - /// This setup allows the [_ReflectedInstanceMirror] to provide access to both - /// the compile-time and runtime type information of the reflected instance, - /// as well as the underlying object itself. - _ReflectedInstanceMirror(this.mirror) - : super(_ReflectedClassMirror(mirror.type), - _ReflectedClassMirror(mirror.type), mirror.reflectee); - - /// Retrieves the value of a field from the reflected instance. - /// - /// This method allows access to field values of the object represented by this - /// [_ReflectedInstanceMirror] through reflection. - /// - /// Parameters: - /// - [name]: A [String] representing the name of the field to retrieve. - /// - /// Returns: - /// A [ReflectedInstance] representing the value of the specified field. - /// This returned instance is wrapped in a [_ReflectedInstanceMirror]. - /// - /// Throws: - /// May throw exceptions if the field does not exist or if access is not allowed. - /// - /// Example: - /// ```dart - /// var fieldValue = reflectedInstance.getField('myField'); - /// ``` - /// - /// Note: - /// This method uses the underlying [dart.InstanceMirror]'s [getField] method - /// to perform the actual field access. - @override - ReflectedInstance getField(String name) { - return _ReflectedInstanceMirror(mirror.getField(Symbol(name))); - } -} - -/// Represents a reflected method using dart:mirrors. -/// -/// This class extends [ReflectedFunction] and wraps a [dart.MethodMirror] -/// to provide reflection capabilities for methods in Dart. -/// -/// Key features: -/// - Reflects method name, parameters, and return type -/// - Provides access to method metadata (annotations) -/// - Supports invocation of the reflected method (if a ClosureMirror is available) -/// -/// The class uses both [dart.MethodMirror] and optionally [dart.ClosureMirror] -/// to represent and potentially invoke the reflected method. -/// -/// Usage: -/// - Created internally by the reflection system to represent methods -/// - Can be used to inspect method details or invoke the method if a ClosureMirror is provided -/// -/// Note: -/// - Invocation is only possible if a ClosureMirror is provided during construction -/// - Throws a StateError if invoke is called without a ClosureMirror -class _ReflectedMethodMirror extends ReflectedFunction { - /// The [dart.MethodMirror] instance representing the reflected method. - /// - /// This mirror provides access to the details of the method, such as its name, - /// parameters, return type, and other metadata. It is used internally by the - /// [_ReflectedMethodMirror] class to implement reflection capabilities - /// for methods. - /// - /// The [dart.MethodMirror] is a crucial component in the reflection process, - /// allowing for introspection of method properties and behavior at runtime. - final dart.MethodMirror mirror; - - /// An optional [dart.ClosureMirror] representing the closure of the reflected method. - /// - /// This field is used to store a [dart.ClosureMirror] when the reflected method - /// is associated with a callable object (i.e., a closure). The presence of this - /// mirror enables the [invoke] method to directly call the reflected method. - /// - /// If this field is null, it indicates that the reflected method cannot be - /// directly invoked through this [_ReflectedMethodMirror] instance. - /// - /// Note: - /// - This field is crucial for supporting method invocation via reflection. - /// - It's typically set when reflecting on instance methods or standalone functions. - /// - For class-level method declarations that aren't bound to an instance, - /// this field may be null. - final dart.ClosureMirror? closureMirror; - - /// Constructs a [_ReflectedMethodMirror] instance. - /// - /// This constructor initializes a new [_ReflectedMethodMirror] with the given [mirror] - /// and optional [closureMirror]. It extracts various properties from the [dart.MethodMirror] - /// to populate the superclass constructor. - /// - /// Parameters: - /// - [mirror]: A [dart.MethodMirror] representing the reflected method. - /// - [closureMirror]: An optional [dart.ClosureMirror] for method invocation. - /// - /// The constructor initializes the following: - /// - Method name from the mirror's [simpleName] - /// - An empty list of reflected type parameters - /// - Metadata (annotations) as [_ReflectedInstanceMirror] objects - /// - Reflected parameters using [_reflectParameter] - /// - Getter and setter flags from the mirror - /// - Return type, using [dynamic] if the mirror doesn't have a reflected type - /// - /// This setup allows the [_ReflectedMethodMirror] to provide comprehensive - /// reflection capabilities for the method, including its signature, metadata, - /// and potential invocation (if a [closureMirror] is provided). - _ReflectedMethodMirror(this.mirror, [this.closureMirror]) - : super( - dart.MirrorSystem.getName(mirror.simpleName), - [], - mirror.metadata - .map((mirror) => _ReflectedInstanceMirror(mirror)) - .toList(), - mirror.parameters.map(_reflectParameter).toList(), - mirror.isGetter, - mirror.isSetter, - returnType: !mirror.returnType.hasReflectedType - ? const MirrorsReflector().reflectType(dynamic) - : const MirrorsReflector() - .reflectType(mirror.returnType.reflectedType)); - - /// Reflects a parameter of a method using dart:mirrors. - /// - /// This static method creates a [ReflectedParameter] instance from a given [dart.ParameterMirror]. - /// It extracts various properties from the mirror to construct a comprehensive reflection of the parameter. - /// - /// Parameters: - /// - [mirror]: A [dart.ParameterMirror] representing the parameter to be reflected. - /// - /// Returns: - /// A [ReflectedParameter] instance containing the reflected information of the parameter. - /// - /// The method extracts the following information: - /// - Parameter name from the mirror's [simpleName] - /// - Metadata (annotations) as [_ReflectedInstanceMirror] objects - /// - Parameter type, reflected using [MirrorsReflector] - /// - Whether the parameter is required (not optional) - /// - Whether the parameter is named - /// - /// This method is typically used internally by the reflection system to create - /// parameter reflections for method signatures. - static ReflectedParameter _reflectParameter(dart.ParameterMirror mirror) { - return ReflectedParameter( - dart.MirrorSystem.getName(mirror.simpleName), - mirror.metadata - .map((mirror) => _ReflectedInstanceMirror(mirror)) - .toList(), - const MirrorsReflector().reflectType(mirror.type.reflectedType), - !mirror.isOptional, - mirror.isNamed); - } - - /// Invokes the reflected method with the given invocation details. - /// - /// This method allows for dynamic invocation of the reflected method using the - /// provided [Invocation] object. It requires that a [closureMirror] was provided - /// during the construction of this [_ReflectedMethodMirror]. - /// - /// Parameters: - /// - [invocation]: An [Invocation] object containing the details of the method call, - /// including the method name, positional arguments, and named arguments. - /// - /// Returns: - /// A [ReflectedInstance] representing the result of the method invocation. - /// - /// Throws: - /// - [StateError] if this [_ReflectedMethodMirror] was created without a [closureMirror], - /// indicating that direct invocation is not possible. - /// - /// Example: - /// ```dart - /// var result = reflectedMethod.invoke(Invocation.method(#methodName, [arg1, arg2])); - /// ``` - /// - /// Note: - /// This method relies on the presence of a [closureMirror] to perform the actual - /// invocation. If no [closureMirror] is available, it means the reflected method - /// cannot be directly invoked, and an error will be thrown. - @override - ReflectedInstance invoke(Invocation invocation) { - if (closureMirror == null) { - throw StateError( - 'This object was reflected without a ClosureMirror, and therefore cannot be directly invoked.'); - } - - return _ReflectedInstanceMirror(closureMirror!.invoke(invocation.memberName, - invocation.positionalArguments, invocation.namedArguments)); - } -} diff --git a/packages/container/container/lib/src/reflectable/reflectable.dart b/packages/container/container/lib/src/reflectable/reflectable.dart deleted file mode 100644 index 8e88713..0000000 --- a/packages/container/container/lib/src/reflectable/reflectable.dart +++ /dev/null @@ -1,8 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ diff --git a/packages/container/container/lib/src/reflector.dart b/packages/container/container/lib/src/reflector.dart deleted file mode 100644 index 3b72136..0000000 --- a/packages/container/container/lib/src/reflector.dart +++ /dev/null @@ -1,298 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'package:collection/collection.dart'; -import 'package:quiver/core.dart'; - -/// Abstract class representing a reflector for introspection of Dart types and instances. -/// -/// This class provides methods to reflect on various Dart constructs such as classes, -/// functions, types, and instances. It allows for runtime inspection and manipulation -/// of code elements. -/// -/// The methods in this class are designed to be implemented by concrete reflector -/// classes, potentially using different reflection mechanisms (e.g., mirrors, code -/// generation). -/// -/// Note: The `reflectFutureOf` method throws an `UnsupportedError` by default and -/// requires `dart:mirrors` for implementation. -abstract class Reflector { - /// Constructs a new [Reflector] instance. - /// - /// This constructor is declared as `const` to allow for compile-time constant creation - /// of [Reflector] instances. Subclasses of [Reflector] may override this constructor - /// to provide their own initialization logic if needed. - const Reflector(); - - String? getName(Symbol symbol); - - ReflectedClass? reflectClass(Type clazz); - - ReflectedFunction? reflectFunction(Function function); - - ReflectedType? reflectType(Type type); - - ReflectedInstance? reflectInstance(Object object); - - ReflectedType reflectFutureOf(Type type) { - throw UnsupportedError('`reflectFutureOf` requires `dart:mirrors`.'); - } -} - -/// Represents a reflected instance of an object. -/// -/// This abstract class provides a way to introspect and manipulate object instances -/// at runtime. It encapsulates information about the object's type, class, and the -/// actual object instance (reflectee). -/// -/// The [type] property represents the reflected type of the instance. -/// The [clazz] property represents the reflected class of the instance. -/// The [reflectee] property holds the actual object instance being reflected. -/// -/// This class also provides methods for comparing instances and accessing fields. -/// -/// Use the [getField] method to retrieve a reflected instance of a specific field. -abstract class ReflectedInstance { - final ReflectedType type; - final ReflectedClass clazz; - final Object? reflectee; - - const ReflectedInstance(this.type, this.clazz, this.reflectee); - - @override - int get hashCode => hash2(type, clazz); - - @override - bool operator ==(other) => - other is ReflectedInstance && other.type == type && other.clazz == clazz; - - ReflectedInstance getField(String name); -} - -/// Represents a reflected type in the Dart language. -/// -/// This abstract class encapsulates information about a Dart type, including its name, -/// type parameters, and the actual Dart [Type] it represents. -/// -/// The [name] property holds the name of the type. -/// The [typeParameters] list contains the type parameters if the type is generic. -/// The [reflectedType] property holds the actual Dart [Type] being reflected. -/// -/// This class provides methods for creating new instances of the type, comparing types, -/// and checking type assignability. -/// -/// The [newInstance] method allows for dynamic creation of new instances of the type. -/// The [isAssignableTo] method checks if this type is assignable to another type. -/// -/// This class also overrides [hashCode] and [operator ==] for proper equality comparisons. -abstract class ReflectedType { - final String name; - final List typeParameters; - final Type reflectedType; - - const ReflectedType(this.name, this.typeParameters, this.reflectedType); - - @override - int get hashCode => hash3(name, typeParameters, reflectedType); - - @override - bool operator ==(other) => - other is ReflectedType && - other.name == name && - const ListEquality() - .equals(other.typeParameters, typeParameters) && - other.reflectedType == reflectedType; - - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map namedArguments = const {}, - List typeArguments = const []]); - - bool isAssignableTo(ReflectedType? other); -} - -/// Represents a reflected class in the Dart language. -/// -/// This abstract class extends [ReflectedType] and provides additional information -/// specific to classes, including annotations, constructors, and declarations. -/// -/// The [annotations] list contains reflected instances of annotations applied to the class. -/// The [constructors] list contains reflected functions representing the class constructors. -/// The [declarations] list contains reflected declarations (fields, methods, etc.) of the class. -/// -/// This class overrides [hashCode] and [operator ==] to include the additional properties -/// in equality comparisons and hash code calculations. -abstract class ReflectedClass extends ReflectedType { - final List annotations; - final List constructors; - final List declarations; - - const ReflectedClass( - String name, - List typeParameters, - this.annotations, - this.constructors, - this.declarations, - Type reflectedType) - : super(name, typeParameters, reflectedType); - - @override - int get hashCode => - hash4(super.hashCode, annotations, constructors, declarations); - - @override - bool operator ==(other) => - other is ReflectedClass && - super == other && - const ListEquality() - .equals(other.annotations, annotations) && - const ListEquality() - .equals(other.constructors, constructors) && - const ListEquality() - .equals(other.declarations, declarations); -} - -/// Represents a reflected declaration in the Dart language. -/// -/// This class encapsulates information about a declaration within a class or object, -/// such as a method, field, or property. -/// -/// The [name] property holds the name of the declaration. -/// The [isStatic] property indicates whether the declaration is static. -/// The [function] property, if non-null, represents the reflected function associated -/// with this declaration (applicable for methods and some properties). -/// -/// This class provides methods for comparing declarations and calculating hash codes. -/// It overrides [hashCode] and [operator ==] for proper equality comparisons. -class ReflectedDeclaration { - final String name; - final bool isStatic; - final ReflectedFunction? function; - - const ReflectedDeclaration(this.name, this.isStatic, this.function); - - @override - int get hashCode => hash3(name, isStatic, function); - - @override - bool operator ==(other) => - other is ReflectedDeclaration && - other.name == name && - other.isStatic == isStatic && - other.function == function; -} - -/// Represents a reflected function in the Dart language. -/// -/// This abstract class encapsulates information about a function, including its name, -/// type parameters, annotations, return type, parameters, and whether it's a getter or setter. -/// -/// The [name] property holds the name of the function. -/// The [typeParameters] list contains the type parameters if the function is generic. -/// The [annotations] list contains reflected instances of annotations applied to the function. -/// The [returnType] property represents the function's return type (if applicable). -/// The [parameters] list contains the function's parameters. -/// The [isGetter] and [isSetter] properties indicate if the function is a getter or setter. -/// -/// This class provides methods for comparing functions and calculating hash codes. -/// It also includes an [invoke] method for dynamically calling the function. -/// -/// This class overrides [hashCode] and [operator ==] for proper equality comparisons. -abstract class ReflectedFunction { - final String name; - final List typeParameters; - final List annotations; - final ReflectedType? returnType; - final List parameters; - final bool isGetter, isSetter; - - const ReflectedFunction(this.name, this.typeParameters, this.annotations, - this.parameters, this.isGetter, this.isSetter, - {this.returnType}); - - @override - int get hashCode => hashObjects([ - name, - typeParameters, - annotations, - returnType, - parameters, - isGetter, - isSetter - ]); - - @override - bool operator ==(other) => - other is ReflectedFunction && - other.name == name && - const ListEquality() - .equals(other.typeParameters, typeParameters) && - const ListEquality() - .equals(other.annotations, annotations) && - other.returnType == returnType && - const ListEquality() - .equals(other.parameters, other.parameters) && - other.isGetter == isGetter && - other.isSetter == isSetter; - - ReflectedInstance invoke(Invocation invocation); -} - -/// Represents a reflected parameter in the Dart language. -/// -/// This class encapsulates information about a function or method parameter, -/// including its name, annotations, type, and properties such as whether it's -/// required or named. -/// -/// Properties: -/// - [name]: The name of the parameter. -/// - [annotations]: A list of reflected instances of annotations applied to the parameter. -/// - [type]: The reflected type of the parameter. -/// - [isRequired]: Indicates whether the parameter is required. -/// - [isNamed]: Indicates whether the parameter is a named parameter. -/// -/// This class provides methods for comparing parameters and calculating hash codes. -/// It overrides [hashCode] and [operator ==] for proper equality comparisons. -class ReflectedParameter { - final String name; - final List annotations; - final ReflectedType type; - final bool isRequired; - final bool isNamed; - - const ReflectedParameter( - this.name, this.annotations, this.type, this.isRequired, this.isNamed); - - @override - int get hashCode => - hashObjects([name, annotations, type, isRequired, isNamed]); - - @override - bool operator ==(other) => - other is ReflectedParameter && - other.name == name && - const ListEquality() - .equals(other.annotations, annotations) && - other.type == type && - other.isRequired == isRequired && - other.isNamed == isNamed; -} - -class ReflectedTypeParameter { - final String name; - - const ReflectedTypeParameter(this.name); - - @override - int get hashCode => hashObjects([name]); - - @override - bool operator ==(other) => - other is ReflectedTypeParameter && other.name == name; -} diff --git a/packages/container/container/lib/src/static/static.dart b/packages/container/container/lib/src/static/static.dart deleted file mode 100644 index ff9c4df..0000000 --- a/packages/container/container/lib/src/static/static.dart +++ /dev/null @@ -1,179 +0,0 @@ -/* - * This file is part of the Protevus Platform. - * - * (C) Protevus - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -import 'package:platform_container/container.dart'; - -/// A static implementation of the [Reflector] class that performs simple [Map] lookups. -/// -/// `package:platform_container_generator` uses this to create reflectors from analysis metadata. -class StaticReflector extends Reflector { - /// A map that associates [Symbol] objects with their corresponding string names. - /// - /// This map is used to store and retrieve the string representations of symbols, - /// which can be useful for reflection and debugging purposes. - final Map names; - - /// A map that associates [Type] objects with their corresponding [ReflectedType] objects. - /// - /// This map is used to store and retrieve reflection information for different types, - /// allowing for runtime introspection of type metadata and structure. - final Map types; - - /// A map that associates [Function] objects with their corresponding [ReflectedFunction] objects. - /// - /// This map is used to store and retrieve reflection information for functions, - /// enabling runtime introspection of function metadata, parameters, and return types. - final Map functions; - - /// A map that associates [Object] instances with their corresponding [ReflectedInstance] objects. - /// - /// This map is used to store and retrieve reflection information for specific object instances, - /// allowing for runtime introspection of object properties, methods, and metadata. - final Map instances; - - /// Creates a new [StaticReflector] instance with optional parameters. - /// - /// The [StaticReflector] constructor allows you to initialize the reflector - /// with pre-populated maps for names, types, functions, and instances. - /// - /// Parameters: - /// - [names]: A map of [Symbol] to [String] for symbol name lookups. Defaults to an empty map. - /// - [types]: A map of [Type] to [ReflectedType] for type reflection. Defaults to an empty map. - /// - [functions]: A map of [Function] to [ReflectedFunction] for function reflection. Defaults to an empty map. - /// - [instances]: A map of [Object] to [ReflectedInstance] for instance reflection. Defaults to an empty map. - /// - /// All parameters are optional and default to empty constant maps if not provided. - const StaticReflector( - {this.names = const {}, - this.types = const {}, - this.functions = const {}, - this.instances = const {}}); - - /// Returns the string name associated with the given [Symbol]. - /// - /// This method looks up the string representation of the provided [symbol] - /// in the [names] map. If the symbol is found, its corresponding string - /// name is returned. If the symbol is not found in the map, an [ArgumentError] - /// is thrown. - /// - /// Parameters: - /// - [symbol]: The [Symbol] for which to retrieve the string name. - /// - /// Returns: - /// The string name associated with the given [symbol], or null if not found. - /// - /// Throws: - /// - [ArgumentError]: If the provided [symbol] is not found in the [names] map. - @override - String? getName(Symbol symbol) { - if (!names.containsKey(symbol)) { - throw ArgumentError( - 'The value of $symbol is unknown - it was not generated.'); - } - - return names[symbol]; - } - - /// Reflects a class based on its [Type]. - /// - /// This method attempts to reflect the given class [Type] by calling [reflectType] - /// and casting the result to [ReflectedClass]. If the reflection is successful - /// and the result is a [ReflectedClass], it is returned. Otherwise, null is returned. - /// - /// Parameters: - /// - [clazz]: The [Type] of the class to reflect. - /// - /// Returns: - /// A [ReflectedClass] instance if the reflection is successful and the result - /// is a [ReflectedClass], or null otherwise. - @override - ReflectedClass? reflectClass(Type clazz) => - reflectType(clazz) as ReflectedClass?; - - /// Reflects a function based on its [Function] object. - /// - /// This method attempts to retrieve reflection information for the given [function] - /// from the [functions] map. If the function is found in the map, its corresponding - /// [ReflectedFunction] object is returned. If the function is not found, an - /// [ArgumentError] is thrown. - /// - /// Parameters: - /// - [function]: The [Function] object to reflect. - /// - /// Returns: - /// A [ReflectedFunction] object containing reflection information about the - /// given function, or null if not found. - /// - /// Throws: - /// - [ArgumentError]: If there is no reflection information available for - /// the given [function]. - @override - ReflectedFunction? reflectFunction(Function function) { - if (!functions.containsKey(function)) { - throw ArgumentError( - 'There is no reflection information available about $function.'); - } - - return functions[function]; - } - - /// Reflects an object instance to retrieve its reflection information. - /// - /// This method attempts to retrieve reflection information for the given [object] - /// from the [instances] map. If the object is found in the map, its corresponding - /// [ReflectedInstance] object is returned. If the object is not found, an - /// [ArgumentError] is thrown. - /// - /// Parameters: - /// - [object]: The object instance to reflect. - /// - /// Returns: - /// A [ReflectedInstance] object containing reflection information about the - /// given object instance, or null if not found. - /// - /// Throws: - /// - [ArgumentError]: If there is no reflection information available for - /// the given [object]. - @override - ReflectedInstance? reflectInstance(Object object) { - if (!instances.containsKey(object)) { - throw ArgumentError( - 'There is no reflection information available about $object.'); - } - - return instances[object]; - } - - /// Reflects a type to retrieve its reflection information. - /// - /// This method attempts to retrieve reflection information for the given [type] - /// from the [types] map. If the type is found in the map, its corresponding - /// [ReflectedType] object is returned. If the type is not found, an - /// [ArgumentError] is thrown. - /// - /// Parameters: - /// - [type]: The [Type] to reflect. - /// - /// Returns: - /// A [ReflectedType] object containing reflection information about the - /// given type, or null if not found. - /// - /// Throws: - /// - [ArgumentError]: If there is no reflection information available for - /// the given [type]. - @override - ReflectedType? reflectType(Type type) { - if (!types.containsKey(type)) { - throw ArgumentError( - 'There is no reflection information available about $type.'); - } - - return types[type]; - } -} diff --git a/packages/container/container/lib/src/throwing.dart b/packages/container/container/lib/src/throwing.dart deleted file mode 100644 index 322940f..0000000 --- a/packages/container/container/lib/src/throwing.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'package:platform_container/src/container_const.dart'; -import 'empty/empty.dart'; -import 'reflector.dart'; - -/// A [Reflector] implementation that throws exceptions on all attempts -/// to perform reflection. -/// -/// Use this in contexts where you know you won't need any reflective capabilities. -class ThrowingReflector extends Reflector { - /// The error message to give the end user when an [UnsupportedError] is thrown. - final String errorMessage; - - /* - static const String defaultErrorMessage = - 'You attempted to perform a reflective action, but you are using `ThrowingReflector`, ' - 'a class which disables reflection. Consider using the `MirrorsReflector` ' - 'class if you need reflection.'; - */ - - /// Creates a [ThrowingReflector] instance. - /// - /// [errorMessage] is the message to be used when throwing an [UnsupportedError]. - /// If not provided, it defaults to [ContainerConst.defaultErrorMessage]. - const ThrowingReflector( - {this.errorMessage = ContainerConst.defaultErrorMessage}); - - /// Retrieves the name associated with the given [symbol]. - /// - /// This method delegates the task to an instance of [EmptyReflector]. - /// It returns the name as a [String] if found, or `null` if not found. - /// - /// [symbol] is the [Symbol] for which to retrieve the name. - /// - /// Returns a [String] representing the name of the symbol, or `null` if not found. - @override - String? getName(Symbol symbol) => const EmptyReflector().getName(symbol); - - /// Creates and returns an [UnsupportedError] with the specified [errorMessage]. - /// - /// This method is used internally to generate consistent error messages - /// when reflection operations are attempted on this [ThrowingReflector]. - /// - /// Returns an [UnsupportedError] instance with the configured error message. - UnsupportedError _error() => UnsupportedError(errorMessage); - - /// Reflects on a given class type and throws an [UnsupportedError]. - /// - /// This method is part of the [ThrowingReflector] implementation and is designed - /// to prevent reflective operations. When called, it throws an [UnsupportedError] - /// with the configured error message. - /// - /// [clazz] is the [Type] of the class to reflect on. - /// - /// Throws an [UnsupportedError] when invoked, as reflection is not supported. - @override - ReflectedClass reflectClass(Type clazz) => throw _error(); - - /// Reflects on a given object instance and throws an [UnsupportedError]. - /// - /// This method is part of the [ThrowingReflector] implementation and is designed - /// to prevent reflective operations on object instances. When called, it throws - /// an [UnsupportedError] with the configured error message. - /// - /// [object] is the object instance to reflect on. - /// - /// Throws an [UnsupportedError] when invoked, as reflection is not supported. - @override - ReflectedInstance reflectInstance(Object object) => throw _error(); - - /// Reflects on a given type and throws an [UnsupportedError]. - /// - /// This method is part of the [ThrowingReflector] implementation and is designed - /// to prevent reflective operations on types. When called, it throws an - /// [UnsupportedError] with the configured error message. - /// - /// [type] is the [Type] to reflect on. - /// - /// Throws an [UnsupportedError] when invoked, as reflection is not supported. - @override - ReflectedType reflectType(Type type) => throw _error(); - - /// Reflects on a given function and throws an [UnsupportedError]. - /// - /// This method is part of the [ThrowingReflector] implementation and is designed - /// to prevent reflective operations on functions. When called, it throws an - /// [UnsupportedError] with the configured error message. - /// - /// [function] is the [Function] to reflect on. - /// - /// Throws an [UnsupportedError] when invoked, as reflection is not supported. - @override - ReflectedFunction reflectFunction(Function function) => throw _error(); -} diff --git a/packages/container/container/pubspec.yaml b/packages/container/container/pubspec.yaml deleted file mode 100644 index 8982eb5..0000000 --- a/packages/container/container/pubspec.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: platform_container -version: 9.0.0 -description: Protevus Platform hierarchical DI container, and pluggable backends for reflection. -homepage: https://protevus.com -documentation: https://docs.protevus.com -repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/container/container -environment: - sdk: '>=3.3.0 <4.0.0' -dependencies: - collection: ^1.19.1 - quiver: ^3.2.2 -dev_dependencies: - test: ^1.25.8 - lints: ^4.0.0 diff --git a/packages/container/container/test/common.dart b/packages/container/container/test/common.dart deleted file mode 100644 index 327ef93..0000000 --- a/packages/container/container/test/common.dart +++ /dev/null @@ -1,122 +0,0 @@ -import 'dart:async'; - -import 'package:platform_container/container.dart'; -import 'package:test/test.dart'; - -void returnVoidFromAFunction(int x) {} - -void testReflector(Reflector reflector) { - var blaziken = Pokemon('Blaziken', PokemonType.fire); - late Container container; - - setUp(() { - container = Container(reflector); - container.registerSingleton(blaziken); - container.registerFactory>((_) async => 46); - }); - - test('get field', () { - var blazikenMirror = reflector.reflectInstance(blaziken)!; - expect(blazikenMirror.getField('type').reflectee, blaziken.type); - }); - - group('reflectFunction', () { - var mirror = reflector.reflectFunction(returnVoidFromAFunction); - - test('void return type returns dynamic', () { - expect(mirror!.returnType, reflector.reflectType(dynamic)); - }); - - test('counts parameters', () { - expect(mirror!.parameters, hasLength(1)); - }); - - test('counts types parameters', () { - expect(mirror!.typeParameters, isEmpty); - }); - - test('correctly reflects parameter types', () { - var p = mirror!.parameters[0]; - expect(p.name, 'x'); - expect(p.isRequired, true); - expect(p.isNamed, false); - expect(p.annotations, isEmpty); - expect(p.type, reflector.reflectType(int)); - }); - }); - - test('make on singleton type returns singleton', () { - expect(container.make(Pokemon), blaziken); - }); - - test('make with generic returns same as make with explicit type', () { - expect(container.make(), blaziken); - }); - - test('make async returns async object', () async { - expect(container.makeAsync(), completion(46)); - }); - - test('make async returns sync object', () async { - expect(container.makeAsync(), completion(blaziken)); - }); - - test('make on aliased singleton returns singleton', () { - container.registerSingleton(blaziken, as: StateError); - expect(container.make(StateError), blaziken); - }); - - test('constructor injects singleton', () { - var lower = container.make(); - expect(lower.lowercaseName, blaziken.name.toLowerCase()); - }); - - test('newInstance works', () { - var type = container.reflector.reflectType(Pokemon)!; - var instance = - type.newInstance('changeName', [blaziken, 'Charizard']).reflectee - as Pokemon; - print(instance); - expect(instance.name, 'Charizard'); - expect(instance.type, PokemonType.fire); - }); - - test('isAssignableTo', () { - var pokemonType = container.reflector.reflectType(Pokemon); - var kantoPokemonType = container.reflector.reflectType(KantoPokemon)!; - - expect(kantoPokemonType.isAssignableTo(pokemonType), true); - expect( - kantoPokemonType - .isAssignableTo(container.reflector.reflectType(String)), - false); - }); -} - -class LowerPokemon { - final Pokemon pokemon; - - LowerPokemon(this.pokemon); - - String get lowercaseName => pokemon.name.toLowerCase(); -} - -class Pokemon { - final String name; - final PokemonType type; - - Pokemon(this.name, this.type); - - factory Pokemon.changeName(Pokemon other, String name) { - return Pokemon(name, other.type); - } - - @override - String toString() => 'NAME: $name, TYPE: $type'; -} - -class KantoPokemon extends Pokemon { - KantoPokemon(super.name, super.type); -} - -enum PokemonType { water, fire, grass, ice, poison, flying } diff --git a/packages/container/container/test/empty_reflector_test.dart b/packages/container/container/test/empty_reflector_test.dart deleted file mode 100644 index a6ef382..0000000 --- a/packages/container/container/test/empty_reflector_test.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'package:platform_container/container.dart'; -import 'package:test/test.dart'; - -void main() { - var reflector = const EmptyReflector(); - - test('getName', () { - expect(reflector.getName(#foo), 'foo'); - expect(reflector.getName(#==), '=='); - }); - - group('reflectClass', () { - var mirror = reflector.reflectClass(Truck); - - test('name returns empty', () { - expect(mirror.name, '(empty)'); - }); - - test('annotations returns empty', () { - expect(mirror.annotations, isEmpty); - }); - - test('typeParameters returns empty', () { - expect(mirror.typeParameters, isEmpty); - }); - - test('declarations returns empty', () { - expect(mirror.declarations, isEmpty); - }); - - test('constructors returns empty', () { - expect(mirror.constructors, isEmpty); - }); - - test('reflectedType returns Object', () { - expect(mirror.reflectedType, Object); - }); - - test('cannot call newInstance', () { - expect(() => mirror.newInstance('', []), throwsUnsupportedError); - }); - - test('isAssignableTo self', () { - expect(mirror.isAssignableTo(mirror), true); - }); - }); - - group('reflectType', () { - var mirror = reflector.reflectType(Truck); - - test('name returns empty', () { - expect(mirror.name, '(empty)'); - }); - - test('typeParameters returns empty', () { - expect(mirror.typeParameters, isEmpty); - }); - - test('reflectedType returns Object', () { - expect(mirror.reflectedType, Object); - }); - - test('cannot call newInstance', () { - expect(() => mirror.newInstance('', []), throwsUnsupportedError); - }); - - test('isAssignableTo self', () { - expect(mirror.isAssignableTo(mirror), true); - }); - }); - - group('reflectFunction', () { - void doIt(int x) {} - - var mirror = reflector.reflectFunction(doIt); - - test('name returns empty', () { - expect(mirror.name, '(empty)'); - }); - - test('annotations returns empty', () { - expect(mirror.annotations, isEmpty); - }); - - test('typeParameters returns empty', () { - expect(mirror.typeParameters, isEmpty); - }); - - test('parameters returns empty', () { - expect(mirror.parameters, isEmpty); - }); - - test('return type is dynamic', () { - expect(mirror.returnType, reflector.reflectType(dynamic)); - }); - - test('isGetter returns false', () { - expect(mirror.isGetter, false); - }); - - test('isSetter returns false', () { - expect(mirror.isSetter, false); - }); - - test('cannot invoke', () { - var invocation = Invocation.method(#drive, []); - expect(() => mirror.invoke(invocation), throwsUnsupportedError); - }); - }); - - group('reflectInstance', () { - var mirror = reflector.reflectInstance(Truck()); - - test('reflectee returns null', () { - expect(mirror.reflectee, null); - }); - - test('type returns empty', () { - expect(mirror.type.name, '(empty)'); - }); - - test('clazz returns empty', () { - expect(mirror.clazz.name, '(empty)'); - }); - - test('cannot getField', () { - expect(() => mirror.getField('wheelCount'), throwsUnsupportedError); - }); - }); -} - -class Truck { - int get wheelCount => 4; - - void drive() { - print('Vroom!!!'); - } -} diff --git a/packages/container/container/test/has_test.dart b/packages/container/container/test/has_test.dart deleted file mode 100644 index 9cce770..0000000 --- a/packages/container/container/test/has_test.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:platform_container/container.dart'; -import 'package:test/test.dart'; - -void main() { - late Container container; - - setUp(() { - container = Container(const EmptyReflector()) - ..registerSingleton(Song(title: 'I Wish')) - ..registerNamedSingleton('foo', 1) - ..registerFactory((container) { - return Artist( - name: 'Stevie Wonder', - song: container.make(), - ); - }); - }); - - test('hasNamed', () { - var child = container.createChild()..registerNamedSingleton('bar', 2); - expect(child.hasNamed('foo'), true); - expect(child.hasNamed('bar'), true); - expect(child.hasNamed('baz'), false); - }); - - test('has on singleton', () { - var result = container.has(); - expect(result, true); - }); - - test('has on factory', () { - expect(container.has(), true); - }); - - test('false if neither', () { - expect(container.has(), false); - }); -} - -class Artist { - final String? name; - final Song? song; - - Artist({this.name, this.song}); -} - -class Song { - final String? title; - - Song({this.title}); -} diff --git a/packages/container/container/test/lazy_test.dart b/packages/container/container/test/lazy_test.dart deleted file mode 100644 index 9564eb7..0000000 --- a/packages/container/container/test/lazy_test.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:platform_container/container.dart'; -import 'package:test/test.dart'; - -void main() { - test('returns the same instance', () { - var container = Container(const EmptyReflector()) - ..registerLazySingleton((_) => Dummy('a')); - - var first = container.make(); - expect(container.make(), first); - }); -} - -class Dummy { - final String s; - - Dummy(this.s); -} diff --git a/packages/container/container/test/mirrors_test.dart b/packages/container/container/test/mirrors_test.dart deleted file mode 100644 index 2b3680f..0000000 --- a/packages/container/container/test/mirrors_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'dart:async'; -import 'package:platform_container/container.dart'; -import 'package:platform_container/mirrors.dart'; -import 'package:test/test.dart'; -import 'common.dart'; - -void main() { - testReflector(const MirrorsReflector()); - - test('futureOf', () { - var r = MirrorsReflector(); - var fStr = r.reflectFutureOf(String); - expect(fStr.reflectedType.toString(), 'Future'); - // expect(fStr.reflectedType, Future.value(null).runtimeType); - }); - - test('concrete future make', () async { - var c = Container(MirrorsReflector()); - c.registerFactory>((_) async => 'hey'); - var fStr = c.reflector.reflectFutureOf(String); - var s1 = await c.make(fStr.reflectedType); - var s2 = await c.makeAsync(String); - print([s1, s2]); - expect(s1, s2); - }); -} diff --git a/packages/container/container/test/named_test.dart b/packages/container/container/test/named_test.dart deleted file mode 100644 index c43f119..0000000 --- a/packages/container/container/test/named_test.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:platform_container/container.dart'; -import 'package:test/test.dart'; - -void main() { - late Container container; - - setUp(() { - container = Container(const EmptyReflector()); - container.registerNamedSingleton('foo', Foo(bar: 'baz')); - }); - - test('fetch by name', () { - expect(container.findByName('foo').bar, 'baz'); - }); - - test('cannot redefine', () { - expect(() => container.registerNamedSingleton('foo', Foo(bar: 'quux')), - throwsStateError); - }); - - test('throws on unknown name', () { - expect(() => container.findByName('bar'), throwsStateError); - }); - - test('throws on incorrect type', () { - expect(() => container.findByName>('foo'), throwsA(anything)); - }); -} - -class Foo { - final String? bar; - - Foo({this.bar}); -} diff --git a/packages/container/container/test/throwing_reflector_test.dart b/packages/container/container/test/throwing_reflector_test.dart deleted file mode 100644 index c6a297c..0000000 --- a/packages/container/container/test/throwing_reflector_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:platform_container/container.dart'; -import 'package:test/test.dart'; - -void main() { - var reflector = const ThrowingReflector(); - - test('getName', () { - expect(reflector.getName(#foo), 'foo'); - expect(reflector.getName(#==), '=='); - }); - - test('reflectClass fails', () { - expect(() => reflector.reflectClass(Truck), throwsUnsupportedError); - }); - - test('reflectType fails', () { - expect(() => reflector.reflectType(Truck), throwsUnsupportedError); - }); - - test('reflectFunction throws', () { - void doIt(int x) {} - expect(() => reflector.reflectFunction(doIt), throwsUnsupportedError); - }); - - test('reflectInstance throws', () { - expect(() => reflector.reflectInstance(Truck()), throwsUnsupportedError); - }); -} - -class Truck { - int get wheelCount => 4; - - void drive() { - print('Vroom!!!'); - } -} diff --git a/packages/container/container_generator/.gitignore b/packages/container/container_generator/.gitignore deleted file mode 100644 index 4b16115..0000000 --- a/packages/container/container_generator/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# See https://www.dartlang.org/guides/libraries/private-files - -# Files and directories created by pub -.dart_tool/ -.packages -.pub/ -build/ -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock - -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - -test/*.reflectable.dart -example/*.reflectable.dart diff --git a/packages/container/container_generator/CHANGELOG.md b/packages/container/container_generator/CHANGELOG.md deleted file mode 100644 index 5fecd3e..0000000 --- a/packages/container/container_generator/CHANGELOG.md +++ /dev/null @@ -1,58 +0,0 @@ -# Change Log - -## 8.1.1 - -* Updated repository link - -## 8.1.0 - -* Updated `lints` to 3.0.0 -* Fixed analyser warnings - -## 8.0.0 - -* Require Dart >= 3.0 - -## 7.1.0-beta.1 - -* Require Dart >= 2.19 -* Upgraded `relectable` to 4.x.x - -## 7.0.0 - -* Require Dart >= 2.17 - -## 6.0.0 - -* Require Dart >= 2.16 - -## 5.0.0 - -* Skipped release - -## 4.0.0 - -* Skipped release - -## 3.0.1 - -* Updated `package:angel3_container` - -## 3.0.0 - -* Fixed NNBD issues -* All 9 test cases passed - -## 3.0.0-beta.1 - -* Migrated to support Dart >= 2.12 NNBD -* Updated linter to `package:lints` -* Updated to use `platform_` packages - -## 2.0.0 - -* Migrated to work with Dart >= 2.12 Non NNBD - -## 1.0.1 - -* Update for `pkg:angel_container@1.0.3`. diff --git a/packages/container/container_generator/LICENSE b/packages/container/container_generator/LICENSE deleted file mode 100644 index df5e063..0000000 --- a/packages/container/container_generator/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2021, dukefirehawk.com -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/container/container_generator/README.md b/packages/container/container_generator/README.md deleted file mode 100644 index 432ce12..0000000 --- a/packages/container/container_generator/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Protevus Container Generator - -![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_container_generator?include_prereleases) -[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety) -[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion) -[![License](https://img.shields.io/github/license/dart-backend/angel)](https://github.com/dart-backend/angel/tree/master/packages/container/angel3_container_generator/LICENSE) - -An alternative container for Protevus that uses `reflectable` package instead of `dart:mirrors` for reflection. However, `reflectable` has more limited relfection capabilities when compared to `dart:mirrors`. - -## Usage - -* Annotable the class with `@contained`. -* Run `dart run build_runner build ` -* Alternatively create a `build.xml` file with the following content - - ```yaml - targets: - $default: - builders: - reflectable: - generate_for: - - bin/**_controller.dart - options: - formatted: true - ``` - -## Known limitation - -* `analyser` 6.x is not supported due to `reflectable` -* Reflection on functions/closures is not supported -* Reflection on private declarations is not supported -* Reflection on generic type is not supported diff --git a/packages/container/container_generator/analysis_options.yaml b/packages/container/container_generator/analysis_options.yaml deleted file mode 100644 index ea2c9e9..0000000 --- a/packages/container/container_generator/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:lints/recommended.yaml \ No newline at end of file diff --git a/packages/container/container_generator/example/main.dart b/packages/container/container_generator/example/main.dart deleted file mode 100644 index bc24685..0000000 --- a/packages/container/container_generator/example/main.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'dart:async'; - -import 'package:platform_container/container.dart'; -import 'package:platform_container_generator/generator.dart'; - -Future main() async { - // Create a container instance. - Container container = Container(GeneratedReflector()); - - // Register a singleton. - container.registerSingleton(Engine(40)); - - // You can also omit the type annotation, in which the object's runtime type will be used. - // If you're injecting an abstract class, prefer the type annotation. - // - // container.registerSingleton(Engine(40)); - - // Register a factory that creates a truck. - container.registerFactory((container) { - return _TruckImpl(container.make()); - }); - - // Use `make` to create an instance. - var truck = container.make(); - - // You can also resolve injections asynchronously. - container.registerFactory>((_) async => 24); - print(await container.makeAsync()); - - // Asynchronous resolution also works for plain objects. - await container.makeAsync().then((t) => t.drive()); - - // Register a named singleton. - container.registerNamedSingleton('the_truck', truck); - - // Should print: 'Vroom! I have 40 horsepower in my engine.' - truck.drive(); - - // Should print the same. - container.findByName('the_truck').drive(); - - // We can make a child container with its own factory. - var childContainer = container.createChild(); - - childContainer.registerFactory((container) { - return _TruckImpl(Engine(5666)); - }); - - // Make a truck with 5666 HP. - childContainer.make().drive(); - - // However, calling `make` will return the Engine singleton we created above. - print(childContainer.make().horsePower); -} - -abstract class Truck { - void drive(); -} - -class Engine { - final int horsePower; - - Engine(this.horsePower); -} - -class _TruckImpl implements Truck { - final Engine engine; - - _TruckImpl(this.engine); - - @override - void drive() { - print('Vroom! I have ${engine.horsePower} horsepower in my engine.'); - } -} diff --git a/packages/container/container_generator/lib/generator.dart b/packages/container/container_generator/lib/generator.dart deleted file mode 100644 index 40dd09f..0000000 --- a/packages/container/container_generator/lib/generator.dart +++ /dev/null @@ -1,255 +0,0 @@ -import 'package:platform_container/container.dart'; -import 'package:reflectable/reflectable.dart'; - -/// A [Reflectable] instance that can be used as an annotation on types to generate metadata for them. -const Reflectable contained = ContainedReflectable(); - -@contained -class ContainedReflectable extends Reflectable { - const ContainedReflectable() - : super( - topLevelInvokeCapability, - typeAnnotationQuantifyCapability, - superclassQuantifyCapability, - libraryCapability, - invokingCapability, - metadataCapability, - reflectedTypeCapability, - typeCapability, - typingCapability); -} - -/// A [Reflector] instance that uses a [Reflectable] to reflect upon data. -class GeneratedReflector extends Reflector { - final Reflectable reflectable; - - const GeneratedReflector([this.reflectable = contained]); - - @override - String getName(Symbol symbol) { - return symbol.toString().substring(7); - } - - @override - ReflectedClass reflectClass(Type clazz) { - return reflectType(clazz) as ReflectedClass; - } - - @override - ReflectedFunction reflectFunction(Function function) { - if (!reflectable.canReflect(function)) { - throw UnsupportedError('Cannot reflect $function.'); - } - - var mirror = reflectable.reflect(function); - - if (mirror is ClosureMirror) { - return _GeneratedReflectedFunction(mirror.function, this, mirror); - } else { - throw ArgumentError('$function is not a Function.'); - } - } - - @override - ReflectedInstance reflectInstance(Object object) { - if (!reflectable.canReflect(object)) { - throw UnsupportedError('Cannot reflect $object.'); - } else { - var mirror = reflectable.reflect(object); - return _GeneratedReflectedInstance(mirror, this); - } - } - - @override - ReflectedType reflectType(Type type) { - if (!reflectable.canReflectType(type)) { - throw UnsupportedError('Cannot reflect $type.'); - } else { - var mirror = reflectable.reflectType(type); - return mirror is ClassMirror - ? _GeneratedReflectedClass(mirror, this) - : _GeneratedReflectedType(mirror); - } - } -} - -class _GeneratedReflectedInstance extends ReflectedInstance { - final InstanceMirror mirror; - final GeneratedReflector reflector; - - _GeneratedReflectedInstance(this.mirror, this.reflector) - : super(_GeneratedReflectedType(mirror.type), - _GeneratedReflectedClass(mirror.type, reflector), mirror.reflectee); - - @override - ReflectedType get type => clazz; - - @override - ReflectedInstance getField(String name) { - var result = mirror.invokeGetter(name)!; - var instance = reflector.reflectable.reflect(result); - return _GeneratedReflectedInstance(instance, reflector); - } -} - -class _GeneratedReflectedClass extends ReflectedClass { - final ClassMirror mirror; - final Reflector reflector; - - _GeneratedReflectedClass(this.mirror, this.reflector) - : super(mirror.simpleName, [], [], [], [], mirror.reflectedType); - - @override - List get typeParameters => - mirror.typeVariables.map(_convertTypeVariable).toList(); - - @override - List get constructors => - _constructorsOf(mirror.declarations, reflector); - - @override - List get declarations => - _declarationsOf(mirror.declarations, reflector); - - @override - List get annotations => mirror.metadata - .map(reflector.reflectInstance) - .whereType() - .toList(); - - @override - bool isAssignableTo(ReflectedType? other) { - if (other is _GeneratedReflectedClass) { - return mirror.isAssignableTo(other.mirror); - } else if (other is _GeneratedReflectedType) { - return mirror.isAssignableTo(other.mirror); - } else { - return false; - } - } - - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map? namedArguments, List? typeArguments]) { - namedArguments ??= {}; - var result = mirror.newInstance(constructorName, positionalArguments, - namedArguments.map((k, v) => MapEntry(Symbol(k), v))); - return reflector.reflectInstance(result)!; - } -} - -class _GeneratedReflectedType extends ReflectedType { - final TypeMirror mirror; - - _GeneratedReflectedType(this.mirror) - : super(mirror.simpleName, [], mirror.reflectedType); - - @override - List get typeParameters => - mirror.typeVariables.map(_convertTypeVariable).toList(); - - @override - bool isAssignableTo(ReflectedType? other) { - if (other is _GeneratedReflectedClass) { - return mirror.isAssignableTo(other.mirror); - } else if (other is _GeneratedReflectedType) { - return mirror.isAssignableTo(other.mirror); - } else { - return false; - } - } - - @override - ReflectedInstance newInstance( - String constructorName, List positionalArguments, - [Map namedArguments = const {}, - List typeArguments = const []]) { - throw UnsupportedError('Cannot create a new instance of $reflectedType.'); - } -} - -class _GeneratedReflectedFunction extends ReflectedFunction { - final MethodMirror mirror; - final Reflector reflector; - final ClosureMirror? closure; - - _GeneratedReflectedFunction(this.mirror, this.reflector, [this.closure]) - : super( - mirror.simpleName, - [], - [], - mirror.parameters - .map((p) => _convertParameter(p, reflector)) - .toList(), - mirror.isGetter, - mirror.isSetter, - returnType: !mirror.isRegularMethod - ? null - : _GeneratedReflectedType(mirror.returnType)); - - @override - List get annotations => mirror.metadata - .map(reflector.reflectInstance) - .whereType() - .toList(); - - @override - ReflectedInstance invoke(Invocation invocation) { - if (closure != null) { - throw UnsupportedError('Only closures can be invoked directly.'); - } else { - var result = closure!.delegate(invocation)!; - return reflector.reflectInstance(result)!; - } - } -} - -List _constructorsOf( - Map map, Reflector reflector) { - return map.entries.fold>([], (out, entry) { - var v = entry.value; - - if (v is MethodMirror && v.isConstructor) { - return out..add(_GeneratedReflectedFunction(v, reflector)); - } else { - return out; - } - }); -} - -List _declarationsOf( - Map map, Reflector reflector) { - return map.entries.fold>([], (out, entry) { - var v = entry.value; - - if (v is VariableMirror) { - var decl = ReflectedDeclaration(v.simpleName, v.isStatic, null); - return out..add(decl); - } - if (v is MethodMirror) { - var decl = ReflectedDeclaration( - v.simpleName, v.isStatic, _GeneratedReflectedFunction(v, reflector)); - return out..add(decl); - } else { - return out; - } - }); -} - -ReflectedTypeParameter _convertTypeVariable(TypeVariableMirror mirror) { - return ReflectedTypeParameter(mirror.simpleName); -} - -ReflectedParameter _convertParameter( - ParameterMirror mirror, Reflector reflector) { - return ReflectedParameter( - mirror.simpleName, - mirror.metadata - .map(reflector.reflectInstance) - .whereType() - .toList(), - reflector.reflectType(mirror.type.reflectedType)!, - !mirror.isOptional, - mirror.isNamed); -} diff --git a/packages/container/container_generator/pubspec.yaml b/packages/container/container_generator/pubspec.yaml deleted file mode 100644 index d3aed3e..0000000 --- a/packages/container/container_generator/pubspec.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: platform_container_generator -version: 9.0.0 -description: Protevus Platform Codegen support for using pkg:reflectable with pkg:platform_container. -homepage: https://protevus.com -documentation: https://docs.protevus.com -repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/container/container_generator -environment: - sdk: '>=3.3.0 <4.0.0' -dependencies: - platform_container: ^9.0.0 - reflectable: ^4.0.12 -dev_dependencies: - build_runner: ^2.4.13 - build_test: ^2.2.2 - test: ^1.25.8 - lints: ^4.0.0 -# dependency_overrides: -# platform_container: -# path: ../platform_container diff --git a/packages/container/container_generator/test/reflector_test.dart b/packages/container/container_generator/test/reflector_test.dart deleted file mode 100644 index e2bd7d9..0000000 --- a/packages/container/container_generator/test/reflector_test.dart +++ /dev/null @@ -1,179 +0,0 @@ -import 'package:platform_container/container.dart'; -import 'package:platform_container_generator/generator.dart'; - -import 'package:test/test.dart'; -import 'reflector_test.reflectable.dart'; - -void main() { - initializeReflectable(); - - var reflector = const GeneratedReflector(); - late Container container; - - setUp(() { - container = Container(reflector); - container.registerSingleton(Artist(name: 'Stevie Wonder')); - }); - - group('reflectClass', () { - var mirror = reflector.reflectClass(Artist); - - test('name', () { - expect(mirror.name, 'Artist'); - }); - }); - - test('inject constructor parameters', () { - var album = container.make(); - print(album.title); - expect(album.title, 'flowers by stevie wonder'); - }); - - // Skip as pkg:reflectable cannot reflect on closures at all (yet) - //testReflector(reflector); -} - -@contained -void returnVoidFromAFunction(int x) {} - -void testReflector(Reflector reflector) { - var blaziken = Pokemon('Blaziken', PokemonType.fire); - late Container container; - - setUp(() { - container = Container(reflector); - container.registerSingleton(blaziken); - }); - - test('get field', () { - var blazikenMirror = reflector.reflectInstance(blaziken)!; - expect(blazikenMirror.getField('type').reflectee, blaziken.type); - }); - - group('reflectFunction', () { - var mirror = reflector.reflectFunction(returnVoidFromAFunction); - - test('void return type returns dynamic', () { - expect(mirror?.returnType, reflector.reflectType(dynamic)); - }); - - test('counts parameters', () { - expect(mirror?.parameters, hasLength(1)); - }); - - test('counts types parameters', () { - expect(mirror?.typeParameters, isEmpty); - }); - - test('correctly reflects parameter types', () { - var p = mirror?.parameters[0]; - expect(p?.name, 'x'); - expect(p?.isRequired, true); - expect(p?.isNamed, false); - expect(p?.annotations, isEmpty); - expect(p?.type, reflector.reflectType(int)); - }); - }, skip: 'pkg:reflectable cannot reflect on closures at all (yet)'); - - test('make on singleton type returns singleton', () { - expect(container.make(Pokemon), blaziken); - }); - - test('make with generic returns same as make with explicit type', () { - expect(container.make(), blaziken); - }); - - test('make on aliased singleton returns singleton', () { - container.registerSingleton(blaziken, as: StateError); - expect(container.make(StateError), blaziken); - }); - - test('constructor injects singleton', () { - var lower = container.make(); - expect(lower.lowercaseName, blaziken.name.toLowerCase()); - }); - - test('newInstance works', () { - var type = container.reflector.reflectType(Pokemon)!; - var instance = - type.newInstance('changeName', [blaziken, 'Charizard']).reflectee - as Pokemon; - print(instance); - expect(instance.name, 'Charizard'); - expect(instance.type, PokemonType.fire); - }); - - test('isAssignableTo', () { - var pokemonType = container.reflector.reflectType(Pokemon); - var kantoPokemonType = container.reflector.reflectType(KantoPokemon)!; - - expect(kantoPokemonType.isAssignableTo(pokemonType), true); - - expect( - kantoPokemonType - .isAssignableTo(container.reflector.reflectType(String)), - false); - }); -} - -@contained -class LowerPokemon { - final Pokemon pokemon; - - LowerPokemon(this.pokemon); - - String get lowercaseName => pokemon.name.toLowerCase(); -} - -@contained -class Pokemon { - final String name; - final PokemonType type; - - Pokemon(this.name, this.type); - - factory Pokemon.changeName(Pokemon other, String name) { - return Pokemon(name, other.type); - } - - @override - String toString() => 'NAME: $name, TYPE: $type'; -} - -@contained -class KantoPokemon extends Pokemon { - KantoPokemon(super.name, super.type); -} - -@contained -enum PokemonType { water, fire, grass, ice, poison, flying } - -@contained -class Artist { - final String name; - - Artist({required this.name}); - - String get lowerName { - return name.toLowerCase(); - } -} - -@contained -class Album { - final Artist artist; - - Album(this.artist); - - String get title => 'flowers by ${artist.lowerName}'; -} - -@contained -class AlbumLength { - final Artist artist; - final Album album; - - AlbumLength(this.artist, this.album); - - int get totalLength => artist.name.length + album.title.length; -} diff --git a/packages/contracts/lib/contracts.dart b/packages/contracts/lib/contracts.dart deleted file mode 100644 index 473fb3f..0000000 --- a/packages/contracts/lib/contracts.dart +++ /dev/null @@ -1,71 +0,0 @@ -/// Platform Contracts Library -/// -/// This library provides the core contracts (interfaces) that define -/// the Platform framework's API. These contracts ensure consistency -/// and interoperability between components while enabling loose coupling -/// and dependency injection. - -// Level 0: Core Foundation Contracts - -// Container contracts (from packages/container) -export 'src/container/container.dart'; - -// Reflection contracts (from packages/container) -export 'src/reflection/reflection.dart'; - -// Pipeline contracts (from packages/pipeline) -export 'src/pipeline/pipeline.dart'; - -// Level 1: Infrastructure Contracts - -// Events contracts (from packages/events) -export 'src/events/events.dart'; - -// Bus contracts (from packages/bus) -export 'src/bus/bus.dart'; - -// Model contracts (from packages/model) -export 'src/model/model.dart'; - -// Process contracts (from packages/process) -export 'src/process/process.dart'; - -// Support contracts (from packages/support) -export 'src/support/support.dart'; - -// Level 2: Core Services Contracts - -// Queue contracts (from packages/queue) -export 'src/queue/queue.dart'; - -// Level 3: HTTP Layer Contracts - -// Routing contracts (from packages/route) -export 'src/routing/routing.dart'; - -// HTTP contracts (from packages/core) -export 'src/http/http.dart'; - -// Testing Contracts - -// Testing contracts (from packages/testing) -export 'src/testing/testing.dart'; - -// All contracts have been extracted from implemented packages: -// - Container & Reflection (Level 0) -// - Pipeline (Level 0) -// - Events (Level 1) -// - Bus (Level 1) -// - Model (Level 1) -// - Process (Level 1) -// - Support (Level 1) -// - Queue (Level 2) -// - Route (Level 3) -// - HTTP (Level 3) -// - Testing - -// Next steps: -// 1. Update package dependencies to use these contracts -// 2. Implement contracts in each package -// 3. Add contract compliance tests -// 4. Document contract usage and patterns diff --git a/packages/contracts/lib/src/bus/bus.dart b/packages/contracts/lib/src/bus/bus.dart deleted file mode 100644 index cd46d82..0000000 --- a/packages/contracts/lib/src/bus/bus.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Bus package contracts -export 'bus_contract.dart'; diff --git a/packages/contracts/lib/src/bus/bus_contract.dart b/packages/contracts/lib/src/bus/bus_contract.dart deleted file mode 100644 index 075ceee..0000000 --- a/packages/contracts/lib/src/bus/bus_contract.dart +++ /dev/null @@ -1,196 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for commands. -/// -/// Laravel-compatible: Base interface for command objects that can be -/// dispatched through the command bus. -@sealed -abstract class CommandContract {} - -/// Contract for queueable commands. -/// -/// Laravel-compatible: Marks commands that should be processed -/// through the queue system. -@sealed -abstract class ShouldQueueCommand implements CommandContract {} - -/// Contract for command handlers. -/// -/// Laravel-compatible: Defines how command handlers should process -/// their associated commands, with platform-specific typing. -@sealed -abstract class HandlerContract { - /// Handles a command. - /// - /// Laravel-compatible: Core handler method with platform-specific - /// return type for more flexibility. - /// - /// Parameters: - /// - [command]: The command to handle. - Future handle(CommandContract command); -} - -/// Type definition for command pipe functions. -/// -/// Platform-specific: Defines transformation functions that can modify -/// commands as they flow through the pipeline. -typedef CommandPipe = CommandContract Function(CommandContract); - -/// Contract for command dispatching. -/// -/// This contract defines the core interface for dispatching -/// and processing commands through the command bus. -@sealed -abstract class CommandDispatcherContract { - /// Dispatches a command. - /// - /// Laravel-compatible: Core dispatch method. - /// - /// Parameters: - /// - [command]: The command to dispatch. - Future dispatch(CommandContract command); - - /// Dispatches a command synchronously. - /// - /// Platform-specific: Provides explicit sync dispatch with optional handler. - /// - /// Parameters: - /// - [command]: The command to dispatch. - /// - [handler]: Optional specific handler. - Future dispatchSync(CommandContract command, - [HandlerContract? handler]); - - /// Dispatches a command immediately. - /// - /// Laravel-compatible: Immediate dispatch without queueing. - /// Extended with optional handler parameter. - /// - /// Parameters: - /// - [command]: The command to dispatch. - /// - [handler]: Optional specific handler. - Future dispatchNow(CommandContract command, - [HandlerContract? handler]); - - /// Dispatches a command to queue. - /// - /// Laravel-compatible: Queue-based dispatch. - /// - /// Parameters: - /// - [command]: The command to queue. - Future dispatchToQueue(CommandContract command); - - /// Finds a command batch. - /// - /// Platform-specific: Provides batch lookup functionality. - /// - /// Parameters: - /// - [batchId]: The batch ID to find. - Future findBatch(String batchId); - - /// Creates a command batch. - /// - /// Laravel-compatible: Creates command batches. - /// Extended with platform-specific batch contract. - /// - /// Parameters: - /// - [commands]: Commands to include in batch. - PendingCommandBatchContract batch(List commands); - - /// Creates a command chain. - /// - /// Laravel-compatible: Creates command chains. - /// Extended with platform-specific chain contract. - /// - /// Parameters: - /// - [commands]: Commands to chain. - CommandChainContract chain(List commands); - - /// Maps command types to handlers. - /// - /// Platform-specific: Provides explicit handler mapping. - /// - /// Parameters: - /// - [handlers]: Map of command types to handler types. - CommandDispatcherContract map(Map handlers); - - /// Applies transformation pipes to commands. - /// - /// Platform-specific: Adds pipeline transformation support. - /// - /// Parameters: - /// - [pipes]: List of command transformation functions. - CommandDispatcherContract pipeThrough(List pipes); - - /// Dispatches after current response. - /// - /// Laravel-compatible: Delayed dispatch after response. - /// - /// Parameters: - /// - [command]: Command to dispatch later. - void dispatchAfterResponse(CommandContract command); -} - -/// Contract for command batches. -/// -/// Laravel-compatible: Defines batch structure and operations. -/// Extended with additional status tracking. -@sealed -abstract class CommandBatchContract { - /// Gets the batch ID. - String get id; - - /// Gets commands in the batch. - List get commands; - - /// Gets batch status. - /// - /// Platform-specific: Provides detailed status tracking. - String get status; - - /// Whether batch allows failures. - /// - /// Laravel-compatible: Controls batch failure handling. - bool get allowsFailures; - - /// Gets finished command count. - /// - /// Platform-specific: Tracks completion progress. - int get finished; - - /// Gets failed command count. - /// - /// Platform-specific: Tracks failure count. - int get failed; - - /// Gets pending command count. - /// - /// Platform-specific: Tracks remaining commands. - int get pending; -} - -/// Contract for pending command batches. -/// -/// Laravel-compatible: Defines batch configuration and dispatch. -@sealed -abstract class PendingCommandBatchContract { - /// Allows failures in batch. - /// - /// Laravel-compatible: Configures failure handling. - PendingCommandBatchContract allowFailures(); - - /// Dispatches the batch. - /// - /// Laravel-compatible: Executes the batch. - Future dispatch(); -} - -/// Contract for command chains. -/// -/// Laravel-compatible: Defines sequential command execution. -@sealed -abstract class CommandChainContract { - /// Dispatches the chain. - /// - /// Laravel-compatible: Executes commands in sequence. - Future dispatch(); -} diff --git a/packages/contracts/lib/src/container/container.dart b/packages/contracts/lib/src/container/container.dart deleted file mode 100644 index 88578ff..0000000 --- a/packages/contracts/lib/src/container/container.dart +++ /dev/null @@ -1,3 +0,0 @@ -/// Container package contracts -export 'container_contract.dart'; -export 'contextual_binding_contract.dart'; diff --git a/packages/contracts/lib/src/container/container_contract.dart b/packages/contracts/lib/src/container/container_contract.dart deleted file mode 100644 index dc2c414..0000000 --- a/packages/contracts/lib/src/container/container_contract.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'package:meta/meta.dart'; -import '../reflection/reflector_contract.dart'; - -/// Core container contract defining dependency injection functionality. -/// -/// This contract defines the interface that all dependency injection containers -/// must implement. It provides methods for registering and resolving dependencies, -/// creating child containers, and managing named instances. -@sealed -abstract class ContainerContract { - /// Gets the reflector instance used by this container. - ReflectorContract get reflector; - - /// Whether this is a root container (has no parent). - bool get isRoot; - - /// Creates a child container that inherits from this container. - /// - /// The child container can access all dependencies registered in its parent containers, - /// but can also define its own dependencies that override or extend the parent's. - /// This enables scoped dependency injection contexts. - ContainerContract createChild(); - - /// Checks if a type is registered in this container or its parents. - /// - /// Parameters: - /// - [T]: The type to check for. If [T] is dynamic, [t] must be provided. - /// - [t]: Optional type parameter that overrides [T] if provided. - /// - /// Returns true if the type is registered, false otherwise. - bool has([Type? t]); - - /// Checks if a named instance exists in this container or its parents. - /// - /// Parameters: - /// - [name]: The name to check for. - /// - /// Returns true if a named instance exists, false otherwise. - bool hasNamed(String name); - - /// Makes an instance of type [T]. - /// - /// This will: - /// 1. Return a singleton if registered - /// 2. Create an instance via factory if registered - /// 3. Use reflection to create a new instance - /// - /// Parameters: - /// - [type]: Optional type parameter that overrides [T] if provided. - /// - /// Throws: - /// - ReflectionException if [T] is not a class or has no default constructor - T make([Type? type]); - - /// Makes an instance of type [T] asynchronously. - /// - /// This will attempt to resolve a Future in the following order: - /// 1. Wrap a synchronous [T] in Future - /// 2. Return a registered Future - /// 3. Create a Future via reflection - /// - /// Parameters: - /// - [type]: Optional type parameter that overrides [T] if provided. - /// - /// Throws: - /// - ReflectionException if no suitable injection is found - Future makeAsync([Type? type]); - - /// Registers a singleton instance. - /// - /// The instance will be shared across the container hierarchy. - /// - /// Parameters: - /// - [object]: The singleton instance to register. - /// - [as]: Optional type to register the singleton as. - /// - /// Returns the registered instance. - /// - /// Throws: - /// - StateError if a singleton is already registered for the type - T registerSingleton(T object, {Type? as}); - - /// Registers a factory function. - /// - /// The factory will be called each time an instance is needed. - /// - /// Parameters: - /// - [factory]: Function that creates instances. - /// - [as]: Optional type to register the factory as. - /// - /// Returns the factory function. - /// - /// Throws: - /// - StateError if a factory is already registered for the type - T Function(ContainerContract) registerFactory( - T Function(ContainerContract) factory, - {Type? as}); - - /// Registers a lazy singleton. - /// - /// The singleton will be created on first use. - /// - /// Parameters: - /// - [factory]: Function that creates the singleton. - /// - [as]: Optional type to register the singleton as. - /// - /// Returns the factory function. - T Function(ContainerContract) registerLazySingleton( - T Function(ContainerContract) factory, - {Type? as}); - - /// Gets a named singleton. - /// - /// Parameters: - /// - [name]: The name of the singleton to retrieve. - /// - /// Returns the named singleton instance. - /// - /// Throws: - /// - StateError if no singleton exists with the given name - T findByName(String name); - - /// Registers a named singleton. - /// - /// Parameters: - /// - [name]: The name to register the singleton under. - /// - [object]: The singleton instance. - /// - /// Returns the registered instance. - /// - /// Throws: - /// - StateError if a singleton already exists with the given name - T registerNamedSingleton(String name, T object); -} diff --git a/packages/contracts/lib/src/container/contextual_binding_contract.dart b/packages/contracts/lib/src/container/contextual_binding_contract.dart deleted file mode 100644 index 7071c36..0000000 --- a/packages/contracts/lib/src/container/contextual_binding_contract.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for contextual binding in dependency injection. -/// -/// This contract defines the interface for creating contextual bindings, -/// allowing dependencies to be resolved differently based on context. -@sealed -abstract class ContextualBindingContract { - /// Specifies the concrete type that triggers this contextual binding. - /// - /// Parameters: - /// - [concrete]: The concrete type that needs dependencies. - /// - /// Returns a builder for specifying what type is needed. - ContextualNeedsContract when(Type concrete); -} - -/// Contract for specifying contextual needs. -/// -/// This contract defines the interface for specifying what type -/// is needed in a particular context. -@sealed -abstract class ContextualNeedsContract { - /// Specifies the type needed in this context. - /// - /// Returns a builder for specifying what to give. - ContextualGiveContract needs(); -} - -/// Contract for specifying contextual implementations. -/// -/// This contract defines the interface for specifying what -/// implementation to provide in a particular context. -@sealed -abstract class ContextualGiveContract { - /// Specifies what to give for this contextual binding. - /// - /// Parameters: - /// - [implementation]: The implementation to provide. - /// This can be an instance, a factory function, or a type. - void give(dynamic implementation); -} diff --git a/packages/contracts/lib/src/events/event_dispatcher_contract.dart b/packages/contracts/lib/src/events/event_dispatcher_contract.dart deleted file mode 100644 index 47e2308..0000000 --- a/packages/contracts/lib/src/events/event_dispatcher_contract.dart +++ /dev/null @@ -1,199 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for event dispatching functionality. -/// -/// This contract defines the interface for dispatching events, -/// managing listeners, and handling event broadcasting. -/// -/// The contract includes both Laravel-compatible methods and platform-specific -/// extensions for enhanced functionality. -@sealed -abstract class EventDispatcherContract { - /// Registers an event listener. - /// - /// Laravel-compatible: Registers event listeners, but with platform-specific - /// dynamic typing for more flexible event handling. - /// - /// Parameters: - /// - [events]: Event type or list of event types to listen for. - /// - [listener]: Function to handle the event. - void listen(dynamic events, dynamic listener); - - /// Checks if event has listeners. - /// - /// Platform-specific: Provides listener existence checking. - /// - /// Parameters: - /// - [eventName]: Name of the event to check. - bool hasListeners(String eventName); - - /// Pushes an event for delayed processing. - /// - /// Platform-specific: Supports delayed event processing. - /// - /// Parameters: - /// - [event]: Name of the event. - /// - [payload]: Optional event payload. - void push(String event, [dynamic payload]); - - /// Flushes delayed events. - /// - /// Platform-specific: Processes delayed events immediately. - /// - /// Parameters: - /// - [event]: Name of the event to flush. - Future flush(String event); - - /// Subscribes an event subscriber. - /// - /// Laravel-compatible: Registers event subscribers, but with platform-specific - /// dynamic typing for more flexible subscription handling. - /// - /// Parameters: - /// - [subscriber]: The subscriber to register. - void subscribe(dynamic subscriber); - - /// Waits for an event to occur. - /// - /// Platform-specific: Provides event waiting functionality. - /// - /// Parameters: - /// - [event]: Event to wait for. - /// - [payload]: Optional payload to dispatch. - Future until(dynamic event, [dynamic payload]); - - /// Dispatches an event. - /// - /// Laravel-compatible: Dispatches events, with platform-specific - /// extensions for halting and payload handling. - /// - /// Parameters: - /// - [event]: Event to dispatch. - /// - [payload]: Optional event payload. - /// - [halt]: Whether to halt after first handler. - Future dispatch(dynamic event, [dynamic payload, bool? halt]); - - /// Gets registered listeners. - /// - /// Laravel-compatible: Retrieves event listeners. - /// - /// Parameters: - /// - [eventName]: Name of the event. - List getListeners(String eventName); - - /// Removes an event listener. - /// - /// Laravel-compatible: Removes event listeners. - /// - /// Parameters: - /// - [event]: Event to remove listener for. - void forget(String event); - - /// Removes pushed event listeners. - /// - /// Platform-specific: Cleans up delayed event listeners. - void forgetPushed(); - - /// Sets queue resolver. - /// - /// Laravel-compatible: Configures queue integration. - /// - /// Parameters: - /// - [resolver]: Queue resolver function. - void setQueueResolver(Function resolver); - - /// Sets transaction manager resolver. - /// - /// Laravel-compatible: Configures transaction integration. - /// - /// Parameters: - /// - [resolver]: Transaction manager resolver function. - void setTransactionManagerResolver(Function resolver); - - /// Gets raw event listeners. - /// - /// Platform-specific: Provides access to raw listener data. - Map> getRawListeners(); -} - -/// Contract for event subscribers. -/// -/// Laravel-compatible: Defines how event subscribers register -/// their event handling methods. -@sealed -abstract class EventSubscriberContract { - /// Subscribes to events. - /// - /// Laravel-compatible: Returns event handler mappings. - /// - /// Returns a map of event types to handler functions. - Map subscribe(); -} - -/// Marker interface for broadcastable events. -/// -/// Laravel-compatible: Events implementing this interface will be broadcast -/// across the application. -@sealed -abstract class ShouldBroadcast { - /// Gets channels to broadcast on. - /// - /// Laravel-compatible: Defines broadcast channels. - List broadcastOn(); - - /// Gets event name for broadcasting. - /// - /// Laravel-compatible: Defines broadcast event name. - String broadcastAs() => runtimeType.toString(); - - /// Gets broadcast data. - /// - /// Laravel-compatible: Defines broadcast payload. - Map get broadcastWith => {}; -} - -/// Marker interface for queueable events. -/// -/// Laravel-compatible: Events implementing this interface will be processed -/// through the queue system. -@sealed -abstract class ShouldQueue { - /// Gets the queue name. - /// - /// Laravel-compatible: Defines target queue. - String get queue => 'default'; - - /// Gets the processing delay. - /// - /// Laravel-compatible: Defines queue delay. - Duration? get delay => null; - - /// Gets maximum retry attempts. - /// - /// Laravel-compatible: Defines retry limit. - int get tries => 1; -} - -/// Marker interface for encrypted events. -/// -/// Laravel-compatible: Events implementing this interface will be encrypted -/// before being stored or transmitted. -@sealed -abstract class ShouldBeEncrypted { - /// Whether the event should be encrypted. - /// - /// Laravel-compatible: Controls event encryption. - bool get shouldBeEncrypted => true; -} - -/// Marker interface for events that should dispatch after commit. -/// -/// Laravel-compatible: Events implementing this interface will only be dispatched -/// after the current database transaction commits. -@sealed -abstract class ShouldDispatchAfterCommit { - /// Whether to dispatch after commit. - /// - /// Laravel-compatible: Controls transaction-based dispatch. - bool get afterCommit => true; -} diff --git a/packages/contracts/lib/src/events/events.dart b/packages/contracts/lib/src/events/events.dart deleted file mode 100644 index 6f6e5c1..0000000 --- a/packages/contracts/lib/src/events/events.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Events package contracts -export 'event_dispatcher_contract.dart'; diff --git a/packages/contracts/lib/src/http/http.dart b/packages/contracts/lib/src/http/http.dart deleted file mode 100644 index 4fb3ab6..0000000 --- a/packages/contracts/lib/src/http/http.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// HTTP package contracts -export 'http_contract.dart'; diff --git a/packages/contracts/lib/src/http/http_contract.dart b/packages/contracts/lib/src/http/http_contract.dart deleted file mode 100644 index 5f54ffa..0000000 --- a/packages/contracts/lib/src/http/http_contract.dart +++ /dev/null @@ -1,299 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for HTTP requests. -/// -/// Laravel-compatible: Core request functionality matching Laravel's Request -/// interface, with platform-specific stream handling. -@sealed -abstract class RequestContract { - /// Gets the request method. - /// - /// Laravel-compatible: HTTP method accessor. - String get method; - - /// Gets the request URI. - /// - /// Laravel-compatible: Request URI using Dart's Uri class. - Uri get uri; - - /// Gets request headers. - /// - /// Laravel-compatible: Header access with platform-specific - /// multi-value support. - Map> get headers; - - /// Gets query parameters. - /// - /// Laravel-compatible: Query parameter access. - Map get query; - - /// Gets POST data. - /// - /// Laravel-compatible: POST data access. - Map get post; - - /// Gets cookies. - /// - /// Laravel-compatible: Cookie access. - Map get cookies; - - /// Gets uploaded files. - /// - /// Laravel-compatible: File upload handling with - /// platform-specific contract. - Map get files; - - /// Gets the request body. - /// - /// Platform-specific: Stream-based body access. - Stream> get body; - - /// Gets a request header. - /// - /// Laravel-compatible: Single header access. - String? header(String name, [String? defaultValue]); - - /// Gets a query parameter. - /// - /// Laravel-compatible: Single query parameter access. - String? query_(String name, [String? defaultValue]); - - /// Gets a POST value. - /// - /// Laravel-compatible: Single POST value access. - dynamic post_(String name, [dynamic defaultValue]); - - /// Gets a cookie value. - /// - /// Laravel-compatible: Single cookie access. - String? cookie(String name, [String? defaultValue]); - - /// Gets an uploaded file. - /// - /// Laravel-compatible: Single file access. - UploadedFileContract? file(String name); - - /// Gets all input data (query + post). - /// - /// Laravel-compatible: Combined input access. - Map all(); - - /// Gets input value from any source. - /// - /// Laravel-compatible: Universal input access. - dynamic input(String name, [dynamic defaultValue]); - - /// Checks if input exists. - /// - /// Laravel-compatible: Input existence check. - bool has(String name); - - /// Gets the raw request body as string. - /// - /// Platform-specific: Async text body access. - Future text(); - - /// Gets the request body as JSON. - /// - /// Platform-specific: Async JSON body access. - Future json(); -} - -/// Contract for HTTP responses. -/// -/// Laravel-compatible: Core response functionality matching Laravel's Response -/// interface, with platform-specific async features. -@sealed -abstract class ResponseContract { - /// Gets response headers. - /// - /// Laravel-compatible: Header access with platform-specific - /// multi-value support. - Map> get headers; - - /// Gets the status code. - /// - /// Laravel-compatible: Status code accessor. - int get status; - - /// Sets the status code. - /// - /// Laravel-compatible: Status code mutator. - set status(int value); - - /// Sets a response header. - /// - /// Laravel-compatible: Single header setting. - void header(String name, String value); - - /// Sets multiple headers. - /// - /// Laravel-compatible: Bulk header setting. - void headers_(Map headers); - - /// Sets a cookie. - /// - /// Laravel-compatible: Cookie setting with platform-specific - /// security options. - void cookie( - String name, - String value, { - Duration? maxAge, - DateTime? expires, - String? domain, - String? path, - bool secure = false, - bool httpOnly = false, - String? sameSite, - }); - - /// Writes response body content. - /// - /// Laravel-compatible: Content writing. - void write(dynamic content); - - /// Sends JSON response. - /// - /// Laravel-compatible: JSON response. - void json(dynamic data); - - /// Sends file download. - /// - /// Laravel-compatible: File download with platform-specific - /// async handling. - Future download(String path, [String? name]); - - /// Redirects to another URL. - /// - /// Laravel-compatible: Redirect response. - void redirect(String url, [int status = 302]); - - /// Sends the response. - /// - /// Platform-specific: Async response sending. - Future send(); -} - -/// Contract for uploaded files. -/// -/// Laravel-compatible: File upload handling matching Laravel's UploadedFile -/// interface, with platform-specific async operations. -@sealed -abstract class UploadedFileContract { - /// Gets the original client filename. - /// - /// Laravel-compatible: Original filename. - String get filename; - - /// Gets the file MIME type. - /// - /// Laravel-compatible: MIME type. - String get mimeType; - - /// Gets the file size in bytes. - /// - /// Laravel-compatible: File size. - int get size; - - /// Gets temporary file path. - /// - /// Laravel-compatible: Temporary storage. - String get path; - - /// Moves file to new location. - /// - /// Laravel-compatible: File movement with platform-specific - /// async handling. - Future moveTo(String path); - - /// Gets file contents as bytes. - /// - /// Platform-specific: Async binary content access. - Future> bytes(); - - /// Gets file contents as string. - /// - /// Platform-specific: Async text content access. - Future text(); -} - -/// Contract for HTTP middleware. -/// -/// Laravel-compatible: Middleware functionality matching Laravel's Middleware -/// interface, with platform-specific async handling. -@sealed -abstract class MiddlewareContract { - /// Handles the request. - /// - /// Laravel-compatible: Middleware handling with platform-specific - /// async processing. - /// - /// Parameters: - /// - [request]: The incoming request. - /// - [next]: Function to pass to next middleware. - Future handle(RequestContract request, - Future Function(RequestContract) next); -} - -/// Contract for HTTP kernel. -/// -/// Laravel-compatible: HTTP kernel functionality matching Laravel's HttpKernel -/// interface, with platform-specific async processing. -@sealed -abstract class HttpKernelContract { - /// Gets global middleware. - /// - /// Laravel-compatible: Global middleware list. - List get middleware; - - /// Gets middleware groups. - /// - /// Laravel-compatible: Middleware grouping. - Map> get middlewareGroups; - - /// Gets route middleware. - /// - /// Laravel-compatible: Route middleware mapping. - Map get routeMiddleware; - - /// Handles an HTTP request. - /// - /// Laravel-compatible: Request handling with platform-specific - /// async processing. - Future handle(RequestContract request); - - /// Terminates the request/response cycle. - /// - /// Laravel-compatible: Request termination with platform-specific - /// async processing. - Future terminate( - RequestContract request, ResponseContract response); -} - -/// Contract for HTTP context. -/// -/// Platform-specific: Provides request context beyond Laravel's -/// standard request handling. -@sealed -abstract class HttpContextContract { - /// Gets the current request. - RequestContract get request; - - /// Gets the current response. - ResponseContract get response; - - /// Gets context attributes. - Map get attributes; - - /// Gets a context attribute. - T? getAttribute(String key); - - /// Sets a context attribute. - void setAttribute(String key, dynamic value); - - /// Gets the route parameters. - Map get routeParams; - - /// Gets a route parameter. - T? getRouteParam(String name); -} diff --git a/packages/contracts/lib/src/model/model.dart b/packages/contracts/lib/src/model/model.dart deleted file mode 100644 index 9dd4228..0000000 --- a/packages/contracts/lib/src/model/model.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Model package contracts -export 'model_contract.dart'; diff --git a/packages/contracts/lib/src/model/model_contract.dart b/packages/contracts/lib/src/model/model_contract.dart deleted file mode 100644 index b88fe12..0000000 --- a/packages/contracts/lib/src/model/model_contract.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for base model functionality. -/// -/// Laravel-compatible: Provides core model functionality similar to Laravel's -/// Model class, adapted for Dart's type system and patterns. -@sealed -abstract class ModelContract { - /// Gets the model's unique identifier. - /// - /// Laravel-compatible: Primary key accessor. - /// Extended with nullable String type for flexibility. - String? get id; - - /// Sets the model's unique identifier. - /// - /// Laravel-compatible: Primary key mutator. - /// Extended with nullable String type for flexibility. - set id(String? value); - - /// Gets the creation timestamp. - /// - /// Laravel-compatible: Created at timestamp accessor. - /// Uses Dart's DateTime instead of Carbon. - DateTime? get createdAt; - - /// Sets the creation timestamp. - /// - /// Laravel-compatible: Created at timestamp mutator. - /// Uses Dart's DateTime instead of Carbon. - set createdAt(DateTime? value); - - /// Gets the last update timestamp. - /// - /// Laravel-compatible: Updated at timestamp accessor. - /// Uses Dart's DateTime instead of Carbon. - DateTime? get updatedAt; - - /// Sets the last update timestamp. - /// - /// Laravel-compatible: Updated at timestamp mutator. - /// Uses Dart's DateTime instead of Carbon. - set updatedAt(DateTime? value); - - /// Gets the ID as an integer. - /// - /// Platform-specific: Provides integer ID conversion. - /// Returns -1 if ID is null or not a valid integer. - int get idAsInt; - - /// Gets the ID as a string. - /// - /// Platform-specific: Provides string ID conversion. - /// Returns empty string if ID is null. - String get idAsString; -} - -/// Contract for auditable model functionality. -/// -/// Laravel-compatible: Similar to Laravel's auditable trait, -/// providing user tracking for model changes. -@sealed -abstract class AuditableModelContract extends ModelContract { - /// Gets the ID of user who created the record. - /// - /// Laravel-compatible: Created by user tracking. - /// Uses String ID instead of user model reference. - String? get createdBy; - - /// Sets the ID of user who created the record. - /// - /// Laravel-compatible: Created by user tracking. - /// Uses String ID instead of user model reference. - set createdBy(String? value); - - /// Gets the ID of user who last updated the record. - /// - /// Laravel-compatible: Updated by user tracking. - /// Uses String ID instead of user model reference. - String? get updatedBy; - - /// Sets the ID of user who last updated the record. - /// - /// Laravel-compatible: Updated by user tracking. - /// Uses String ID instead of user model reference. - set updatedBy(String? value); -} - -/// Optional contract for model serialization. -/// -/// Laravel-compatible: Similar to Laravel's serialization features, -/// adapted for Dart's type system. -@sealed -abstract class SerializableModelContract { - /// Converts model to a map. - /// - /// Laravel-compatible: Similar to toArray() method. - Map toMap(); - - /// Creates model from a map. - /// - /// Laravel-compatible: Similar to fill() method. - void fromMap(Map map); -} - -/// Optional contract for model validation. -/// -/// Platform-specific: Provides built-in validation support, -/// inspired by Laravel's validation but adapted for Dart. -@sealed -abstract class ValidatableModelContract { - /// Validates the model. - /// - /// Platform-specific: Returns validation errors if invalid. - Map>? validate(); - - /// Gets validation rules. - /// - /// Platform-specific: Defines validation rules. - Map> get rules; - - /// Gets custom error messages. - /// - /// Platform-specific: Defines custom validation messages. - Map get messages; -} - -/// Optional contract for model events. -/// -/// Laravel-compatible: Similar to Laravel's model events, -/// adapted for Dart's event system. -@sealed -abstract class ObservableModelContract { - /// Gets the event name. - /// - /// Laravel-compatible: Defines event identifier. - String get eventName; - - /// Gets the event timestamp. - /// - /// Platform-specific: Adds timestamp tracking to events. - DateTime get eventTimestamp; - - /// Gets event data. - /// - /// Laravel-compatible: Provides event payload. - Map get eventData; -} diff --git a/packages/contracts/lib/src/pipeline/pipeline.dart b/packages/contracts/lib/src/pipeline/pipeline.dart deleted file mode 100644 index a834069..0000000 --- a/packages/contracts/lib/src/pipeline/pipeline.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Pipeline package contracts -export 'pipeline_contract.dart'; diff --git a/packages/contracts/lib/src/pipeline/pipeline_contract.dart b/packages/contracts/lib/src/pipeline/pipeline_contract.dart deleted file mode 100644 index 1e2f8db..0000000 --- a/packages/contracts/lib/src/pipeline/pipeline_contract.dart +++ /dev/null @@ -1,127 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for a pipe that processes objects in a pipeline. -/// -/// Laravel-compatible: Core pipe functionality matching Laravel's -/// pipe interface, with platform-specific async handling. -@sealed -abstract class PipeContract { - /// Handles the passable object. - /// - /// Laravel-compatible: Core pipe handling with platform-specific - /// async processing. - /// - /// Parameters: - /// - [passable]: The object being passed through the pipeline. - /// - [next]: Function to pass the object to the next pipe. - /// - /// Returns the processed object, possibly modified. - Future handle( - dynamic passable, Future Function(dynamic) next); -} - -/// Contract for a pipeline that processes objects through a series of pipes. -/// -/// Laravel-compatible: Core pipeline functionality matching Laravel's -/// Pipeline class, with platform-specific fluent interface. -@sealed -abstract class PipelineContract { - /// Sets the object to be passed through the pipeline. - /// - /// Laravel-compatible: Pipeline input setting. - /// - /// Parameters: - /// - [passable]: The object to process. - /// - /// Returns the pipeline instance for fluent chaining. - PipelineContract send(dynamic passable); - - /// Sets the array of pipes to process the object through. - /// - /// Laravel-compatible: Pipe configuration with platform-specific - /// flexibility for pipe types. - /// - /// Parameters: - /// - [pipes]: The pipes to process the object through. - /// Can be a single pipe or an iterable of pipes. - /// - /// Returns the pipeline instance for fluent chaining. - PipelineContract through(dynamic pipes); - - /// Adds additional pipes to the pipeline. - /// - /// Platform-specific: Additional method for pipe configuration - /// following Laravel's fluent pattern. - /// - /// Parameters: - /// - [pipes]: The pipes to add. - /// Can be a single pipe or an iterable of pipes. - /// - /// Returns the pipeline instance for fluent chaining. - PipelineContract pipe(dynamic pipes); - - /// Sets the method to call on the pipes. - /// - /// Laravel-compatible: Method name configuration. - /// - /// Parameters: - /// - [method]: The name of the method to call. - /// - /// Returns the pipeline instance for fluent chaining. - PipelineContract via(String method); - - /// Runs the pipeline with a final destination callback. - /// - /// Laravel-compatible: Pipeline execution with platform-specific - /// async processing. - /// - /// Parameters: - /// - [destination]: Function to process the final result. - /// - /// Returns the processed result. - Future then(dynamic Function(dynamic) destination); - - /// Runs the pipeline and returns the result. - /// - /// Platform-specific: Direct result access following Laravel's - /// pipeline execution pattern. - /// - /// Returns the processed object directly. - Future thenReturn(); -} - -/// Contract for a pipeline hub that manages multiple pipelines. -/// -/// Laravel-compatible: Pipeline management functionality matching -/// Laravel's pipeline hub features. -@sealed -abstract class PipelineHubContract { - /// Gets or creates a pipeline with the given name. - /// - /// Laravel-compatible: Named pipeline access. - /// - /// Parameters: - /// - [name]: The name of the pipeline. - /// - /// Returns the pipeline instance. - PipelineContract pipeline(String name); - - /// Sets the default pipes for a pipeline. - /// - /// Laravel-compatible: Default pipe configuration. - /// - /// Parameters: - /// - [name]: The name of the pipeline. - /// - [pipes]: The default pipes for the pipeline. - void defaults(String name, List pipes); - - /// Registers a pipe type with a name. - /// - /// Platform-specific: Named pipe type registration following - /// Laravel's service registration pattern. - /// - /// Parameters: - /// - [name]: The name to register the pipe type under. - /// - [type]: The pipe type to register. - void registerPipeType(String name, Type type); -} diff --git a/packages/contracts/lib/src/process/process.dart b/packages/contracts/lib/src/process/process.dart deleted file mode 100644 index 4155b10..0000000 --- a/packages/contracts/lib/src/process/process.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Process package contracts -export 'process_contract.dart'; diff --git a/packages/contracts/lib/src/process/process_contract.dart b/packages/contracts/lib/src/process/process_contract.dart deleted file mode 100644 index afe9824..0000000 --- a/packages/contracts/lib/src/process/process_contract.dart +++ /dev/null @@ -1,251 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:meta/meta.dart'; - -/// Contract for process management. -/// -/// Platform-specific: Provides system process management following Laravel's -/// architectural patterns for resource management and lifecycle control. -@sealed -abstract class ProcessManagerContract { - /// Starts a new process. - /// - /// Platform-specific: Creates and starts a new system process with - /// Laravel-style identifier and configuration options. - /// - /// Parameters: - /// - [id]: Unique identifier for the process. - /// - [command]: Command to execute. - /// - [arguments]: Command arguments. - /// - [workingDirectory]: Optional working directory. - /// - [environment]: Optional environment variables. - /// - [timeout]: Optional execution timeout. - /// - [tty]: Whether to run in a terminal. - /// - [enableReadError]: Whether to enable error stream reading. - Future start( - String id, - String command, - List arguments, { - String? workingDirectory, - Map? environment, - Duration? timeout, - bool tty = false, - bool enableReadError = true, - }); - - /// Gets a running process by ID. - /// - /// Platform-specific: Retrieves process by identifier, - /// following Laravel's repository pattern. - ProcessContract? get(String id); - - /// Kills a process. - /// - /// Platform-specific: Terminates a process with optional signal, - /// following Laravel's resource cleanup patterns. - /// - /// Parameters: - /// - [id]: Process ID to kill. - /// - [signal]: Signal to send (default: SIGTERM). - Future kill(String id, {ProcessSignal signal = ProcessSignal.sigterm}); - - /// Kills all managed processes. - /// - /// Platform-specific: Bulk process termination, - /// following Laravel's collection operation patterns. - Future killAll({ProcessSignal signal = ProcessSignal.sigterm}); - - /// Gets process events stream. - /// - /// Platform-specific: Event streaming following Laravel's - /// event broadcasting patterns. - Stream get events; - - /// Runs processes in a pool. - /// - /// Platform-specific: Concurrent process execution following - /// Laravel's job queue worker pool patterns. - /// - /// Parameters: - /// - [processes]: Processes to run. - /// - [concurrency]: Max concurrent processes. - Future> pool( - List processes, { - int concurrency = 5, - }); - - /// Runs processes in a pipeline. - /// - /// Platform-specific: Sequential process execution following - /// Laravel's pipeline pattern. - Future pipeline(List processes); - - /// Disposes the manager and all processes. - /// - /// Platform-specific: Resource cleanup following Laravel's - /// service provider cleanup patterns. - void dispose(); -} - -/// Contract for process instances. -/// -/// Platform-specific: Defines individual process behavior following -/// Laravel's resource management patterns. -@sealed -abstract class ProcessContract { - /// Gets the process command. - String get command; - - /// Gets the process ID. - int? get pid; - - /// Gets process start time. - DateTime? get startTime; - - /// Gets process end time. - DateTime? get endTime; - - /// Gets process output stream. - Stream> get output; - - /// Gets process error stream. - Stream> get errorOutput; - - /// Gets process exit code. - Future get exitCode; - - /// Whether the process is running. - bool get isRunning; - - /// Starts the process. - Future start(); - - /// Runs the process to completion. - Future run(); - - /// Runs the process with a timeout. - /// - /// Parameters: - /// - [timeout]: Maximum execution time. - /// - /// Throws TimeoutException if process exceeds timeout. - Future runWithTimeout(Duration timeout); - - /// Writes input to the process. - Future write(String input); - - /// Writes multiple lines to the process. - Future writeLines(List lines); - - /// Kills the process. - Future kill({ProcessSignal signal = ProcessSignal.sigterm}); - - /// Sends a signal to the process. - bool sendSignal(ProcessSignal signal); - - /// Gets process output as string. - Future get outputAsString; - - /// Gets process error output as string. - Future get errorOutputAsString; - - /// Disposes the process. - Future dispose(); -} - -/// Contract for process results. -/// -/// Platform-specific: Defines process execution results following -/// Laravel's response/result patterns. -@sealed -abstract class ProcessResultContract { - /// Gets the process ID. - int get pid; - - /// Gets the exit code. - int get exitCode; - - /// Gets the process output. - String get output; - - /// Gets the process error output. - String get errorOutput; - - /// Gets string representation. - @override - String toString() { - return 'ProcessResult(pid: $pid, exitCode: $exitCode, output: ${output.length} chars, errorOutput: ${errorOutput.length} chars)'; - } -} - -/// Contract for process events. -/// -/// Platform-specific: Defines process lifecycle events following -/// Laravel's event system patterns. -@sealed -abstract class ProcessEventContract { - /// Gets the process ID. - String get id; - - /// Gets the event timestamp. - DateTime get timestamp; -} - -/// Contract for process started events. -/// -/// Platform-specific: Defines process start event following -/// Laravel's event naming and structure patterns. -@sealed -abstract class ProcessStartedEventContract extends ProcessEventContract { - /// Gets the started process. - ProcessContract get process; - - @override - String toString() => - 'ProcessStartedEvent(id: $id, command: ${process.command})'; -} - -/// Contract for process exited events. -/// -/// Platform-specific: Defines process exit event following -/// Laravel's event naming and structure patterns. -@sealed -abstract class ProcessExitedEventContract extends ProcessEventContract { - /// Gets the exit code. - int get exitCode; - - @override - String toString() => 'ProcessExitedEvent(id: $id, exitCode: $exitCode)'; -} - -/// Contract for process pools. -/// -/// Platform-specific: Defines concurrent process execution following -/// Laravel's worker pool patterns. -@sealed -abstract class ProcessPoolContract { - /// Gets maximum concurrent processes. - int get concurrency; - - /// Gets active processes. - List get active; - - /// Gets pending processes. - List get pending; - - /// Runs processes in the pool. - Future> run(List processes); -} - -/// Contract for process pipelines. -/// -/// Platform-specific: Defines sequential process execution following -/// Laravel's pipeline pattern. -@sealed -abstract class ProcessPipelineContract { - /// Gets pipeline processes. - List get processes; - - /// Runs the pipeline. - Future run(); -} diff --git a/packages/contracts/lib/src/queue/queue.dart b/packages/contracts/lib/src/queue/queue.dart deleted file mode 100644 index 2501fd2..0000000 --- a/packages/contracts/lib/src/queue/queue.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Queue package contracts -export 'queue_contract.dart'; diff --git a/packages/contracts/lib/src/queue/queue_contract.dart b/packages/contracts/lib/src/queue/queue_contract.dart deleted file mode 100644 index 94c0a55..0000000 --- a/packages/contracts/lib/src/queue/queue_contract.dart +++ /dev/null @@ -1,284 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for queue operations. -/// -/// Laravel-compatible: Core queue functionality matching Laravel's Queue -/// interface, adapted for Dart's type system and async patterns. -@sealed -abstract class QueueContract { - /// Pushes a job onto the queue. - /// - /// Laravel-compatible: Core push method. - /// Uses dynamic job type for flexibility. - Future push(dynamic job, [String? queue]); - - /// Pushes a job onto a specific queue. - /// - /// Laravel-compatible: Queue-specific push. - /// Uses dynamic job type for flexibility. - Future pushOn(String queue, dynamic job); - - /// Pushes a delayed job onto the queue. - /// - /// Laravel-compatible: Delayed job push. - /// Uses Duration instead of DateTime/Carbon. - Future later(Duration delay, dynamic job, [String? queue]); - - /// Pushes a delayed job onto a specific queue. - /// - /// Laravel-compatible: Queue-specific delayed push. - /// Uses Duration instead of DateTime/Carbon. - Future laterOn(String queue, Duration delay, dynamic job); - - /// Pushes multiple jobs onto the queue. - /// - /// Laravel-compatible: Bulk job push. - /// Uses dynamic job type for flexibility. - Future bulk(List jobs, [String? queue]); - - /// Gets the next job from the queue. - /// - /// Laravel-compatible: Job pop operation. - Future pop([String? queue]); - - /// Creates a job batch. - /// - /// Laravel-compatible: Batch creation. - BatchContract batch(List jobs); - - /// Gets a queue connection. - /// - /// Laravel-compatible: Connection retrieval. - QueueConnectionContract connection([String? name]); -} - -/// Contract for queue jobs. -/// -/// Laravel-compatible: Core job interface matching Laravel's Job -/// contract, with platform-specific extensions. -@sealed -abstract class JobContract { - /// Gets the job ID. - /// - /// Laravel-compatible: Job identifier. - String get id; - - /// Gets the job payload. - /// - /// Laravel-compatible: Job data. - Map get payload; - - /// Gets the number of attempts. - /// - /// Laravel-compatible: Attempt tracking. - int get attempts; - - /// Gets the maximum number of tries. - /// - /// Laravel-compatible: Retry limit. - int get tries; - - /// Gets the job timeout in seconds. - /// - /// Laravel-compatible: Timeout configuration. - int get timeout; - - /// Gets the queue name. - /// - /// Laravel-compatible: Queue designation. - String? get queue; - - /// Gets the job delay. - /// - /// Laravel-compatible: Delay configuration. - /// Uses Duration instead of DateTime/Carbon. - Duration? get delay; - - /// Whether the job should be encrypted. - /// - /// Platform-specific: Adds encryption support. - bool get shouldBeEncrypted; - - /// Whether to dispatch after commit. - /// - /// Laravel-compatible: Transaction support. - bool get afterCommit; - - /// Executes the job. - /// - /// Laravel-compatible: Core job execution. - Future handle(); - - /// Handles job failure. - /// - /// Laravel-compatible: Failure handling. - Future failed([Exception? exception]); - - /// Releases the job back to the queue. - /// - /// Laravel-compatible: Job release. - /// Uses Duration instead of DateTime/Carbon. - Future release([Duration? delay]); - - /// Deletes the job. - /// - /// Laravel-compatible: Job deletion. - Future delete(); -} - -/// Contract for job batches. -/// -/// Laravel-compatible: Batch operations matching Laravel's batch -/// functionality, with platform-specific extensions. -@sealed -abstract class BatchContract { - /// Gets the batch ID. - /// - /// Laravel-compatible: Batch identifier. - String get id; - - /// Gets the jobs in the batch. - /// - /// Laravel-compatible: Batch jobs. - List get jobs; - - /// Adds jobs to the batch. - /// - /// Laravel-compatible: Job addition. - void add(List jobs); - - /// Dispatches the batch. - /// - /// Laravel-compatible: Batch dispatch. - Future dispatch(); - - /// Allows failures in the batch. - /// - /// Laravel-compatible: Failure configuration. - BatchContract allowFailures(); - - /// Sets the batch name. - /// - /// Laravel-compatible: Batch naming. - BatchContract name(String name); - - /// Adds a callback when all jobs finish. - /// - /// Laravel-compatible: Success callback. - BatchContract then(void Function(BatchContract) callback); - - /// Adds a callback when the batch fails. - /// - /// Laravel-compatible: Error callback. - BatchContract onError(void Function(BatchContract, dynamic) callback); - - /// Gets the batch progress. - /// - /// Platform-specific: Progress tracking. - double get progress; - - /// Gets finished job count. - /// - /// Platform-specific: Completion tracking. - int get finished; - - /// Gets failed job count. - /// - /// Platform-specific: Failure tracking. - int get failed; - - /// Gets pending job count. - /// - /// Platform-specific: Pending tracking. - int get pending; - - /// Gets total job count. - /// - /// Platform-specific: Size tracking. - int get total; -} - -/// Contract for queue connections. -/// -/// Laravel-compatible: Connection management matching Laravel's -/// queue connection functionality. -@sealed -abstract class QueueConnectionContract { - /// Gets the connection name. - /// - /// Laravel-compatible: Connection identifier. - String get name; - - /// Gets the connection driver. - /// - /// Laravel-compatible: Driver type. - String get driver; - - /// Gets the connection config. - /// - /// Laravel-compatible: Configuration access. - Map get config; - - /// Pushes a job onto the queue. - /// - /// Laravel-compatible: Job push. - Future push(dynamic job, [String? queue]); - - /// Gets the next job from the queue. - /// - /// Laravel-compatible: Job pop. - Future pop([String? queue]); - - /// Gets queue size. - /// - /// Laravel-compatible: Size check. - Future size([String? queue]); - - /// Clears the queue. - /// - /// Laravel-compatible: Queue clear. - Future clear([String? queue]); - - /// Pauses job processing. - /// - /// Laravel-compatible: Processing pause. - Future pause([String? queue]); - - /// Resumes job processing. - /// - /// Laravel-compatible: Processing resume. - Future resume([String? queue]); -} - -/// Contract for queue manager. -/// -/// Laravel-compatible: Manager functionality matching Laravel's -/// queue manager interface. -@sealed -abstract class QueueManagerContract { - /// Gets a queue connection. - /// - /// Laravel-compatible: Connection retrieval. - QueueConnectionContract connection([String? name]); - - /// Gets the default connection name. - /// - /// Laravel-compatible: Default connection. - String get defaultConnection; - - /// Sets the default connection name. - /// - /// Laravel-compatible: Default connection. - set defaultConnection(String name); - - /// Gets connection configuration. - /// - /// Laravel-compatible: Config access. - Map getConfig(String name); - - /// Extends available drivers. - /// - /// Laravel-compatible: Driver extension. - void extend(String driver, - QueueConnectionContract Function(Map) callback); -} diff --git a/packages/contracts/lib/src/reflection/reflection.dart b/packages/contracts/lib/src/reflection/reflection.dart deleted file mode 100644 index 5d24e43..0000000 --- a/packages/contracts/lib/src/reflection/reflection.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Reflection package contracts -export 'reflector_contract.dart'; diff --git a/packages/contracts/lib/src/reflection/reflector_contract.dart b/packages/contracts/lib/src/reflection/reflector_contract.dart deleted file mode 100644 index 7d53a25..0000000 --- a/packages/contracts/lib/src/reflection/reflector_contract.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for reflected type parameters -@sealed -abstract class ReflectedTypeParameterContract { - /// Gets the name of the type parameter - String get name; -} - -/// Contract for reflected types -@sealed -abstract class ReflectedTypeContract { - /// Gets the name of the type - String get name; - - /// Gets the type parameters if the type is generic - List get typeParameters; - - /// Gets the actual Dart type being reflected - Type get reflectedType; - - /// Checks if this type is assignable to another type - bool isAssignableTo(ReflectedTypeContract? other); - - /// Creates a new instance of this type - ReflectedInstanceContract newInstance( - String constructorName, List positionalArguments, - [Map namedArguments = const {}, - List typeArguments = const []]); -} - -/// Contract for reflected parameters -@sealed -abstract class ReflectedParameterContract { - /// Gets the parameter name - String get name; - - /// Gets the parameter annotations - List get annotations; - - /// Gets the parameter type - ReflectedTypeContract get type; - - /// Whether the parameter is required - bool get isRequired; - - /// Whether the parameter is named - bool get isNamed; -} - -/// Contract for reflected functions -@sealed -abstract class ReflectedFunctionContract { - /// Gets the function name - String get name; - - /// Gets the function's type parameters - List get typeParameters; - - /// Gets the function's annotations - List get annotations; - - /// Gets the function's return type - ReflectedTypeContract? get returnType; - - /// Gets the function's parameters - List get parameters; - - /// Whether the function is a getter - bool get isGetter; - - /// Whether the function is a setter - bool get isSetter; - - /// Invokes the function - ReflectedInstanceContract invoke(Invocation invocation); -} - -/// Contract for reflected declarations -@sealed -abstract class ReflectedDeclarationContract { - /// Gets the declaration name - String get name; - - /// Whether the declaration is static - bool get isStatic; - - /// Gets the associated function if any - ReflectedFunctionContract? get function; -} - -/// Contract for reflected classes -@sealed -abstract class ReflectedClassContract extends ReflectedTypeContract { - /// Gets the class annotations - List get annotations; - - /// Gets the class constructors - List get constructors; - - /// Gets the class declarations - List get declarations; -} - -/// Contract for reflected instances -@sealed -abstract class ReflectedInstanceContract { - /// Gets the instance type - ReflectedTypeContract get type; - - /// Gets the instance class - ReflectedClassContract get clazz; - - /// Gets the actual instance being reflected - Object? get reflectee; - - /// Gets a field value - ReflectedInstanceContract getField(String name); -} - -/// Core reflector contract for type introspection. -/// -/// This contract defines the interface for reflection capabilities, -/// allowing runtime inspection and manipulation of types, classes, -/// functions, and instances. -@sealed -abstract class ReflectorContract { - /// Gets the name from a symbol - String? getName(Symbol symbol); - - /// Reflects a class type - ReflectedClassContract? reflectClass(Type clazz); - - /// Reflects a function - ReflectedFunctionContract? reflectFunction(Function function); - - /// Reflects a type - ReflectedTypeContract? reflectType(Type type); - - /// Reflects an instance - ReflectedInstanceContract? reflectInstance(Object object); - - /// Reflects the Future of a type - /// - /// Throws: - /// - UnsupportedError if dart:mirrors is not available - ReflectedTypeContract reflectFutureOf(Type type); -} diff --git a/packages/contracts/lib/src/routing/routing.dart b/packages/contracts/lib/src/routing/routing.dart deleted file mode 100644 index af283b4..0000000 --- a/packages/contracts/lib/src/routing/routing.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Routing package contracts -export 'routing_contract.dart'; diff --git a/packages/contracts/lib/src/routing/routing_contract.dart b/packages/contracts/lib/src/routing/routing_contract.dart deleted file mode 100644 index 684e7eb..0000000 --- a/packages/contracts/lib/src/routing/routing_contract.dart +++ /dev/null @@ -1,260 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for router functionality. -/// -/// Laravel-compatible: Core routing functionality matching Laravel's Router -/// interface, with platform-specific generic type support. -@sealed -abstract class RouterContract { - /// Adds a route that responds to any HTTP method. - /// - /// Laravel-compatible: Any-method route registration. - RouteContract any(String path, T handler, - {Iterable middleware = const []}); - - /// Adds a route that responds to GET requests. - /// - /// Laravel-compatible: GET route registration. - RouteContract get(String path, T handler, - {Iterable middleware = const []}); - - /// Adds a route that responds to POST requests. - /// - /// Laravel-compatible: POST route registration. - RouteContract post(String path, T handler, - {Iterable middleware = const []}); - - /// Adds a route that responds to PUT requests. - /// - /// Laravel-compatible: PUT route registration. - RouteContract put(String path, T handler, - {Iterable middleware = const []}); - - /// Adds a route that responds to DELETE requests. - /// - /// Laravel-compatible: DELETE route registration. - RouteContract delete(String path, T handler, - {Iterable middleware = const []}); - - /// Adds a route that responds to PATCH requests. - /// - /// Laravel-compatible: PATCH route registration. - RouteContract patch(String path, T handler, - {Iterable middleware = const []}); - - /// Adds a route that responds to OPTIONS requests. - /// - /// Laravel-compatible: OPTIONS route registration. - RouteContract options(String path, T handler, - {Iterable middleware = const []}); - - /// Creates a route group with shared attributes. - /// - /// Laravel-compatible: Route grouping with platform-specific - /// callback-based configuration. - /// - /// Parameters: - /// - [path]: The prefix path for the group. - /// - [callback]: Function to define routes within the group. - /// - [middleware]: Middleware to apply to all routes in the group. - void group(String path, void Function(RouterContract router) callback, - {Iterable middleware = const []}); - - /// Mounts another router at a path prefix. - /// - /// Platform-specific: Provides router composition functionality. - /// - /// Parameters: - /// - [path]: The path to mount at. - /// - [router]: The router to mount. - void mount(String path, RouterContract router); - - /// Resolves a route for a request. - /// - /// Laravel-compatible: Route matching with platform-specific - /// match result contract. - /// - /// Parameters: - /// - [method]: The HTTP method. - /// - [path]: The request path. - RouteMatchContract? resolve(String method, String path); -} - -/// Contract for route definitions. -/// -/// Laravel-compatible: Route definition interface matching Laravel's Route -/// class, with platform-specific enhancements. -@sealed -abstract class RouteContract { - /// Gets the route path pattern. - /// - /// Laravel-compatible: Route URI pattern. - String get path; - - /// Gets the HTTP method this route responds to. - /// - /// Laravel-compatible: HTTP method. - String get method; - - /// Gets the route handler. - /// - /// Laravel-compatible: Route action with generic typing. - T get handler; - - /// Gets the route middleware. - /// - /// Laravel-compatible: Route middleware. - Iterable get middleware; - - /// Gets the route name. - /// - /// Laravel-compatible: Route name accessor. - String? get name; - - /// Sets the route name. - /// - /// Laravel-compatible: Route name mutator. - set name(String? value); - - /// Gets the route parameters. - /// - /// Laravel-compatible: Route parameters. - Map get parameters; - - /// Makes a URI for this route. - /// - /// Laravel-compatible: URL generation. - /// - /// Parameters: - /// - [params]: The parameter values to use. - String makeUri(Map params); - - /// Gets the route's regular expression pattern. - /// - /// Platform-specific: Direct access to route pattern. - RegExp get pattern; - - /// Whether the route matches a path. - /// - /// Platform-specific: Direct path matching. - bool matches(String path); -} - -/// Contract for route matching results. -/// -/// Platform-specific: Defines detailed match results beyond -/// Laravel's basic route matching. -@sealed -abstract class RouteMatchContract { - /// Gets the matched route. - RouteContract get route; - - /// Gets the matched parameters. - Map get params; - - /// Gets any remaining path after the match. - String get remaining; - - /// Gets the full matched path. - String get matched; -} - -/// Contract for route parameters. -/// -/// Laravel-compatible: Parameter handling matching Laravel's -/// parameter constraints, with platform-specific validation. -@sealed -abstract class RouteParameterContract { - /// Gets the parameter name. - String get name; - - /// Gets the parameter pattern. - String? get pattern; - - /// Whether the parameter is optional. - bool get isOptional; - - /// Gets the default value. - dynamic get defaultValue; - - /// Validates a parameter value. - bool validate(String value); -} - -/// Contract for route collection. -/// -/// Laravel-compatible: Route collection functionality matching -/// Laravel's RouteCollection, with platform-specific enhancements. -@sealed -abstract class RouteCollectionContract { - /// Gets all routes. - /// - /// Laravel-compatible: Route listing. - Iterable> get routes; - - /// Gets routes by method. - /// - /// Laravel-compatible: Method filtering. - Iterable> getByMethod(String method); - - /// Gets a route by name. - /// - /// Laravel-compatible: Named route lookup. - RouteContract? getByName(String name); - - /// Adds a route to the collection. - /// - /// Laravel-compatible: Route registration. - void add(RouteContract route); - - /// Removes a route from the collection. - /// - /// Laravel-compatible: Route removal. - void remove(RouteContract route); - - /// Gets routes with a specific middleware. - /// - /// Platform-specific: Middleware filtering. - Iterable> getByMiddleware(T middleware); -} - -/// Contract for route groups. -/// -/// Laravel-compatible: Route grouping functionality matching -/// Laravel's route group features, with platform-specific additions. -@sealed -abstract class RouteGroupContract { - /// Gets the group prefix. - /// - /// Laravel-compatible: Group prefix. - String get prefix; - - /// Gets the group middleware. - /// - /// Laravel-compatible: Group middleware. - Iterable get middleware; - - /// Gets the group namespace. - /// - /// Laravel-compatible: Group namespace. - String? get namespace; - - /// Gets routes in this group. - /// - /// Laravel-compatible: Group routes. - Iterable> get routes; - - /// Adds a route to the group. - /// - /// Laravel-compatible: Route addition with platform-specific - /// middleware support. - RouteContract addRoute(String method, String path, T handler, - {Iterable middleware = const []}); - - /// Creates a sub-group. - /// - /// Laravel-compatible: Nested grouping with platform-specific - /// namespace support. - RouteGroupContract group(String prefix, - {Iterable middleware = const [], String? namespace}); -} diff --git a/packages/contracts/lib/src/support/support.dart b/packages/contracts/lib/src/support/support.dart deleted file mode 100644 index d8e5ba5..0000000 --- a/packages/contracts/lib/src/support/support.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Support package contracts -export 'support_contract.dart'; diff --git a/packages/contracts/lib/src/support/support_contract.dart b/packages/contracts/lib/src/support/support_contract.dart deleted file mode 100644 index 2f06ed0..0000000 --- a/packages/contracts/lib/src/support/support_contract.dart +++ /dev/null @@ -1,263 +0,0 @@ -import 'package:meta/meta.dart'; - -/// Contract for service providers. -/// -/// Laravel-compatible: Core service provider functionality matching -/// Laravel's ServiceProvider class, adapted for Dart's type system. -@sealed -abstract class ServiceProviderContract { - /// Registers application services. - /// - /// Laravel-compatible: Core registration method. - void register(); - - /// Bootstraps application services. - /// - /// Laravel-compatible: Core bootstrap method. - void boot(); - - /// Gets services provided by this provider. - /// - /// Laravel-compatible: Lists provided services. - List provides(); - - /// Gets events that trigger registration. - /// - /// Laravel-compatible: Lists registration triggers. - List when(); - - /// Whether provider is deferred. - /// - /// Laravel-compatible: Controls lazy loading. - bool isDeferred(); - - /// Gets the application instance. - /// - /// Laravel-compatible: Application access. - /// Uses dynamic type for flexibility. - dynamic get app; - - /// Sets the application instance. - /// - /// Laravel-compatible: Application injection. - /// Uses dynamic type for flexibility. - set app(dynamic value); - - /// Gets booting callbacks. - /// - /// Laravel-compatible: Boot phase callbacks. - List get bootingCallbacks; - - /// Gets booted callbacks. - /// - /// Laravel-compatible: Post-boot callbacks. - List get bootedCallbacks; - - /// Registers a booting callback. - /// - /// Laravel-compatible: Boot phase hook. - void booting(Function callback); - - /// Registers a booted callback. - /// - /// Laravel-compatible: Post-boot hook. - void booted(Function callback); - - /// Calls booting callbacks. - /// - /// Laravel-compatible: Executes boot phase hooks. - void callBootingCallbacks(); - - /// Calls booted callbacks. - /// - /// Laravel-compatible: Executes post-boot hooks. - void callBootedCallbacks(); - - /// Merges configuration. - /// - /// Laravel-compatible: Config merging. - void mergeConfigFrom(String path, String key); - - /// Replaces configuration recursively. - /// - /// Laravel-compatible: Deep config replacement. - void replaceConfigRecursivelyFrom(String path, String key); - - /// Loads routes from file. - /// - /// Laravel-compatible: Route loading. - void loadRoutesFrom(String path); - - /// Loads views from directory. - /// - /// Laravel-compatible: View loading. - void loadViewsFrom(String path, String namespace); - - /// Loads view components. - /// - /// Laravel-compatible: Component loading. - void loadViewComponentsAs(String prefix, List components); - - /// Loads translations from directory. - /// - /// Laravel-compatible: Translation loading. - void loadTranslationsFrom(String path, String namespace); - - /// Loads JSON translations. - /// - /// Laravel-compatible: JSON translation loading. - void loadJsonTranslationsFrom(String path); - - /// Loads database migrations. - /// - /// Laravel-compatible: Migration loading. - void loadMigrationsFrom(dynamic paths); - - /// Loads model factories. - /// - /// Laravel-compatible: Factory loading. - @Deprecated('Will be removed in a future version.') - void loadFactoriesFrom(dynamic paths); - - /// Sets up after resolving listener. - /// - /// Laravel-compatible: Resolution hook. - void callAfterResolving(String name, Function callback); - - /// Publishes migrations. - /// - /// Laravel-compatible: Migration publishing. - void publishesMigrations(List paths, [dynamic groups]); - - /// Registers publishable paths. - /// - /// Laravel-compatible: Asset publishing. - void registerPublishables(Map paths, [dynamic groups]); - - /// Legacy method for registering publishables. - /// - /// Laravel-compatible: Legacy publish method. - @Deprecated('Use registerPublishables instead') - void publishes(Map paths, [dynamic groups]); - - /// Initializes publish array. - /// - /// Laravel-compatible: Publish setup. - void ensurePublishArrayInitialized(String className); - - /// Adds a publish group. - /// - /// Laravel-compatible: Group publishing. - void addPublishGroup(String group, Map paths); - - /// Gets paths to publish. - /// - /// Laravel-compatible: Publish path lookup. - Map pathsToPublish([String? provider, String? group]); - - /// Gets paths for provider or group. - /// - /// Laravel-compatible: Provider/group path lookup. - Map pathsForProviderOrGroup(String? provider, String? group); - - /// Gets paths for provider and group. - /// - /// Laravel-compatible: Combined path lookup. - Map pathsForProviderAndGroup(String provider, String group); - - /// Gets publishable providers. - /// - /// Laravel-compatible: Provider listing. - List publishableProviders(); - - /// Gets publishable migration paths. - /// - /// Laravel-compatible: Migration path listing. - List publishableMigrationPaths(); - - /// Gets publishable groups. - /// - /// Laravel-compatible: Group listing. - List publishableGroups(); - - /// Registers commands. - /// - /// Laravel-compatible: Command registration. - void commands(List commands); - - /// Gets default providers. - /// - /// Laravel-compatible: Default provider listing. - List defaultProviders(); - - /// Adds provider to bootstrap file. - /// - /// Laravel-compatible: Provider bootstrapping. - bool addProviderToBootstrapFile(String provider, [String? path]); - - /// Registers a singleton. - /// - /// Laravel-compatible: Singleton binding with Dart typing. - void singleton(T instance); - - /// Registers a factory binding. - /// - /// Laravel-compatible: Factory binding with Dart typing. - void bind(T Function(dynamic) factory); - - /// Gets a service. - /// - /// Laravel-compatible: Service resolution with Dart typing. - T make([Type? type]); - - /// Checks if service exists. - /// - /// Laravel-compatible: Binding check with Dart typing. - bool has(); - - /// Registers tagged bindings. - /// - /// Laravel-compatible: Tag binding with Dart typing. - void tag(List abstracts, List tags); - - /// Registers an event listener. - /// - /// Laravel-compatible: Event listener registration. - void listen(String event, Function listener); - - /// Registers middleware. - /// - /// Laravel-compatible: Middleware registration. - void middleware(String name, Function handler); -} - -/// Contract for deferrable providers. -/// -/// Laravel-compatible: Defines providers that can be loaded -/// on demand rather than at application startup. -@sealed -abstract class DeferrableProviderContract { - /// Gets services provided by this provider. - /// - /// Laravel-compatible: Lists deferred services. - List provides(); -} - -/// Contract for provider static functionality. -/// -/// Platform-specific: Provides static helper methods and properties -/// following Laravel's patterns for static configuration. -@sealed -abstract class ServiceProviderStaticContract { - /// Gets publishable migration paths. - static final List publishableMigrationPaths = []; - - /// Gets publishable paths. - static final Map> publishablePaths = {}; - - /// Gets publishable groups. - static final Map> publishableGroups = {}; - - /// Gets publishable provider paths. - static final Map> publishableProviderPaths = {}; -} diff --git a/packages/contracts/lib/src/testing/testing.dart b/packages/contracts/lib/src/testing/testing.dart deleted file mode 100644 index 1bb17b1..0000000 --- a/packages/contracts/lib/src/testing/testing.dart +++ /dev/null @@ -1,2 +0,0 @@ -/// Testing package contracts -export 'testing_contract.dart'; diff --git a/packages/contracts/lib/src/testing/testing_contract.dart b/packages/contracts/lib/src/testing/testing_contract.dart deleted file mode 100644 index af9cc43..0000000 --- a/packages/contracts/lib/src/testing/testing_contract.dart +++ /dev/null @@ -1,302 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; -import 'package:meta/meta.dart'; - -/// Contract for mock HTTP requests. -/// -/// This contract defines how HTTP requests should be mocked -/// for testing purposes. -@sealed -abstract class MockHttpRequestContract - implements HttpRequest, StreamSink>, StringSink { - /// Gets the request method. - @override - String get method; - - /// Gets the request URI. - @override - Uri get uri; - - /// Gets request headers. - @override - HttpHeaders get headers; - - /// Gets request cookies. - @override - List get cookies; - - /// Gets connection info. - @override - HttpConnectionInfo get connectionInfo; - - /// Gets request session. - @override - HttpSession get session; - - /// Gets request content length. - @override - int get contentLength; - - /// Gets protocol version. - @override - String get protocolVersion; - - /// Gets SSL/TLS certificate. - @override - X509Certificate? get certificate; - - /// Gets whether connection is persistent. - @override - bool get persistentConnection; - - /// Gets requested URI. - @override - Uri get requestedUri; - - /// Sets requested URI. - set requestedUri(Uri value); - - /// Gets response object. - @override - HttpResponse get response; -} - -/// Contract for mock HTTP responses. -/// -/// This contract defines how HTTP responses should be mocked -/// for testing purposes. -@sealed -abstract class MockHttpResponseContract - implements HttpResponse, Stream> { - /// Gets/sets status code. - @override - int get statusCode; - @override - set statusCode(int value); - - /// Gets/sets reason phrase. - @override - String get reasonPhrase; - @override - set reasonPhrase(String value); - - /// Gets/sets content length. - @override - int get contentLength; - @override - set contentLength(int value); - - /// Gets/sets deadline. - @override - Duration? get deadline; - @override - set deadline(Duration? value); - - /// Gets/sets encoding. - @override - Encoding get encoding; - @override - set encoding(Encoding value); - - /// Gets/sets persistent connection flag. - @override - bool get persistentConnection; - @override - set persistentConnection(bool value); - - /// Gets/sets buffer output flag. - @override - bool get bufferOutput; - @override - set bufferOutput(bool value); - - /// Gets response headers. - @override - HttpHeaders get headers; - - /// Gets response cookies. - @override - List get cookies; - - /// Gets connection info. - @override - HttpConnectionInfo get connectionInfo; - - /// Gets done future. - @override - Future get done; - - /// Detaches socket. - @override - Future detachSocket({bool writeHeaders = true}); - - /// Redirects to location. - @override - Future redirect(Uri location, {int status = HttpStatus.movedTemporarily}); -} - -/// Contract for mock HTTP sessions. -/// -/// This contract defines how HTTP sessions should be mocked -/// for testing purposes. -@sealed -abstract class MockHttpSessionContract implements HttpSession { - /// Gets session ID. - @override - String get id; - - /// Gets/sets whether session is new. - @override - bool get isNew; - @override - set isNew(bool value); - - /// Gets session data. - Map get data; - - /// Gets session value. - @override - dynamic operator [](Object? key); - - /// Sets session value. - @override - void operator []=(dynamic key, dynamic value); - - /// Removes session value. - @override - dynamic remove(Object? key); - - /// Clears all session data. - @override - void clear(); - - /// Destroys the session. - @override - Future destroy(); -} - -/// Contract for mock HTTP headers. -/// -/// This contract defines how HTTP headers should be mocked -/// for testing purposes. -@sealed -abstract class MockHttpHeadersContract implements HttpHeaders { - /// Gets header value. - @override - String? value(String name); - - /// Adds header value. - @override - void add(String name, Object value, {bool preserveHeaderCase = false}); - - /// Removes header. - @override - void remove(String name, Object value); - - /// Removes all headers. - @override - void removeAll(String name); - - /// Sets header value. - @override - void set(String name, Object value, {bool preserveHeaderCase = false}); - - /// Gets header values. - @override - List? operator [](String name); - - /// Gets all header names. - @override - List get names; - - /// Gets header values. - @override - Iterable? getAll(String name); - - /// Clears all headers. - @override - void clear(); - - /// Gets whether headers are mutable. - @override - bool get mutable; - - /// Gets content type. - @override - ContentType? get contentType; - - /// Sets content type. - @override - set contentType(ContentType? value); - - /// Gets date. - @override - DateTime? get date; - - /// Sets date. - @override - set date(DateTime? value); - - /// Gets expires date. - @override - DateTime? get expires; - - /// Sets expires date. - @override - set expires(DateTime? value); - - /// Gets if-modified-since date. - @override - DateTime? get ifModifiedSince; - - /// Sets if-modified-since date. - @override - set ifModifiedSince(DateTime? value); - - /// Gets host. - @override - String? get host; - - /// Sets host. - @override - set host(String? value); - - /// Gets port. - @override - int? get port; - - /// Sets port. - @override - set port(int? value); - - /// Locks headers from modification. - void lock(); - - /// Gets whether headers are locked. - bool get locked; -} - -/// Contract for mock connection info. -/// -/// This contract defines how connection info should be mocked -/// for testing purposes. -@sealed -abstract class MockConnectionInfoContract implements HttpConnectionInfo { - /// Gets local address. - @override - InternetAddress get localAddress; - - /// Gets local port. - @override - int get localPort; - - /// Gets remote address. - @override - InternetAddress get remoteAddress; - - /// Gets remote port. - @override - int get remotePort; -} diff --git a/packages/contracts/pubspec.lock b/packages/contracts/pubspec.lock deleted file mode 100644 index 101471f..0000000 --- a/packages/contracts/pubspec.lock +++ /dev/null @@ -1,402 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77" - url: "https://pub.dev" - source: hosted - version: "73.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.2" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a" - url: "https://pub.dev" - source: hosted - version: "6.8.0" - args: - dependency: transitive - description: - name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 - url: "https://pub.dev" - source: hosted - version: "2.6.0" - async: - dependency: transitive - description: - name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 - url: "https://pub.dev" - source: hosted - version: "2.12.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5" - url: "https://pub.dev" - source: hosted - version: "1.11.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" - url: "https://pub.dev" - source: hosted - version: "4.1.1" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf - url: "https://pub.dev" - source: hosted - version: "0.7.1" - lints: - dependency: "direct dev" - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - macros: - dependency: transitive - description: - name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" - url: "https://pub.dev" - source: hosted - version: "0.1.2-main.4" - matcher: - dependency: transitive - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - meta: - dependency: "direct main" - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 - url: "https://pub.dev" - source: hosted - version: "1.1.3" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" - url: "https://pub.dev" - source: hosted - version: "1.12.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test: - dependency: "direct dev" - description: - name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" - url: "https://pub.dev" - source: hosted - version: "1.25.8" - test_api: - dependency: transitive - description: - name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" - url: "https://pub.dev" - source: hosted - version: "0.7.3" - test_core: - dependency: transitive - description: - name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" - url: "https://pub.dev" - source: hosted - version: "0.6.5" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" - url: "https://pub.dev" - source: hosted - version: "14.3.1" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" - url: "https://pub.dev" - source: hosted - version: "0.1.6" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.5.0 <4.0.0" diff --git a/packages/contracts/pubspec.yaml b/packages/contracts/pubspec.yaml deleted file mode 100644 index c95ca4b..0000000 --- a/packages/contracts/pubspec.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: platform_contracts -description: Core contracts for the Platform framework -version: 1.0.0 - -environment: - sdk: '>=3.0.0 <4.0.0' - -dependencies: - meta: ^1.9.0 - -dev_dependencies: - lints: ^2.0.0 - test: ^1.21.0 diff --git a/packages/events/.gitignore b/packages/cookie/.gitignore similarity index 100% rename from packages/events/.gitignore rename to packages/cookie/.gitignore diff --git a/packages/events/CHANGELOG.md b/packages/cookie/CHANGELOG.md similarity index 100% rename from packages/events/CHANGELOG.md rename to packages/cookie/CHANGELOG.md diff --git a/packages/events/LICENSE.md b/packages/cookie/LICENSE.md similarity index 100% rename from packages/events/LICENSE.md rename to packages/cookie/LICENSE.md diff --git a/packages/cookie/README.md b/packages/cookie/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/cookie/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/events/analysis_options.yaml b/packages/cookie/analysis_options.yaml similarity index 100% rename from packages/events/analysis_options.yaml rename to packages/cookie/analysis_options.yaml diff --git a/packages/cookie/doc/.gitkeep b/packages/cookie/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/cookie/example/.gitkeep b/packages/cookie/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/cookie/lib/src/.gitkeep b/packages/cookie/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/events/pubspec.yaml b/packages/cookie/pubspec.yaml similarity index 57% rename from packages/events/pubspec.yaml rename to packages/cookie/pubspec.yaml index 22bde60..3ebd3a8 100644 --- a/packages/events/pubspec.yaml +++ b/packages/cookie/pubspec.yaml @@ -1,19 +1,15 @@ -name: platform_events -description: The Events Package for the Protevus Platform +name: platform_cookie +description: The Cookie 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: diff --git a/packages/cookie/test/.gitkeep b/packages/cookie/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/core/.gitignore b/packages/core/.gitignore deleted file mode 100644 index 24d6831..0000000 --- a/packages/core/.gitignore +++ /dev/null @@ -1,71 +0,0 @@ -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub -.dart_tool -.packages -.pub/ -build/ - -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock - -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - -### Dart template -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub - -# SDK 1.20 and later (no longer creates packages directories) - -# Older SDK versions -# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20) -.project -.buildlog -**/packages/ - - -# Files created by dart2js -# (Most Dart developers will use pub build to compile Dart, use/modify these -# rules if you intend to use dart2js directly -# Convention is to use extension '.dart.js' for Dart compiled to Javascript to -# differentiate from explicit Javascript files) -*.dart.js -*.part.js -*.js.deps -*.js.map -*.info.json - -# Directory created by dartdoc - -# Don't commit pubspec lock file -# (Library packages only! Remove pattern if developing an application package) -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: - -## VsCode -.vscode/ - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -.idea/ -/out/ -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties diff --git a/packages/core/AUTHORS.md b/packages/core/AUTHORS.md deleted file mode 100644 index ac95ab5..0000000 --- a/packages/core/AUTHORS.md +++ /dev/null @@ -1,12 +0,0 @@ -Primary Authors -=============== - -* __[Thomas Hii](dukefirehawk.apps@gmail.com)__ - - Thomas is the current maintainer of the code base. He has refactored and migrated the - code base to support NNBD. - -* __[Tobe O](thosakwe@gmail.com)__ - - Tobe has written much of the original code prior to NNBD migration. He has moved on and - is no longer involved with the project. diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md deleted file mode 100644 index 28c3e12..0000000 --- a/packages/core/CHANGELOG.md +++ /dev/null @@ -1,452 +0,0 @@ -# Change Log - -## 8.4.0 - -* Require Dart >= 3.3 -* Updated `lints` to 4.0.0 - -## 8.3.2 - -* Updated README - -## 8.3.1 - -* Updated repository link - -## 8.3.0 - -* Updated `lints` to 3.0.0 -* Fixed linter warnings - -## 8.2.0 - -* Add `addResponseHeader` to `PlatformHttp` to add headers to HTTP default response -* Add `removeResponseHeader` to `PlatformHttp` to remove headers from HTTP default response - -## 8.1.1 - -* Updated broken image on README - -## 8.1.0 - -* Updated `uuid` to 4.0.0 - -## 8.0.0 - -* Require Dart >= 3.0 -* Updated `http` to 1.0.0 - -## 7.0.4 - -* Updated `Expose` fields to non-nullable -* Updated `Controller` to use non-nullable field - -## 7.0.3 - -* Fixed issue #83. Allow Http request to return null headers instead of throwing an exception. - -## 7.0.2 - -* Added performance benchmark to README - -## 7.0.1 - -* Fixed `BytesBuilder` warnings - -## 7.0.0 - -* Require Dart >= 2.17 - -## 6.0.0 - -* Require Dart >= 2.16 -* Updated `container` to non nullable -* Updated `angel` to non nullable -* Updated `logger` to non nullable -* Refactored error handler - -## 5.0.0 - -* Skipped release - -## 4.2.4 - -* Fixed issue 48. Log not working in development - -## 4.2.3 - -* Fixed `res.json()` throwing bad state exception - -## 4.2.2 - -* Added `Date` to response header -* Updated `Server: Protevus` response header - -## 4.2.1 - -* Updated `package:angel3_container` - -## 4.2.0 - -* Updated to `package:belatuk_combinator` -* Updated to `package:belatuk_merge_map` -* Updated linter to `package:lints` - -## 4.1.3 - -* Updated README - -## 4.1.2 - -* Updated README -* Fixed NNBD issues - -## 4.1.1 - -* Updated link to `Protevus` home page -* Fixed pedantic warnings - -## 4.1.0 - -* Replaced `http_server` with `belatuk_http_server` - -## 4.0.4 - -* Fixed response returning incorrect status code - -## 4.0.3 - -* Fixed "Primitive after parsed param injection" test case -* Fixed "Cannot remove all unless explicitly set" test case -* Fixed "null" test case - -## 4.0.2 - -* Updated README - -## 4.0.1 - -* Updated README - -## 4.0.0 - -* Migrated to support Dart >= 2.12 NNBD - -## 3.0.0 - -* Migrated to work with Dart >= 2.12 Non NNBD - -## 2.1.1 - -* `PlatformHttp.uri` now returns an empty `Uri` if the server is not listening. - -## 2.1.0 - -* This release was originally planned to be `2.0.5`, but it adds several features, and has -therefore been bumped to `2.1.0`. -* Fix a new (did not appear before 2.6/2.7) type error causing compilation to fail. - - -## 2.0.5-beta - -* Make `@Expose()` in `Controller` optional. -* Add `allowHttp1` to `PlatformHttp2` constructors. -* Add `deserializeBody` and `decodeBody` to `RequestContext`. -* Add `HostnameRouter`, which allows for routing based on hostname. -* Default to using `ThrowingReflector`, instead of `EmptyReflector`. This will give a more descriptive -error when trying to use controllers, etc. without reflection enabled. -* `mountController` returns the mounted controller. - -## 2.0.4+1 - -* Run `Controller.configureRoutes` before mounting `@Expose` routes. -* Make `Controller.configureServer` always return a `Future`. - -## 2.0.4 - -* Prepare for Dart SDK change to `Stream>` that are now - `Stream`. -* Accept any content type if accept header is missing. See -[this PR](https://github.com/angel-dart/framework/pull/239). - -## 2.0.3 - -* Patch up a bug caused by an upstream change to Dart's stream semantics. -See more: - -## 2.0.2+1 - -* Fix a bug in the implementation of `Controller.applyRoutes`. - -## 2.0.2 - -* Make `ResponseContext` *explicitly* implement `StreamConsumer` (though technically it already did???) -* Split `Controller.configureServer` to create `Controller.applyRoutes`. - -## 2.0.1 - -* Tracked down a bug in `Driver.runPipeline` that allowed fallback -handlers to run, even after the response was closed. -* Add `RequestContext.shutdownHooks`. -* Call `RequestContext.close` in `Driver.sendResponse`. -* ProtevusConfigurer is now `FutureOr`, instead of just `FutureOr`. -* Use a `Container.has` check in `Driver.sendResponse`. -* Remove unnecessary `new` and `const`. - -## 2.0.0 - -* Protevus 2! :angel: :rocket: - -## 2.0.0-rc.10 - -* Fix an error that prevented `PlatformHttp2.custom` from working properly. -* Add `startSharedHttp2`. - -## 2.0.0-rc.9 - -* Fix some bugs in the `HookedService` implementation that skipped -the outputs of `before` events. - -## 2.0.0-rc.8 - -* Fix `MapService` flaw where clients could remove all records, even if `allowRemoveAll` were `false`. - -## 2.0.0-rc.7 - -* `AnonymousService` can override `readData`. -* `Service.map` now overrides `readData`. -* `HookedService.readData` forwards to `inner`. - -## 2.0.0-rc.6 - -* Make `redirect` and `download` methods asynchronous. - -## 2.0.0-rc.5 - -* Make `serializer` `FutureOr Function(Object)`. -* Make `ResponseContext.serialize` return `Future`. - -## 2.0.0-rc.4 - -* Support resolution of asynchronous injections in controllers and `ioc`. -* Inject `RequestContext` and `ResponseContext` into requests. - -## 2.0.0-rc.3 - -* `MapService.modify` was not actually modifying items. - -## 2.0.0-rc.2 - -* Fixes Pub analyzer lints (see `angel_route@3.0.6`) - -## 2.0.0-rc.1 - -* Fix logic error that allowed content to be written to streaming responses after `close` was closed. - -## 2.0.0-rc.0 - -* Log a warning when no `reflector` is provided. -* Add `ProtevusEnvironment` class. - * Add `Protevus.environment`. - * Deprecated `app.isProduction` in favor of `app.environment.isProduction`. -* Allow setting of `bodyAsObject`, `bodyAsMap`, or `bodyAsList` **exactly once**. -* Resolve named singletons in `resolveInjection`. -* Fix a bug where `Service.parseId` would attempt to parse an `int`. -* Replace as Data cast in Service.dart with a method that throws a 400 on error. - -## 2.0.0-alpha.24 - -* Add `ProtevusEnv` class to `core`. -* Deprecate `Protevus.isProduction`, in favor of `ProtevusEnv`. - -## 2.0.0-alpha.23 - -* `ResponseContext.render` sets `charset` to `utf8` in `contentType`. - -## 2.0.0-alpha.22 - -* Update pipeline handling mechanism, and inject a `MiddlewarePipelineIterator`. - * This allows routes to know where in the resolution process they exist, at runtime. - -## 2.0.0-alpha.21 - -* Update for `angel_route@3.0.4` compatibility. -* Add `readAsBytes` and `readAsString` to `UploadedFile`. -* URI-decode path components in HTTP2. - -## 2.0.0-alpha.20 - -* Inject the `MiddlewarePipeline` into requests. - -## 2.0.0-alpha.19 - -* `parseBody` checks for null content type, and throws a `400` if none was given. -* Add `ResponseContext.contentLength`. -* Update `streamFile` to set content length, and also to work on `HEAD` requests. - -## 2.0.0-alpha.18 - -* Upgrade `http2` dependency. -* Upgrade `uuid` dependency. -* Fixed a bug that prevented body parsing from ever completing with `http2`. -* Add `Providers.hashCode`. - -## 2.0.0-alpha.17 - -* Revert the migration to `lumberjack` for now. In the future, when it's more -stable, there'll be a conversion, perhaps. - -## 2.0.0-alpha.16 - -* Use `package:lumberjack` for logging. - -## 2.0.0-alpha.15 - -* Remove dependency on `body_parser`. -* `RequestContext` now exposes a `Stream> get body` getter. - * Calling `RequestContext.parseBody()` parses its contents. - * Added `bodyAsMap`, `bodyAsList`, `bodyAsObject`, and `uploadedFiles` to `RequestContext`. - * Removed `Protevus.keepRawRequestBuffers` and anything that had to do with buffering request bodies. - -## 2.0.0-alpha.14 - -* Patch `HttpResponseContext._openStream` to send content-length. - -## 2.0.0-alpha.13 - -* Fixed a logic error in `HttpResponseContext` that prevented status codes from being sent. - -## 2.0.0-alpha.12 - -* Remove `ResponseContext.sendFile`. -* Add `Protevus.mimeTypeResolver`. -* Fix a bug where an unknown MIME type on `streamFile` would return a 500. - -## 2.0.0-alpha.11 - -* Add `readMany` to `Service`. -* Allow `ResponseContext.redirect` to take a `Uri`. -* Add `Protevus.mountController`. -* Add `Protevus.findServiceOf`. -* Roll in HTTP/2. See `pkg:angel_framework/http2.dart`. - -## 2.0.0-alpha.10 - -* All calls to `Service.parseId` are now affixed with the `` argument. -* Added `uri` getter to `PlatformHttp`. -* The default for `parseQuery` now wraps query parameters in `Map.from`. - This resolves a bug in `package:angel_validate`. - -## 2.0.0-alpha.9 - -* Add `Service.map`. - -## 2.0.0-alpha.8 - -* No longer export HTTP-specific code from `angel_framework.dart`. - An import of `import 'package:angel_framework/http.dart';` will be necessary in most cases now. - -## 2.0.0-alpha.7 - -* Force a tigher contract on services. They now must return `Data` on all - methods except for `index`, which returns a `List`. - -## 2.0.0-alpha.6 - -* Allow passing a custom `Container` to `handleContained` and co. - -## 2.0.0-alpha.5 - -* `MapService` methods now explicitly return `Map`. - -## 2.0.0-alpha.4 - -* Renamed `waterfall` to `chain`. -* Renamed `Routable.service` to `Routable.findService`. - * Also `Routable.findHookedService`. - -## 2.0.0-alpha.3 - -* Added `` type parameters to `Service`. -* `HookedService` now follows suit, and takes a third parameter, pointing to the inner service. -* `Routable.use` now uses the generic parameters added to `Service`. -* Added generic usage to `HookedServiceListener`, etc. -* All service methods take `Map` as `params` now. - -## 2.0.0-alpha.2 - -* Added `ResponseContext.detach`. - -## 2.0.0-alpha.1 - -* Removed `Protevus.injectEncoders`. -* Added `Providers.toJson`. -* Moved `Providers.graphql` to `Providers.graphQL`. -* `Protevus.optimizeForProduction` no longer calls `preInject`, - as it does not need to. -* Rename `ResponseContext.enableBuffer` to `ResponseContext.useBuffer`. - -## 2.0.0-alpha - -* Removed `random_string` dependency. -* Moved reflection to `package:angel_container`. -* Upgraded `package:file` to `5.0.0`. -* `ResponseContext.sendFile` now uses `package:file`. -* Abandon `ContentType` in favor of `MediaType`. -* Changed view engine to use `Map`. -* Remove dependency on `package:json_god` by default. -* Remove dependency on `package:dart2_constant`. -* Moved `lib/hooks.dart` into `package:angel_hooks`. -* Moved `TypedService` into `package:angel_typed_service`. -* Completely removed the `ProtevusBase` class. -* Removed all `@deprecated` symbols. -* `Service.toId` was renamed to `Service.parseId`; it also now uses its - single type argument to determine how to parse a value. \* In addition, this method was also made `static`. -* `RequestContext` and `ResponseContext` are now generic, and take a - single type argument pointing to the underlying request/response type, - respectively. -* `RequestContext.io` and `ResponseContext.io` are now permanently - gone. -* `HttpRequestContextImpl` and `HttpResponseContextImpl` were renamed to - `HttpRequestContext` and `HttpResponseContext`. -* Lazy-parsing request bodies is now the default; `Protevus.lazyParseBodies` was replaced - with `Protevus.eagerParseRequestBodies`. -* `Protevus.storeOriginalBuffer` -> `Protevus.storeRawRequestBuffers`. -* The methods `lazyBody`, `lazyFiles`, and `lazyOriginalBuffer` on `ResponseContext` were all - replaced with `parseBody`, `parseUploadedFiles`, and `parseRawRequestBuffer`, respectively. -* Removed the synchronous equivalents of the above methods (`body`, `files`, and `originalBuffer`), - as well as `query`. -* Removed `Protevus.injections` and `RequestContext.injections`. -* Removed `Protevus.inject` and `RequestContext.inject`. -* Removed a dependency on `package:pool`, which also meant removing `PlatformHttp.throttle`. -* Remove the `RequestMiddleware` typedef; from now on, one should use `ResponseContext.end` - exclusively to close responses. -* `waterfall` will now only accept `RequestHandler`. -* `Routable`, and all of its subclasses, now extend `Router`, and therefore only - take routes in the form of `FutureOr myFunc(RequestContext, ResponseContext res)`. -* `@Middleware` now takes an `Iterable` of `RequestHandler`s. -* `@Expose.path` now *must* be a `String`, not just any `Pattern`. -* `@Expose.middleware` now takes `Iterable`, instead of just `List`. -* `createDynamicHandler` was renamed to `ioc`, and is now used to run IoC-aware handlers in a - type-safe manner. -* `RequestContext.params` is now a `Map`, rather than just a `Map`. -* Removed `RequestContext.grab`. -* Removed `RequestContext.properties`. -* Removed the defunct `debug` property where it still existed. -* `Routable.use` now only accepts a `Service`. -* Removed `Protevus.createZoneForRequest`. -* Removed `Protevus.defaultZoneCreator`. -* Added all flags to the `Protevus` constructor, ex. `Protevus.eagerParseBodies`. -* Fix a bug where synchronous errors in `handleRequest` would not be caught. -* `PlatformHttp.useZone` now defaults to `false`. -* `ResponseContext` now starts in streaming mode by default; the response buffer is opt-in, - as in many cases it is unnecessary and slows down response time. -* `ResponseContext.streaming` was replaced by `ResponseContext.isBuffered`. -* Made `LockableBytesBuilder` public. -* Removed the now-obsolete `ResponseContext.willCloseItself`. -* Removed `ResponseContext.dispose`. -* Removed the now-obsolete `ResponseContext.end`. -* Removed the now-obsolete `ResponseContext.releaseCorrespondingRequest`. -* `preInject` now takes a `Reflector` as its second argument. -* `Protevus.reflector` defaults to `const EmptyReflector()`, disabling - reflection out-of-the-box. diff --git a/packages/core/LICENSE b/packages/core/LICENSE deleted file mode 100644 index df5e063..0000000 --- a/packages/core/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2021, dukefirehawk.com -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/core/README.md b/packages/core/README.md deleted file mode 100644 index 56ea484..0000000 --- a/packages/core/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Protevus Platform Core - -

Protevus Logo

- -[![Pub Version (including pre-releases)](https://img.shields.io/pub/v/protevus_core?include_prereleases)](https://pub.dev/packages/protevus_core) -[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety) -[![License](https://img.shields.io/github/license/protevus/platform)](https://github.com/protevus/platform/blob/main/packages/core/LICENSE) - -Protevus Platform Core is a high-powered HTTP server framework for Dart, designed to be minimal yet extensible. It provides a robust foundation for building scalable and flexible web applications. - -## Features - -- Dependency injection -- Sophisticated routing -- Authentication support -- ORM integration -- GraphQL support -- Extensible plugin architecture -- HTTP/2 support -- WebSocket capabilities -- File handling and MIME type detection -- Environment configuration management -- Performance optimization with caching mechanisms - -## Installation - -Add `protevus_core` to your `pubspec.yaml`: - -```yaml -dependencies: - protevus_core: ^latest_version -``` \ No newline at end of file diff --git a/packages/core/analysis_options.yaml b/packages/core/analysis_options.yaml deleted file mode 100644 index ea2c9e9..0000000 --- a/packages/core/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:lints/recommended.yaml \ No newline at end of file diff --git a/packages/core/dev.key b/packages/core/dev.key deleted file mode 100644 index 5d49ae7..0000000 --- a/packages/core/dev.key +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIE5DAcBgoqhkiG9w0BDAEBMA4ECL7L6rj6uEHGAgIIAASCBMLbucyfqAkgCbhP -xNSHYllPMAv/dsIjtnsBwepCXPGkCBCuOAw/2FaCHjN9hBqL5V7fkrKeaemhm2YE -ycPtlHJYPDf3kEkyMjdZ9rIY6kePGfQizs2uJPcXj4YPyQ4HsfVXpOicKfQrouf5 -Mze9bGzeMN065q3iP4dYUMwHAyZYteXCsanQNHlqvsWli0W+H8St8fdsXefZhnv1 -qVatKWdNdWQ9t5MuljgNU2Vv56sHKEYXI0yLxk2QUMk8KlJfnmt8foYUsnPUXHmc -gIjLKwwVkpdololnEHSNu0cEOUPowjgJru+uMpn7vdNl7TPEQ9jbEgdNg4JwoYzU -0nao8WzjaSp7kzvZz0VFwKnk5AjstGvvuAWckADdq23QElbn/mF7AG1m/TBpYxzF -gTt37UdndS/AcvVznWVVrRP5iTSIawdIwvqI4s7rqsoE0GCcak+RhchgAz2gWKkS -oODUo0JL6pPVbJ3l4ebbaO6c99nDVc8dViPtc1EkStJEJ2O4kI4xgLSCr4Y9ahKn -oAaoSkX7Xxq3aQm+BzqSpLjdGL8atsqR/YVOIHYIl3gThvP0NfZGx1xHyvO5mCdZ -kHxSA7tKWxauZ3eQ2clbnzeRsl4El0WMHy/5K1ovene4v7sunmoXVtghBC8hK6eh -zMO9orex2PNQ/VQC7HCvtytunOVx1lkSBoNo7hR70igg6rW9H7UyoAoBOwMpT1xa -J6V62nqruTKOqFNfur7aHJGpHGtDb5/ickHeYCyPTvmGp67u4wChzKReeg02oECe -d1E5FKAcIa8s9TVOB6Z+HvTRNQZu2PsI6TJnjQRowvY9DAHiWTlJZBBY/pko3hxX -TsIeybpvRdEHpDWv86/iqtw1hv9CUxS/8ZTWUgBo+osShHW79FeDASr9FC4/Zn76 -ZDERTgV4YWlW/klVWcG2lFo7jix+OPXAB+ZQavLhlN1xdWBcIz1AUWjAM4hdPylW -HCX4PB9CQIPl2E7F+Y2p6nMcMWSJVBi5UIH7E9LfaBguXSzMmTk2Fw5p1aOQ6wfN -goVAMVwi8ppAVs741PfHdZ295xMmK/1LCxz5DeAdD/tsA/SYfT753GotioDuC7im -EyJ5JyvTr5I6RFFBuqt3NlUb3Hp16wP3B2x9DZiB6jxr0l341/NHgsyeBXkuIy9j -ON2mvpBPCJhS8kgWo3G0UyyKnx64tcgpGuSvZhGwPz843B6AbYyE6pMRfSWRMkMS -YZYa+VNKhR4ixdj07ocFZEWLVjCH7kxkE8JZXKt8jKYmkWd0lS1QVjgaKlO6lRa3 -q6SPJkhW6pvqobvcqVNXwi1XuzpZeEbuh0B7OTekFTTxx5g9XeDl56M8SVQ1KEhT -Q1t7H2Nba18WCB7cf+6PN0F0K0Jz1Kq7ZWaqEI/grX1m4RQuvNF5807sB/QKMO/Z -Gz3NXvHg5xTJRd/567lxPGkor0cE7qD1EZfmJ2HrBYXQ91bhgA7LToBuMZo6ZRXH -QfsanjbP4FPLMiGdQigLjj3A35L/f4sQOOVac/sRaFnm7pzcxsMvyVU/YtvGcjYE -xaOOVnamg661Wo0wksXoDjeSz/JIyyKO3Gwp1FSm2wGLjjy/Ehmqcqy8rvHuf07w -AUukhVtTNn4= ------END ENCRYPTED PRIVATE KEY----- \ No newline at end of file diff --git a/packages/core/dev.pem b/packages/core/dev.pem deleted file mode 100644 index 01756b2..0000000 --- a/packages/core/dev.pem +++ /dev/null @@ -1,57 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDKTCCAhGgAwIBAgIJAOWmjTS+OnTEMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV -BAMMDGludGVybWVkaWF0ZTAeFw0xNTA1MTgwOTAwNDBaFw0yMzA4MDQwOTAwNDBa -MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALlcwQJuzd+xH8QFgfJSn5tRlvhkldSX98cE7NiA602NBbnAVyUrkRXq -Ni75lgt0kwjYfA9z674m8WSVbgpLPintPCla9CYky1TH0keIs8Rz6cGWHryWEHiu -EDuljQynu2b3sAFuHu9nfWurbJwZnFakBKpdQ9m4EyOZCHC/jHYY7HacKSXg1Cki -we2ca0BWDrcqy8kLy0dZ5oC6IZG8O8drAK8f3f44CRYw59D3sOKBrKXaabpvyEcb -N7Wk2HDBVwHpUJo1reVwtbM8dhqQayYSD8oXnGpP3RQNu/e2rzlXRyq/BfcDY1JI -7TbC4t/7/N4EcPSpGsTcSOC9A7FpzvECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglg -hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O -BBYEFCnwiEMMFZh7NhCr+qA8K0w4Q+AOMB8GA1UdIwQYMBaAFB0h1Evsaw2vfrmS -YuoCTmC4EE6ZMA0GCSqGSIb3DQEBCwUAA4IBAQAcFmHMaXRxyoNaeOowQ6iQWoZd -AUbvG7SHr7I6Pi2aqdqofsKWts7Ytm5WsS0M2nN+sW504houu0iCPeJJX8RQw2q4 -CCcNOs9IXk+2uMzlpocHpv+yYoUiD5DxgWh7eghQMLyMpf8FX3Gy4VazeuXznHOM -4gE4L417xkDzYOzqVTp0FTyAPUv6G2euhNCD6TMru9REcRhYul+K9kocjA5tt2KG -MH6y28LXbLyq4YJUxSUU9gY/xlnbbZS48KDqEcdYC9zjW9nQ0qS+XQuQuFIcwjJ5 -V4kAUYxDu6FoTpyQjgsrmBbZlKNxH7Nj4NDlcdJhp/zeSKHqWa5hSWjjKIxp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAeqgAwIBAgIJAOWmjTS+OnTDMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV -BAMMDXJvb3RhdXRob3JpdHkwHhcNMTUwNTE4MDkwMDQwWhcNMjMwODA0MDkwMDQw -WjAXMRUwEwYDVQQDDAxpbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDSrAO1CoPvUllgLOzDm5nG0skDF7vh1DUgAIDVGz0ecD0JFbQx -EF79pju/6MbtpTW2FYvRp11t/G7rGtX923ybOHY/1MNFQrdIvPlO1VV7IGKjoMwP -DNeb0fIGjHoE9QxaDxR8NX8xQbItpsw+TUtRfc9SLkR+jaYJfVRoM21BOncZbSHE -YKiZlEbpecB/+EtwVpgvl+8mPD5U07Fi4fp/lza3WXInXQPyiTVllIEJCt4PKmlu -MocNaJOW38bysL7i0PzDpVZtOxLHOTaW68yF3FckIHNCaA7k1ABEEEegjFMmIao7 -B9w7A0jvr4jZVvNmui5Djjn+oJxwEVVgyf8LAgMBAAGjUDBOMB0GA1UdDgQWBBQd -IdRL7GsNr365kmLqAk5guBBOmTAfBgNVHSMEGDAWgBRk81s9d0ZbiZhh44KckwPb -oTc0XzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBZQTK0plfdB5PC -cC5icut4EmrByJa1RbU7ayuEE70e7hla6KVmVjVdCBGltI4jBYwfhKbRItHiAJ/8 -x+XZKBG8DLPFuDb7lAa1ObhAYF7YThUFPQYaBhfzKcWrdmWDBFpvNv6E0Mm364dZ -e7Yxmbe5S4agkYPoxEzgEYmcUk9jbjdR6eTbs8laG169ljrECXfEU9RiAcqz5iSX -NLSewqB47hn3B9qgKcQn+PsgO2j7M+rfklhNgeGJeWmy7j6clSOuCsIjWHU0RLQ4 -0W3SB/rpEAJ7fgQbYUPTIUNALSOWi/o1tDX2mXPRjBoxqAv7I+vYk1lZPmSzkyRh -FKvRDxsW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAzCCAeugAwIBAgIJAJ0MomS4Ck+8MA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV -BAMMDXJvb3RhdXRob3JpdHkwHhcNMTUwNTE4MDkwMDQwWhcNMjMwODA0MDkwMDQw -WjAYMRYwFAYDVQQDDA1yb290YXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAts1ijtBV92S2cOvpUMOSTp9c6A34nIGr0T5Nhz6XiqRVT+gv -dQgmkdKJQjbvR60y6jzltYFsI2MpGVXY8h/oAL81D/k7PDB2aREgyBfTPAhBHyGw -siR+2xYt5b/Zs99q5RdRqQNzNpLPJriIKvUsRyQWy1UiG2s7pRXQeA8qB0XtJdCj -kFIi+G2bDsaffspGeDOCqt7t+yqvRXfSES0c/l7DIHaiMbbp4//ZNML3RNgAjPz2 -hCezZ+wOYajOIyoSPK8IgICrhYFYxvgWxwbLDBEfC5B3jOQsySe10GoRAKZz1gBV -DmgReu81tYJmdgkc9zknnQtIFdA0ex+GvZlfWQIDAQABo1AwTjAdBgNVHQ4EFgQU -ZPNbPXdGW4mYYeOCnJMD26E3NF8wHwYDVR0jBBgwFoAUZPNbPXdGW4mYYeOCnJMD -26E3NF8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATzkZ97K777uZ -lQcduNX3ey4IbCiEzFA2zO5Blj+ilfIwNbZXNOgm/lqNvVGDYs6J1apJJe30vL3X -J+t2zsZWzzQzb9uIU37zYemt6m0fHrSrx/iy5lGNqt3HMfqEcOqSCOIK3PCTMz2/ -uyGe1iw33PVeWsm1JUybQ9IrU/huJjbgOHU4wab+8SJCM49ipArp68Fr6j4lcEaE -4rfRg1ZsvxiOyUB3qPn6wyL/JB8kOJ+QCBe498376eaem8AEFk0kQRh6hDaWtq/k -t6IIXQLjx+EBDVP/veK0UnVhKRP8YTOoV8ZiG1NcdlJmX/Uk7iAfevP7CkBfSN8W -r6AL284qtw== ------END CERTIFICATE----- \ No newline at end of file diff --git a/packages/core/example/controller.dart b/packages/core/example/controller.dart deleted file mode 100644 index 583bece..0000000 --- a/packages/core/example/controller.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:logging/logging.dart'; - -void main() async { - // Logging set up/boilerplate - Logger.root.onRecord.listen(print); - - // Create our server. - var app = - Application(logger: Logger('protevus'), reflector: MirrorsReflector()); - var http = PlatformHttp(app); - - await app.mountController(); - - // Simple fallback to throw a 404 on unknown paths. - app.fallback((req, res) { - throw PlatformHttpException.notFound( - message: 'Unknown path: "${req.uri!.path}"', - ); - }); - - app.errorHandler = (e, req, res) => e.toJson(); - - await http.startServer('127.0.0.1', 3000); - print('Listening at ${http.uri}'); - app.dumpTree(); -} - -class ArtistsController extends Controller { - List index() { - return ['Elvis', 'Stevie', 'Van Gogh']; - } - - String getById(int id, RequestContext req) { - return 'You fetched ID: $id from IP: ${req.ip}'; - } - - @Expose.post - Future form(RequestContext req) async { - // Deserialize the body into an artist. - var artist = await req.deserializeBody((m) { - return Artist(name: m!['name'] as String? ?? '(unknown name)'); - }); - - // Return it (it will be serialized to JSON). - return artist; - } -} - -class Artist { - final String? name; - - Artist({this.name}); - - Map toJson() { - return {'name': name}; - } -} diff --git a/packages/core/example/handle_error.dart b/packages/core/example/handle_error.dart deleted file mode 100644 index 05a9e36..0000000 --- a/packages/core/example/handle_error.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:logging/logging.dart'; - -void main() async { - var app = Application(reflector: MirrorsReflector()) - ..logger = (Logger('protevus') - ..onRecord.listen((rec) { - print(rec); - if (rec.error != null) print(rec.error); - if (rec.stackTrace != null) print(rec.stackTrace); - })) - ..encoders.addAll({'gzip': gzip.encoder}); - - app.fallback( - (req, res) => Future.error('Throwing just because I feel like!')); - - var http = PlatformHttp(app); - HttpServer? server = await http.startServer('127.0.0.1', 3000); - var url = 'http://${server.address.address}:${server.port}'; - print('Listening at $url'); -} diff --git a/packages/core/example/hostname.dart b/packages/core/example/hostname.dart deleted file mode 100644 index d485725..0000000 --- a/packages/core/example/hostname.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:async'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:logging/logging.dart'; - -Future apiConfigurer(Application app) async { - app.get('/', (req, res) => 'Hello, API!'); - app.fallback((req, res) { - return 'fallback on ${req.uri} (within the API)'; - }); -} - -Future frontendConfigurer(Application app) async { - app.fallback((req, res) => '(usually an index page would be shown here.)'); -} - -void main() async { - // Logging set up/boilerplate - hierarchicalLoggingEnabled = true; - //Logger.root.onRecord.listen(prettyLog); - - var app = Application(logger: Logger('protevus')); - var http = PlatformHttp(app); - var multiHost = HostnameRouter.configure({ - 'api.localhost:3000': apiConfigurer, - 'localhost:3000': frontendConfigurer, - }); - - app - ..fallback(multiHost.handleRequest) - ..fallback((req, res) { - res.write('Uncaught hostname: ${req.hostname}'); - }); - - app.errorHandler = (e, req, res) { - print(e.message); - print(e.stackTrace); - return e.toJson(); - }; - - await http.startServer('127.0.0.1', 3000); - print('Listening at ${http.uri}'); - print('See what happens when you visit http://localhost:3000 instead ' - 'of http://127.0.0.1:3000. Then, try ' - 'http://api.localhost:3000.'); -} diff --git a/packages/core/example/http2/body_parsing.dart b/packages/core/example/http2/body_parsing.dart deleted file mode 100644 index 1592b5e..0000000 --- a/packages/core/example/http2/body_parsing.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:io'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_core/http2.dart'; -import 'package:file/local.dart'; -import 'package:logging/logging.dart'; - -void main() async { - var app = Application(); - app.logger = Logger('protevus') - ..onRecord.listen((rec) { - print(rec); - if (rec.error != null) print(rec.error); - if (rec.stackTrace != null) print(rec.stackTrace); - }); - - var publicDir = Directory('example/public'); - var indexHtml = - const LocalFileSystem().file(publicDir.uri.resolve('body_parsing.html')); - - app.get('/', (req, res) => res.streamFile(indexHtml)); - - app.post('/', (req, res) => req.parseBody().then((_) => req.bodyAsMap)); - - var ctx = SecurityContext() - ..useCertificateChain('dev.pem') - ..usePrivateKey('dev.key', password: 'dartdart'); - - try { - ctx.setAlpnProtocols(['h2'], true); - } catch (e, st) { - app.logger.severe( - 'Cannot set ALPN protocol on server to `h2`. The server will only serve HTTP/1.x.', - e, - st); - } - - var http1 = PlatformHttp(app); - var http2 = PlatformHttp2(app, ctx); - - // HTTP/1.x requests will fallback to `PlatformHttp` - http2.onHttp1.listen(http1.handleRequest); - - var server = await http2.startServer('127.0.0.1', 3000); - print('Listening at https://${server.address.address}:${server.port}'); -} diff --git a/packages/core/example/http2/common.dart b/packages/core/example/http2/common.dart deleted file mode 100644 index b937b43..0000000 --- a/packages/core/example/http2/common.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:logging/logging.dart'; - -void dumpError(LogRecord rec) { - print(rec); - if (rec.error != null) print(rec.error); - if (rec.stackTrace != null) print(rec.stackTrace); -} diff --git a/packages/core/example/http2/dev.key b/packages/core/example/http2/dev.key deleted file mode 100644 index 5d49ae7..0000000 --- a/packages/core/example/http2/dev.key +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIE5DAcBgoqhkiG9w0BDAEBMA4ECL7L6rj6uEHGAgIIAASCBMLbucyfqAkgCbhP -xNSHYllPMAv/dsIjtnsBwepCXPGkCBCuOAw/2FaCHjN9hBqL5V7fkrKeaemhm2YE -ycPtlHJYPDf3kEkyMjdZ9rIY6kePGfQizs2uJPcXj4YPyQ4HsfVXpOicKfQrouf5 -Mze9bGzeMN065q3iP4dYUMwHAyZYteXCsanQNHlqvsWli0W+H8St8fdsXefZhnv1 -qVatKWdNdWQ9t5MuljgNU2Vv56sHKEYXI0yLxk2QUMk8KlJfnmt8foYUsnPUXHmc -gIjLKwwVkpdololnEHSNu0cEOUPowjgJru+uMpn7vdNl7TPEQ9jbEgdNg4JwoYzU -0nao8WzjaSp7kzvZz0VFwKnk5AjstGvvuAWckADdq23QElbn/mF7AG1m/TBpYxzF -gTt37UdndS/AcvVznWVVrRP5iTSIawdIwvqI4s7rqsoE0GCcak+RhchgAz2gWKkS -oODUo0JL6pPVbJ3l4ebbaO6c99nDVc8dViPtc1EkStJEJ2O4kI4xgLSCr4Y9ahKn -oAaoSkX7Xxq3aQm+BzqSpLjdGL8atsqR/YVOIHYIl3gThvP0NfZGx1xHyvO5mCdZ -kHxSA7tKWxauZ3eQ2clbnzeRsl4El0WMHy/5K1ovene4v7sunmoXVtghBC8hK6eh -zMO9orex2PNQ/VQC7HCvtytunOVx1lkSBoNo7hR70igg6rW9H7UyoAoBOwMpT1xa -J6V62nqruTKOqFNfur7aHJGpHGtDb5/ickHeYCyPTvmGp67u4wChzKReeg02oECe -d1E5FKAcIa8s9TVOB6Z+HvTRNQZu2PsI6TJnjQRowvY9DAHiWTlJZBBY/pko3hxX -TsIeybpvRdEHpDWv86/iqtw1hv9CUxS/8ZTWUgBo+osShHW79FeDASr9FC4/Zn76 -ZDERTgV4YWlW/klVWcG2lFo7jix+OPXAB+ZQavLhlN1xdWBcIz1AUWjAM4hdPylW -HCX4PB9CQIPl2E7F+Y2p6nMcMWSJVBi5UIH7E9LfaBguXSzMmTk2Fw5p1aOQ6wfN -goVAMVwi8ppAVs741PfHdZ295xMmK/1LCxz5DeAdD/tsA/SYfT753GotioDuC7im -EyJ5JyvTr5I6RFFBuqt3NlUb3Hp16wP3B2x9DZiB6jxr0l341/NHgsyeBXkuIy9j -ON2mvpBPCJhS8kgWo3G0UyyKnx64tcgpGuSvZhGwPz843B6AbYyE6pMRfSWRMkMS -YZYa+VNKhR4ixdj07ocFZEWLVjCH7kxkE8JZXKt8jKYmkWd0lS1QVjgaKlO6lRa3 -q6SPJkhW6pvqobvcqVNXwi1XuzpZeEbuh0B7OTekFTTxx5g9XeDl56M8SVQ1KEhT -Q1t7H2Nba18WCB7cf+6PN0F0K0Jz1Kq7ZWaqEI/grX1m4RQuvNF5807sB/QKMO/Z -Gz3NXvHg5xTJRd/567lxPGkor0cE7qD1EZfmJ2HrBYXQ91bhgA7LToBuMZo6ZRXH -QfsanjbP4FPLMiGdQigLjj3A35L/f4sQOOVac/sRaFnm7pzcxsMvyVU/YtvGcjYE -xaOOVnamg661Wo0wksXoDjeSz/JIyyKO3Gwp1FSm2wGLjjy/Ehmqcqy8rvHuf07w -AUukhVtTNn4= ------END ENCRYPTED PRIVATE KEY----- \ No newline at end of file diff --git a/packages/core/example/http2/dev.pem b/packages/core/example/http2/dev.pem deleted file mode 100644 index 01756b2..0000000 --- a/packages/core/example/http2/dev.pem +++ /dev/null @@ -1,57 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDKTCCAhGgAwIBAgIJAOWmjTS+OnTEMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV -BAMMDGludGVybWVkaWF0ZTAeFw0xNTA1MTgwOTAwNDBaFw0yMzA4MDQwOTAwNDBa -MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALlcwQJuzd+xH8QFgfJSn5tRlvhkldSX98cE7NiA602NBbnAVyUrkRXq -Ni75lgt0kwjYfA9z674m8WSVbgpLPintPCla9CYky1TH0keIs8Rz6cGWHryWEHiu -EDuljQynu2b3sAFuHu9nfWurbJwZnFakBKpdQ9m4EyOZCHC/jHYY7HacKSXg1Cki -we2ca0BWDrcqy8kLy0dZ5oC6IZG8O8drAK8f3f44CRYw59D3sOKBrKXaabpvyEcb -N7Wk2HDBVwHpUJo1reVwtbM8dhqQayYSD8oXnGpP3RQNu/e2rzlXRyq/BfcDY1JI -7TbC4t/7/N4EcPSpGsTcSOC9A7FpzvECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglg -hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O -BBYEFCnwiEMMFZh7NhCr+qA8K0w4Q+AOMB8GA1UdIwQYMBaAFB0h1Evsaw2vfrmS -YuoCTmC4EE6ZMA0GCSqGSIb3DQEBCwUAA4IBAQAcFmHMaXRxyoNaeOowQ6iQWoZd -AUbvG7SHr7I6Pi2aqdqofsKWts7Ytm5WsS0M2nN+sW504houu0iCPeJJX8RQw2q4 -CCcNOs9IXk+2uMzlpocHpv+yYoUiD5DxgWh7eghQMLyMpf8FX3Gy4VazeuXznHOM -4gE4L417xkDzYOzqVTp0FTyAPUv6G2euhNCD6TMru9REcRhYul+K9kocjA5tt2KG -MH6y28LXbLyq4YJUxSUU9gY/xlnbbZS48KDqEcdYC9zjW9nQ0qS+XQuQuFIcwjJ5 -V4kAUYxDu6FoTpyQjgsrmBbZlKNxH7Nj4NDlcdJhp/zeSKHqWa5hSWjjKIxp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAeqgAwIBAgIJAOWmjTS+OnTDMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV -BAMMDXJvb3RhdXRob3JpdHkwHhcNMTUwNTE4MDkwMDQwWhcNMjMwODA0MDkwMDQw -WjAXMRUwEwYDVQQDDAxpbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDSrAO1CoPvUllgLOzDm5nG0skDF7vh1DUgAIDVGz0ecD0JFbQx -EF79pju/6MbtpTW2FYvRp11t/G7rGtX923ybOHY/1MNFQrdIvPlO1VV7IGKjoMwP -DNeb0fIGjHoE9QxaDxR8NX8xQbItpsw+TUtRfc9SLkR+jaYJfVRoM21BOncZbSHE -YKiZlEbpecB/+EtwVpgvl+8mPD5U07Fi4fp/lza3WXInXQPyiTVllIEJCt4PKmlu -MocNaJOW38bysL7i0PzDpVZtOxLHOTaW68yF3FckIHNCaA7k1ABEEEegjFMmIao7 -B9w7A0jvr4jZVvNmui5Djjn+oJxwEVVgyf8LAgMBAAGjUDBOMB0GA1UdDgQWBBQd -IdRL7GsNr365kmLqAk5guBBOmTAfBgNVHSMEGDAWgBRk81s9d0ZbiZhh44KckwPb -oTc0XzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBZQTK0plfdB5PC -cC5icut4EmrByJa1RbU7ayuEE70e7hla6KVmVjVdCBGltI4jBYwfhKbRItHiAJ/8 -x+XZKBG8DLPFuDb7lAa1ObhAYF7YThUFPQYaBhfzKcWrdmWDBFpvNv6E0Mm364dZ -e7Yxmbe5S4agkYPoxEzgEYmcUk9jbjdR6eTbs8laG169ljrECXfEU9RiAcqz5iSX -NLSewqB47hn3B9qgKcQn+PsgO2j7M+rfklhNgeGJeWmy7j6clSOuCsIjWHU0RLQ4 -0W3SB/rpEAJ7fgQbYUPTIUNALSOWi/o1tDX2mXPRjBoxqAv7I+vYk1lZPmSzkyRh -FKvRDxsW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAzCCAeugAwIBAgIJAJ0MomS4Ck+8MA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV -BAMMDXJvb3RhdXRob3JpdHkwHhcNMTUwNTE4MDkwMDQwWhcNMjMwODA0MDkwMDQw -WjAYMRYwFAYDVQQDDA1yb290YXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAts1ijtBV92S2cOvpUMOSTp9c6A34nIGr0T5Nhz6XiqRVT+gv -dQgmkdKJQjbvR60y6jzltYFsI2MpGVXY8h/oAL81D/k7PDB2aREgyBfTPAhBHyGw -siR+2xYt5b/Zs99q5RdRqQNzNpLPJriIKvUsRyQWy1UiG2s7pRXQeA8qB0XtJdCj -kFIi+G2bDsaffspGeDOCqt7t+yqvRXfSES0c/l7DIHaiMbbp4//ZNML3RNgAjPz2 -hCezZ+wOYajOIyoSPK8IgICrhYFYxvgWxwbLDBEfC5B3jOQsySe10GoRAKZz1gBV -DmgReu81tYJmdgkc9zknnQtIFdA0ex+GvZlfWQIDAQABo1AwTjAdBgNVHQ4EFgQU -ZPNbPXdGW4mYYeOCnJMD26E3NF8wHwYDVR0jBBgwFoAUZPNbPXdGW4mYYeOCnJMD -26E3NF8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATzkZ97K777uZ -lQcduNX3ey4IbCiEzFA2zO5Blj+ilfIwNbZXNOgm/lqNvVGDYs6J1apJJe30vL3X -J+t2zsZWzzQzb9uIU37zYemt6m0fHrSrx/iy5lGNqt3HMfqEcOqSCOIK3PCTMz2/ -uyGe1iw33PVeWsm1JUybQ9IrU/huJjbgOHU4wab+8SJCM49ipArp68Fr6j4lcEaE -4rfRg1ZsvxiOyUB3qPn6wyL/JB8kOJ+QCBe498376eaem8AEFk0kQRh6hDaWtq/k -t6IIXQLjx+EBDVP/veK0UnVhKRP8YTOoV8ZiG1NcdlJmX/Uk7iAfevP7CkBfSN8W -r6AL284qtw== ------END CERTIFICATE----- \ No newline at end of file diff --git a/packages/core/example/http2/main.dart b/packages/core/example/http2/main.dart deleted file mode 100644 index 395ac38..0000000 --- a/packages/core/example/http2/main.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'dart:io'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_core/http2.dart'; -import 'package:logging/logging.dart'; -import 'common.dart'; - -void main() async { - var app = Application() - ..encoders.addAll({ - 'gzip': gzip.encoder, - 'deflate': zlib.encoder, - }); - app.logger = Logger('protevus')..onRecord.listen(dumpError); - - app.get('/', (req, res) => 'Hello HTTP/2!!!'); - - app.fallback((req, res) => throw PlatformHttpException.notFound( - message: 'No file exists at ${req.uri}')); - - var ctx = SecurityContext() - ..useCertificateChain('dev.pem') - ..usePrivateKey('dev.key', password: 'dartdart'); - - try { - ctx.setAlpnProtocols(['h2'], true); - } catch (e, st) { - app.logger.severe( - 'Cannot set ALPN protocol on server to `h2`. The server will only serve HTTP/1.x.', - e, - st, - ); - } - - var http1 = PlatformHttp(app); - var http2 = PlatformHttp2(app, ctx); - - // HTTP/1.x requests will fallback to `PlatformHttp` - http2.onHttp1.listen(http1.handleRequest); - - await http2.startServer('127.0.0.1', 3000); - print('Listening at ${http2.uri}'); -} diff --git a/packages/core/example/http2/public/app.js b/packages/core/example/http2/public/app.js deleted file mode 100644 index 5b08ee9..0000000 --- a/packages/core/example/http2/public/app.js +++ /dev/null @@ -1,27 +0,0 @@ -window.onload = function() { - var $app = document.getElementById('app'); - var $loading = document.getElementById('loading'); - $app.removeChild($loading); - var $button = document.createElement('button'); - var $h1 = document.createElement('h1'); - $app.appendChild($h1); - $app.appendChild($button); - - $h1.textContent = '~Protevus HTTP/2 server push~'; - - $button.textContent = 'Change color'; - $button.onclick = function() { - var color = Math.floor(Math.random() * 0xffffff); - $h1.style.color = '#' + color.toString(16); - }; - - $button.onclick(); - - window.setInterval($button.onclick, 2000); - - var rotation = 0; - window.setInterval(function() { - rotation += .6; - $button.style.transform = 'rotate(' + rotation + 'deg)'; - }, 10); -}; \ No newline at end of file diff --git a/packages/core/example/http2/public/body_parsing.html b/packages/core/example/http2/public/body_parsing.html deleted file mode 100644 index 8ad8a1a..0000000 --- a/packages/core/example/http2/public/body_parsing.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Protevus HTTP/2 - - - -
- - - - - -
- - \ No newline at end of file diff --git a/packages/core/example/http2/public/index.html b/packages/core/example/http2/public/index.html deleted file mode 100644 index 67a1e80..0000000 --- a/packages/core/example/http2/public/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Protevus HTTP/2 - - - -
Loading...
- - - \ No newline at end of file diff --git a/packages/core/example/http2/public/style.css b/packages/core/example/http2/public/style.css deleted file mode 100644 index e434813..0000000 --- a/packages/core/example/http2/public/style.css +++ /dev/null @@ -1,20 +0,0 @@ -button { - margin-top: 2em; -} - -html, body { - background-color: #000; -} - -#app { - text-align: center; -} - -#app h1 { - font-style: italic; - text-decoration: underline; -} - -#loading { - color: red; -} \ No newline at end of file diff --git a/packages/core/example/http2/server_push.dart b/packages/core/example/http2/server_push.dart deleted file mode 100644 index f3d16c6..0000000 --- a/packages/core/example/http2/server_push.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'dart:io'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_core/http2.dart'; -import 'package:file/local.dart'; -import 'package:logging/logging.dart'; - -void main() async { - var app = Application(); - app.logger = Logger('protevus') - ..onRecord.listen((rec) { - print(rec); - if (rec.error != null) print(rec.error); - if (rec.stackTrace != null) print(rec.stackTrace); - }); - - var publicDir = Directory('example/http2/public'); - var indexHtml = - const LocalFileSystem().file(publicDir.uri.resolve('index.html')); - var styleCss = - const LocalFileSystem().file(publicDir.uri.resolve('style.css')); - var appJs = const LocalFileSystem().file(publicDir.uri.resolve('app.js')); - - // Send files when requested - app - ..get('/style.css', (req, res) => res.streamFile(styleCss)) - ..get('/app.js', (req, res) => res.streamFile(appJs)); - - app.get('/', (req, res) async { - // Regardless of whether we pushed other resources, let's still send /index.html. - await res.streamFile(indexHtml); - - // If the client is HTTP/2 and supports server push, let's - // send down /style.css and /app.js as well, to improve initial load time. - if (res is Http2ResponseContext && res.canPush) { - await res.push('/style.css').streamFile(styleCss); - await res.push('/app.js').streamFile(appJs); - } - }); - - var ctx = SecurityContext() - ..useCertificateChain('dev.pem') - ..usePrivateKey('dev.key', password: 'dartdart'); - - try { - ctx.setAlpnProtocols(['h2'], true); - } catch (e, st) { - app.logger.severe( - 'Cannot set ALPN protocol on server to `h2`. The server will only serve HTTP/1.x.', - e, - st); - } - - var http1 = PlatformHttp(app); - var http2 = PlatformHttp2(app, ctx); - - // HTTP/1.x requests will fallback to `PlatformHttp` - http2.onHttp1.listen(http1.handleRequest); - - var server = await http2.startServer('127.0.0.1', 3000); - print('Listening at https://${server.address.address}:${server.port}'); -} diff --git a/packages/core/example/json.dart b/packages/core/example/json.dart deleted file mode 100644 index 679c057..0000000 --- a/packages/core/example/json.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'dart:isolate'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; - -void main() async { - var x = 0; - var c = Completer(); - var exit = ReceivePort(); - var isolates = []; - - exit.listen((_) { - if (++x >= 50) { - c.complete(); - } - }); - - for (var i = 1; i < Platform.numberOfProcessors; i++) { - var isolate = await Isolate.spawn(serverMain, null); - isolates.add(isolate); - print('Spawned isolate #${i + 1}...'); - - isolate.addOnExitListener(exit.sendPort); - } - - serverMain(null); - - print('Protevus listening at http://localhost:3000'); - await c.future; -} - -void serverMain(_) async { - var app = Application(); - var http = - PlatformHttp.custom(app, startShared, useZone: false); // Run a cluster - - app.get('/', (req, res) { - return res.serialize({ - 'foo': 'bar', - 'one': [2, 'three'], - 'bar': {'baz': 'quux'} - }); - }); - - app.errorHandler = (e, req, res) { - print(e.message); - print(e.stackTrace); - }; - - var server = await http.startServer('127.0.0.1', 3000); - print('Listening at http://${server.address.address}:${server.port}'); -} diff --git a/packages/core/example/main.dart b/packages/core/example/main.dart deleted file mode 100644 index e8cf5a3..0000000 --- a/packages/core/example/main.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:logging/logging.dart'; - -void main() async { - // Logging set up/boilerplate - //Logger.root.onRecord.listen(prettyLog); - - // Create our server. - var app = Application( - logger: Logger('protevus'), - reflector: MirrorsReflector(), - ); - - // Index route. Returns JSON. - app.get('/', (req, res) => 'Welcome to Protevus!'); - - // Accepts a URL like /greet/foo or /greet/bob. - app.get( - '/greet/:name', - (req, res) { - var name = req.params['name']; - res - ..write('Hello, $name!') - ..close(); - }, - ); - - // Pattern matching - only call this handler if the query value of `name` equals 'emoji'. - app.get( - '/greet', - ioc((@Query('name', match: 'emoji') String name) => '😇🔥🔥🔥'), - ); - - // Handle any other query value of `name`. - app.get( - '/greet', - ioc((@Query('name') String name) => 'Hello, $name!'), - ); - - // Simple fallback to throw a 404 on unknown paths. - app.fallback((req, res) { - throw PlatformHttpException.notFound( - message: 'Unknown path: "${req.uri!.path}"', - ); - }); - - var http = PlatformHttp(app); - var server = await http.startServer('127.0.0.1', 3000); - var url = 'http://${server.address.address}:${server.port}'; - print('Listening at $url'); - print('Visit these pages to see Protevus in action:'); - print('* $url/greet/bob'); - print('* $url/greet/?name=emoji'); - print('* $url/greet/?name=jack'); - print('* $url/nonexistent_page'); -} diff --git a/packages/core/example/map_service.dart b/packages/core/example/map_service.dart deleted file mode 100644 index f9aa9b1..0000000 --- a/packages/core/example/map_service.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:logging/logging.dart'; - -void main() async { - // Logging set up/boilerplate - Logger.root.onRecord.listen(print); - - // Create our server. - var app = Application( - logger: Logger('protevus'), - reflector: MirrorsReflector(), - ); - - // Create a RESTful service that manages an in-memory collection. - app.use('/api/todos', MapService()); - - var http = PlatformHttp(app); - await http.startServer('127.0.0.1', 0); - print('Listening at ${http.uri}'); -} diff --git a/packages/core/example/status.dart b/packages/core/example/status.dart deleted file mode 100644 index 3f8ac38..0000000 --- a/packages/core/example/status.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; - -void main() async { - var app = Application(); - var http = PlatformHttp(app); - - app.fallback((req, res) { - res.statusCode = 304; - }); - - await http.startServer('127.0.0.1', 3000); - print('Listening at ${http.uri}'); -} diff --git a/packages/core/example/view.dart b/packages/core/example/view.dart deleted file mode 100644 index 4893053..0000000 --- a/packages/core/example/view.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; - -void main() async { - var app = Application(reflector: MirrorsReflector()); - - app.viewGenerator = (name, [data]) async => - 'View generator invoked with name $name and data: $data'; - - // Index route. Returns JSON. - app.get('/', (req, res) => res.render('index', {'foo': 'bar'})); - - var http = PlatformHttp(app); - var server = await http.startServer('127.0.0.1', 3000); - var url = 'http://${server.address.address}:${server.port}'; - print('Listening at $url'); -} diff --git a/packages/core/example/views/index.jl b/packages/core/example/views/index.jl deleted file mode 100644 index 53ac639..0000000 --- a/packages/core/example/views/index.jl +++ /dev/null @@ -1,9 +0,0 @@ - - - - Title - - -

Hello!

- - \ No newline at end of file diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart deleted file mode 100644 index 83bb2f8..0000000 --- a/packages/core/lib/core.dart +++ /dev/null @@ -1,7 +0,0 @@ -/// An easily-extensible web server framework in Dart. -library platform_core; - -export 'package:platform_support/exceptions.dart'; -export 'package:platform_model/model.dart'; -export 'package:platform_route/route.dart'; -export 'src/core/core.dart'; diff --git a/packages/core/lib/http.dart b/packages/core/lib/http.dart deleted file mode 100644 index 5f00eff..0000000 --- a/packages/core/lib/http.dart +++ /dev/null @@ -1 +0,0 @@ -export 'src/http/http.dart'; diff --git a/packages/core/lib/http2.dart b/packages/core/lib/http2.dart deleted file mode 100644 index 7fd2aaf..0000000 --- a/packages/core/lib/http2.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'src/http2/protevus_http2.dart'; -export 'src/http2/http2_request_context.dart'; -export 'src/http2/http2_response_context.dart'; diff --git a/packages/core/lib/src/core/anonymous_service.dart b/packages/core/lib/src/core/anonymous_service.dart deleted file mode 100644 index e43e4f2..0000000 --- a/packages/core/lib/src/core/anonymous_service.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'dart:async'; -import 'service.dart'; - -/// An easy helper class to create one-off services without having to create an entire class. -/// -/// Well-suited for testing. -class AnonymousService extends Service { - FutureOr> Function([Map?])? _index; - FutureOr Function(Id, [Map?])? _read, _remove; - FutureOr Function(Data, [Map?])? _create; - FutureOr Function(Id, Data, [Map?])? _modify, _update; - - AnonymousService( - {FutureOr> Function([Map? params])? index, - FutureOr Function(Id id, [Map? params])? read, - FutureOr Function(Data data, [Map? params])? - create, - FutureOr Function(Id id, Data data, [Map? params])? - modify, - FutureOr Function(Id id, Data data, [Map? params])? - update, - FutureOr Function(Id id, [Map? params])? remove, - super.readData}) { - _index = index; - _read = read; - _create = create; - _modify = modify; - _update = update; - _remove = remove; - } - - @override - Future> index([Map? params]) => - Future.sync(() => _index != null ? _index!(params) : super.index(params)); - - @override - Future read(Id id, [Map? params]) => Future.sync( - () => _read != null ? _read!(id, params) : super.read(id, params)); - - @override - Future create(Data data, [Map? params]) => - Future.sync(() => _create != null - ? _create!(data, params) - : super.create(data, params)); - - @override - Future modify(Id id, Data data, [Map? params]) => - Future.sync(() => _modify != null - ? _modify!(id, data, params) - : super.modify(id, data, params)); - - @override - Future update(Id id, Data data, [Map? params]) => - Future.sync(() => _update != null - ? _update!(id, data, params) - : super.update(id, data, params)); - - @override - Future remove(Id id, [Map? params]) => Future.sync( - () => _remove != null ? _remove!(id, params) : super.remove(id, params)); -} diff --git a/packages/core/lib/src/core/controller.dart b/packages/core/lib/src/core/controller.dart deleted file mode 100644 index 3625164..0000000 --- a/packages/core/lib/src/core/controller.dart +++ /dev/null @@ -1,242 +0,0 @@ -library platform_core.http.controller; - -import 'dart:async'; -import 'package:platform_container/container.dart'; -import 'package:platform_route/route.dart'; -import 'package:meta/meta.dart'; -import 'package:recase/recase.dart'; -import '../core/core.dart'; - -/// Supports grouping routes with shared functionality. -class Controller { - Application? _app; - - /// The [Application] application powering this controller. - Application get app { - if (_app == null) { - throw ArgumentError("Protevus is not instantiated."); - } - - return _app!; - } - - /// If `true` (default), this class will inject itself as a singleton into the [app]'s container when bootstrapped. - final bool injectSingleton; - - /// Middleware to run before all handlers in this class. - List middleware = []; - - /// A mapping of route paths to routes, produced from the [Expose] annotations on this class. - Map routeMappings = {}; - - SymlinkRoute? _mountPoint; - - /// The route at which this controller is mounted on the server. - SymlinkRoute? get mountPoint => _mountPoint; - - Controller({this.injectSingleton = true}); - - /// Applies routes, DI, and other configuration to an [app]. - @mustCallSuper - Future configureServer(Application app) async { - _app = app; - - if (injectSingleton != false) { - if (!app.container.has(runtimeType)) { - _app!.container.registerSingleton(this, as: runtimeType); - } - } - - var name = await applyRoutes(app, app.container.reflector); - app.controllers[name] = this; - //return null; - } - - /// Applies the routes from this [Controller] to some [router]. - Future applyRoutes( - Router router, Reflector reflector) async { - // Load global expose decl - var classMirror = reflector.reflectClass(runtimeType)!; - var exposeDecl = findExpose(reflector); - - if (exposeDecl == null) { - throw Exception('All controllers must carry an @Expose() declaration.'); - } - - var routable = Routable(); - _mountPoint = router.mount(exposeDecl.path, routable); - //_mountPoint = m; - var typeMirror = reflector.reflectType(runtimeType); - - // Pre-reflect methods - var instanceMirror = reflector.reflectInstance(this); - final handlers = [...exposeDecl.middleware, ...middleware]; - final routeBuilder = - _routeBuilder(reflector, instanceMirror, routable, handlers); - await configureRoutes(routable); - classMirror.declarations.forEach(routeBuilder); - - // Return the name. - var result = - exposeDecl.as?.isNotEmpty == true ? exposeDecl.as : typeMirror!.name; - - return Future.value(result); - } - - void Function(ReflectedDeclaration) _routeBuilder( - Reflector reflector, - ReflectedInstance? instanceMirror, - Routable routable, - Iterable handlers) { - return (ReflectedDeclaration decl) { - var methodName = decl.name; - - // Ignore built-in methods. - if (methodName != 'toString' && - methodName != 'noSuchMethod' && - methodName != 'call' && - methodName != 'equals' && - methodName != '==') { - var exposeDecl = decl.function!.annotations - .map((m) => m.reflectee) - .firstWhere((r) => r is Expose, orElse: () => null) as Expose?; - - if (exposeDecl == null) { - // If this has a @noExpose, return null. - if (decl.function!.annotations.any((m) => m.reflectee is NoExpose)) { - return; - } else { - // Otherwise, create an @Expose. - exposeDecl = Expose(''); - } - } - - var reflectedMethod = - instanceMirror!.getField(methodName).reflectee as Function?; - var middleware = [ - ...handlers, - ...exposeDecl.middleware - ]; - var name = - exposeDecl.as?.isNotEmpty == true ? exposeDecl.as : methodName; - - // Check if normal - var method = decl.function!; - if (method.parameters.length == 2 && - method.parameters[0].type.reflectedType == RequestContext && - method.parameters[1].type.reflectedType == ResponseContext) { - // Create a regular route - routeMappings[name ?? ''] = routable - .addRoute(exposeDecl.method, exposeDecl.path, - (RequestContext req, ResponseContext res) { - var result = reflectedMethod!(req, res); - return result is RequestHandler ? result(req, res) : result; - }, middleware: middleware); - return; - } - - var injection = preInject(reflectedMethod!, reflector); - - if (exposeDecl.allowNull.isNotEmpty == true) { - injection.optional.addAll(exposeDecl.allowNull); - } - - // If there is no path, reverse-engineer one. - var path = exposeDecl.path; - var httpMethod = exposeDecl.method; - if (path == '') { - // Try to build a route path by finding all potential - // path segments, and then joining them. - var parts = []; - - // If the name starts with get/post/patch, etc., then that - // should be the path. - var methodMatch = _methods.firstMatch(method.name); - if (methodMatch != null) { - var rest = method.name.replaceAll(_methods, ''); - var restPath = ReCase(rest.isEmpty ? 'index' : rest) - .snakeCase - .replaceAll(_rgxMultipleUnderscores, '_'); - httpMethod = methodMatch[1]!.toUpperCase(); - - if (['index', 'by_id'].contains(restPath)) { - parts.add('/'); - } else { - parts.add(restPath); - } - } - // If the name does NOT start with get/post/patch, etc. then - // snake_case-ify the name, and add it to the list of segments. - // If the name is index, though, add "/". - else { - if (method.name == 'index') { - parts.add('/'); - } else { - parts.add(ReCase(method.name) - .snakeCase - .replaceAll(_rgxMultipleUnderscores, '_')); - } - } - - // Try to infer String, int, or double. We called - // preInject() earlier, so we can figure out the types - // of required parameters, and add those to the path. - for (var p in injection.required) { - if (p is List && p.length == 2 && p[0] is String && p[1] is Type) { - var name = p[0] as String; - var type = p[1] as Type; - if (type == String) { - parts.add(':$name'); - } else if (type == int) { - parts.add('int:$name'); - } else if (type == double) { - parts.add('double:$name'); - } - } - } - - path = parts.join('/'); - if (!path.startsWith('/')) path = '/$path'; - } - - routeMappings[name ?? ''] = routable.addRoute( - httpMethod, path, handleContained(reflectedMethod, injection), - middleware: middleware); - } - }; - } - - /// Used to add additional routes or middlewares to the router from within - /// a [Controller]. - /// - /// ```dart - /// @override - /// FutureOr configureRoutes(Routable routable) { - /// routable.all('*', myMiddleware); - /// } - /// ``` - FutureOr configureRoutes(Routable routable) {} - - static final RegExp _methods = RegExp(r'^(get|post|patch|delete)'); - static final RegExp _rgxMultipleUnderscores = RegExp(r'__+'); - - /// Finds the [Expose] declaration for this class. - /// - /// If [concreteOnly] is `false`, then if there is no actual - /// [Expose], one will be automatically created. - Expose? findExpose(Reflector reflector, {bool concreteOnly = false}) { - var existing = reflector - .reflectClass(runtimeType)! - .annotations - .map((m) => m.reflectee) - .firstWhere((r) => r is Expose, orElse: () => null) as Expose?; - return existing ?? - (concreteOnly - ? null - : Expose(ReCase(runtimeType.toString()) - .snakeCase - .replaceAll('_controller', '') - .replaceAll('_ctrl', '') - .replaceAll(_rgxMultipleUnderscores, '_'))); - } -} diff --git a/packages/core/lib/src/core/core.dart b/packages/core/lib/src/core/core.dart deleted file mode 100644 index a7a0da4..0000000 --- a/packages/core/lib/src/core/core.dart +++ /dev/null @@ -1,14 +0,0 @@ -export 'anonymous_service.dart'; -export 'controller.dart'; -export 'driver.dart'; -export 'env.dart'; -export 'hooked_service.dart'; -export 'hostname_parser.dart'; -export 'hostname_router.dart'; -export 'map_service.dart'; -export 'metadata.dart'; -export 'request_context.dart'; -export 'response_context.dart'; -export 'routable.dart'; -export 'server.dart'; -export 'service.dart'; diff --git a/packages/core/lib/src/core/driver.dart b/packages/core/lib/src/core/driver.dart deleted file mode 100644 index 4c262de..0000000 --- a/packages/core/lib/src/core/driver.dart +++ /dev/null @@ -1,401 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' show Cookie; -import 'package:platform_support/exceptions.dart'; -import 'package:platform_route/route.dart'; -import 'package:belatuk_combinator/belatuk_combinator.dart'; -import 'package:stack_trace/stack_trace.dart'; -import 'package:tuple/tuple.dart'; -import 'core.dart'; - -/// Base driver class for Protevus implementations. -/// -/// Powers both PlatformHttp and PlatformHttp2. -abstract class Driver< - Request, - Response, - Server extends Stream, - RequestContextType extends RequestContext, - ResponseContextType extends ResponseContext> { - final Application app; - final bool useZone; - bool _closed = false; - - StreamSubscription? _sub; - //final log = Logger('Driver'); - - /// The function used to bind this instance to a server.. - final Future Function(dynamic, int) serverGenerator; - - Driver(this.app, this.serverGenerator, {this.useZone = true}); - - /// The path at which this server is listening for requests. - Uri get uri; - - /// The native server running this instance. - Server? server; - - Future generateServer(address, int port) => - serverGenerator(address, port); - - /// Starts, and returns the server. - Future startServer([address, int port = 0]) { - var host = address ?? '127.0.0.1'; - return generateServer(host, port).then((server) { - this.server = server; - - return Future.wait(app.startupHooks.map(app.configure)).then((_) { - app.optimizeForProduction(); - _sub = this.server?.listen((request) { - var stream = createResponseStreamFromRawRequest(request); - stream.listen((response) { - // TODO: To be revisited - handleRawRequest(request, response); - }); - }); - return Future.value(this.server!); - }); - }).catchError((error) { - app.logger.severe('Failed to create server', error); - throw ArgumentError('[Driver]Failed to create server'); - }); - } - - /// Shuts down the underlying server. - Future close() { - if (_closed) { - //return Future.value(_server); - return Future.value(); - } - _closed = true; - - _sub?.cancel(); - - return app.close().then((_) => - Future.wait(app.shutdownHooks.map(app.configure)) - .then((_) => Future.value())); - /* - return app.close().then((_) => - Future.wait(app.shutdownHooks.map(app.configure)) - .then((_) => Future.value(_server))); - */ - } - - Future createRequestContext( - Request request, Response response); - - Future createResponseContext( - Request request, Response response, - [RequestContextType? correspondingRequest]); - - void setHeader(Response response, String key, String value); - - void setContentLength(Response response, int length); - - void setChunkedEncoding(Response response, bool value); - - void setStatusCode(Response response, int value); - - void addCookies(Response response, Iterable cookies); - - void writeStringToResponse(Response response, String value); - - void writeToResponse(Response response, List data); - - Future closeResponse(Response response); - - Stream createResponseStreamFromRawRequest(Request request); - - /// Handles a single request. - Future handleRawRequest(Request request, Response response) { - app.logger.info('[Server] Called handleRawRequest'); - - return createRequestContext(request, response).then((req) { - return createResponseContext(request, response, req).then((res) { - Future handle() { - var path = req.path; - if (path == '/') path = ''; - - Tuple4, ParseResult, - MiddlewarePipeline> resolveTuple() { - var r = app.optimizedRouter; - var resolved = - r.resolveAbsolute(path, method: req.method, strip: false); - var pipeline = MiddlewarePipeline(resolved); - return Tuple4( - pipeline.handlers, - resolved.fold>( - {}, (out, r) => out..addAll(r.allParams)), - //(resolved.isEmpty ? null : resolved.first.parseResult), - resolved.first.parseResult, - pipeline, - ); - } - - var cacheKey = req.method + path; - var tuple = app.environment.isProduction - ? app.handlerCache.putIfAbsent(cacheKey, resolveTuple) - : resolveTuple(); - var line = tuple.item4 as MiddlewarePipeline; - var it = MiddlewarePipelineIterator(line); - - req.params.addAll(tuple.item2); - - req.container - ?..registerSingleton(req) - ..registerSingleton(res) - ..registerSingleton(tuple.item4) - ..registerSingleton>(line) - ..registerSingleton(it) - ..registerSingleton>(it) - ..registerSingleton?>(tuple.item3) - ..registerSingleton(tuple.item3); - - if (!app.environment.isProduction) { - req.container?.registerSingleton(Stopwatch()..start()); - } - - return runPipeline(it, req, res, app) - .then((_) => sendResponse(request, response, req, res)); - } - - if (useZone == false) { - Future f; - - try { - f = handle(); - } catch (e, st) { - f = Future.error(e, st); - } - - return f.catchError((e, StackTrace st) { - if (e is FormatException) { - throw PlatformHttpException.badRequest(message: e.message) - ..stackTrace = st; - } - throw PlatformHttpException( - stackTrace: st, - statusCode: (e is PlatformHttpException) ? e.statusCode : 500, - message: e?.toString() ?? '500 Internal Server Error'); - }, test: (e) => e is PlatformHttpException).catchError( - (ee, StackTrace st) { - //print(">>>> Framework error: $ee"); - //var t = (st).runtimeType; - //print(">>>> StackTrace: $t"); - PlatformHttpException e; - if (ee is PlatformHttpException) { - e = ee; - } else { - e = PlatformHttpException( - stackTrace: st, - statusCode: 500, - message: ee?.toString() ?? '500 Internal Server Error'); - } - - var error = e.error ?? e; - var trace = Trace.from(StackTrace.current).terse; - app.logger.severe(e.message, error, trace); - - return handleHttpException(e, st, req, res, request, response); - }); - } else { - var zoneSpec = ZoneSpecification( - print: (self, parent, zone, line) { - app.logger.info(line); - }, - handleUncaughtError: (self, parent, zone, error, stackTrace) { - var trace = Trace.from(stackTrace).terse; - - // TODO: To be revisited - Future(() { - PlatformHttpException e; - - if (error is FormatException) { - e = PlatformHttpException.badRequest(message: error.message); - } else if (error is PlatformHttpException) { - e = error; - } else { - e = PlatformHttpException( - stackTrace: stackTrace, message: error.toString()); - } - - app.logger.severe(e.message, error, trace); - - return handleHttpException( - e, trace, req, res, request, response); - }).catchError((e, StackTrace st) { - var trace = Trace.from(st).terse; - closeResponse(response); - // Ideally, we won't be in a position where an absolutely fatal error occurs, - // but if so, we'll need to log it. - app.logger.severe( - 'Fatal error occurred when processing $uri.', e, trace); - }); - }, - ); - - var zone = Zone.current.fork(specification: zoneSpec); - req.container?.registerSingleton(zone); - req.container?.registerSingleton(zoneSpec); - - // If a synchronous error is thrown, it's not caught by `zone.run`, - // so use a try/catch, and recover when need be. - - try { - return zone.run(handle); - } catch (e, st) { - zone.handleUncaughtError(e, st); - return Future.value(); - } - } - }); - }); - } - - /// Handles an [PlatformHttpException]. - Future handleHttpException( - PlatformHttpException e, - StackTrace st, - RequestContext? req, - ResponseContext? res, - Request request, - Response response, - {bool ignoreFinalizers = false}) { - if (req == null || res == null) { - try { - app.logger.severe('500 Internal Server Error', e, st); - setStatusCode(response, 500); - writeStringToResponse(response, '500 Internal Server Error'); - closeResponse(response); - } catch (e) { - app.logger.severe('500 Internal Server Error', e); - } - return Future.value(); - } - - Future handleError; - - if (!res.isOpen) { - handleError = Future.value(); - } else { - res.statusCode = e.statusCode; - handleError = - Future.sync(() => app.errorHandler(e, req, res)).then((result) { - return app.executeHandler(result, req, res).then((_) => res.close()); - }); - } - - return handleError.then((_) => sendResponse(request, response, req, res, - ignoreFinalizers: ignoreFinalizers == true)); - } - - /// Sends a response. - Future sendResponse(Request request, Response response, RequestContext req, - ResponseContext res, - {bool ignoreFinalizers = false}) { - //app.logger.fine("Calling SendResponse"); - Future cleanup(_) { - if (!app.environment.isProduction && req.container!.has()) { - var sw = req.container!.make(); - app.logger.fine( - "${res.statusCode} ${req.method} ${req.uri} (${sw.elapsedMilliseconds} ms)"); - } - return req.close(); - } - - // TODO: Debugging header - /* - for (var key in res.headers.keys) { - app.logger.fine("Response header key: $key"); - } - */ - - if (!res.isBuffered) { - //if (res.isOpen) { - return res.close().then(cleanup); - //} - //return Future.value(); - } - - //app.logger.fine("Calling finalizers"); - - var finalizers = ignoreFinalizers == true - ? Future.value() - : Future.forEach(app.responseFinalizers, (dynamic f) => f(req, res)); - - return finalizers.then((_) { - //if (res.isOpen) res.close(); - - for (var key in res.headers.keys) { - app.logger.fine("Response header key: $key"); - setHeader(response, key, res.headers[key] ?? ''); - } - - setContentLength(response, res.buffer?.length ?? 0); - setChunkedEncoding(response, res.chunked ?? true); - - var outputBuffer = res.buffer?.toBytes() ?? []; - - if (res.encoders.isNotEmpty) { - var allowedEncodings = req.headers - ?.value('accept-encoding') - ?.split(',') - .map((s) => s.trim()) - .where((s) => s.isNotEmpty) - .map((str) { - // Ignore quality specifications in accept-encoding - // ex. gzip;q=0.8 - if (!str.contains(';')) return str; - return str.split(';')[0]; - }); - - if (allowedEncodings != null) { - for (var encodingName in allowedEncodings) { - var key = encodingName; - - Converter, List>? encoder; - if (res.encoders.containsKey(encodingName)) { - encoder = res.encoders[encodingName]; - } else if (encodingName == '*') { - encoder = res.encoders[key = res.encoders.keys.first]; - } - - if (encoder != null) { - setHeader(response, 'content-encoding', key); - outputBuffer = - res.encoders[key]?.convert(outputBuffer) ?? []; - setContentLength(response, outputBuffer.length); - break; - } - } - } - } - - setStatusCode(response, res.statusCode); - addCookies(response, res.cookies); - writeToResponse(response, outputBuffer); - return closeResponse(response).then(cleanup); - }); - } - - /// Runs a [MiddlewarePipeline]. - static Future runPipeline( - MiddlewarePipelineIterator it, - RequestContextType req, - ResponseContextType res, - Application app) async { - var broken = false; - while (it.moveNext()) { - var current = it.current.handlers.iterator; - - while (!broken && current.moveNext()) { - var result = await app.executeHandler(current.current, req, res); - if (result != true) { - broken = true; - break; - } - } - } - } -} diff --git a/packages/core/lib/src/core/env.dart b/packages/core/lib/src/core/env.dart deleted file mode 100644 index 1508db6..0000000 --- a/packages/core/lib/src/core/env.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'dart:io'; - -/// A constant instance of [ProtevusEnv]. -const ProtevusEnvironment protevusEnv = ProtevusEnvironment(); - -/// Queries the environment's `ANGEL_ENV` value. -class ProtevusEnvironment { - final String? _customValue; - - /// You can optionally provide a custom value, in order to override the system's - /// value. - const ProtevusEnvironment([this._customValue]); - - /// Returns the value of the `ANGEL_ENV` variable; defaults to `'development'`. - String get value => - (_customValue ?? Platform.environment['PROTEVUS_ENV'] ?? 'development') - .toLowerCase(); - - /// Returns whether the [value] is `'development'`. - bool get isDevelopment => value == 'development'; - - /// Returns whether the [value] is `'production'`. - bool get isProduction => value == 'production'; - - /// Returns whether the [value] is `'staging'`. - bool get isStaging => value == 'staging'; -} diff --git a/packages/core/lib/src/core/hooked_service.dart b/packages/core/lib/src/core/hooked_service.dart deleted file mode 100644 index 0cf31f3..0000000 --- a/packages/core/lib/src/core/hooked_service.dart +++ /dev/null @@ -1,605 +0,0 @@ -library platform_core.core.hooked_service; - -import 'dart:async'; - -import '../util.dart'; -import 'metadata.dart'; -import 'request_context.dart'; -import 'response_context.dart'; -import 'routable.dart'; -import 'server.dart'; -import 'service.dart'; - -/// Wraps another service in a service that broadcasts events on actions. -class HookedService> - extends Service { - final List> _ctrl = []; - - /// Tbe service that is proxied by this hooked one. - final T inner; - - final HookedServiceEventDispatcher beforeIndexed = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher beforeRead = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher beforeCreated = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher beforeModified = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher beforeUpdated = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher beforeRemoved = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher afterIndexed = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher afterRead = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher afterCreated = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher afterModified = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher afterUpdated = - HookedServiceEventDispatcher(); - final HookedServiceEventDispatcher afterRemoved = - HookedServiceEventDispatcher(); - - HookedService(this.inner) { - // Clone app instance - if (inner.isAppActive) { - app = inner.app; - } - } - - @override - FutureOr Function(RequestContext, ResponseContext)? get readData => - inner.readData; - - RequestContext? _getRequest(Map? params) { - if (params == null) return null; - return params['__requestctx'] as RequestContext?; - } - - ResponseContext? _getResponse(Map? params) { - if (params == null) return null; - return params['__responsectx'] as ResponseContext?; - } - - Map _stripReq(Map? params) { - if (params == null) { - return {}; - } else { - return params.keys - .where((key) => key != '__requestctx' && key != '__responsectx') - .fold>( - {}, (map, key) => map..[key] = params[key]); - } - } - - /// Closes any open [StreamController]s on this instance. **Internal use only**. - @override - Future close() { - for (var c in _ctrl) { - c.close(); - } - beforeIndexed._close(); - beforeRead._close(); - beforeCreated._close(); - beforeModified._close(); - beforeUpdated._close(); - beforeRemoved._close(); - afterIndexed._close(); - afterRead._close(); - afterCreated._close(); - afterModified._close(); - afterUpdated._close(); - afterRemoved._close(); - inner.close(); - return Future.value(); - } - - /// Adds hooks to this instance. - void addHooks(Application app) { - var hooks = getAnnotation(inner, app.container.reflector); - var before = >[]; - var after = >[]; - - if (hooks != null) { - before.addAll(hooks.before.cast()); - after.addAll(hooks.after.cast()); - } - - void applyListeners( - Function fn, HookedServiceEventDispatcher dispatcher, - [bool? isAfter]) { - var hooks = getAnnotation(fn, app.container.reflector); - final listeners = >[ - ...isAfter == true ? after : before - ]; - - if (hooks != null) { - listeners.addAll((isAfter == true ? hooks.after : hooks.before).cast()); - } - - listeners.forEach(dispatcher.listen); - } - - applyListeners(inner.index, beforeIndexed); - applyListeners(inner.read, beforeRead); - applyListeners(inner.create, beforeCreated); - applyListeners(inner.modify, beforeModified); - applyListeners(inner.update, beforeUpdated); - applyListeners(inner.remove, beforeRemoved); - applyListeners(inner.index, afterIndexed, true); - applyListeners(inner.read, afterRead, true); - applyListeners(inner.create, afterCreated, true); - applyListeners(inner.modify, afterModified, true); - applyListeners(inner.update, afterUpdated, true); - applyListeners(inner.remove, afterRemoved, true); - } - - @override - List get bootstrappers => - List.from(super.bootstrappers) - ..add((RequestContext req, ResponseContext res) { - req.serviceParams - ..['__requestctx'] = req - ..['__responsectx'] = res; - return true; - }); - - @override - void addRoutes([Service? service]) { - super.addRoutes(service ?? inner); - } - - /// Runs the [listener] before every service method specified. - void before(Iterable eventNames, - HookedServiceEventListener listener) { - eventNames.map((name) { - switch (name) { - case HookedServiceEvent.indexed: - return beforeIndexed; - case HookedServiceEvent.read: - return beforeRead; - case HookedServiceEvent.created: - return beforeCreated; - case HookedServiceEvent.modified: - return beforeModified; - case HookedServiceEvent.updated: - return beforeUpdated; - case HookedServiceEvent.removed: - return beforeRemoved; - default: - throw ArgumentError('Invalid service method: $name'); - } - }).forEach((HookedServiceEventDispatcher dispatcher) => - dispatcher.listen(listener)); - } - - /// Runs the [listener] after every service method specified. - void after(Iterable eventNames, - HookedServiceEventListener listener) { - eventNames.map((name) { - switch (name) { - case HookedServiceEvent.indexed: - return afterIndexed; - case HookedServiceEvent.read: - return afterRead; - case HookedServiceEvent.created: - return afterCreated; - case HookedServiceEvent.modified: - return afterModified; - case HookedServiceEvent.updated: - return afterUpdated; - case HookedServiceEvent.removed: - return afterRemoved; - default: - throw ArgumentError('Invalid service method: $name'); - } - }).forEach((HookedServiceEventDispatcher dispatcher) => - dispatcher.listen(listener)); - } - - /// Runs the [listener] before every service method. - void beforeAll(HookedServiceEventListener listener) { - beforeIndexed.listen(listener); - beforeRead.listen(listener); - beforeCreated.listen(listener); - beforeModified.listen(listener); - beforeUpdated.listen(listener); - beforeRemoved.listen(listener); - } - - /// Runs the [listener] after every service method. - void afterAll(HookedServiceEventListener listener) { - afterIndexed.listen(listener); - afterRead.listen(listener); - afterCreated.listen(listener); - afterModified.listen(listener); - afterUpdated.listen(listener); - afterRemoved.listen(listener); - } - - /// Returns a [Stream] of all events fired before every service method. - /// - /// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee - /// that events coming out of this [Stream] will see changes you make within the [Stream] - /// callback. - Stream> beforeAllStream() { - var ctrl = StreamController>(); - _ctrl.add(ctrl); - before(HookedServiceEvent.all, ctrl.add); - return ctrl.stream; - } - - /// Returns a [Stream] of all events fired after every service method. - /// - /// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee - /// that events coming out of this [Stream] will see changes you make within the [Stream] - /// callback. - Stream> afterAllStream() { - var ctrl = StreamController>(); - _ctrl.add(ctrl); - before(HookedServiceEvent.all, ctrl.add); - return ctrl.stream; - } - - /// Returns a [Stream] of all events fired before every service method specified. - /// - /// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee - /// that events coming out of this [Stream] will see changes you make within the [Stream] - /// callback. - Stream> beforeStream( - Iterable eventNames) { - var ctrl = StreamController>(); - _ctrl.add(ctrl); - before(eventNames, ctrl.add); - return ctrl.stream; - } - - /// Returns a [Stream] of all events fired AFTER every service method specified. - /// - /// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee - /// that events coming out of this [Stream] will see changes you make within the [Stream] - /// callback. - Stream> afterStream( - Iterable eventNames) { - var ctrl = StreamController>(); - _ctrl.add(ctrl); - after(eventNames, ctrl.add); - return ctrl.stream; - } - - /// Runs the [listener] before [create], [modify] and [update]. - void beforeModify(HookedServiceEventListener listener) { - beforeCreated.listen(listener); - beforeModified.listen(listener); - beforeUpdated.listen(listener); - } - - @override - Future> index([Map? params]) { - var localParams = _stripReq(params); - return beforeIndexed - ._emit(HookedServiceEvent(false, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.indexed, - params: localParams)) - .then((before) { - if (before._canceled) { - return afterIndexed - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.indexed, - params: localParams, result: before.result)) - .then((after) => after.result as List); - } - - return inner.index(localParams).then((result) { - return afterIndexed - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.indexed, - params: localParams, result: result)) - .then((after) => after.result as List); - }); - }); - } - - @override - Future read(Id id, [Map? params]) { - var localParams = _stripReq(params); - return beforeRead - ._emit(HookedServiceEvent(false, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.read, - id: id, params: localParams)) - .then((before) { - if (before._canceled) { - return afterRead - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.read, - id: id, params: localParams, result: before.result)) - .then((after) => after.result as Data); - } - - return inner.read(id, localParams).then((result) { - return afterRead - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.read, - id: id, params: localParams, result: result)) - .then((after) => after.result as Data); - }); - }); - } - - @override - Future create(Data data, [Map? params]) { - var localParams = _stripReq(params); - return beforeCreated - ._emit(HookedServiceEvent(false, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.created, - data: data, params: localParams)) - .then((before) { - if (before._canceled) { - return afterCreated - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.created, - data: before.data, params: localParams, result: before.result)) - .then((after) => after.result as Data); - } - - return inner.create(before.data as Data, localParams).then((result) { - return afterCreated - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.created, - data: before.data, params: localParams, result: result)) - .then((after) => after.result as Data); - }); - }); - } - - @override - Future modify(Id id, Data data, [Map? params]) { - var localParams = _stripReq(params); - return beforeModified - ._emit(HookedServiceEvent(false, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.modified, - id: id, data: data, params: localParams)) - .then((before) { - if (before._canceled) { - return afterModified - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.modified, - id: id, - data: before.data, - params: localParams, - result: before.result)) - .then((after) => after.result as Data); - } - - return inner.modify(id, before.data as Data, localParams).then((result) { - return afterModified - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.created, - id: id, data: before.data, params: localParams, result: result)) - .then((after) => after.result as Data); - }); - }); - } - - @override - Future update(Id id, Data data, [Map? params]) { - var localParams = _stripReq(params); - return beforeUpdated - ._emit(HookedServiceEvent(false, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.updated, - id: id, data: data, params: localParams)) - .then((before) { - if (before._canceled) { - return afterUpdated - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.updated, - id: id, - data: before.data, - params: localParams, - result: before.result)) - .then((after) => after.result as Data); - } - - return inner.update(id, before.data as Data, localParams).then((result) { - return afterUpdated - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.updated, - id: id, data: before.data, params: localParams, result: result)) - .then((after) => after.result as Data); - }); - }); - } - - @override - Future remove(Id id, [Map? params]) { - var localParams = _stripReq(params); - return beforeRemoved - ._emit(HookedServiceEvent(false, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.removed, - id: id, params: localParams)) - .then((before) { - if (before._canceled) { - return afterRemoved - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.removed, - id: id, params: localParams, result: before.result)) - .then((after) => after.result) as Data; - } - - return inner.remove(id, localParams).then((result) { - return afterRemoved - ._emit(HookedServiceEvent(true, _getRequest(params), - _getResponse(params), inner, HookedServiceEvent.removed, - id: id, params: localParams, result: result)) - .then((after) => after.result as Data); - }); - }); - } - - /// Fires an `after` event. This will not be propagated to clients, - /// but will be broadcasted to WebSockets, etc. - Future> fire(String eventName, result, - [HookedServiceEventListener? callback]) { - HookedServiceEventDispatcher dispatcher; - - switch (eventName) { - case HookedServiceEvent.indexed: - dispatcher = afterIndexed; - break; - case HookedServiceEvent.read: - dispatcher = afterRead; - break; - case HookedServiceEvent.created: - dispatcher = afterCreated; - break; - case HookedServiceEvent.modified: - dispatcher = afterModified; - break; - case HookedServiceEvent.updated: - dispatcher = afterUpdated; - break; - case HookedServiceEvent.removed: - dispatcher = afterRemoved; - break; - default: - throw ArgumentError("Invalid service event name: '$eventName'"); - } - - var ev = - HookedServiceEvent(true, null, null, inner, eventName); - return fireEvent(dispatcher, ev, callback); - } - - /// Sends an arbitrary event down the hook chain. - Future> fireEvent( - HookedServiceEventDispatcher dispatcher, - HookedServiceEvent event, - [HookedServiceEventListener? callback]) { - Future? f; - if (callback != null && event._canceled != true) { - f = Future.sync(() => callback(event)); - } - f ??= Future.value(); - return f.then((_) => dispatcher._emit(event)); - } -} - -/// Fired when a hooked service is invoked. -class HookedServiceEvent> { - static const String indexed = 'indexed'; - static const String read = 'read'; - static const String created = 'created'; - static const String modified = 'modified'; - static const String updated = 'updated'; - static const String removed = 'removed'; - - static const List all = [ - indexed, - read, - created, - modified, - updated, - removed - ]; - - /// Use this to end processing of an event. - void cancel([result]) { - _canceled = true; - this.result = result ?? this.result; - } - - /// Resolves a service from the application. - /// - /// Shorthand for `e.service.app.service(...)`. - Service? getService(Pattern path) => service.app.findService(path); - - bool _canceled = false; - final String _eventName; - Id? _id; - final bool _isAfter; - Data? data; - Map? _params; - final RequestContext? _request; - final ResponseContext? _response; - dynamic result; - - String get eventName => _eventName; - - Id? get id => _id; - - bool get isAfter => _isAfter == true; - - bool get isBefore => !isAfter; - - Map get params => _params ?? {}; - - RequestContext? get request => _request; - - ResponseContext? get response => _response; - - /// The inner service whose method was hooked. - T service; - - HookedServiceEvent(this._isAfter, this._request, this._response, this.service, - this._eventName, - {Id? id, this.data, Map? params, this.result}) { - //_data = data; - _id = id; - _params = params ?? {}; - } -} - -/// Triggered on a hooked service event. -typedef HookedServiceEventListener> - = FutureOr Function(HookedServiceEvent event); - -/// Can be listened to, but events may be canceled. -class HookedServiceEventDispatcher> { - final List>> _ctrl = []; - final List> listeners = []; - - void _close() { - for (var c in _ctrl) { - c.close(); - } - listeners.clear(); - } - - /// Fires an event, and returns it once it is either canceled, or all listeners have run. - Future> _emit( - HookedServiceEvent event) { - if (event._canceled == true || listeners.isEmpty) { - return Future.value(event); - } - - var f = Future>.value(event); - - for (var listener in listeners) { - f = f.then((event) { - if (event._canceled) return event; - return Future.sync(() => listener(event)).then((_) => event); - }); - } - - return f; - } - - /// Returns a [Stream] containing all events fired by this dispatcher. - /// - /// *NOTE*: Callbacks on the returned [Stream] cannot be guaranteed to run before other [listeners]. - /// Use this only if you need a read-only stream of events. - Stream> asStream() { - var ctrl = StreamController>(); - _ctrl.add(ctrl); - listen(ctrl.add); - return ctrl.stream; - } - - /// Registers the listener to be called whenever an event is triggered. - void listen(HookedServiceEventListener listener) { - listeners.add(listener); - } -} diff --git a/packages/core/lib/src/core/hostname_parser.dart b/packages/core/lib/src/core/hostname_parser.dart deleted file mode 100644 index 02abf1e..0000000 --- a/packages/core/lib/src/core/hostname_parser.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'dart:collection'; -import 'package:string_scanner/string_scanner.dart'; - -/// Parses a string into a [RegExp] that is matched against hostnames. -class HostnameSyntaxParser { - final SpanScanner _scanner; - final _safe = RegExp(r'[0-9a-zA-Z-_:]+'); - - HostnameSyntaxParser(String hostname) - : _scanner = SpanScanner(hostname, sourceUrl: hostname); - - FormatException _formatExc(String message) { - var span = _scanner.lastSpan ?? _scanner.emptySpan; - return FormatException( - '${span.start.toolString}: $message\n${span.highlight(color: true)}'); - } - - RegExp parse() { - var b = StringBuffer(); - var parts = Queue(); - - while (!_scanner.isDone) { - if (_scanner.scan('|')) { - if (parts.isEmpty) { - throw _formatExc('No hostname parts found before "|".'); - } else { - var next = _parseHostnamePart(); - if (next.isEmpty) { - throw _formatExc('No hostname parts found after "|".'); - } else { - var prev = parts.removeLast(); - parts.addLast('(($prev)|($next))'); - } - } - } else { - var part = _parseHostnamePart(); - if (part.isNotEmpty) { - if (_scanner.scan('.')) { - var subPart = _parseHostnamePart(shouldThrow: false); - while (subPart.isNotEmpty) { - part += '\\.$subPart'; - if (_scanner.scan('.')) { - subPart = _parseHostnamePart(shouldThrow: false); - } else { - break; - } - } - } - parts.add(part); - } - } - } - - while (parts.isNotEmpty) { - b.write(parts.removeFirst()); - } - - if (b.isEmpty) { - throw _formatExc('Invalid or empty hostname.'); - } else { - return RegExp('^$b\$', caseSensitive: false); - } - } - - String _parseHostnamePart({bool shouldThrow = true}) { - if (_scanner.scan('*.')) { - return r'([^$.]+\.)?'; - } else if (_scanner.scan('*')) { - return r'[^$]*'; - } else if (_scanner.scan('+')) { - return r'[^$]+'; - } else if (_scanner.scan(_safe)) { - return _scanner.lastMatch?[0] ?? ''; - } else if (!_scanner.isDone && shouldThrow) { - var s = String.fromCharCode(_scanner.peekChar()!); - throw _formatExc('Unexpected character "$s".'); - } else { - return ''; - } - } -} diff --git a/packages/core/lib/src/core/hostname_router.dart b/packages/core/lib/src/core/hostname_router.dart deleted file mode 100644 index 9b7e121..0000000 --- a/packages/core/lib/src/core/hostname_router.dart +++ /dev/null @@ -1,117 +0,0 @@ -import 'dart:async'; -import 'package:platform_container/container.dart'; -import 'package:platform_route/route.dart'; -import 'package:logging/logging.dart'; -import 'env.dart'; -import 'hostname_parser.dart'; -import 'request_context.dart'; -import 'response_context.dart'; -import 'routable.dart'; -import 'server.dart'; - -/// A utility that allows requests to be handled based on their -/// origin's hostname. -/// -/// For example, an application could handle example.com and api.example.com -/// separately. -/// -/// The provided patterns can be any `Pattern`. If a `String` is provided, a simple -/// grammar (see [HostnameSyntaxParser]) is used to create [RegExp]. -/// -/// For example: -/// * `example.com` -> `/example\.com/` -/// * `*.example.com` -> `/([^$.]\.)?example\.com/` -/// * `example.*` -> `/example\./[^$]*` -/// * `example.+` -> `/example\./[^$]+` -class HostnameRouter { - final Map _apps = {}; - final Map Function()> _creators = {}; - final List _patterns = []; - - HostnameRouter( - {Map apps = const {}, - Map Function()> creators = const {}}) { - Map parseMap(Map map) { - return map.map((p, c) { - Pattern pp; - - if (p is String) { - pp = HostnameSyntaxParser(p).parse(); - } else { - pp = p; - } - - return MapEntry(pp, c); - }); - } - - apps = parseMap(apps); - creators = parseMap(creators); - var patterns = apps.keys.followedBy(creators.keys).toSet().toList(); - _apps.addAll(apps); - _creators.addAll(creators); - _patterns.addAll(patterns); - // print(_creators); - } - - factory HostnameRouter.configure( - Map Function(Application)> configurers, - {Reflector reflector = const EmptyReflector(), - ProtevusEnvironment environment = protevusEnv, - Logger? logger, - bool allowMethodOverrides = true, - FutureOr Function(dynamic)? serializer, - ViewGenerator? viewGenerator}) { - var creators = configurers.map((p, c) { - return MapEntry(p, () async { - var app = Application( - reflector: reflector, - environment: environment, - logger: logger, - allowMethodOverrides: allowMethodOverrides, - serializer: serializer, - viewGenerator: viewGenerator); - await app.configure(c); - return app; - }); - }); - return HostnameRouter(creators: creators); - } - - /// Attempts to handle a request, according to its hostname. - /// - /// If none is matched, then `true` is returned. - /// Also returns `true` if all of the sub-app's handlers returned - /// `true`. - Future handleRequest(RequestContext req, ResponseContext res) async { - for (var pattern in _patterns) { - // print('${req.hostname} vs $_creators'); - if (pattern.allMatches(req.hostname).isNotEmpty) { - // Resolve the entire pipeline within the context of the selected app. - var app = _apps[pattern] ??= (await _creators[pattern]!()); - // print('App for ${req.hostname} = $app from $pattern'); - // app.dumpTree(); - - var r = app.optimizedRouter; - var resolved = r.resolveAbsolute(req.path, method: req.method); - var pipeline = MiddlewarePipeline(resolved); - // print('Pipeline: $pipeline'); - for (var handler in pipeline.handlers) { - // print(handler); - // Avoid stack overflow. - if (handler == handleRequest) { - continue; - } else if (!await app.executeHandler(handler, req, res)) { - // print('$handler TERMINATED'); - return false; - } else { - // print('$handler CONTINUED'); - } - } - } - } - - // Otherwise, return true. - return true; - } -} diff --git a/packages/core/lib/src/core/injection.dart b/packages/core/lib/src/core/injection.dart deleted file mode 100644 index eb4a0b0..0000000 --- a/packages/core/lib/src/core/injection.dart +++ /dev/null @@ -1,208 +0,0 @@ -part of 'request_context.dart'; - -const List _primitiveTypes = [String, int, num, double, Null]; - -/// Shortcut for calling [preInject], and then [handleContained]. -/// -/// Use this to instantly create a request handler for a DI-enabled method. -/// -/// Calling [ioc] also auto-serializes the result of a [handler]. -RequestHandler ioc(Function handler, {Iterable optional = const []}) { - return (req, res) { - RequestHandler? contained; - - if (req.app?.container != null) { - var injection = preInject(handler, req.app!.container.reflector); - //if (injection != null) { - injection.optional.addAll(optional); - contained = handleContained(handler, injection); - //} - } - - return req.app!.executeHandler(contained, req, res); - }; -} - -Future resolveInjection(requirement, InjectionRequest injection, - RequestContext req, ResponseContext res, bool throwOnUnresolved, - [Container? container]) async { - dynamic propFromApp; - container ??= req.container ?? res.app!.container; - - if (requirement == RequestContext) { - return req; - } else if (requirement == ResponseContext) { - return res; - } else if (requirement is String && - injection.parameters.containsKey(requirement)) { - var param = injection.parameters[requirement]!; - var value = param.getValue(req); - if (value == null && param.required != false) throw param.error as Object; - return value; - } else if (requirement is String) { - if (req.container!.hasNamed(requirement)) { - return req.container!.findByName(requirement); - } - if (req.params.containsKey(requirement)) { - return req.params[requirement]; - } else if ((propFromApp = req.app!.findProperty(requirement)) != null) { - return propFromApp; - } else if (injection.optional.contains(requirement)) { - return null; - } else if (throwOnUnresolved) { - throw ArgumentError( - "Cannot resolve parameter '$requirement' within handler."); - } - } else if (requirement is List && - requirement.length == 2 && - requirement.first is String && - requirement.last is Type) { - var key = requirement.first; - var type = requirement.last; - if (req.params.containsKey(key) || - req.app!.configuration.containsKey(key) || - _primitiveTypes.contains(type)) { - return await resolveInjection( - key, injection, req, res, throwOnUnresolved, container); - } else { - return await resolveInjection( - type, injection, req, res, throwOnUnresolved, container); - } - } else if (requirement is Type && requirement != dynamic) { - try { - var futureType = container.reflector.reflectFutureOf(requirement); - if (container.has(futureType.reflectedType)) { - return await container.make(futureType.reflectedType); - } - } on UnsupportedError { - // Ignore. - } - - return await container.make(requirement); - } else if (throwOnUnresolved) { - throw ArgumentError( - '$requirement cannot be injected into a request handler.'); - } -} - -/// Checks if an [InjectionRequest] can be sufficiently executed within the current request/response context. -bool suitableForInjection( - RequestContext req, ResponseContext res, InjectionRequest injection) { - return injection.parameters.values.any((p) { - if (p.match == null) return false; - var value = p.getValue(req); - return value == p.match; - }); -} - -/// Handles a request with a DI-enabled handler. -RequestHandler handleContained(Function handler, InjectionRequest injection, - [Container? container]) { - return (RequestContext req, ResponseContext res) async { - if (injection.parameters.isNotEmpty && - injection.parameters.values.any((p) => p.match != null) && - !suitableForInjection(req, res, injection)) { - return Future.value(true); - } - - var args = []; - - var named = {}; - - for (var r in injection.required) { - args.add(await resolveInjection(r, injection, req, res, true, container)); - } - - for (var entry in injection.named.entries) { - var name = Symbol(entry.key); - named[name] = await resolveInjection( - [entry.key, entry.value], injection, req, res, false, container); - } - - return Function.apply(handler, args, named); - }; -} - -/// Contains a list of the data required for a DI-enabled method to run. -/// -/// This improves performance by removing the necessity to reflect a method -/// every time it is requested. -/// -/// Regular request handlers can also skip DI entirely, lowering response time -/// and memory use. -class InjectionRequest { - /// Optional, typed data that can be passed to a DI-enabled method. - final Map named; - - /// A list of the arguments required for a DI-enabled method to run. - final List required; - - /// A list of the arguments that can be null in a DI-enabled method. - final List optional; - - /// Extended parameter definitions. - final Map parameters; - - const InjectionRequest.constant( - {this.named = const {}, - this.required = const [], - this.optional = const [], - this.parameters = const {}}); - - InjectionRequest() - : named = {}, - required = [], - optional = [], - parameters = {}; -} - -/// Predetermines what needs to be injected for a handler to run. -InjectionRequest preInject(Function handler, Reflector reflector) { - var injection = InjectionRequest(); - - var closureMirror = reflector.reflectFunction(handler)!; - - if (closureMirror.parameters.isEmpty) return injection; - - // Load parameters - for (var parameter in closureMirror.parameters) { - var name = parameter.name; - var type = parameter.type.reflectedType; - - var p = parameter.annotations - .firstWhereOrNull( - (m) => m.type.isAssignableTo(reflector.reflectType(Parameter))) - ?.reflectee as Parameter?; - //print(p); - if (p != null) { - injection.parameters[name] = Parameter( - cookie: p.cookie, - header: p.header, - query: p.query, - session: p.session, - match: p.match, - defaultValue: p.defaultValue, - required: parameter.isNamed ? false : p.required != false, - ); - } - - if (!parameter.isNamed) { - if (!parameter.isRequired) injection.optional.add(name); - - if (type == RequestContext || type == ResponseContext) { - injection.required.add(type); - } else if (name == 'req') { - injection.required.add(RequestContext); - } else if (name == 'res') { - injection.required.add(ResponseContext); - } else if (type == dynamic) { - injection.required.add(name); - } else { - injection.required.add([name, type]); - } - } else { - injection.named[name] = type; - } - } - return injection; -} diff --git a/packages/core/lib/src/core/map_service.dart b/packages/core/lib/src/core/map_service.dart deleted file mode 100644 index 2e018b3..0000000 --- a/packages/core/lib/src/core/map_service.dart +++ /dev/null @@ -1,172 +0,0 @@ -import 'dart:async'; - -import 'package:platform_support/exceptions.dart'; - -import 'service.dart'; - -/// A basic service that manages an in-memory list of maps. -class MapService extends Service> { - /// If set to `true`, clients can remove all items by passing a `null` `id` to `remove`. - /// - /// `false` by default. - final bool allowRemoveAll; - - /// If set to `true`, parameters in `req.query` are applied to the database query. - final bool allowQuery; - - /// If set to `true` (default), then the service will manage an `id` string and `createdAt` and `updatedAt` fields. - final bool autoIdAndDateFields; - - /// If set to `true` (default), then the keys `created_at` and `updated_at` will automatically be snake_cased. - final bool autoSnakeCaseNames; - - final List> items = []; - - MapService( - {this.allowRemoveAll = false, - this.allowQuery = true, - this.autoIdAndDateFields = true, - this.autoSnakeCaseNames = true}) - : super(); - - String get createdAtKey => - autoSnakeCaseNames == false ? 'createdAt' : 'created_at'; - - String get updatedAtKey => - autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'; - - bool Function(Map) _matchesId(id) { - return (Map item) { - if (item['id'] == null) { - return false; - } else if (autoIdAndDateFields != false) { - return item['id'] == id?.toString(); - } else { - return item['id'] == id; - } - }; - } - - @override - Future>> index([Map? params]) { - if (allowQuery == false || params == null || params['query'] is! Map) { - return Future.value(items); - } else { - var query = params['query'] as Map?; - - return Future.value(items.where((item) { - for (var key in query!.keys) { - if (!item.containsKey(key)) { - return false; - } else if (item[key] != query[key]) { - return false; - } - } - - return true; - }).toList()); - } - } - - @override - Future> read(String? id, - [Map? params]) { - return Future.value(items.firstWhere(_matchesId(id), - orElse: (() => throw PlatformHttpException.notFound( - message: 'No record found for ID $id')))); - } - - @override - Future> create(Map data, - [Map? params]) { - var now = DateTime.now().toIso8601String(); - var result = Map.from(data); - - if (autoIdAndDateFields == true) { - result - ..['id'] = items.length.toString() - ..[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] = now - ..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = now; - } - items.add(result); - return Future.value(result); - } - - @override - Future> modify(String? id, Map data, - [Map? params]) { - //if (data is! Map) { - // throw HttpException.badRequest( - // message: - // 'MapService does not support `modify` with ${data.runtimeType}.'); - //} - if (!items.any(_matchesId(id))) return create(data, params); - - return read(id).then((item) { - var idx = items.indexOf(item); - if (idx < 0) return create(data, params); - var result = Map.from(item)..addAll(data); - - if (autoIdAndDateFields == true) { - result[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = - DateTime.now().toIso8601String(); - } - return Future.value(items[idx] = result); - }); - } - - @override - Future> update(String? id, Map data, - [Map? params]) { - //if (data is! Map) { - // throw HttpException.badRequest( - // message: - // 'MapService does not support `update` with ${data.runtimeType}.'); - //} - if (!items.any(_matchesId(id))) return create(data, params); - - return read(id).then((old) { - if (!items.remove(old)) { - throw PlatformHttpException.notFound( - message: 'No record found for ID $id'); - } - - var result = Map.from(data); - if (autoIdAndDateFields == true) { - result - ..['id'] = id?.toString() - ..[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] = - old[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] - ..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = - DateTime.now().toIso8601String(); - } - items.add(result); - return Future.value(result); - }); - } - - @override - Future> remove(String? id, - [Map? params]) { - if (id == null || id == 'null') { - // Remove everything... - if (!(allowRemoveAll == true || - params?.containsKey('provider') != true)) { - throw PlatformHttpException.forbidden( - message: 'Clients are not allowed to delete all items.'); - } else { - items.clear(); - return Future.value({}); - } - } - - return read(id, params).then((result) { - if (items.remove(result)) { - return result; - } else { - throw PlatformHttpException.notFound( - message: 'No record found for ID $id'); - } - }); - } -} diff --git a/packages/core/lib/src/core/metadata.dart b/packages/core/lib/src/core/metadata.dart deleted file mode 100644 index 3ad4d11..0000000 --- a/packages/core/lib/src/core/metadata.dart +++ /dev/null @@ -1,166 +0,0 @@ -library angel_framework.http.metadata; - -import 'package:platform_support/exceptions.dart'; - -import 'hooked_service.dart' show HookedServiceEventListener; -import 'request_context.dart'; -import 'routable.dart'; - -/// Annotation to map middleware onto a handler. -class Middleware { - final Iterable handlers; - - const Middleware(this.handlers); -} - -/// Attaches hooks to a [HookedService]. -class Hooks { - final List before; - final List after; - - const Hooks({this.before = const [], this.after = const []}); -} - -/// Specifies to NOT expose a method to the Internet. -class NoExpose { - const NoExpose(); -} - -const NoExpose noExpose = NoExpose(); - -/// Exposes a [Controller] or a [Controller] method to the Internet. -/// Example: -/// -/// ```dart -/// @Expose('/elements') -/// class ElementController extends Controller { -/// -/// @Expose('/') -/// List getList() => someComputationHere(); -/// -/// @Expose('/int:elementId') -/// getElement(int elementId) => someOtherComputation(); -/// -/// } -/// ``` -class Expose { - final String method; - final String path; - final Iterable middleware; - final String? as; - final List allowNull; - - static const Expose get = Expose('', method: 'GET'), - post = Expose('', method: 'POST'), - patch = Expose('', method: 'PATCH'), - put = Expose('', method: 'PUT'), - delete = Expose('', method: 'DELETE'), - head = Expose('', method: 'HEAD'); - - const Expose(this.path, - {this.method = 'GET', - this.middleware = const [], - this.as, - this.allowNull = const []}); - - const Expose.method(this.method, - {this.middleware = const [], this.as, this.allowNull = const []}) - : path = ''; -} - -/// Used to apply special dependency injections or functionality to a function parameter. -class Parameter { - /// Inject the value of a request cookie. - final String? cookie; - - /// Inject the value of a request header. - final String? header; - - /// Inject the value of a key from the session. - final String? session; - - /// Inject the value of a key from the query. - final String? query; - - /// Only execute the handler if the value of this parameter matches the given value. - final dynamic match; - - /// Specify a default value. - final dynamic defaultValue; - - /// If `true` (default), then an error will be thrown if this parameter is not present. - final bool required; - - const Parameter( - {this.cookie, - this.query, - this.header, - this.session, - this.match, - this.defaultValue, - this.required = true}); - - /// Returns an error that can be thrown when the parameter is not present. - Object? get error { - if (cookie?.isNotEmpty == true) { - return PlatformHttpException.badRequest( - message: 'Missing required cookie "$cookie".'); - } - if (header?.isNotEmpty == true) { - return PlatformHttpException.badRequest( - message: 'Missing required header "$header".'); - } - if (query?.isNotEmpty == true) { - return PlatformHttpException.badRequest( - message: 'Missing required query parameter "$query".'); - } - if (session?.isNotEmpty == true) { - return StateError('Session does not contain required key "$session".'); - } - - return null; - } - - /// Obtains a value for this parameter from a [RequestContext]. - dynamic getValue(RequestContext req) { - if (cookie?.isNotEmpty == true) { - return req.cookies.firstWhere((c) => c.name == cookie).value; - } - if (header?.isNotEmpty == true) { - return req.headers?.value(header ?? '') ?? defaultValue; - } - if (session?.isNotEmpty == true) { - return req.session?[session] ?? defaultValue; - } - if (query?.isNotEmpty == true) { - return req.uri?.queryParameters[query] ?? defaultValue; - } - return defaultValue; - } -} - -/// Shortcut for declaring a request header [Parameter]. -class Header extends Parameter { - const Header(String header, {super.match, super.defaultValue, super.required}) - : super(header: header); -} - -/// Shortcut for declaring a request session [Parameter]. -class Session extends Parameter { - const Session(String session, - {super.match, super.defaultValue, super.required}) - : super(session: session); -} - -/// Shortcut for declaring a request query [Parameter]. -class Query extends Parameter { - const Query(String query, {super.match, super.defaultValue, super.required}) - : super(query: query); -} - -/// Shortcut for declaring a request cookie [Parameter]. -class CookieValue extends Parameter { - const CookieValue(String cookie, - {super.match, super.defaultValue, super.required}) - : super(cookie: cookie); -} diff --git a/packages/core/lib/src/core/request_context.dart b/packages/core/lib/src/core/request_context.dart deleted file mode 100644 index 5bc3603..0000000 --- a/packages/core/lib/src/core/request_context.dart +++ /dev/null @@ -1,382 +0,0 @@ -library Protevus_framework.http.request_context; - -import 'dart:async'; -import 'dart:convert'; -import 'dart:typed_data' show BytesBuilder; -import 'dart:io' - show Cookie, HeaderValue, HttpHeaders, HttpSession, InternetAddress; - -import 'package:platform_container/container.dart'; -import 'package:http_parser/http_parser.dart'; -import 'package:belatuk_http_server/belatuk_http_server.dart'; -import 'package:meta/meta.dart'; -import 'package:mime/mime.dart'; -import 'package:path/path.dart' as p; -import 'package:collection/collection.dart'; -import 'package:logging/logging.dart'; - -import 'metadata.dart'; -import 'response_context.dart'; -import 'routable.dart'; -import 'server.dart' show Application; - -part 'injection.dart'; - -/// A convenience wrapper around an incoming [RawRequest]. -abstract class RequestContext { - /// Similar to [Application.shutdownHooks], allows for logic to be executed - /// when a [RequestContext] is done being processed. - final _log = Logger('RequestContext'); - - final List Function()> shutdownHooks = []; - - String? _acceptHeaderCache, _extensionCache; - bool? _acceptsAllCache; - Map? _queryParameters; - Object? _bodyObject; - bool _hasParsedBody = false, _closed = false; - Map _bodyFields = {}; - List _bodyList = []; - List _uploadedFiles = []; - MediaType _contentType = MediaType('text', 'plain'); - - /// The underlying [RawRequest] provided by the driver. - RawRequest get rawRequest; - - /// Additional params to be passed to services. - final Map serviceParams = {}; - - /// The [Application] instance that is responding to this request. - Application? app; - - /// Any cookies sent with this request. - List get cookies => []; - - /// All HTTP headers sent with this request. - HttpHeaders? get headers; - - /// The requested hostname. - String get hostname => 'localhost'; - - /// The IoC container that can be used to provide functionality to produce - /// objects of a given type. - /// - /// This is a *child* of the container found in `app`. - Container? get container; - - /// The user's IP. - String get ip => remoteAddress.address; - - /// This request's HTTP method. - /// - /// This may have been processed by an override. See [originalMethod] to get the real method. - String get method => 'GET'; - - /// The original HTTP verb sent to the server. - String get originalMethod => 'GET'; - - /// The content type of an incoming request. - MediaType get contentType { - if (headers?.contentType != null) { - try { - _contentType = MediaType.parse(headers!.contentType.toString()); - } catch (e) { - _log.warning( - 'Invalid media type [${headers!.contentType.toString()}]', e); - } - } - return _contentType; - } - - /// The URL parameters extracted from the request URI. - Map params = {}; - - /// The requested path. - String get path => ''; - - /// Is this an **XMLHttpRequest**? - bool get isXhr { - return headers?.value('X-Requested-With')?.trim().toLowerCase() == - 'xmlhttprequest'; - } - - /// The remote address requesting this resource. - InternetAddress get remoteAddress; - - /// The user's HTTP session. - HttpSession? get session; - - /// The [Uri] instance representing the path this request is responding to. - Uri? get uri; - - /// The [Stream] of incoming binary data sent from the client. - Stream>? get body; - - /// Returns `true` if [parseBody] has been called so far. - bool get hasParsedBody => _hasParsedBody; - - /// Returns a *mutable* [Map] of the fields parsed from the request [body]. - /// - /// Note that [parseBody] must be called first. - Map get bodyAsMap { - if (!hasParsedBody) { - throw StateError('The request body has not been parsed yet.'); - } - // else if (_bodyFields == null) { - // throw StateError('The request body, $_bodyObject, is not a Map.'); - //} - - return _bodyFields; - } - - /// This setter allows you to explicitly set the request body **exactly once**. - /// - /// Use this if the format of the body is not natively parsed by Protevus. - set bodyAsMap(Map? value) => bodyAsObject = value; - - /// Returns a *mutable* [List] parsed from the request [body]. - /// - /// Note that [parseBody] must be called first. - List? get bodyAsList { - if (!hasParsedBody) { - throw StateError('The request body has not been parsed yet.'); - // TODO: Relook at this - //} else if (_bodyList == null) { - } else if (_bodyList.isEmpty) { - throw StateError('The request body, $_bodyObject, is not a List.'); - } - - return _bodyList; - } - - /// This setter allows you to explicitly set the request body **exactly once**. - /// - /// Use this if the format of the body is not natively parsed by Protevus. - set bodyAsList(List? value) => bodyAsObject = value; - - /// Returns the parsed request body, whatever it may be (typically a [Map] or [List]). - /// - /// Note that [parseBody] must be called first. - Object? get bodyAsObject { - if (!hasParsedBody) { - throw StateError('The request body has not been parsed yet.'); - } - - return _bodyObject; - } - - /// This setter allows you to explicitly set the request body **exactly once**. - /// - /// Use this if the format of the body is not natively parsed by Protevus. - set bodyAsObject(value) { - if (_bodyObject != null) { - throw StateError( - 'The request body has already been parsed/set, and cannot be overwritten.'); - } else { - if (value is List) _bodyList = value; - if (value is Map) _bodyFields = value; - _bodyObject = value; - _hasParsedBody = true; - } - } - - /// Returns a *mutable* map of the files parsed from the request [body]. - /// - /// Note that [parseBody] must be called first. - List? get uploadedFiles { - if (!hasParsedBody) { - throw StateError('The request body has not been parsed yet.'); - } - - return _uploadedFiles; - } - - /// Returns a *mutable* map of the fields contained in the query. - Map get queryParameters => _queryParameters ??= - Map.from(uri?.queryParameters ?? {}); - - /// Returns the file extension of the requested path, if any. - /// - /// Includes the leading `.`, if there is one. - String get extension => _extensionCache ??= p.extension(uri?.path ?? ''); - - /// Returns `true` if the client's `Accept` header indicates that the given [contentType] is considered a valid response. - /// - /// You cannot provide a `null` [contentType]. - /// If the `Accept` header's value is `*/*`, this method will always return `true`. - /// To ignore the wildcard (`*/*`), pass [strict] as `true`. - /// - /// [contentType] can be either of the following: - /// * A [ContentType], in which case the `Accept` header will be compared against its `mimeType` property. - /// * Any other Dart value, in which case the `Accept` header will be compared against the result of a `toString()` call. - bool accepts(contentType, {bool strict = false}) { - var contentTypeString = contentType is MediaType - ? contentType.mimeType - : contentType?.toString(); - - // Change to assert - if (contentTypeString == null) { - _log.severe('RequestContext.accepts is null'); - throw ArgumentError( - 'RequestContext.accepts expects the `contentType` parameter to NOT be null.'); - } - - _acceptHeaderCache ??= headers?.value('accept'); - - if (_acceptHeaderCache == null) { - return true; - } else if (strict != true && _acceptHeaderCache!.contains('*/*')) { - return true; - } else { - return _acceptHeaderCache!.contains(contentTypeString); - } - } - - /// Returns as `true` if the client's `Accept` header indicates that it will accept any response content type. - bool get acceptsAll => _acceptsAllCache ??= accepts('*/*'); - - /// Shorthand for deserializing [bodyAsMap], using some transformer function [f]. - Future deserializeBody(FutureOr Function(Map?) f, - {Encoding encoding = utf8}) async { - await parseBody(encoding: encoding); - return await f(bodyAsMap); - } - - /// Shorthand for decoding [bodyAsMap], using some [codec]. - Future decodeBody(Codec codec, {Encoding encoding = utf8}) => - deserializeBody(codec.decode, encoding: encoding); - - /// Manually parses the request body, if it has not already been parsed. - Future parseBody({Encoding encoding = utf8}) async { - //if (contentType == null) { - // throw FormatException('Missing "content-type" header.'); - //} - - if (!_hasParsedBody) { - _hasParsedBody = true; - - var contentBody = body ?? Stream.empty(); - - if (contentType.type == 'application' && contentType.subtype == 'json') { - _uploadedFiles = []; - - var parsed = (_bodyObject = - await encoding.decoder.bind(contentBody).join().then(json.decode)); - - if (parsed is Map) { - _bodyFields = Map.from(parsed); - } else if (parsed is List) { - _bodyList = parsed; - } - } else if (contentType.type == 'application' && - contentType.subtype == 'x-www-form-urlencoded') { - _uploadedFiles = []; - var parsed = await encoding.decoder - .bind(contentBody) - .join() - .then((s) => Uri.splitQueryString(s, encoding: encoding)); - _bodyFields = Map.from(parsed); - } else if (contentType.type == 'multipart' && - contentType.subtype == 'form-data' && - contentType.parameters.containsKey('boundary')) { - var boundary = contentType.parameters['boundary'] ?? ''; - var transformer = MimeMultipartTransformer(boundary); - var parts = transformer.bind(contentBody).map((part) => - HttpMultipartFormData.parse(part, defaultEncoding: encoding)); - _bodyFields = {}; - _uploadedFiles = []; - - await for (var part in parts) { - if (part.isBinary) { - _uploadedFiles.add(UploadedFile(part)); - } else if (part.isText && - part.contentDisposition.parameters.containsKey('name')) { - // If there is no name, then don't parse it. - var key = part.contentDisposition.parameters['name']; - if (key != null) { - var value = await part.join(); - _bodyFields[key] = value; - } - } - } - } else { - _bodyFields = {}; - _uploadedFiles = []; - } - } - } - - /// Disposes of all resources. - @mustCallSuper - Future close() async { - if (!_closed) { - _closed = true; - _acceptsAllCache = null; - _acceptHeaderCache = null; - serviceParams.clear(); - params.clear(); - await Future.forEach(shutdownHooks, (dynamic hook) => hook()); - } - } -} - -/// Reads information about a binary chunk uploaded to the server. -class UploadedFile { - /// The underlying `form-data` item. - final HttpMultipartFormData formData; - final log = Logger('UploadedFile'); - - MediaType _contentType = MediaType('multipart', 'form-data'); - - UploadedFile(this.formData); - - /// Returns the binary stream from [formData]. - Stream> get data => formData.cast>(); - - /// The filename associated with the data on the user's system. - /// Returns [:null:] if not present. - String? get filename => formData.contentDisposition.parameters['filename']; - - /// The name of the field associated with this data. - /// Returns [:null:] if not present. - String? get name => formData.contentDisposition.parameters['name']; - - /// The parsed [:Content-Type:] header of the [:HttpMultipartFormData:]. - /// Returns [:null:] if not present. - //MediaType get contentType => _contentType ??= (formData.contentType == null - // ? null - // : MediaType.parse(formData.contentType.toString())); - - MediaType get contentType { - if (formData.contentType != null) { - try { - _contentType = MediaType.parse(formData.contentType.toString()); - } catch (e) { - log.warning( - 'Invalue media type [${formData.contentType.toString()}]', e); - } - } - - return _contentType; - } - - /// The parsed [:Content-Transfer-Encoding:] header of the - /// [:HttpMultipartFormData:]. This field is used to determine how to decode - /// the data. Returns [:null:] if not present. - HeaderValue? get contentTransferEncoding => formData.contentTransferEncoding; - - /// Reads the contents of the file into a single linear buffer. - /// - /// Note that this leads to holding the whole file in memory, which might - /// not be ideal for large files.w - Future> readAsBytes() { - return data - .fold(BytesBuilder(), (bb, out) => bb..add(out)) - .then((bb) => bb.takeBytes()); - } - - /// Reads the contents of the file as [String], using the given [encoding]. - Future readAsString({Encoding encoding = utf8}) { - return encoding.decoder.bind(data).join(); - } -} diff --git a/packages/core/lib/src/core/response_context.dart b/packages/core/lib/src/core/response_context.dart deleted file mode 100644 index 0ab77b6..0000000 --- a/packages/core/lib/src/core/response_context.dart +++ /dev/null @@ -1,456 +0,0 @@ -library platform_core.http.response_context; - -import 'dart:async'; -import 'dart:convert'; -import 'dart:convert' as c show json; -import 'dart:io' show BytesBuilder, Cookie; -import 'dart:typed_data'; - -import 'package:platform_route/route.dart'; -import 'package:file/file.dart'; -import 'package:http_parser/http_parser.dart'; -import 'package:mime/mime.dart'; - -import 'controller.dart'; -import 'request_context.dart'; -import 'server.dart' show Application; - -final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)'); - -/// A convenience wrapper around an outgoing HTTP request. -abstract class ResponseContext - implements StreamConsumer>, StreamSink>, StringSink { - final Map properties = {}; - final CaseInsensitiveMap _headers = CaseInsensitiveMap.from( - {'content-type': 'text/plain', 'server': 'Protevus3'}); - - //final log = Logger('ResponseContext'); - - Completer? _done; - int _statusCode = 200; - - /// The [Application] instance that is sending a response. - Application? app; - - /// Is `Transfer-Encoding` chunked? - bool? chunked; - - /// Any and all cookies to be sent to the user. - final List cookies = []; - - /// A set of [Converter] objects that can be used to encode response data. - /// - /// At most one encoder will ever be used to convert data. - final Map, List>> encoders = {}; - - /// A [Map] of data to inject when `res.render` is called. - /// - /// This can be used to reduce boilerplate when using templating engines. - final Map renderParams = {}; - - /// Points to the [RequestContext] corresponding to this response. - RequestContext? get correspondingRequest; - - @override - Future get done => (_done ?? Completer()).future; - - /// Headers that will be sent to the user. - /// - /// Note that if you have already started writing to the underlying stream, headers will not persist. - CaseInsensitiveMap get headers => _headers; - - /// Serializes response data into a String. - /// - /// The default is conversion into JSON via `json.encode`. - /// - /// If you are 100% sure that your response handlers will only - /// be JSON-encodable objects (i.e. primitives, `List`s and `Map`s), - /// then consider setting [serializer] to `JSON.encode`. - /// - /// To set it globally for the whole [app], use the following helper: - /// ```dart - /// app.injectSerializer(JSON.encode); - /// ``` - FutureOr Function(dynamic) serializer = c.json.encode; - - /// This response's status code. - int get statusCode => _statusCode; - - set statusCode(int value) { - if (!isOpen) { - throw closed(); - } else { - _statusCode = value; // ?? 200; - } - } - - /// Returns `true` if the response is still available for processing by Protevus. - /// - /// If it is `false`, then Protevus will stop executing handlers, and will only run - /// response finalizers if the response [isBuffered]. - bool get isOpen; - - /// Returns `true` if response data is being written to a buffer, rather than to the underlying stream. - bool get isBuffered; - - /// A set of UTF-8 encoded bytes that will be written to the response. - BytesBuilder? get buffer; - - /// The underlying [RawResponse] under this instance. - RawResponse get rawResponse; - - /// Signals Protevus that the response is being held alive deliberately, and that the framework should not automatically close it. - /// - /// This is mostly used in situations like WebSocket handlers, where the connection should remain - /// open indefinitely. - FutureOr detach(); - - /// Gets or sets the content length to send back to a client. - /// - /// Returns `null` if the header is invalidly formatted. - int? get contentLength { - return int.tryParse(headers['content-length'] ?? '-1'); - } - - /// Gets or sets the content length to send back to a client. - /// - /// If [value] is `null`, then the header will be removed. - set contentLength(int? value) { - if (value == null || value == -1) { - headers.remove('content-length'); - } else { - headers['content-length'] = value.toString(); - } - } - - /// Gets or sets the content type to send back to a client. - MediaType get contentType { - try { - return MediaType.parse(headers['content-type']!); - } catch (_) { - return MediaType('text', 'plain'); - } - } - - /// Gets or sets the content type to send back to a client. - set contentType(MediaType value) { - headers['content-type'] = value.toString(); - } - - static StateError closed() => StateError('Cannot modify a closed response.'); - - /// Sends a download as a response. - Future download(File file, {String? filename}) async { - if (!isOpen) throw closed(); - - headers['Content-Disposition'] = - 'attachment; filename="${filename ?? file.path}"'; - contentType = MediaType.parse(lookupMimeType(file.path)!); - headers['content-length'] = file.lengthSync().toString(); - - if (!isBuffered) { - await file.openRead().cast>().pipe(this); - } else { - buffer!.add(file.readAsBytesSync()); - await close(); - } - } - - /// Prevents more data from being written to the response, and locks it entire from further editing. - @override - Future close() { - if (buffer is LockableBytesBuilder) { - (buffer as LockableBytesBuilder).lock(); - } - - if (_done?.isCompleted == false) _done!.complete(); - return Future.value(); - } - - /// Serializes JSON to the response. - Future json(value) => - serialize(value, contentType: MediaType('application', 'json')); - - /// Returns a JSONP response. - /// - /// You can override the [contentType] sent; by default it is `application/javascript`. - Future jsonp(value, - {String callbackName = 'callback', MediaType? contentType}) { - if (!isOpen) throw closed(); - this.contentType = contentType ?? MediaType('application', 'javascript'); - write('$callbackName(${serializer(value)})'); - return close(); - } - - /// Renders a view to the response stream, and closes the response. - Future render(String view, [Map? data]) { - if (!isOpen) throw closed(); - contentType = MediaType('text', 'html', {'charset': 'utf-8'}); - return Future.sync(() => app!.viewGenerator!( - view, - Map.from(renderParams) - ..addAll(data ?? {}))).then((content) { - write(content); - return close(); - }); - } - - /// Redirects to user to the given URL. - /// - /// [url] can be a `String`, or a `List`. - /// If it is a `List`, a URI will be constructed - /// based on the provided params. - /// - /// See [Router]#navigate for more. :) - Future redirect(url, {bool absolute = true, int? code}) { - if (!isOpen) throw closed(); - headers - ..['content-type'] = 'text/html' - ..['location'] = (url is String || url is Uri) - ? url.toString() - : app!.navigate(url as Iterable, absolute: absolute); - statusCode = code ?? 302; - write(''' - - - - Redirecting... - - - -

Currently redirecting you...

-
- Click here if you are not automatically redirected... - - - - '''); - return close(); - } - - /// Redirects to the given named [Route]. - Future redirectTo(String name, [Map? params, int? code]) async { - if (!isOpen) throw closed(); - Route? findRoute(Router r) { - for (var route in r.routes) { - if (route is SymlinkRoute) { - final m = findRoute(route.router); - - if (m != null) return m; - } else if (route.name == name) { - return route; - } - } - - return null; - } - - var matched = findRoute(app!); - - if (matched != null) { - await redirect( - matched.makeUri(params!.keys.fold>({}, (out, k) { - return out..[k.toString()] = params[k]; - })), - code: code); - return; - } - - throw ArgumentError.notNull('Route to redirect to ($name)'); - } - - /// Redirects to the given [Controller] action. - Future redirectToAction(String action, [Map? params, int? code]) { - if (!isOpen) throw closed(); - // UserController@show - var split = action.split('@'); - - if (split.length < 2) { - throw Exception( - "Controller redirects must take the form of 'Controller@action'. You gave: $action"); - } - - var controller = app!.controllers[split[0].replaceAll(_straySlashes, '')]; - - if (controller == null) { - throw Exception("Could not find a controller named '${split[0]}'"); - } - - var matched = controller.routeMappings[split[1]]; - - if (matched == null) { - throw Exception( - "Controller '${split[0]}' does not contain any action named '${split[1]}'"); - } - - final head = controller - .findExpose(app!.container.reflector)! - .path - .toString() - .replaceAll(_straySlashes, ''); - var tail = ''; - if (params != null) { - tail = matched - .makeUri(params.keys.fold>({}, (out, k) { - return out..[k.toString()] = params[k]; - })) - .replaceAll(_straySlashes, ''); - } - return redirect('$head/$tail'.replaceAll(_straySlashes, ''), code: code); - } - - /// Serializes data to the response. - Future serialize(value, {MediaType? contentType}) async { - if (!isOpen) { - throw closed(); - } - this.contentType = contentType ?? MediaType('application', 'json'); - var text = await serializer(value); - if (text.isEmpty) return true; - write(text); - await close(); - return false; - } - - /// Streams a file to this response. - /// - /// `HEAD` responses will not actually write data. - Future streamFile(File file) async { - if (!isOpen) { - throw closed(); - } - var mimeType = app!.mimeTypeResolver.lookup(file.path); - contentLength = await file.length(); - contentType = mimeType == null - ? MediaType('application', 'octet-stream') - : MediaType.parse(mimeType); - - if (correspondingRequest!.method != 'HEAD') { - return addStream(file.openRead().cast>()).then((_) => close()); - } - } - - /// Configure the response to write to an intermediate response buffer, rather than to the stream directly. - void useBuffer(); - - /// Adds a stream directly the underlying response. - /// - /// If this instance has access to a [correspondingRequest], then it will attempt to transform - /// the content using at most one of the response [encoders]. - @override - Future addStream(Stream> stream); - - @override - void addError(Object error, [StackTrace? stackTrace]) { - if (_done?.isCompleted == false) { - _done!.completeError(error, stackTrace); - } else if (_done == null) { - if (stackTrace != null) { - Zone.current.handleUncaughtError(error, stackTrace); - } else { - app?.logger.warning('[ResponseContext] stackTrace is null'); - } - } - } - - /// Writes data to the response. - @override - void write(value, {Encoding? encoding}) { - encoding ??= utf8; - - if (!isOpen && isBuffered) { - throw closed(); - } else if (!isBuffered) { - add(encoding.encode(value.toString())); - } else { - buffer!.add(encoding.encode(value.toString())); - } - } - - @override - void writeCharCode(int charCode) { - if (!isOpen && isBuffered) { - throw closed(); - } else if (!isBuffered) { - add([charCode]); - } else { - buffer!.addByte(charCode); - } - } - - @override - void writeln([Object? obj = '']) { - write(obj.toString()); - write('\r\n'); - } - - @override - void writeAll(Iterable objects, [String separator = '']) { - write(objects.join(separator)); - } -} - -abstract class LockableBytesBuilder implements BytesBuilder { - factory LockableBytesBuilder() { - return _LockableBytesBuilderImpl(); - } - - void lock(); -} - -class _LockableBytesBuilderImpl implements LockableBytesBuilder { - final BytesBuilder _buf = BytesBuilder(copy: false); - bool _closed = false; - - StateError _deny() => - StateError('Cannot modified a closed response\'s buffer.'); - - @override - void lock() { - _closed = true; - } - - @override - void add(List bytes) { - if (_closed) { - throw _deny(); - } else { - _buf.add(bytes); - } - } - - @override - void addByte(int byte) { - if (_closed) { - throw _deny(); - } else { - _buf.addByte(byte); - } - } - - @override - void clear() { - _buf.clear(); - } - - @override - bool get isEmpty => _buf.isEmpty; - - @override - bool get isNotEmpty => _buf.isNotEmpty; - - @override - int get length => _buf.length; - - @override - Uint8List takeBytes() { - return _buf.takeBytes(); - } - - @override - Uint8List toBytes() { - return _buf.toBytes(); - } -} diff --git a/packages/core/lib/src/core/routable.dart b/packages/core/lib/src/core/routable.dart deleted file mode 100644 index e4a8598..0000000 --- a/packages/core/lib/src/core/routable.dart +++ /dev/null @@ -1,140 +0,0 @@ -library angel_framework.http.routable; - -import 'dart:async'; - -import 'package:platform_container/container.dart'; -import 'package:platform_route/route.dart'; - -import '../util.dart'; -import 'hooked_service.dart'; -import 'metadata.dart'; -import 'request_context.dart'; -import 'response_context.dart'; -import 'service.dart'; - -final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)'); - -/// A function that receives an incoming [RequestContext] and responds to it. -typedef RequestHandler = FutureOr Function( - RequestContext req, ResponseContext res); - -/// Sequentially runs a list of [handlers] of middleware, and returns early if any does not -/// return `true`. Works well with [Router].chain. -RequestHandler chain(Iterable handlers) { - return (req, res) { - Future Function()? runPipeline; - - for (var handler in handlers) { - //if (handler == null) break; - - if (runPipeline == null) { - runPipeline = () => Future.sync(() => handler(req, res)); - } else { - var current = runPipeline; - runPipeline = () => current().then((result) => !res.isOpen - ? Future.value(result) - : req.app!.executeHandler(handler, req, res)); - } - } - - runPipeline ??= () => Future.value(); - return runPipeline(); - }; -} - -/// A routable server that can handle dynamic requests. -class Routable extends Router { - final Map _services = {}; - final Map _serviceLookups = {}; - - /// A [Map] of application-specific data that can be accessed. - /// - /// Packages like `package:angel3_configuration` populate this map - /// for you. - final Map configuration = {}; - - final Container _container; - - Routable([Reflector? reflector]) -// : _container = reflector == null ? null : Container(reflector), - : _container = Container(reflector ?? ThrowingReflector()), - super(); - - /// A [Container] used to inject dependencies. - Container get container => _container; - - void close() { - _services.clear(); - configuration.clear(); - _onService.close(); - } - - /// A set of [Service] objects that have been mapped into routes. - Map get services => _services; - - final StreamController _onService = - StreamController.broadcast(); - - /// Fired whenever a service is added to this instance. - /// - /// **NOTE**: This is a broadcast stream. - Stream get onService => _onService.stream; - - /// Retrieves the service assigned to the given path. - T? findService(Pattern path) { - return _serviceLookups.putIfAbsent(path, () { - return _services[path] ?? - _services[path.toString().replaceAll(_straySlashes, '')]; - }) as T?; - } - - /// Shorthand for finding a [Service] in a statically-typed manner. - Service? findServiceOf(Pattern path) { - return findService>(path); - } - - /// Shorthand for finding a [HookedService] in a statically-typed manner. - HookedService? findHookedService( - Pattern path) { - return findService(path) as HookedService?; - } - - @override - Route addRoute( - String method, String path, RequestHandler handler, - {Iterable middleware = const {}}) { - final handlers = []; - // Merge @Middleware declaration, if any - var reflector = _container.reflector; - if (reflector is! ThrowingReflector) { - var middlewareDeclaration = - getAnnotation(handler, _container.reflector); - if (middlewareDeclaration != null) { - handlers.addAll(middlewareDeclaration.handlers); - } - } - - final handlerSequence = []; - handlerSequence.addAll(middleware); - handlerSequence.addAll(handlers); - - return super.addRoute(method, path.toString(), handler, - middleware: handlerSequence); - } - - /// Mounts a [service] at the given [path]. - /// - /// Returns a [HookedService] that can be used to hook into - /// events dispatched by this service. - HookedService use>( - String path, T service) { - var hooked = HookedService(service); - _services[path.toString().trim().replaceAll(RegExp(r'(^/+)|(/+$)'), '')] = - hooked; - hooked.addRoutes(); - mount(path.toString(), hooked); - service.onHooked(hooked); - _onService.add(hooked); - return hooked; - } -} diff --git a/packages/core/lib/src/core/server.dart b/packages/core/lib/src/core/server.dart deleted file mode 100644 index 37c682c..0000000 --- a/packages/core/lib/src/core/server.dart +++ /dev/null @@ -1,423 +0,0 @@ -library platform_core.http.server; - -import 'dart:async'; -import 'dart:collection' show HashMap; -import 'dart:convert'; -import 'package:platform_container/container.dart'; -import 'package:platform_support/exceptions.dart'; -import 'package:platform_route/route.dart'; -import 'package:belatuk_combinator/belatuk_combinator.dart'; -import 'package:http_parser/http_parser.dart'; -import 'package:logging/logging.dart'; -import 'package:mime/mime.dart'; -import 'package:tuple/tuple.dart'; -import 'controller.dart'; -import 'env.dart'; -import 'hooked_service.dart'; -import 'request_context.dart'; -import 'response_context.dart'; -import 'routable.dart'; -import 'service.dart'; - -//final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)'); - -/// A function that configures an [Application] server. -typedef PlatformConfigurer = FutureOr Function(Application app); - -/// A function that asynchronously generates a view from the given path and data. -typedef ViewGenerator = FutureOr Function(String path, - [Map? data]); - -/// A function that handles error -typedef PlatformErrorHandler = dynamic Function( - PlatformHttpException e, RequestContext req, ResponseContext res); - -/// The default error handler for [Application] server -Future _defaultErrorHandler( - PlatformHttpException e, RequestContext req, ResponseContext res) async { - if (!req.accepts('text/html', strict: true) && - (req.accepts('application/json') || - req.accepts('application/javascript'))) { - await res.json(e.toJson()); - return Future.value(false); - } else { - res.contentType = MediaType('text', 'html', {'charset': 'utf8'}); - res.statusCode = e.statusCode; - res.write('${e.message}'); - res.write('

${e.message}

    '); - - for (var error in e.errors) { - res.write('
  • $error
  • '); - } - - res.write('
'); - return Future.value(false); - } -} - -/// Default ROOT level logger -Logger _defaultLogger() { - Logger logger = Logger('ROOT') - ..onRecord.listen((rec) { - if (rec.error == null) { - print(rec.message); - } - - if (rec.error != null) { - var err = rec.error; - if (err is PlatformHttpException && err.statusCode != 500) return; - print('${rec.message} \n'); - print(rec.error); - if (rec.stackTrace != null) { - print(rec.stackTrace); - } - } - }); - - return logger; -} - -/// A powerful real-time/REST/MVC server class. -class Application extends Routable { - static Future _noViewEngineConfigured(String view, [Map? data]) => - Future.value('No view engine has been configured yet.'); - - final List _children = []; - final Map< - String, - Tuple4, ParseResult, - MiddlewarePipeline>> handlerCache = HashMap(); - - Router? _flattened; - Application? _parent; - - /// A global Map of converters that can transform responses bodies. - final Map, List>> encoders = {}; - - final Map _preContained = {}; - - /// A [MimeTypeResolver] that can be used to specify the MIME types of files not known by `package:mime`. - final MimeTypeResolver mimeTypeResolver = MimeTypeResolver(); - - /// A middleware to inject a serialize on every request. - FutureOr Function(dynamic)? serializer; - - /// A [Map] of dependency data obtained via reflection. - /// - /// You may modify this [Map] yourself if you intend to avoid reflection entirely. - Map get preContained => _preContained; - - /// Returns the [flatten]ed version of this router in production. - Router get optimizedRouter => _flattened ?? this; - - /// Determines whether to allow HTTP request method overrides. - bool allowMethodOverrides = true; - - /// All child application mounted on this instance. - List get children => List.unmodifiable(_children); - - final Map _controllers = {}; - - /// A set of [Controller] objects that have been loaded into the application. - Map get controllers => _controllers; - - /// The [ProtevusEnvironment] in which the application is running. - /// - /// By default, it is automatically inferred. - final ProtevusEnvironment environment; - - /// Returns the parent instance of this application, if any. - Application? get parent => _parent; - - /// Outputs diagnostics and debug messages. - Logger _logger = _defaultLogger(); - - Logger get logger => _logger; - - /// Assign a custom logger. - /// Passing null will reset to default logger - set logger(Logger? log) { - _logger.clearListeners(); - - _logger = log ?? _defaultLogger(); - } - - /// Plug-ins to be called right before server startup. - /// - /// If the server is never started, they will never be called. - final List startupHooks = []; - - /// Plug-ins to be called right before server shutdown. - /// - /// If the server is never [close]d, they will never be called. - final List shutdownHooks = []; - - /// Always run before responses are sent. - /// - /// These will only not run if a response's `willCloseItself` is set to `true`. - final List responseFinalizers = []; - - /// A function that renders views. - /// - /// Called by [ResponseContext]@`render`. - ViewGenerator? viewGenerator = _noViewEngineConfigured; - - /// The handler currently configured to run on [PlatformHttpException]s. - PlatformErrorHandler errorHandler = _defaultErrorHandler; - - @override - Route addRoute( - String method, String path, RequestHandler handler, - {Iterable middleware = const []}) { - if (_flattened != null) { - logger.warning( - 'WARNING: You added a route ($method $path) to the router, after it had been optimized.'); - logger.warning( - 'This route will be ignored, and no requests will ever reach it.'); - } - - return super.addRoute(method, path, handler, middleware: middleware); - } - - @override - SymlinkRoute mount( - String path, Router router) { - if (_flattened != null) { - logger.warning( - 'WARNING: You added mounted a child router ($path) on the router, after it had been optimized.'); - logger.warning( - 'This route will be ignored, and no requests will ever reach it.'); - } - - if (router is Application) { - router._parent = this; - _children.add(router); - } - - return super.mount(path.toString(), router); - } - - /// Loads some base dependencies into the service container. - void bootstrapContainer() { - if (runtimeType != Application) { - container.registerSingleton(this); - } - - container.registerSingleton(this); - container.registerSingleton(this); - container.registerSingleton(this); - } - - /// Shuts down the server, and closes any open [StreamController]s. - /// - /// The server will be **COMPLETELY DEFUNCT** after this operation! - @override - Future close() { - Future.forEach(services.values, (Service service) { - service.close(); - }); - - super.close(); - viewGenerator = _noViewEngineConfigured; - _preContained.clear(); - handlerCache.clear(); - encoders.clear(); - _children.clear(); - //_parent = null; - //logger = null; - //_flattened = null; - startupHooks.clear(); - shutdownHooks.clear(); - responseFinalizers.clear(); - return Future.value(); - } - - @override - void dumpTree( - {Function(String tree)? callback, - String header = 'Dumping route tree:', - String tab = ' ', - bool showMatchers = false}) { - if (environment.isProduction) { - _flattened ??= flatten(this); - - _flattened!.dumpTree( - callback: callback, - header: header.isNotEmpty == true - ? header - : (environment.isProduction - ? 'Dumping flattened route tree:' - : 'Dumping route tree:'), - tab: tab); - } else { - super.dumpTree( - callback: callback, - header: header.isNotEmpty == true - ? header - : (environment.isProduction - ? 'Dumping flattened route tree:' - : 'Dumping route tree:'), - tab: tab); - } - } - - Future getHandlerResult(handler, RequestContext req, ResponseContext res) { - if (handler is RequestHandler) { - var result = handler(req, res); - return getHandlerResult(result, req, res); - } - - if (handler is Future) { - return handler.then((result) => getHandlerResult(result, req, res)); - } - - if (handler is Function) { - var result = runContained(handler, req, res); - return getHandlerResult(result, req, res); - } - - if (handler is Stream) { - return getHandlerResult(handler.toList(), req, res); - } - - return Future.value(handler); - } - - /// Runs some [handler]. Returns `true` if request execution should continue. - Future executeHandler( - handler, RequestContext req, ResponseContext res) { - return getHandlerResult(handler, req, res).then((result) { - if (result == null) { - return false; - } else if (result is bool) { - return result; - } else if (result != null) { - return res.serialize(result); - } else { - return res.isOpen; - } - }); - } - - /// Attempts to find a property by the given name within this application. - dynamic findProperty(key) { - if (configuration.containsKey(key)) return configuration[key]; - - //return parent != null ? parent?.findProperty(key) : null; - if (parent != null) { - return parent?.findProperty(key); - } - - return null; - } - - /// Runs several optimizations, *if* [protevusEnv.isProduction] is `true`. - /// - /// * Preprocesses all dependency injection, and eliminates the burden of reflecting handlers - /// at run-time. - /// * [flatten]s the route tree into a linear one. - /// - /// You may [force] the optimization to run, if you are not running in production. - void optimizeForProduction({bool force = false}) { - if (environment.isProduction || force == true) { - _flattened ??= flatten(this); - logger.info('Protevus is running in production mode.'); - } - } - - /// Run a function after injecting from service container. - /// If this function has been reflected before, then - /// the execution will be faster, as the injection requirements were stored beforehand. - Future runContained(Function handler, RequestContext req, ResponseContext res, - [Container? container]) { - container ??= Container(EmptyReflector()); - return Future.sync(() { - if (_preContained.containsKey(handler)) { - return handleContained(handler, _preContained[handler]!, container)( - req, res); - } - - return runReflected(handler, req, res, container); - }); - } - - /// Runs with DI, and *always* reflects. Prefer [runContained]. - Future runReflected(Function handler, RequestContext req, ResponseContext res, - [Container? container]) { - container ??= - req.container ?? res.app?.container ?? Container(EmptyReflector()); - - if (container.reflector is EmptyReflector) { - throw ArgumentError("No `reflector` passed"); - } - var h = handleContained( - handler, - _preContained[handler] = preInject(handler, container.reflector), - container); - return Future.sync(() => h(req, res)); - // return closureMirror.apply(args).reflectee; - } - - /// Applies an [PlatformConfigurer] to this instance. - Future configure(PlatformConfigurer configurer) { - return Future.sync(() => configurer(this)); - } - - /// Shorthand for using the [container] to instantiate, and then mount a [Controller]. - /// Returns the created controller. - /// - /// Just like [Container].make, in contexts without properly-reified generics (dev releases of Dart 2), - /// provide a [type] argument as well. - /// - /// If you are on `Dart >=2.0.0`, simply call `mountController()`. - Future mountController([Type? type]) { - var controller = container.make(type); - return configure(controller.configureServer).then((_) => controller); - } - - /// Shorthand for calling `all('*', handler)`. - Route fallback(RequestHandler handler) { - return all('*', handler); - } - - @override - HookedService use>( - String path, T service) { - service.app = this; - return super.use(path, service)..app = this; - } - - static const String _reflectionErrorMessage = - '${ContainerConst.defaultErrorMessage} $_reflectionInfo'; - - static const String _reflectionInfo = - 'Features like controllers, constructor dependency injection, and `ioc` require reflection, ' - 'and will not work without it.\n\n' - 'For more, see the documentation:\n' - 'https://docs.angel-dart.dev/guides/dependency-injection#enabling-dart-mirrors-or-other-reflection'; - - Application( - {Reflector reflector = - const ThrowingReflector(errorMessage: _reflectionErrorMessage), - this.environment = protevusEnv, - Logger? logger, - this.allowMethodOverrides = true, - this.serializer, - this.viewGenerator}) - : super(reflector) { - // Override default logger - if (logger != null) { - this.logger = logger; - } - - if (reflector is EmptyReflector || reflector is ThrowingReflector) { - var msg = - 'No `reflector` was passed to the Protevus constructor, so reflection will not be available.\n$_reflectionInfo'; - this.logger.warning(msg); - } - - bootstrapContainer(); - viewGenerator ??= _noViewEngineConfigured; - serializer ??= json.encode; - } -} diff --git a/packages/core/lib/src/core/service.dart b/packages/core/lib/src/core/service.dart deleted file mode 100644 index 894c96e..0000000 --- a/packages/core/lib/src/core/service.dart +++ /dev/null @@ -1,380 +0,0 @@ -library platform_core.http.service; - -import 'dart:async'; -import 'package:platform_support/exceptions.dart'; -import 'package:belatuk_merge_map/belatuk_merge_map.dart'; -import 'package:quiver/core.dart'; -import '../util.dart'; -import 'anonymous_service.dart'; -import 'hooked_service.dart' show HookedService; -import 'metadata.dart'; -import 'request_context.dart'; -import 'response_context.dart'; -import 'routable.dart'; -import 'server.dart'; - -/// Indicates how the service was accessed. -/// -/// This will be passed to the `params` object in a service method. -/// When requested on the server side, this will be null. -class Providers { - /// The transport through which the client is accessing this service. - final String via; - - const Providers(this.via); - - static const String viaRest = 'rest'; - static const String viaWebsocket = 'websocket'; - static const String viaGraphQL = 'graphql'; - - /// Represents a request via REST. - static const Providers rest = Providers(viaRest); - - /// Represents a request over WebSockets. - static const Providers websocket = Providers(viaWebsocket); - - /// Represents a request parsed from GraphQL. - static const Providers graphQL = Providers(viaGraphQL); - - @override - int get hashCode => hashObjects([via]); - - @override - bool operator ==(other) => other is Providers && other.via == via; - - Map toJson() { - return {'via': via}; - } - - @override - String toString() { - return 'via:$via'; - } -} - -/// A front-facing interface that can present data to and operate on data on behalf of the user. -/// -/// Heavily inspired by FeathersJS. <3 -class Service extends Routable { - /// A [List] of keys that services should ignore, should they see them in the query. - static const List specialQueryKeys = [ - r'$limit', - r'$sort', - 'page', - 'token' - ]; - - /// Handlers that must run to ensure this service's functionality. - List get bootstrappers => []; - - /// The [Application] app powering this service. - Application? _app; - - Application get app { - if (_app == null) { - throw ArgumentError("Protevus is not initialized"); - } - return _app!; - } - - set app(Application protevus) { - _app = protevus; - } - - bool get isAppActive => _app != null; - - /// Closes this service, including any database connections or stream controllers. - @override - void close() {} - - /// An optional [readData] function can be passed to handle non-map/non-json bodies. - Service( - {FutureOr Function(RequestContext, ResponseContext)? readData}) { - _readData = readData; - - _readData ??= (req, res) { - if (req.bodyAsObject is! Data) { - throw PlatformHttpException.badRequest( - message: - 'Invalid request body. Expected $Data; found ${req.bodyAsObject} instead.'); - } else { - return req.bodyAsObject as Data; - } - }; - } - - FutureOr Function(RequestContext, ResponseContext)? _readData; - - /// A [Function] that reads the request body and converts it into [Data]. - FutureOr Function(RequestContext, ResponseContext)? get readData => - _readData; - - /// Retrieves the first object from the result of calling [index] with the given [params]. - /// - /// If the result of [index] is `null`, OR an empty [Iterable], a 404 `HttpException` will be thrown. - /// - /// If the result is both non-null and NOT an [Iterable], it will be returned as-is. - /// - /// If the result is a non-empty [Iterable], [findOne] will return `it.first`, where `it` is the aforementioned [Iterable]. - /// - /// A custom [errorMessage] may be provided. - Future findOne( - [Map? params, - String errorMessage = 'No record was found matching the given query.']) { - return index(params).then((result) { - if (result.isEmpty) { - throw PlatformHttpException.notFound(message: errorMessage); - } else { - return result.first; - } - }); - } - - /// Retrieves all resources. - Future> index([Map? params]) { - throw PlatformHttpException.methodNotAllowed(); - } - - /// Retrieves the desired resource. - Future read(Id id, [Map? params]) { - throw PlatformHttpException.methodNotAllowed(); - } - - /// Reads multiple resources at once. - /// - /// Service implementations should override this to ensure data is fetched within a - /// single round trip. - Future> readMany(List ids, [Map? params]) { - return Future.wait(ids.map((id) => read(id, params))); - } - - /// Creates a resource. - Future create(Data data, [Map? params]) { - throw PlatformHttpException.methodNotAllowed(); - } - - /// Modifies a resource. - Future modify(Id id, Data data, [Map? params]) { - throw PlatformHttpException.methodNotAllowed(); - } - - /// Overwrites a resource. - Future update(Id id, Data data, [Map? params]) { - throw PlatformHttpException.methodNotAllowed(); - } - - /// Removes the given resource. - Future remove(Id id, [Map? params]) { - throw PlatformHttpException.methodNotAllowed(); - } - - /// Creates an [AnonymousService] that wraps over this one, and maps input and output - /// using two converter functions. - /// - /// Handy utility for handling data in a type-safe manner. - Service map(U Function(Data) encoder, Data Function(U) decoder, - {FutureOr Function(RequestContext, ResponseContext)? readData}) { - readData ??= (req, res) async { - var inner = await this.readData!(req, res)!; - return encoder(inner); - }; - - return AnonymousService( - readData: readData, - index: ([params]) { - return index(params).then((it) => it.map(encoder).toList()); - }, - read: (id, [params]) { - return read(id, params).then(encoder); - }, - create: (data, [params]) { - return create(decoder(data), params).then(encoder); - }, - modify: (id, data, [params]) { - return modify(id, decoder(data), params).then(encoder); - }, - update: (id, data, [params]) { - return update(id, decoder(data), params).then(encoder); - }, - remove: (id, [params]) { - return remove(id, params).then(encoder); - }, - ); - } - - /// Transforms an [id] (whether it is a String, num, etc.) into one acceptable by a service. - /// - /// The single type argument, [T], is used to determine how to parse the [id]. - /// - /// For example, `parseId` attempts to parse the value as a [bool]. - static T parseId(id) { - if (id == null || id == 'null') { - return 'null' as T; - //throw ArgumentError("[Service] Null is not supported"); - } else if (T == String) { - return id.toString() as T; - } else if (T == int) { - return int.parse(id.toString()) as T; - } else if (T == bool) { - return (id == true || id.toString() == 'true') as T; - } else if (T == double) { - return double.parse(id.toString()) as T; - } else if (T == num) { - return num.parse(id.toString()) as T; - } else { - return id as T; - } - } - - /// Generates RESTful routes pointing to this class's methods. - void addRoutes([Service? service]) { - _addRoutesInner(service ?? this, bootstrappers); - } - - void _addRoutesInner(Service service, Iterable handlerss) { - var restProvider = {'provider': Providers.rest}; - var handlers = List.from(handlerss); - - // Add global middleware if declared on the instance itself - var before = getAnnotation(service, app.container.reflector); - - if (before != null) handlers.addAll(before.handlers); - - var indexMiddleware = - getAnnotation(service.index, app.container.reflector); - get('/', (req, res) { - return index(mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])); - }, middleware: [ - ...handlers, - ...(indexMiddleware == null) ? [] : indexMiddleware.handlers.toList() - ]); - - var createMiddleware = - getAnnotation(service.create, app.container.reflector); - post('/', (req, ResponseContext res) { - return req.parseBody().then((_) async { - return await create( - (await readData!(req, res))!, - mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])).then((r) { - res.statusCode = 201; - return r; - }); - }); - }, middleware: [ - ...handlers, - ...(createMiddleware == null) ? [] : createMiddleware.handlers.toList() - ]); - - var readMiddleware = - getAnnotation(service.read, app.container.reflector); - - get('/:id', (req, res) { - return read( - parseId(req.params['id']), - mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])); - }, middleware: [ - ...handlers, - ...(readMiddleware == null) ? [] : readMiddleware.handlers.toList() - ]); - - var modifyMiddleware = - getAnnotation(service.modify, app.container.reflector); - - patch('/:id', (req, res) { - return req.parseBody().then((_) async { - return await modify( - parseId(req.params['id']), - (await readData!(req, res))!, - mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])); - }); - }, middleware: [ - ...handlers, - ...(modifyMiddleware == null) ? [] : modifyMiddleware.handlers.toList() - ]); - - var updateMiddleware = - getAnnotation(service.update, app.container.reflector); - post('/:id', (req, res) { - return req.parseBody().then((_) async { - return await update( - parseId(req.params['id']), - (await readData!(req, res))!, - mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])); - }); - }, middleware: [ - ...handlers, - ...(updateMiddleware == null) ? [] : updateMiddleware.handlers.toList() - ]); - - put('/:id', (req, res) { - return req.parseBody().then((_) async { - return await update( - parseId(req.params['id']), - (await readData!(req, res))!, - mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])); - }); - }, middleware: [ - ...handlers, - ...(updateMiddleware == null) ? [] : updateMiddleware.handlers.toList() - ]); - - var removeMiddleware = - getAnnotation(service.remove, app.container.reflector); - delete('/', (req, res) { - return remove( - '' as Id, - mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])); - }, middleware: [ - ...handlers, - ...(removeMiddleware == null) ? [] : removeMiddleware.handlers.toList() - ]); - - delete('/:id', (req, res) { - return remove( - parseId(req.params['id']), - mergeMap([ - {'query': req.queryParameters}, - restProvider, - req.serviceParams - ])); - }, middleware: [ - ...handlers, - ...(removeMiddleware == null) ? [] : removeMiddleware.handlers.toList() - ]); - - // REST compliance - put('/', (req, res) => throw PlatformHttpException.notFound()); - patch('/', (req, res) => throw PlatformHttpException.notFound()); - } - - /// Invoked when this service is wrapped within a [HookedService]. - void onHooked(HookedService hookedService) {} -} diff --git a/packages/core/lib/src/fast_name_from_symbol.dart b/packages/core/lib/src/fast_name_from_symbol.dart deleted file mode 100644 index 6005ff1..0000000 --- a/packages/core/lib/src/fast_name_from_symbol.dart +++ /dev/null @@ -1,10 +0,0 @@ -final Map _cache = {}; - -String fastNameFromSymbol(Symbol s) { - return _cache.putIfAbsent(s, () { - var str = s.toString(); - var open = str.indexOf('"'); - var close = str.lastIndexOf('"'); - return str.substring(open + 1, close); - }); -} diff --git a/packages/core/lib/src/http/http.dart b/packages/core/lib/src/http/http.dart deleted file mode 100644 index 27e7f73..0000000 --- a/packages/core/lib/src/http/http.dart +++ /dev/null @@ -1,19 +0,0 @@ -/// Various libraries useful for creating highly-extensible servers. -library platform_core.http; - -import 'dart:async'; -import 'dart:io'; -export 'protevus_http.dart'; -export 'http_request_context.dart'; -export 'http_response_context.dart'; - -/// Boots a shared server instance. Use this if launching multiple isolates. -Future startShared(address, int port) => - HttpServer.bind(address ?? '127.0.0.1', port, shared: true); - -Future Function(dynamic, int) startSharedSecure( - SecurityContext securityContext) { - return (address, int port) => HttpServer.bindSecure( - address ?? '127.0.0.1', port, securityContext, - shared: true); -} diff --git a/packages/core/lib/src/http/http_request_context.dart b/packages/core/lib/src/http/http_request_context.dart deleted file mode 100644 index bbc0cb5..0000000 --- a/packages/core/lib/src/http/http_request_context.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:platform_container/container.dart'; -import 'package:http_parser/http_parser.dart'; - -import '../core/core.dart'; - -/// An implementation of [RequestContext] that wraps a [HttpRequest]. -class HttpRequestContext extends RequestContext { - Container? _container; - MediaType _contentType = MediaType('text', 'plain'); - HttpRequest? _io; - String? _override; - String _path = ''; - - @override - Container? get container => _container; - - @override - MediaType get contentType { - return _contentType; - } - - @override - List get cookies { - return rawRequest?.cookies ?? []; - } - - @override - HttpHeaders? get headers { - return rawRequest?.headers; - } - - @override - String get hostname { - return rawRequest?.headers.value('host') ?? 'localhost'; - } - - /// The underlying [HttpRequest] instance underneath this context. - @override - HttpRequest? get rawRequest => _io; - - @override - Stream>? get body => _io; - - @override - String get method { - return _override ?? originalMethod; - } - - @override - String get originalMethod { - return rawRequest?.method ?? ''; - } - - @override - String get path { - return _path; - } - - @override - InternetAddress get remoteAddress { - return rawRequest?.connectionInfo?.remoteAddress ?? - InternetAddress("127.0.0.1"); - } - - @override - HttpSession? get session { - return rawRequest?.session; - } - - @override - Uri get uri { - return rawRequest?.uri ?? Uri(); - } - - /// Magically transforms an [HttpRequest] into a [RequestContext]. - static Future from( - HttpRequest request, Application app, String path) { - var ctx = HttpRequestContext().._container = app.container.createChild(); - - var override = request.method; - - if (app.allowMethodOverrides == true) { - override = - request.headers.value('x-http-method-override')?.toUpperCase() ?? - request.method; - } - - ctx.app = app; - ctx._contentType = request.headers.contentType == null - ? MediaType('text', 'plain') - : MediaType.parse(request.headers.contentType.toString()); - ctx._override = override; - ctx._path = path; - ctx._io = request; - - return Future.value(ctx); - } - - @override - Future close() { - //_contentType = null; - _io = null; - _override = null; - //_path = null; - return super.close(); - } -} diff --git a/packages/core/lib/src/http/http_response_context.dart b/packages/core/lib/src/http/http_response_context.dart deleted file mode 100644 index ed3d06b..0000000 --- a/packages/core/lib/src/http/http_response_context.dart +++ /dev/null @@ -1,220 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' hide BytesBuilder; -import 'dart:typed_data' show BytesBuilder; -import 'package:http_parser/http_parser.dart'; - -import '../core/core.dart'; -import 'http_request_context.dart'; - -/// An implementation of [ResponseContext] that abstracts over an [HttpResponse]. -class HttpResponseContext extends ResponseContext { - /// The underlying [HttpResponse] under this instance. - @override - final HttpResponse rawResponse; - - LockableBytesBuilder? _buffer; - - final HttpRequestContext? _correspondingRequest; - bool _isDetached = false, _isClosed = false, _streamInitialized = false; - - HttpResponseContext(this.rawResponse, Application? app, - [this._correspondingRequest]) { - this.app = app; - } - - @override - HttpResponse detach() { - _isDetached = true; - return rawResponse; - } - - @override - RequestContext? get correspondingRequest { - return _correspondingRequest; - } - - @override - bool get isOpen { - return !_isClosed && !_isDetached; - } - - @override - bool get isBuffered => _buffer != null; - - @override - BytesBuilder? get buffer => _buffer; - - @override - void addError(Object error, [StackTrace? stackTrace]) { - rawResponse.addError(error, stackTrace); - super.addError(error, stackTrace); - } - - @override - void useBuffer() { - _buffer = LockableBytesBuilder(); - } - - Iterable? __allowedEncodings; - - Iterable? get _allowedEncodings { - return __allowedEncodings ??= correspondingRequest?.headers - ?.value('accept-encoding') - ?.split(',') - .map((s) => s.trim()) - .where((s) => s.isNotEmpty) - .map((str) { - // Ignore quality specifications in accept-encoding - // ex. gzip;q=0.8 - if (!str.contains(';')) return str; - return str.split(';')[0]; - }); - } - - @override - set contentType(MediaType value) { - super.contentType = value; - if (!_streamInitialized) { - rawResponse.headers.contentType = - ContentType(value.type, value.subtype, parameters: value.parameters); - } - } - - bool _openStream() { - if (!_streamInitialized) { - // If this is the first stream added to this response, - // then add headers, status code, etc. - rawResponse - ..statusCode = statusCode - ..cookies.addAll(cookies); - headers.forEach(rawResponse.headers.set); - - rawResponse.headers.date = DateTime.now(); - - if (headers.containsKey('content-length')) { - rawResponse.contentLength = int.tryParse(headers['content-length']!) ?? - rawResponse.contentLength; - } - - rawResponse.headers.contentType = ContentType( - contentType.type, contentType.subtype, - charset: contentType.parameters['charset'], - parameters: contentType.parameters); - - if (encoders.isNotEmpty && correspondingRequest != null) { - if (_allowedEncodings != null) { - for (var encodingName in _allowedEncodings!) { - Converter, List>? encoder; - var key = encodingName; - - if (encoders.containsKey(encodingName)) { - encoder = encoders[encodingName]; - } else if (encodingName == '*') { - encoder = encoders[key = encoders.keys.first]; - } - - if (encoder != null) { - rawResponse.headers.set('content-encoding', key); - break; - } - } - } - } - - //_isClosed = true; - return _streamInitialized = true; - } - - return false; - } - - @override - Future addStream(Stream> stream) { - if (_isClosed && isBuffered) throw ResponseContext.closed(); - _openStream(); - - var output = stream; - - if (encoders.isNotEmpty && correspondingRequest != null) { - if (_allowedEncodings != null) { - for (var encodingName in _allowedEncodings!) { - Converter, List>? encoder; - var key = encodingName; - - if (encoders.containsKey(encodingName)) { - encoder = encoders[encodingName]; - } else if (encodingName == '*') { - encoder = encoders[key = encoders.keys.first]; - } - - if (encoder != null) { - output = encoders[key]!.bind(output); - break; - } - } - } - } - - return rawResponse.addStream(output); - } - - @override - void add(List data) { - if (_isClosed && isBuffered) { - throw ResponseContext.closed(); - } else if (!isBuffered) { - if (!_isClosed) { - _openStream(); - - if (encoders.isNotEmpty && correspondingRequest != null) { - if (_allowedEncodings != null) { - for (var encodingName in _allowedEncodings!) { - Converter, List>? encoder; - var key = encodingName; - - if (encoders.containsKey(encodingName)) { - encoder = encoders[encodingName]; - } else if (encodingName == '*') { - encoder = encoders[key = encoders.keys.first]; - } - - if (encoder != null) { - data = encoders[key]!.convert(data); - break; - } - } - } - } - - rawResponse.add(data); - } - } else { - buffer!.add(data); - } - } - - @override - Future close() { - if (!_isDetached) { - if (!_isClosed) { - if (!isBuffered) { - try { - _openStream(); - rawResponse.close(); - } catch (_) { - // This only seems to occur on `MockHttpRequest`, but - // this try/catch prevents a crash. - } - } else { - _buffer!.lock(); - } - - _isClosed = true; - } - - super.close(); - } - return Future.value(); - } -} diff --git a/packages/core/lib/src/http/protevus_http.dart b/packages/core/lib/src/http/protevus_http.dart deleted file mode 100644 index bcc9bc5..0000000 --- a/packages/core/lib/src/http/protevus_http.dart +++ /dev/null @@ -1,144 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' - show - Cookie, - HttpRequest, - HttpResponse, - HttpServer, - Platform, - SecurityContext; -import 'package:platform_core/core.dart'; -import 'http_request_context.dart'; -import 'http_response_context.dart'; - -final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)'); - -typedef ServerGeneratorType = Future Function(dynamic, int); - -/// Adapts `dart:io`'s [HttpServer] to serve Protevus. -class PlatformHttp extends Driver { - @override - Uri get uri { - return Uri( - scheme: 'http', host: server?.address.address, port: server?.port); - } - - PlatformHttp._(super.app, super.serverGenerator, bool useZone) - : super(useZone: useZone); - - factory PlatformHttp(Application app, {bool useZone = true}) { - return PlatformHttp._(app, HttpServer.bind, useZone); - } - - /// An instance mounted on a server started by the [serverGenerator]. - factory PlatformHttp.custom( - Application app, ServerGeneratorType serverGenerator, - {bool useZone = true, Map headers = const {}}) { - return PlatformHttp._(app, serverGenerator, useZone); - } - - factory PlatformHttp.fromSecurityContext( - Application app, SecurityContext context, - {bool useZone = true}) { - return PlatformHttp._(app, (address, int port) { - return HttpServer.bindSecure(address, port, context); - }, useZone); - } - - /// Creates an HTTPS server. - /// - /// Provide paths to a certificate chain and server key (both .pem). - /// If no password is provided, a random one will be generated upon running - /// the server. - factory PlatformHttp.secure( - Application app, String certificateChainPath, String serverKeyPath, - {String? password, bool useZone = true}) { - var certificateChain = - Platform.script.resolve(certificateChainPath).toFilePath(); - var serverKey = Platform.script.resolve(serverKeyPath).toFilePath(); - var serverContext = SecurityContext(); - serverContext.useCertificateChain(certificateChain, password: password); - serverContext.usePrivateKey(serverKey, password: password); - - return PlatformHttp.fromSecurityContext(app, serverContext, - useZone: useZone); - } - - Future handleRequest(HttpRequest request) => - handleRawRequest(request, request.response); - - @override - void addCookies(HttpResponse response, Iterable cookies) => - response.cookies.addAll(cookies); - - @override - Future close() async { - return await super.close(); - } - - /// Remove headers from HTTP Response - void removeResponseHeader(Map headers) { - headers.forEach((key, value) { - server?.defaultResponseHeaders.remove(key, value); - }); - } - - /// Add headers to HTTP Response - void addResponseHeader(Map headers) { - headers.forEach((key, value) { - server?.defaultResponseHeaders.add(key, value); - }); - } - - @override - Future closeResponse(HttpResponse response) => response.close(); - - @override - Future createRequestContext( - HttpRequest request, HttpResponse response) { - var path = request.uri.path.replaceAll(_straySlashes, ''); - if (path.isEmpty) path = '/'; - return HttpRequestContext.from(request, app, path); - } - - @override - Future createResponseContext( - HttpRequest request, HttpResponse response, - [HttpRequestContext? correspondingRequest]) { - var context = HttpResponseContext(response, app, correspondingRequest); - context.serializer = (app.serializer ?? json.encode); - context.encoders.addAll(app.encoders); - return Future.value(context); - } - - @override - Stream createResponseStreamFromRawRequest( - HttpRequest request) => - Stream.fromIterable([request.response]); - - @override - void setChunkedEncoding(HttpResponse response, bool value) => - response.headers.chunkedTransferEncoding = value; - - @override - void setContentLength(HttpResponse response, int length) => - response.headers.contentLength = length; - - @override - void setHeader(HttpResponse response, String key, String value) => - response.headers.set(key, value); - - @override - void setStatusCode(HttpResponse response, int value) => - response.statusCode = value; - - @override - void writeStringToResponse(HttpResponse response, String value) => - response.write(value); - - @override - void writeToResponse(HttpResponse response, List data) => - response.add(data); -} diff --git a/packages/core/lib/src/http2/http2_request_context.dart b/packages/core/lib/src/http2/http2_request_context.dart deleted file mode 100644 index 8f38a3d..0000000 --- a/packages/core/lib/src/http2/http2_request_context.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:platform_container/container.dart'; -import 'package:platform_core/core.dart'; -import 'package:collection/collection.dart' show IterableExtension; -import 'package:http2/transport.dart'; -import 'package:platform_testing/http.dart'; -import 'package:uuid/uuid.dart'; - -final RegExp _comma = RegExp(r',\s*'); -final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)'); - -class Http2RequestContext extends RequestContext { - final StreamController> _body = StreamController(); - @override - final Container container; - List _cookies = []; - HttpHeaders? _headers; - String? _method, _override, _path; - late Socket _socket; - ServerTransportStream? _stream; - Uri? _uri; - HttpSession? _session; - - Http2RequestContext._(this.container); - - @override - Stream> get body => _body.stream; - - static Future from( - ServerTransportStream stream, - Socket socket, - Application app, - Map sessions, - Uuid uuid) { - var c = Completer(); - var req = Http2RequestContext._(app.container.createChild()) - ..app = app - .._socket = socket - .._stream = stream; - - var headers = req._headers = MockHttpHeaders(); - // String scheme = 'https', host = socket.address.address, path = ''; - var uri = - Uri(scheme: 'https', host: socket.address.address, port: socket.port); - var cookies = []; - - void finalize() { - req - .._cookies = List.unmodifiable(cookies) - .._uri = uri; - if (!c.isCompleted) c.complete(req); - } - - void parseHost(String value) { - var inUri = Uri.tryParse(value); - if (inUri == null) return; - // if (uri == null || uri.scheme == 'localhost') return; - - if (inUri.hasScheme) uri = uri.replace(scheme: inUri.scheme); - - if (inUri.hasAuthority) { - uri = uri.replace(host: inUri.host, userInfo: inUri.userInfo); - } - - if (inUri.hasPort) uri = uri.replace(port: inUri.port); - } - - stream.incomingMessages.listen((msg) { - if (msg is DataStreamMessage) { - finalize(); - req._body.add(msg.bytes); - } else if (msg is HeadersStreamMessage) { - for (var header in msg.headers) { - var name = ascii.decode(header.name).toLowerCase(); - var value = Uri.decodeComponent(ascii.decode(header.value)); - - switch (name) { - case ':method': - req._method = value; - break; - case ':path': - var inUri = Uri.parse(value); - uri = uri.replace(path: inUri.path); - if (inUri.hasQuery) uri = uri.replace(query: inUri.query); - var path = uri.path.replaceAll(_straySlashes, ''); - req._path = path; - if (path.isEmpty) req._path = '/'; - break; - case ':scheme': - uri = uri.replace(scheme: value); - break; - case ':authority': - parseHost(value); - break; - case 'cookie': - var cookieStrings = value.split(';').map((s) => s.trim()); - - for (var cookieString in cookieStrings) { - try { - cookies.add(Cookie.fromSetCookieValue(cookieString)); - } catch (_) { - // Ignore malformed cookies, and just don't add them to the container. - } - } - break; - default: - var name = ascii.decode(header.name).toLowerCase(); - - if (name == 'host') { - parseHost(value); - } - - headers.add(name, value.split(_comma)); - break; - } - } - - if (msg.endStream) finalize(); - } - }, onDone: () { - finalize(); - req._body.close(); - }, cancelOnError: true, onError: c.completeError); - - // Apply session - var dartSessId = cookies.firstWhereOrNull((c) => c.name == 'DARTSESSID'); - - dartSessId ??= Cookie('DARTSESSID', uuid.v4()); - - req._session = sessions.putIfAbsent( - dartSessId.value, - () => MockHttpSession(id: dartSessId!.value), - ); - - return c.future; - } - - @override - List get cookies => _cookies; - - /// The underlying HTTP/2 [ServerTransportStream]. - ServerTransportStream? get stream => _stream; - - @override - Uri? get uri => _uri; - - @override - HttpSession? get session { - return _session; - } - - @override - InternetAddress get remoteAddress => _socket.remoteAddress; - - @override - String get path { - return _path ?? ''; - } - - @override - String get originalMethod { - return _method ?? 'GET'; - } - - @override - String get method { - return _override ?? _method ?? 'GET'; - } - - @override - String get hostname => _headers?.value('host') ?? 'localhost'; - - @override - HttpHeaders? get headers => _headers; - - @override - Future close() { - _body.close(); - return super.close(); - } - - @override - ServerTransportStream? get rawRequest => _stream; -} diff --git a/packages/core/lib/src/http2/http2_response_context.dart b/packages/core/lib/src/http2/http2_response_context.dart deleted file mode 100644 index 7e164c6..0000000 --- a/packages/core/lib/src/http2/http2_response_context.dart +++ /dev/null @@ -1,233 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' hide BytesBuilder; -import 'dart:typed_data'; -import 'package:platform_core/core.dart' hide Header; -import 'package:http2/transport.dart'; -import 'http2_request_context.dart'; - -class Http2ResponseContext extends ResponseContext { - final ServerTransportStream stream; - - @override - ServerTransportStream get rawResponse => stream; - - LockableBytesBuilder? _buffer; - - final Http2RequestContext? _req; - - bool _isDetached = false, - _isClosed = false, - _streamInitialized = false, - _isPush = false; - - Uri? _targetUri; - - Http2ResponseContext(Application? app, this.stream, this._req) { - this.app = app; - _targetUri = _req?.uri; - } - - final List _pushes = []; - - /// Returns `true` if an attempt to [push] a resource will succeed. - /// - /// See [ServerTransportStream].`push`. - bool get canPush => stream.canPush; - - /// Returns a [List] of all resources that have [push]ed to the client. - List get pushes => List.unmodifiable(_pushes); - - @override - ServerTransportStream detach() { - _isDetached = true; - return stream; - } - - @override - RequestContext? get correspondingRequest => _req; - - Uri? get targetUri => _targetUri; - - @override - bool get isOpen { - return !_isClosed && !_isDetached; - } - - @override - bool get isBuffered => _buffer != null; - - @override - BytesBuilder? get buffer => _buffer; - - // @override - // void addError(Object error, [StackTrace? stackTrace]) { - // super.addError(error, stackTrace); - // } - - @override - void useBuffer() { - _buffer = LockableBytesBuilder(); - } - - /// Write headers, status, etc. to the underlying [stream]. - bool _openStream() { - if (_isPush || _streamInitialized) return false; - - var headers =
[ - Header.ascii(':status', statusCode.toString()), - ]; - - if (encoders.isNotEmpty && correspondingRequest != null) { - if (_allowedEncodings != null) { - for (var encodingName in _allowedEncodings!) { - Converter, List>? encoder; - var key = encodingName; - - if (encoders.containsKey(encodingName)) { - encoder = encoders[encodingName]; - } else if (encodingName == '*') { - encoder = encoders[key = encoders.keys.first]; - } - - if (encoder != null) { - this.headers['content-encoding'] = key; - break; - } - } - } - } - - // Add all normal headers - for (var key in this.headers.keys) { - headers.add(Header.ascii(key.toLowerCase(), this.headers[key]!)); - } - - // Persist session ID - cookies.add(Cookie('DARTSESSID', _req!.session!.id)); - - // Send all cookies - for (var cookie in cookies) { - headers.add(Header.ascii('set-cookie', cookie.toString())); - } - - stream.sendHeaders(headers); - return _streamInitialized = true; - } - - Iterable? __allowedEncodings; - - Iterable? get _allowedEncodings { - return __allowedEncodings ??= correspondingRequest?.headers - ?.value('accept-encoding') - ?.split(',') - .map((s) => s.trim()) - .where((s) => s.isNotEmpty) - .map((str) { - // Ignore quality specifications in accept-encoding - // ex. gzip;q=0.8 - if (!str.contains(';')) return str; - return str.split(';')[0]; - }); - } - - @override - Future addStream(Stream> stream) { - if (!isOpen && isBuffered) throw ResponseContext.closed(); - _openStream(); - - var output = stream; - - if (encoders.isNotEmpty && correspondingRequest != null) { - if (_allowedEncodings != null) { - for (var encodingName in _allowedEncodings!) { - Converter, List>? encoder; - var key = encodingName; - - if (encoders.containsKey(encodingName)) { - encoder = encoders[encodingName]; - } else if (encodingName == '*') { - encoder = encoders[key = encoders.keys.first]; - } - - if (encoder != null) { - output = encoders[key]!.bind(output); - break; - } - } - } - } - - return output.forEach(this.stream.sendData); - } - - @override - void add(List data) { - if (!isOpen && isBuffered) { - throw ResponseContext.closed(); - } else if (!isBuffered) { - _openStream(); - - if (!_isClosed) { - if (encoders.isNotEmpty && correspondingRequest != null) { - if (_allowedEncodings != null) { - for (var encodingName in _allowedEncodings!) { - Converter, List>? encoder; - var key = encodingName; - - if (encoders.containsKey(encodingName)) { - encoder = encoders[encodingName]; - } else if (encodingName == '*') { - encoder = encoders[key = encoders.keys.first]; - } - - if (encoder != null) { - data = encoders[key]!.convert(data); - break; - } - } - } - } - - stream.sendData(data); - } - } else { - buffer!.add(data); - } - } - - @override - Future close() async { - if (!_isDetached && !_isClosed && !isBuffered) { - _openStream(); - await stream.outgoingMessages.close(); - } - - _isClosed = true; - await super.close(); - } - - /// Pushes a resource to the client. - Http2ResponseContext push(String path, - {Map headers = const {}, String method = 'GET'}) { - var targetUri = _req!.uri!.replace(path: path); - - var h =
[ - Header.ascii(':authority', targetUri.authority), - Header.ascii(':method', method), - Header.ascii(':path', targetUri.path), - Header.ascii(':scheme', targetUri.scheme), - ]; - - for (var key in headers.keys) { - h.add(Header.ascii(key, headers[key]!)); - } - - var s = stream.push(h); - var r = Http2ResponseContext(app, s, _req) - .._isPush = true - .._targetUri = targetUri; - _pushes.add(r); - return r; - } -} diff --git a/packages/core/lib/src/http2/protevus_http2.dart b/packages/core/lib/src/http2/protevus_http2.dart deleted file mode 100644 index cd12b59..0000000 --- a/packages/core/lib/src/http2/protevus_http2.dart +++ /dev/null @@ -1,243 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:platform_core/core.dart' hide Header; -import 'package:platform_core/http.dart'; -import 'package:http2/transport.dart'; -import 'package:platform_testing/http.dart'; -import 'http2_request_context.dart'; -import 'http2_response_context.dart'; -import 'package:uuid/uuid.dart'; - -/// Boots a shared server instance. Use this if launching multiple isolates. -Future startSharedHttp2( - address, int port, SecurityContext ctx) { - return SecureServerSocket.bind(address, port, ctx, shared: true); -} - -/// Adapts `package:http2`'s [ServerTransportConnection] to serve Protevus. -class PlatformHttp2 extends Driver { - final ServerSettings? settings; - late PlatformHttp _http; - final StreamController _onHttp1 = StreamController(); - final Map _sessions = {}; - final Uuid _uuid = Uuid(); - _ProtevusHttp2ServerSocket? _artificial; - - SecureServerSocket? get socket => _artificial; - - PlatformHttp2._( - Application app, - Future Function(dynamic, int) serverGenerator, - bool useZone, - bool allowHttp1, - this.settings) - : super( - app, - serverGenerator, - useZone: useZone, - ) { - if (allowHttp1) { - _http = PlatformHttp(app, useZone: useZone); - onHttp1.listen(_http.handleRequest); - } - } - - factory PlatformHttp2(Application app, SecurityContext securityContext, - {bool useZone = true, - bool allowHttp1 = false, - ServerSettings? settings}) { - return PlatformHttp2.custom(app, securityContext, SecureServerSocket.bind, - allowHttp1: allowHttp1, settings: settings); - } - - factory PlatformHttp2.custom( - Application app, - SecurityContext ctx, - Future Function( - InternetAddress? address, int port, SecurityContext ctx) - serverGenerator, - {bool useZone = true, - bool allowHttp1 = false, - ServerSettings? settings}) { - return PlatformHttp2._(app, (address, port) { - var addr = address is InternetAddress - ? address - : InternetAddress(address.toString()); - return Future.sync(() => serverGenerator(addr, port, ctx)); - }, useZone, allowHttp1, settings); - } - - /// Fires when an HTTP/1.x request is received. - Stream get onHttp1 => _onHttp1.stream; - - @override - Future generateServer([address, int? port]) async { - var s = await serverGenerator(address ?? '127.0.0.1', port ?? 0); - return _artificial = _ProtevusHttp2ServerSocket(s, this); - } - - @override - Future close() async { - await _artificial?.close(); - await _http.close(); - return await super.close(); - } - - @override - void addCookies(ServerTransportStream response, Iterable cookies) { - var headers = - cookies.map((cookie) => Header.ascii('set-cookie', cookie.toString())); - response.sendHeaders(headers.toList()); - } - - @override - Future closeResponse(ServerTransportStream response) { - response.terminate(); - return Future.value(); - } - - @override - Future createRequestContext( - Socket request, ServerTransportStream response) { - return Http2RequestContext.from(response, request, app, _sessions, _uuid); - } - - @override - Future createResponseContext( - Socket request, ServerTransportStream response, - [Http2RequestContext? correspondingRequest]) async { - return Http2ResponseContext(app, response, correspondingRequest) - ..encoders.addAll(app.encoders); - } - - @override - Stream createResponseStreamFromRawRequest( - Socket request) { - var connection = - ServerTransportConnection.viaSocket(request, settings: settings); - return connection.incomingStreams; - } - - @override - void setChunkedEncoding(ServerTransportStream response, bool value) { - // Do nothing in HTTP/2 - } - - @override - void setContentLength(ServerTransportStream response, int length) { - setHeader(response, 'content-length', length.toString()); - } - - @override - void setHeader(ServerTransportStream response, String key, String? value) { - response.sendHeaders([Header.ascii(key, value!)]); - } - - @override - void setStatusCode(ServerTransportStream response, int value) { - response.sendHeaders([Header.ascii(':status', value.toString())]); - } - - @override - Uri get uri => Uri( - scheme: 'https', - host: server?.address.address, - port: server?.port != 443 ? server?.port : null); - - @override - void writeStringToResponse(ServerTransportStream response, String value) { - writeToResponse(response, utf8.encode(value)); - } - - @override - void writeToResponse(ServerTransportStream response, List data) { - response.sendData(data); - } -} - -class _FakeServerSocket extends Stream implements ServerSocket { - final _ProtevusHttp2ServerSocket protevus; - final _ctrl = StreamController(); - - _FakeServerSocket(this.protevus); - - @override - InternetAddress get address => protevus.address; - - @override - Future close() async { - await (_ctrl.close()); - return this; - } - - @override - int get port => protevus.port; - - @override - StreamSubscription listen(void Function(Socket event)? onData, - {Function? onError, void Function()? onDone, bool? cancelOnError}) { - return _ctrl.stream.listen(onData, - cancelOnError: cancelOnError, onError: onError, onDone: onDone); - } -} - -class _ProtevusHttp2ServerSocket extends Stream - implements SecureServerSocket { - final SecureServerSocket socket; - final PlatformHttp2 driver; - final _ctrl = StreamController(); - late _FakeServerSocket _fake; - StreamSubscription? _sub; - - _ProtevusHttp2ServerSocket(this.socket, this.driver) { - _fake = _FakeServerSocket(this); - HttpServer.listenOn(_fake).pipe(driver._onHttp1); - _sub = socket.listen( - (socket) { - if (socket.selectedProtocol == null || - socket.selectedProtocol == 'http/1.0' || - socket.selectedProtocol == 'http/1.1') { - _fake._ctrl.add(socket); - } else if (socket.selectedProtocol == 'h2' || - socket.selectedProtocol == 'h2-14') { - _ctrl.add(socket); - } else { - socket.destroy(); - throw Exception( - 'PlatformHttp2 does not support ${socket.selectedProtocol} as an ALPN protocol.'); - } - }, - onDone: _ctrl.close, - onError: (e, st) { - driver.app.logger.warning( - 'HTTP/2 incoming connection failure: ', e, st as StackTrace); - }, - ); - } - - @override - InternetAddress get address => socket.address; - - @override - int get port => socket.port; - - @override - Future close() { - _sub?.cancel(); - _fake.close(); - _ctrl.close(); - return socket.close(); - } - - @override - StreamSubscription listen( - void Function(SecureSocket event)? onData, - {Function? onError, - void Function()? onDone, - bool? cancelOnError}) { - return _ctrl.stream.listen(onData, - cancelOnError: cancelOnError, onError: onError, onDone: onDone); - } -} diff --git a/packages/core/lib/src/safe_stream_controller.dart b/packages/core/lib/src/safe_stream_controller.dart deleted file mode 100644 index fc1643f..0000000 --- a/packages/core/lib/src/safe_stream_controller.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'dart:async'; - -typedef _InitCallback = void Function(); - -/// A [StreamController] boilerplate that prevents memory leaks. -abstract class SafeCtrl { - factory SafeCtrl() => _SingleSafeCtrl(); - - factory SafeCtrl.broadcast() => _BroadcastSafeCtrl(); - - Stream get stream; - - void add(T event); - - void addError(error, [StackTrace? stackTrace]); - - Future close(); - - void whenInitialized(void Function() callback); -} - -class _SingleSafeCtrl implements SafeCtrl { - late StreamController _stream; - bool _hasListener = false, _initialized = false; - _InitCallback? _initializer; - - _SingleSafeCtrl() { - _stream = StreamController(onListen: () { - _hasListener = true; - - if (!_initialized && _initializer != null) { - _initializer!(); - _initialized = true; - } - }, onPause: () { - _hasListener = false; - }, onResume: () { - _hasListener = true; - }, onCancel: () { - _hasListener = false; - }); - } - - @override - Stream get stream => _stream.stream; - - @override - void add(T event) { - if (_hasListener) _stream.add(event); - } - - @override - void addError(error, [StackTrace? stackTrace]) { - if (_hasListener) _stream.addError(error as Object, stackTrace); - } - - @override - Future close() { - return _stream.close(); - } - - @override - void whenInitialized(void Function() callback) { - if (!_initialized) { - if (!_hasListener) { - _initializer = callback; - } else { - _initializer!(); - _initialized = true; - } - } - } -} - -class _BroadcastSafeCtrl implements SafeCtrl { - late StreamController _stream; - int _listeners = 0; - bool _initialized = false; - _InitCallback? _initializer; - - _BroadcastSafeCtrl() { - _stream = StreamController.broadcast(onListen: () { - _listeners++; - - if (!_initialized && _initializer != null) { - _initializer!(); - _initialized = true; - } - }, onCancel: () { - _listeners--; - }); - } - - @override - Stream get stream => _stream.stream; - - @override - void add(T event) { - if (_listeners > 0) _stream.add(event); - } - - @override - void addError(error, [StackTrace? stackTrace]) { - if (_listeners > 0) _stream.addError(error as Object, stackTrace); - } - - @override - Future close() { - return _stream.close(); - } - - @override - void whenInitialized(void Function() callback) { - if (!_initialized) { - if (_listeners <= 0) { - _initializer = callback; - } else { - _initializer!(); - _initialized = true; - } - } - } -} diff --git a/packages/core/lib/src/util.dart b/packages/core/lib/src/util.dart deleted file mode 100644 index 53db9a0..0000000 --- a/packages/core/lib/src/util.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:platform_container/container.dart'; - -final RegExp straySlashes = RegExp(r'(^/+)|(/+$)'); - -T? matchingAnnotation(List metadata) { - for (var metaDatum in metadata) { - if (metaDatum.type.reflectedType == T) { - return metaDatum.reflectee as T?; - } - } - - return null; -} - -T? getAnnotation(obj, Reflector? reflector) { - if (reflector == null) { - return null; - } else { - if (obj is Function) { - var methodMirror = reflector.reflectFunction(obj)!; - return matchingAnnotation(methodMirror.annotations); - } else { - var classMirror = reflector.reflectClass(obj.runtimeType)!; - return matchingAnnotation(classMirror.annotations); - } - } -} diff --git a/packages/core/performance/hello/angel.md b/packages/core/performance/hello/angel.md deleted file mode 100644 index 89c1d95..0000000 --- a/packages/core/performance/hello/angel.md +++ /dev/null @@ -1,65 +0,0 @@ -# Platform Performance Results - -5 consecutive trials run on a Windows 10 box with 4GB RAM, and several programs open in the background. - -Setup: - -* Protevus Platform `1.0.8` -* Running `wrk` 4.0.2.2 -* 2 threads -* 256 connections -* 30 seconds - -Average: - -* `11070.18` req/sec -* `11.86` ms latency - -```bash -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 12.23ms 7.56ms 206.05ms 93.09% - Req/Sec 5.48k 761.94 7.18k 87.50% - 324822 requests in 30.06s, 62.88MB read -Requests/sec: 10806.24 -Transfer/sec: 2.09MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 11.06ms 4.88ms 134.86ms 78.68% - Req/Sec 5.98k 539.40 7.50k 91.40% - 356355 requests in 30.11s, 68.99MB read -Requests/sec: 11836.11 -Transfer/sec: 2.29MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 12.03ms 6.18ms 159.93ms 87.89% - Req/Sec 5.52k 0.88k 7.32k 90.31% - 327749 requests in 30.06s, 63.45MB read -Requests/sec: 10901.35 -Transfer/sec: 2.11MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 12.92ms 7.06ms 189.00ms 82.48% - Req/Sec 5.12k 1.00k 6.42k 75.59% - 302273 requests in 30.05s, 58.52MB read -Requests/sec: 10059.96 -Transfer/sec: 1.95MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 11.05ms 4.92ms 104.90ms 69.57% - Req/Sec 5.95k 0.87k 7.65k 76.80% - 352798 requests in 30.03s, 68.30MB read -Requests/sec: 11747.23 -Transfer/sec: 2.27MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ -``` diff --git a/packages/core/performance/hello/main.dart b/packages/core/performance/hello/main.dart deleted file mode 100644 index d8d83ef..0000000 --- a/packages/core/performance/hello/main.dart +++ /dev/null @@ -1,23 +0,0 @@ -/// A basic server that prints "Hello, world!" -library performance.hello; - -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; - -void main() async { - var app = Application(); - var http = PlatformHttp.custom(app, startShared, useZone: false); - - app.get('/', (req, res) => res.write('Hello, world!')); - app.optimizeForProduction(force: true); - - var oldHandler = app.errorHandler; - app.errorHandler = (e, req, res) { - print('Oops: ${e.error ?? e}'); - print(e.stackTrace); - return oldHandler(e, req, res); - }; - - await http.startServer('127.0.0.1', 3000); - print('Listening at ${http.uri}'); -} diff --git a/packages/core/performance/hello/raw.dart b/packages/core/performance/hello/raw.dart deleted file mode 100644 index 33a08ff..0000000 --- a/packages/core/performance/hello/raw.dart +++ /dev/null @@ -1,18 +0,0 @@ -/// A basic server that prints "Hello, world!" -library performance.hello; - -import 'dart:io'; - -Future main() { - return HttpServer.bind('127.0.0.1', 3000, shared: true).then((server) { - print('Listening at http://${server.address.address}:${server.port}'); - - server.listen((request) { - if (request.uri.path == '/') { - request.response.write('Hello, world!'); - } - - request.response.close(); - }); - }); -} diff --git a/packages/core/performance/hello/raw.md b/packages/core/performance/hello/raw.md deleted file mode 100644 index e16631e..0000000 --- a/packages/core/performance/hello/raw.md +++ /dev/null @@ -1,63 +0,0 @@ -# `dart:io` Results - -5 consecutive trials run on a Windows 10 box with 4GB RAM, and several programs open in the background. - -Setup: - -* Running `wrk` 4.0.2.2 -* 2 threads -* 256 connections -* 30 seconds - -Average: - -* `14598.16` req/sec -* `8.88` ms latency - -```bash -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 9.67ms 8.19ms 202.28ms 96.17% - Req/Sec 7.15k 1.47k 9.97k 73.76% - 417716 requests in 30.07s, 82.06MB read -Requests/sec: 13892.50 -Transfer/sec: 2.73MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 8.47ms 3.14ms 100.77ms 65.40% - Req/Sec 7.61k 670.47 8.85k 73.88% - 453301 requests in 30.07s, 89.05MB read -Requests/sec: 15077.15 -Transfer/sec: 2.96MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 8.62ms 3.51ms 73.34ms 63.74% - Req/Sec 7.52k 650.22 8.91k 79.17% - 448445 requests in 30.07s, 88.10MB read -Requests/sec: 14911.53 -Transfer/sec: 2.93MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 8.75ms 3.51ms 70.50ms 64.53% - Req/Sec 7.41k 825.50 10.23k 72.24% - 441338 requests in 30.09s, 86.70MB read -Requests/sec: 14665.62 -Transfer/sec: 2.88MB -tobe@LAPTOP-VBHCSVRH:/mnt/c/Users/thosa$ wrk -c 256 -d 30 -t 2 http://localhost:3000 -Running 30s test @ http://localhost:3000 - 2 threads and 256 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 8.90ms 3.62ms 78.36ms 66.71% - Req/Sec 7.31k 742.11 10.79k 77.84% - 434674 requests in 30.09s, 85.39MB read -Requests/sec: 14443.98 -Transfer/sec: 2.84MB -``` diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock deleted file mode 100644 index 991a8bf..0000000 --- a/packages/core/pubspec.lock +++ /dev/null @@ -1,685 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77" - url: "https://pub.dev" - source: hosted - version: "73.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.2" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a" - url: "https://pub.dev" - source: hosted - version: "6.8.0" - args: - dependency: transitive - description: - name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 - url: "https://pub.dev" - source: hosted - version: "2.6.0" - async: - dependency: transitive - description: - name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 - url: "https://pub.dev" - source: hosted - version: "2.12.0" - belatuk_code_buffer: - dependency: transitive - description: - name: belatuk_code_buffer - sha256: "147d68b24f099ccc6230f354cc05c4f8df1be2a95c26daebb859cbe2096d83f4" - url: "https://pub.dev" - source: hosted - version: "5.2.0" - belatuk_combinator: - dependency: "direct main" - description: - name: belatuk_combinator - sha256: "04bfb2c6f667cdb668529ecf2060a2fa2c79c22c6d85793a76d1cd6d73acf68e" - url: "https://pub.dev" - source: hosted - version: "5.2.0" - belatuk_http_server: - dependency: "direct main" - description: - name: belatuk_http_server - sha256: "3a4cfea80835e7feec47c1cf3f0ce17b3b80433b65f2b48f940d3f95f8ffe9d9" - url: "https://pub.dev" - source: hosted - version: "4.4.0" - belatuk_merge_map: - dependency: "direct main" - description: - name: belatuk_merge_map - sha256: a05dc05da77e7be4a34adeb863c62b44bcd846ff6efa00cf60d17ae91e809a21 - url: "https://pub.dev" - source: hosted - version: "5.2.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - build: - dependency: transitive - description: - name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - build_config: - dependency: transitive - description: - name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 - url: "https://pub.dev" - source: hosted - version: "1.1.1" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" - url: "https://pub.dev" - source: hosted - version: "2.4.13" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe - url: "https://pub.dev" - source: hosted - version: "7.3.1" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb - url: "https://pub.dev" - source: hosted - version: "8.9.2" - charcode: - dependency: "direct main" - description: - name: charcode - sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 - url: "https://pub.dev" - source: hosted - version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff - url: "https://pub.dev" - source: hosted - version: "2.0.3" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 - url: "https://pub.dev" - source: hosted - version: "4.10.0" - collection: - dependency: "direct main" - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: "88b0fddbe4c92910fefc09cc0248f5e7f0cd23e450ded4c28f16ab8ee8f83268" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" - url: "https://pub.dev" - source: hosted - version: "2.3.7" - file: - dependency: "direct main" - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - graphs: - dependency: transitive - description: - name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - http: - dependency: "direct dev" - description: - name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 - url: "https://pub.dev" - source: hosted - version: "1.2.2" - http2: - dependency: "direct main" - description: - name: http2 - sha256: "9ced024a160b77aba8fb8674e38f70875e321d319e6f303ec18e87bd5a4b0c1d" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: "direct main" - description: - name: http_parser - sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" - url: "https://pub.dev" - source: hosted - version: "4.1.1" - io: - dependency: "direct dev" - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf - url: "https://pub.dev" - source: hosted - version: "0.7.1" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - lints: - dependency: "direct dev" - description: - name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - logging: - dependency: "direct main" - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - macros: - dependency: transitive - description: - name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" - url: "https://pub.dev" - source: hosted - version: "0.1.2-main.4" - matcher: - dependency: "direct main" - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - meta: - dependency: "direct main" - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: "direct main" - description: - name: mime - sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" - url: "https://pub.dev" - source: hosted - version: "1.0.6" - mockito: - dependency: "direct dev" - description: - name: mockito - sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" - url: "https://pub.dev" - source: hosted - version: "5.4.4" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: "direct main" - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - platform_container: - dependency: "direct main" - description: - path: "../container/container" - relative: true - source: path - version: "9.0.0" - platform_model: - dependency: "direct main" - description: - path: "../model" - relative: true - source: path - version: "9.0.0" - platform_route: - dependency: "direct main" - description: - path: "../route" - relative: true - source: path - version: "9.0.0" - platform_support: - dependency: "direct main" - description: - path: "../support" - relative: true - source: path - version: "9.0.0" - platform_testing: - dependency: "direct main" - description: - path: "../testing" - relative: true - source: path - version: "9.0.0" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - quiver: - dependency: "direct main" - description: - name: quiver - sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - recase: - dependency: "direct main" - description: - name: recase - sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 - url: "https://pub.dev" - source: hosted - version: "4.1.0" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 - url: "https://pub.dev" - source: hosted - version: "1.1.3" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - stack_trace: - dependency: "direct main" - description: - name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" - url: "https://pub.dev" - source: hosted - version: "1.12.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - string_scanner: - dependency: "direct main" - description: - name: string_scanner - sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test: - dependency: "direct dev" - description: - name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" - url: "https://pub.dev" - source: hosted - version: "1.25.8" - test_api: - dependency: transitive - description: - name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" - url: "https://pub.dev" - source: hosted - version: "0.7.3" - test_core: - dependency: transitive - description: - name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" - url: "https://pub.dev" - source: hosted - version: "0.6.5" - timing: - dependency: transitive - description: - name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - tuple: - dependency: "direct main" - description: - name: tuple - sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 - url: "https://pub.dev" - source: hosted - version: "2.0.2" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" - source: hosted - version: "1.3.2" - uuid: - dependency: "direct main" - description: - name: uuid - sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff - url: "https://pub.dev" - source: hosted - version: "4.5.1" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b - url: "https://pub.dev" - source: hosted - version: "14.3.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" - url: "https://pub.dev" - source: hosted - version: "0.1.6" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.5.0 <4.0.0" diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml deleted file mode 100644 index 2f57930..0000000 --- a/packages/core/pubspec.yaml +++ /dev/null @@ -1,52 +0,0 @@ -name: platform_core -version: 9.0.0 -description: Protevus Platform high-powered HTTP server extensible framework with dependency injection, routing and much more. -homepage: https://protevus.com -documentation: https://docs.protevus.com -repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/core -environment: - sdk: '>=3.3.0 <4.0.0' -dependencies: - platform_container: ^9.0.0 - platform_model: ^9.0.0 - platform_route: ^9.0.0 - platform_support: ^9.0.0 - platform_testing: ^9.0.0 - belatuk_merge_map: ^5.1.0 - belatuk_combinator: ^5.2.0 - belatuk_http_server: ^4.4.0 - charcode: ^1.3.1 - file: ^7.0.1 - http_parser: ^4.1.1 - http2: ^2.3.0 - logging: ^1.3.0 - matcher: ^0.12.16 - meta: ^1.16.0 - mime: ^1.0.0 - path: ^1.9.1 - quiver: ^3.2.2 - recase: ^4.1.0 - stack_trace: ^1.12.0 - string_scanner: ^1.4.0 - tuple: ^2.0.2 - uuid: ^4.5.1 - collection: ^1.19.1 -dev_dependencies: - http: ^1.2.2 - io: ^1.0.4 - test: ^1.25.8 - lints: ^4.0.0 - mockito: ^5.4.4 - build_runner: ^2.4.13 -# dependency_overrides: -# platform_container: -# path: ../container/angel_container -# platform_http_exception: -# path: ../http_exception -# platform_model: -# path: ../model -# platform_route: -# path: ../route -# platform_mock_request: -# path: ../mock_request - diff --git a/packages/core/test/accepts_test.dart b/packages/core/test/accepts_test.dart deleted file mode 100644 index dcf6fed..0000000 --- a/packages/core/test/accepts_test.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -final Uri endpoint = Uri.parse('http://example.com/accept'); - -void main() { - test('no content type', () async { - var req = await acceptContentTypes(); - expect(req.acceptsAll, isFalse); - //expect(req.accepts(ContentType.JSON), isFalse); - expect(req.accepts('application/json'), isFalse); - //expect(req.accepts(ContentType.HTML), isFalse); - expect(req.accepts('text/html'), isFalse); - }); - - test('wildcard', () async { - var req = await acceptContentTypes(['*/*']); - expect(req.acceptsAll, isTrue); - //expect(req.accepts(ContentType.JSON), isTrue); - expect(req.accepts('application/json'), isTrue); - //expect(req.accepts(ContentType.HTML), isTrue); - expect(req.accepts('text/html'), isTrue); - }); - - test('specific type', () async { - var req = await acceptContentTypes(['text/html']); - expect(req.acceptsAll, isFalse); - //expect(req.accepts(ContentType.JSON), isFalse); - expect(req.accepts('application/json'), isFalse); - //expect(req.accepts(ContentType.HTML), isTrue); - expect(req.accepts('text/html'), isTrue); - }); - - test('strict', () async { - var req = await acceptContentTypes(['text/html', '*/*']); - expect(req.accepts('text/html'), isTrue); - //expect(req.accepts(ContentType.HTML), isTrue); - //expect(req.accepts(ContentType.JSON, strict: true), isFalse); - expect(req.accepts('application/json', strict: true), isFalse); - }); - - group('disallow null', () { - late RequestContext req; - - setUp(() async { - req = await acceptContentTypes(); - }); - - test('throws error', () { - expect(() => req.accepts(null), throwsArgumentError); - }); - }); -} - -Future acceptContentTypes( - [Iterable contentTypes = const []]) { - var headerString = - contentTypes.isEmpty ? ContentType.text : contentTypes.join(','); - var rq = MockHttpRequest('GET', endpoint, persistentConnection: false); - rq.headers.set('accept', headerString); - rq.close(); - var app = Application(reflector: MirrorsReflector()); - var http = PlatformHttp(app); - return http.createRequestContext(rq, rq.response); -} diff --git a/packages/core/test/all.dart b/packages/core/test/all.dart deleted file mode 100644 index ae283f1..0000000 --- a/packages/core/test/all.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'dart:io'; -import 'package:io/ansi.dart'; -import 'http_404_hole_test.dart' as hole404; -import 'accepts_test.dart' as accepts; -import 'anonymous_service_test.dart' as anonymous_service; -import 'body_test.dart' as body; -import 'controller_test.dart' as controller; -import 'detach_test.dart' as detach; -import 'di_test.dart' as di; -import 'encoders_buffer_test.dart' as encoders_buffer; -import 'env_test.dart' as env; -import 'exception_test.dart' as exception; -import 'extension_test.dart' as extension_test; -import 'find_one_test.dart' as find_one; -import 'general_test.dart' as general; -import 'hooked_test.dart' as hooked; -import 'parameter_meta_test.dart' as parameter_meta; -import 'parse_id_test.dart' as parse_id; -import 'precontained_test.dart' as precontained; -import 'primitives_test.dart' as primitives; -import 'repeat_request_test.dart' as repeat_request; -import 'req_shutdown_test.dart' as req_shutdown; -import 'routing_test.dart' as routing; -import 'serialize_test.dart' as serialize; -import 'server_test.dart' as server; -import 'service_map_test.dart' as service_map; -import 'services_test.dart' as services; -import 'streaming_test.dart' as streaming; -import 'view_generator_test.dart' as view_generator; -//import 'response_header_test.dart' as response_header; -import 'package:test/test.dart'; - -/// For running with coverage -void main() { - print(cyan.wrap('Running tests on ${Platform.version}')); - group('http_404_hole', hole404.main); - group('accepts', accepts.main); - group('anonymous service', anonymous_service.main); - group('body', body.main); - //group('response_header', response_header.main); - group('controller', controller.main); - group('detach', detach.main); - group('di', di.main); - group('encoders_buffer', encoders_buffer.main); - group('env', env.main); - group('exception', exception.main); - group('extension', extension_test.main); - group('find_one', find_one.main); - group('general', general.main); - group('hooked', hooked.main); - group('parameter_meta', parameter_meta.main); - group('parse_id', parse_id.main); - group('precontained', precontained.main); - group('primitives', primitives.main); - group('repeat_request', repeat_request.main); - group('req_shutdown', req_shutdown.main); - group('routing', routing.main); - group('serialize', serialize.main); - group('server', server.main); - group('service_map', service_map.main); - group('services', services.main); - group('streaming', streaming.main); - group('view generator', view_generator.main); -} diff --git a/packages/core/test/anonymous_service_test.dart b/packages/core/test/anonymous_service_test.dart deleted file mode 100644 index 9785c1a..0000000 --- a/packages/core/test/anonymous_service_test.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:platform_core/core.dart'; -import 'package:test/test.dart'; - -void main() { - test('custom methods', () async { - var svc = AnonymousService( - index: ([p]) async => ['index'], - read: (id, [p]) async => 'read', - create: (data, [p]) async => 'create', - modify: (id, data, [p]) async => 'modify', - update: (id, data, [p]) async => 'update', - remove: (id, [p]) async => 'remove'); - expect(await svc.index(), ['index']); - expect(await svc.read(null), 'read'); - expect(await svc.create(null), 'create'); - expect(await svc.modify(null, null), 'modify'); - expect(await svc.update(null, null), 'update'); - expect(await svc.remove(null), 'remove'); - }); - - test('defaults to throwing', () async { - try { - var svc = AnonymousService(); - await svc.read(1); - throw 'Should have thrown 405!'; - } on PlatformHttpException { - // print('Ok!'); - } - try { - var svc = AnonymousService(); - await svc.modify(2, null); - throw 'Should have thrown 405!'; - } on PlatformHttpException { - // print('Ok!'); - } - try { - var svc = AnonymousService(); - await svc.update(3, null); - throw 'Should have thrown 405!'; - } on PlatformHttpException { - // print('Ok!'); - } - }); -} diff --git a/packages/core/test/body_test.dart b/packages/core/test/body_test.dart deleted file mode 100644 index f57e0a9..0000000 --- a/packages/core/test/body_test.dart +++ /dev/null @@ -1,139 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -void main() { - var app = Application(); - var http = PlatformHttp(app); - - Future request( - {bool asJson = true, - bool parse = true, - Map? bodyFields, - List? bodyList}) async { - var rq = - MockHttpRequest('POST', Uri(path: '/'), persistentConnection: false); - - if (bodyFields != null) { - if (asJson) { - rq - ..headers.contentType = ContentType('application', 'json') - ..write(json.encode(bodyFields)); - } else { - var b = StringBuffer(); - var i = 0; - for (var entry in bodyFields.entries) { - if (i++ > 0) b.write('&'); - b.write(entry.key); - b.write('='); - b.write(Uri.encodeComponent(entry.value.toString())); - } - - rq - ..headers.contentType = - ContentType('application', 'x-www-form-urlencoded') - ..write(json.encode(b.toString())); - } - } else if (bodyList != null) { - rq - ..headers.contentType = ContentType('application', 'json') - ..write(json.encode(bodyList)); - } - - await rq.close(); - var req = await http.createRequestContext(rq, rq.response); - if (parse) await req.parseBody(); - return req; - } - - test('parses json maps', () async { - var req = await request(bodyFields: {'hello': 'world'}); - expect(req.bodyAsObject, TypeMatcher>()); - expect(req.bodyAsMap, {'hello': 'world'}); - }); - - test('parses json lists', () async { - var req = await request(bodyList: ['foo', 'bar']); - expect(req.bodyAsObject, TypeMatcher()); - expect(req.bodyAsList, ['foo', 'bar']); - }); - - test('deserializeBody', () async { - var req = await request( - asJson: true, bodyFields: {'text': 'Hey', 'complete': false}); - var todo = await req.deserializeBody(Todo.fromMap); - expect(todo.text, 'Hey'); - expect(todo.completed, false); - }); - - test('decodeBody', () async { - var req = await request( - asJson: true, bodyFields: {'text': 'Hey', 'complete': false}); - var todo = await req.decodeBody(TodoCodec()); - expect(todo.text, 'Hey'); - expect(todo.completed, false); - }); - - test('throws when body has not been parsed', () async { - var req = await request(parse: false); - expect(() => req.bodyAsObject, throwsStateError); - expect(() => req.bodyAsMap, throwsStateError); - expect(() => req.bodyAsList, throwsStateError); - }); - - test('can set body object exactly once', () async { - var req = await request(parse: false); - req.bodyAsObject = 23; - expect(req.bodyAsObject, 23); - expect(() => req.bodyAsObject = {45.6: '34'}, throwsStateError); - }); - - test('can set body map exactly once', () async { - var req = await request(parse: false); - req.bodyAsMap = {'hey': 'yes'}; - expect(req.bodyAsMap, {'hey': 'yes'}); - expect(() => req.bodyAsMap = {'hm': 'ok'}, throwsStateError); - }); - - test('can set body list exactly once', () async { - var req = await request(parse: false); - req.bodyAsList = [ - {'hey': 'yes'} - ]; - expect(req.bodyAsList, [ - {'hey': 'yes'} - ]); - expect( - () => req.bodyAsList = [ - {'hm': 'ok'} - ], - throwsStateError); - }); -} - -class Todo { - String? text; - bool? completed; - - Todo({this.text, this.completed}); - - static Todo fromMap(Map? m) => - Todo(text: m!['text'] as String?, completed: m['complete'] as bool?); -} - -class TodoCodec extends Codec { - @override - Converter get decoder => TodoDecoder(); - - @override - Converter get encoder => throw UnsupportedError('no encoder'); -} - -class TodoDecoder extends Converter { - @override - Todo convert(Map input) => Todo.fromMap(input); -} diff --git a/packages/core/test/common.dart b/packages/core/test/common.dart deleted file mode 100644 index 5d51d3c..0000000 --- a/packages/core/test/common.dart +++ /dev/null @@ -1,60 +0,0 @@ -library angel_framework.test.common; - -import 'package:platform_core/core.dart'; -import 'package:matcher/matcher.dart'; - -class Todo extends Model { - String? text; - String? over; - - Todo({this.text, this.over}); - - Map toJson() { - return { - 'text': text, - 'over': over, - }; - } -} - -class BookService extends Service { - @override - Future index([params]) async { - print('Book params: $params'); - - return [ - {'foo': 'bar'} - ]; - } -} - -void incrementTodoTimes(e) { - IncrementService.times++; -} - -@Hooks(before: [incrementTodoTimes]) -class IncrementService extends Service { - static int times = 0; - - @override - @Hooks(after: [incrementTodoTimes]) - Future index([params]) async => []; -} - -class IsInstanceOf implements Matcher { - const IsInstanceOf(); - - @override - Description describeMismatch( - item, Description mismatchDescription, Map matchState, bool verbose) { - return mismatchDescription.add('$item is not an instance of $T'); - } - - @override - Description describe(Description description) { - return description.add('is an instance of $T'); - } - - @override - bool matches(item, Map matchState) => item is T; -} diff --git a/packages/core/test/controller_test.dart b/packages/core/test/controller_test.dart deleted file mode 100644 index d8aa584..0000000 --- a/packages/core/test/controller_test.dart +++ /dev/null @@ -1,206 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:http/http.dart' as http; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -import 'common.dart'; - -@Expose('/todos', middleware: [foo]) -class TodoController extends Controller { - List todos = [Todo(text: 'Hello', over: 'world')]; - - @Expose('/:id', middleware: [bar]) - Future fetchTodo( - String id, RequestContext req, ResponseContext res) async { - expect(req, isNotNull); - expect(res, isNotNull); - return todos[int.parse(id)]; - } - - @Expose('/namedRoute/:foo', as: 'foo') - Future someRandomRoute( - RequestContext req, ResponseContext res) async { - return "${req.params['foo']}!"; - } -} - -class NoExposeController extends Controller { - String getIndex() => 'Hey!'; - - int timesTwo(int n) => n * 2; - - String repeatName(String name, int times) { - var b = StringBuffer(); - for (var i = 0; i < times; i++) { - b.writeln(name); - } - return b.toString(); - } - - @Expose('/yellow', method: 'POST') - String someColor() => 'yellow'; - - @Expose.patch - int three() => 333; - - @noExpose - String hideThis() => 'Should not be exposed'; -} - -@Expose('/named', as: 'foo') -class NamedController extends Controller { - @Expose('/optional/:arg?', allowNull: ['arg']) - int optional() => 2; -} - -bool foo(RequestContext req, ResponseContext res) { - res.write('Hello, '); - return true; -} - -bool bar(RequestContext req, ResponseContext res) { - res.write('world!'); - return true; -} - -void main() { - late Application app; - late TodoController todoController; - late NoExposeController noExposeCtrl; - late HttpServer server; - var client = http.Client(); - String? url; - - setUp(() async { - app = Application(reflector: MirrorsReflector()); - app.get( - '/redirect', - (req, res) async => - res.redirectToAction('TodoController@foo', {'foo': 'world'})); - - // Register as a singleton, just for the purpose of this test - if (!app.container.has()) { - app.container.registerSingleton(todoController = TodoController()); - } - - // Using mountController(); - await app.mountController(); - - noExposeCtrl = await app.mountController(); - - // Place controller in group. The applyRoutes() call, however, is async. - // Until https://github.com/angel-dart/route/issues/28 is closed, - // this will need to be done by manually mounting the router. - var subRouter = Router(); - await todoController.applyRoutes(subRouter, app.container.reflector); - app.mount('/ctrl_group', subRouter); - - print(app.controllers); - app.dumpTree(); - - server = await PlatformHttp(app).startServer(); - url = 'http://${server.address.address}:${server.port}'; - }); - - tearDown(() async { - await server.close(force: true); - url = null; - }); - - test('basic', () { - expect(todoController.app, app); - }); - - test('create dynamic handler', () async { - var app = Application(reflector: MirrorsReflector()); - app.get( - '/foo', - ioc(({String? bar}) { - return 2; - }, optional: ['bar'])); - var rq = MockHttpRequest('GET', Uri(path: 'foo')); - await PlatformHttp(app).handleRequest(rq); - var body = await utf8.decoder.bind(rq.response).join(); - expect(json.decode(body), 2); - }); - - test('optional name', () async { - var app = Application(reflector: MirrorsReflector()); - await app.configure(NamedController().configureServer); - expect(app.controllers['foo'], const IsInstanceOf()); - }); - - test('middleware', () async { - var rgx = RegExp('^Hello, world!'); - var response = await client.get(Uri.parse('$url/todos/0')); - print('Response: ${response.body}'); - - expect(rgx.firstMatch(response.body)?.start, equals(0)); - - var todo = json.decode(response.body.replaceAll(rgx, '')) as Map; - print('Todo: $todo'); - expect(todo['text'], equals('Hello')); - expect(todo['over'], equals('world')); - }); - - test('controller in group', () async { - var rgx = RegExp('^Hello, world!'); - var response = await client.get(Uri.parse('$url/ctrl_group/todos/0')); - print('Response: ${response.body}'); - - expect(rgx.firstMatch(response.body)?.start, equals(0)); - - var todo = json.decode(response.body.replaceAll(rgx, '')) as Map; - print('Todo: $todo'); - expect(todo['text'], equals('Hello')); - expect(todo['over'], equals('world')); - }); - - test('named actions', () async { - var response = await client.get(Uri.parse('$url/redirect')); - print('Response: ${response.body}'); - expect(response.body, equals('Hello, "world!"')); - }); - - group('optional expose', () { - test('removes suffixes from controller names', () { - expect(noExposeCtrl.mountPoint!.path, 'no_expose'); - }); - - test('mounts correct routes', () { - print(noExposeCtrl.routeMappings.keys); - expect(noExposeCtrl.routeMappings.keys.toList(), - ['getIndex', 'timesTwo', 'repeatName', 'someColor', 'three']); - }); - - test('mounts correct methods', () { - void expectMethod(String name, String method) { - expect(noExposeCtrl.routeMappings[name]!.method, method); - } - - expectMethod('getIndex', 'GET'); - expectMethod('timesTwo', 'GET'); - expectMethod('repeatName', 'GET'); - expectMethod('someColor', 'POST'); - expectMethod('three', 'PATCH'); - }); - - test('mounts correct paths', () { - void expectPath(String name, String path) { - expect(noExposeCtrl.routeMappings[name]!.path, path); - } - - expectPath('getIndex', '/'); - expectPath('timesTwo', '/times_two/int:n'); - expectPath('repeatName', '/repeat_name/:name/int:times'); - expectPath('someColor', '/yellow'); - expectPath('three', '/three'); - }); - }); -} diff --git a/packages/core/test/detach_test.dart b/packages/core/test/detach_test.dart deleted file mode 100644 index fe2c696..0000000 --- a/packages/core/test/detach_test.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'dart:convert'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -void main() { - late PlatformHttp http; - - setUp(() async { - var app = Application(); - http = PlatformHttp(app); - - app.get('/detach', (req, res) async { - if (res is HttpResponseContext) { - var io = res.detach(); - io.write('Hey!'); - await io.close(); - } else { - throw StateError('This endpoint only supports HTTP/1.1.'); - } - }); - }); - - tearDown(() => http.close()); - - test('detach response', () async { - var rq = MockHttpRequest('GET', Uri.parse('/detach')); - await rq.close(); - var rs = rq.response; - await http.handleRequest(rq); - var body = await rs.transform(utf8.decoder).join(); - expect(body, 'Hey!'); - }); -} diff --git a/packages/core/test/di_test.dart b/packages/core/test/di_test.dart deleted file mode 100644 index 651a232..0000000 --- a/packages/core/test/di_test.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:platform_container/container.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:http/http.dart' as http; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -import 'common.dart'; - -final String sampleText = 'make your bed'; -final String sampleOver = 'never'; - -void main() { - late Application app; - late http.Client client; - late HttpServer server; - String? url; - - setUp(() async { - app = Application(reflector: MirrorsReflector()); - client = http.Client(); - - // Inject some todos - app.container.registerSingleton(Todo(text: sampleText, over: sampleOver)); - app.container.registerFactory>((container) async { - var req = container.make(); - var text = await utf8.decoder.bind(req.body!).join(); - return Foo(text); - }); - - app.get('/errands', ioc((Todo singleton) => singleton)); - app.get( - '/errands3', - ioc(({required Errand singleton, Todo? foo, RequestContext? req}) => - singleton.text)); - app.post('/async', ioc((Foo foo) => {'baz': foo.bar})); - await app.configure(SingletonController().configureServer); - await app.configure(ErrandController().configureServer); - - server = await PlatformHttp(app).startServer(); - url = 'http://${server.address.host}:${server.port}'; - }); - - tearDown(() async { - url = null; - client.close(); - await server.close(force: true); - }); - - test('runContained with custom container', () async { - var app = Application(); - var c = Container(const MirrorsReflector()); - c.registerSingleton(Todo(text: 'Hey!')); - - app.get('/', (req, res) async { - return app.runContained((Todo t) => t.text, req, res, c); - }); - - var rq = MockHttpRequest('GET', Uri(path: '/')); - await rq.close(); - var rs = rq.response; - await PlatformHttp(app).handleRequest(rq); - var text = await rs.transform(utf8.decoder).join(); - expect(text, json.encode('Hey!')); - }); - - test('singleton in route', () async { - validateTodoSingleton(await client.get(Uri.parse('$url/errands'))); - }); - - test('singleton in controller', () async { - validateTodoSingleton(await client.get(Uri.parse('$url/errands2'))); - }); - - test('make in route', () async { - var response = await client.get(Uri.parse('$url/errands3')); - var text = await json.decode(response.body) as String?; - expect(text, equals(sampleText)); - }); - - test('make in controller', () async { - var response = await client.get(Uri.parse('$url/errands4')); - var text = await json.decode(response.body) as String?; - expect(text, equals(sampleText)); - }); - - test('resolve from future in controller', () async { - var response = - await client.post(Uri.parse('$url/errands4/async'), body: 'hey'); - expect(response.body, json.encode({'bar': 'hey'})); - }); - - test('resolve from future in route', () async { - var response = await client.post(Uri.parse('$url/async'), body: 'yes'); - expect(response.body, json.encode({'baz': 'yes'})); - }); -} - -void validateTodoSingleton(response) { - var todo = json.decode(response.body.toString()) as Map; - expect(todo['id'], equals(null)); - expect(todo['text'], equals(sampleText)); - expect(todo['over'], equals(sampleOver)); -} - -@Expose('/errands2') -class SingletonController extends Controller { - @Expose('/') - Todo todo(Todo singleton) => singleton; -} - -@Expose('/errands4') -class ErrandController extends Controller { - @Expose('/') - String? errand(Errand errand) { - return errand.text; - } - - @Expose('/async', method: 'POST') - Map asyncResolve(Foo foo) { - return {'bar': foo.bar}; - } -} - -class Foo { - final String bar; - - Foo(this.bar); -} - -class Errand { - Todo todo; - - String? get text => todo.text; - - Errand(this.todo); -} diff --git a/packages/core/test/encoders_buffer_test.dart b/packages/core/test/encoders_buffer_test.dart deleted file mode 100644 index b39078d..0000000 --- a/packages/core/test/encoders_buffer_test.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' hide BytesBuilder; -import 'dart:typed_data' show BytesBuilder; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -Future> getBody(MockHttpResponse rs) async { - var list = await rs.toList(); - var bb = BytesBuilder(); - list.forEach(bb.add); - return bb.takeBytes(); -} - -void main() { - late Application app; - - setUp(() { - app = Application(reflector: MirrorsReflector()); - app.encoders.addAll( - { - 'deflate': zlib.encoder, - 'gzip': gzip.encoder, - }, - ); - - app.get('/hello', (req, res) { - res - ..useBuffer() - ..write('Hello, world!'); - }); - }); - - tearDown(() => app.close()); - - encodingTests(() => app); -} - -void encodingTests(Application Function() getApp) { - group('encoding', () { - Application app; - late PlatformHttp http; - - setUp(() { - app = getApp(); - http = PlatformHttp(app); - }); - - test('sends plaintext if no accept-encoding', () async { - var rq = MockHttpRequest('GET', Uri.parse('/hello')); - await rq.close(); - var rs = rq.response; - await http.handleRequest(rq); - - var body = await rs.transform(utf8.decoder).join(); - expect(body, 'Hello, world!'); - }); - - test('encodes if wildcard', () async { - var rq = MockHttpRequest('GET', Uri.parse('/hello')) - ..headers.set('accept-encoding', '*'); - await rq.close(); - var rs = rq.response; - await http.handleRequest(rq); - - var body = await getBody(rs); - //print(rs.headers); - expect(rs.headers.value('content-encoding'), 'deflate'); - expect(body, zlib.encode(utf8.encode('Hello, world!'))); - }); - - test('encodes if wildcard + multiple', () async { - var rq = MockHttpRequest('GET', Uri.parse('/hello')) - ..headers.set('accept-encoding', ['foo', 'bar', '*']); - await rq.close(); - var rs = rq.response; - await http.handleRequest(rq); - - var body = await getBody(rs); - expect(rs.headers.value('content-encoding'), 'deflate'); - expect(body, zlib.encode(utf8.encode('Hello, world!'))); - }); - - test('encodes if explicit', () async { - var rq = MockHttpRequest('GET', Uri.parse('/hello')) - ..headers.set('accept-encoding', 'gzip'); - await rq.close(); - var rs = rq.response; - await http.handleRequest(rq); - - var body = await getBody(rs); - expect(rs.headers.value('content-encoding'), 'gzip'); - expect(body, gzip.encode(utf8.encode('Hello, world!'))); - }); - - test('only uses one encoder', () async { - var rq = MockHttpRequest('GET', Uri.parse('/hello')); - rq.headers.set('accept-encoding', ['gzip', 'deflate']); - await rq.close(); - var rs = rq.response; - await http.handleRequest(rq); - - var body = await getBody(rs); - expect(rs.headers.value('content-encoding'), 'gzip'); - expect(body, gzip.encode(utf8.encode('Hello, world!'))); - }); - }); -} diff --git a/packages/core/test/env_test.dart b/packages/core/test/env_test.dart deleted file mode 100644 index d4ca038..0000000 --- a/packages/core/test/env_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'dart:io'; -import 'package:platform_core/core.dart'; -import 'package:test/test.dart'; - -void main() { - test('custom value', () => expect(ProtevusEnvironment('hey').value, 'hey')); - - test('lowercases', () => expect(ProtevusEnvironment('HeY').value, 'hey')); - test( - 'default to env or development', - () => expect(ProtevusEnvironment().value, - (Platform.environment['ANGEL_ENV'] ?? 'development').toLowerCase())); - test('isDevelopment', - () => expect(ProtevusEnvironment('development').isDevelopment, true)); - test('isStaging', - () => expect(ProtevusEnvironment('staging').isStaging, true)); - test('isDevelopment', - () => expect(ProtevusEnvironment('production').isProduction, true)); -} diff --git a/packages/core/test/exception_test.dart b/packages/core/test/exception_test.dart deleted file mode 100644 index 908541e..0000000 --- a/packages/core/test/exception_test.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:platform_core/core.dart'; -import 'dart:convert'; -import 'package:test/test.dart'; - -void main() { - test('named constructors', () { - expect(PlatformHttpException.badRequest(), - isException(400, '400 Bad Request')); - expect(PlatformHttpException.notAuthenticated(), - isException(401, '401 Not Authenticated')); - expect(PlatformHttpException.paymentRequired(), - isException(402, '402 Payment Required')); - expect( - PlatformHttpException.forbidden(), isException(403, '403 Forbidden')); - expect(PlatformHttpException.notFound(), isException(404, '404 Not Found')); - expect(PlatformHttpException.methodNotAllowed(), - isException(405, '405 Method Not Allowed')); - expect(PlatformHttpException.notAcceptable(), - isException(406, '406 Not Acceptable')); - expect( - PlatformHttpException.methodTimeout(), isException(408, '408 Timeout')); - expect(PlatformHttpException.conflict(), isException(409, '409 Conflict')); - expect(PlatformHttpException.notProcessable(), - isException(422, '422 Not Processable')); - expect(PlatformHttpException.notImplemented(), - isException(501, '501 Not Implemented')); - expect(PlatformHttpException.unavailable(), - isException(503, '503 Unavailable')); - }); - - test('fromMap', () { - expect(PlatformHttpException.fromMap({'status_code': -1, 'message': 'ok'}), - isException(-1, 'ok')); - }); - - test('toMap = toJson', () { - var exc = PlatformHttpException.badRequest(); - expect(exc.toMap(), exc.toJson()); - var json_ = json.encode(exc.toJson()); - var exc2 = PlatformHttpException.fromJson(json_); - expect(exc2.toJson(), exc.toJson()); - }); - - test('toString', () { - expect( - PlatformHttpException(statusCode: 420, message: 'Blaze It').toString(), - '420: Blaze It'); - }); -} - -Matcher isException(int statusCode, String message) => - _IsException(statusCode, message); - -class _IsException extends Matcher { - final int statusCode; - final String message; - - _IsException(this.statusCode, this.message); - - @override - Description describe(Description description) => - description.add('has status code $statusCode and message "$message"'); - - @override - bool matches(item, Map matchState) { - return item is PlatformHttpException && - item.statusCode == statusCode && - item.message == message; - } -} diff --git a/packages/core/test/extension_test.dart b/packages/core/test/extension_test.dart deleted file mode 100644 index 0e077a3..0000000 --- a/packages/core/test/extension_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'dart:async'; -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -final Uri endpoint = Uri.parse('http://example.com'); - -void main() { - test('single extension', () async { - var req = await makeRequest('foo.js'); - expect(req.extension, '.js'); - }); - - test('multiple extensions', () async { - var req = await makeRequest('foo.min.js'); - expect(req.extension, '.js'); - }); - - test('no extension', () async { - var req = await makeRequest('foo'); - expect(req.extension, ''); - }); -} - -Future makeRequest(String path) { - var rq = MockHttpRequest('GET', endpoint.replace(path: path))..close(); - var app = Application(reflector: MirrorsReflector()); - var http = PlatformHttp(app); - return http.createRequestContext(rq, rq.response); -} diff --git a/packages/core/test/find_one_test.dart b/packages/core/test/find_one_test.dart deleted file mode 100644 index 645660c..0000000 --- a/packages/core/test/find_one_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:platform_core/core.dart'; -import 'package:test/test.dart'; -import 'common.dart'; - -void main() { - var throwsAnHttpException = - throwsA(const IsInstanceOf()); - - /* - test('throw 404 on null', () { - var service = AnonymousService(index: ([p]) => null); - expect(() => service.findOne(), throwsAnHttpException); - }); - */ - - test('throw 404 on empty iterable', () { - var service = AnonymousService(index: ([p]) => []); - expect(() => service.findOne(), throwsAnHttpException); - }); - - test('return first element of iterable', () async { - var service = AnonymousService(index: ([p]) => [2]); - expect(await service.findOne(), 2); - }); -} diff --git a/packages/core/test/general_test.dart b/packages/core/test/general_test.dart deleted file mode 100644 index 20b7fe9..0000000 --- a/packages/core/test/general_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:io'; -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:test/test.dart'; - -void main() { - late Application app; - late http.Client client; - late HttpServer server; - late String url; - - setUp(() async { - app = Application(reflector: MirrorsReflector()) - ..post('/foo', (req, res) => res.serialize({'hello': 'world'})) - ..all('*', (req, res) => throw PlatformHttpException.notFound()); - client = http.Client(); - - server = await PlatformHttp(app).startServer(); - url = 'http://${server.address.host}:${server.port}'; - }); - - tearDown(() async { - client.close(); - await server.close(force: true); - }); - - test('allow override of method', () async { - var response = await client.get(Uri.parse('$url/foo'), - headers: {'X-HTTP-Method-Override': 'POST'}); - print('Response: ${response.body}'); - expect(json.decode(response.body), equals({'hello': 'world'})); - }); -} diff --git a/packages/core/test/hm.dart b/packages/core/test/hm.dart deleted file mode 100644 index 2480297..0000000 --- a/packages/core/test/hm.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:async'; -import 'package:io/ansi.dart'; -import 'all.dart' as hm; - -void main() async { - var zone = Zone.current.fork( - specification: ZoneSpecification(print: (self, parent, zone, line) { - if (line == 'null') { - parent.print(zone, cyan.wrap(StackTrace.current.toString())!); - } - }), - ); - return await zone.run(hm.main); -} diff --git a/packages/core/test/hooked_test.dart b/packages/core/test/hooked_test.dart deleted file mode 100644 index daa5030..0000000 --- a/packages/core/test/hooked_test.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:http/http.dart' as http; -import 'package:test/test.dart'; -import 'common.dart'; - -void main() { - Map headers = { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }; - - late Application app; - late HttpServer server; - late String url; - late http.Client client; - late HookedService todoService; - - setUp(() async { - app = Application(reflector: MirrorsReflector()); - client = http.Client(); - app.use('/todos', MapService()); - app.use('/books', BookService()); - - todoService = app.findHookedService('todos') - as HookedService; - - todoService.beforeAllStream().listen((e) { - print('Fired ${e.eventName}! Data: ${e.data}; Params: ${e.params}'); - }); - - app.errorHandler = (e, req, res) { - throw e.error as Object; - }; - - server = await PlatformHttp(app).startServer(); - url = 'http://${server.address.host}:${server.port}'; - }); - - tearDown(() async { - await server.close(force: true); - client.close(); - }); - - test('listen before and after', () async { - var count = 0; - - todoService - ..beforeIndexed.listen((_) { - count++; - }) - ..afterIndexed.listen((_) { - count++; - }); - - var response = await client.get(Uri.parse('$url/todos')); - print(response.body); - expect(count, equals(2)); - }); - - test('cancel before', () async { - todoService.beforeCreated - ..listen((HookedServiceEvent event) { - event.cancel({'hello': 'hooked world'}); - }) - ..listen((HookedServiceEvent event) { - event.cancel({'this_hook': 'should never run'}); - }); - - var response = await client.post(Uri.parse('$url/todos'), - body: json.encode({'arbitrary': 'data'}), - headers: headers as Map); - print(response.body); - var result = json.decode(response.body) as Map; - expect(result['hello'], equals('hooked world')); - }); - - test('cancel after', () async { - todoService.afterIndexed - ..listen((HookedServiceEvent event) async { - // Hooks can be Futures ;) - event.cancel([ - {'protevus': 'framework'} - ]); - }) - ..listen((HookedServiceEvent event) { - event.cancel({'this_hook': 'should never run either'}); - }); - - var response = await client.get(Uri.parse('$url/todos')); - print(response.body); - var result = json.decode(response.body) as List; - expect(result[0]['protevus'], equals('framework')); - }); - - test('asStream() fires', () async { - var stream = todoService.afterCreated.asStream(); - await todoService.create({'protevus': 'framework'}); - expect(await stream.first.then((e) => e.result['protevus']), 'framework'); - }); - - test('metadata', () async { - final service = HookedService(IncrementService())..addHooks(app); - expect(service.inner, isNot(const IsInstanceOf())); - IncrementService.times = 0; - await service.index(); - expect(IncrementService.times, equals(2)); - }); - - test('inject request + response', () async { - var books = app.findService('books') - as HookedService>; - - books.beforeIndexed.listen((e) { - expect([e.request, e.response], everyElement(isNotNull)); - print('Indexing books at path: ${e.request?.path}'); - }); - - var response = await client.get(Uri.parse('$url/books')); - print(response.body); - - var result = json.decode(response.body); - expect(result, isList); - expect(result, isNotEmpty); - expect(result[0], equals({'foo': 'bar'})); - }); - - test('contains provider in before and after', () async { - var svc = HookedService(AnonymousService(index: ([p]) async => [])); - - void ensureProviderIsPresent(HookedServiceEvent e) { - var type = e.isBefore ? 'before' : 'after'; - print('Params to $type ${e.eventName}: ${e.params}'); - expect(e.params, isMap); - expect(e.params.keys, contains('provider')); - expect(e.params['provider'], const IsInstanceOf()); - } - - svc - ..beforeAll(ensureProviderIsPresent) - ..afterAll(ensureProviderIsPresent); - - await svc.index({'provider': const Providers('testing')}); - }); -} diff --git a/packages/core/test/http2/adapter_test.dart b/packages/core/test/http2/adapter_test.dart deleted file mode 100644 index ad26840..0000000 --- a/packages/core/test/http2/adapter_test.dart +++ /dev/null @@ -1,305 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' hide BytesBuilder; -import 'dart:typed_data'; -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart' hide Header; -import 'package:platform_core/http2.dart'; -import 'package:collection/collection.dart' show IterableExtension; -import 'package:http/src/multipart_file.dart' as http; -import 'package:http/src/multipart_request.dart' as http; -import 'package:http/io_client.dart'; -import 'package:http2/transport.dart'; -import 'package:http_parser/http_parser.dart'; -import 'package:logging/logging.dart'; -import 'package:test/test.dart'; -import 'http2_client.dart'; - -const String jfk = - 'Ask not what your country can do for you, but what you can do for your country.'; - -Stream> jfkStream() { - return Stream.fromIterable([utf8.encode(jfk)]); -} - -void main() { - var client = Http2Client(); - late IOClient h1c; - Application app; - late PlatformHttp2 http2; - late Uri serverRoot; - - setUp(() async { - app = Application(reflector: MirrorsReflector()) - ..encoders['gzip'] = gzip.encoder; - hierarchicalLoggingEnabled = true; - app.logger = Logger.detached('protevus.http2') - ..onRecord.listen((rec) { - print(rec); - if (rec.error == null) return; - print(rec.error); - if (rec.stackTrace != null) print(rec.stackTrace); - }); - - app.get('/', (req, res) async { - res.write('Hello world'); - await res.close(); - }); - - app.all('/method', (req, res) => req.method); - - app.get('/json', (_, __) => {'foo': 'bar'}); - - app.get('/stream', (req, res) => jfkStream().pipe(res)); - - app.get('/headers', (req, res) async { - res.headers.addAll({'foo': 'bar', 'x-protevus': 'http2'}); - await res.close(); - }); - - app.get('/status', (req, res) async { - res.statusCode = 1337; - await res.close(); - }); - - app.post('/body', (req, res) => req.parseBody().then((_) => req.bodyAsMap)); - - app.post('/upload', (req, res) async { - await req.parseBody(); - var body = req.bodyAsMap; - var files = req.uploadedFiles ?? []; - - var file = files.firstWhereOrNull((f) => f.name == 'file')!; - return [ - await file.data.map((l) => l.length).reduce((a, b) => a + b), - file.contentType.mimeType, - body - ]; - }); - - app.get('/push', (req, res) async { - res.write('ok'); - - if (res is Http2ResponseContext && res.canPush) { - var a = res.push('a')..write('a'); - await a.close(); - - var b = res.push('b')..write('b'); - await b.close(); - } - - await res.close(); - }); - - app.get('/param/:name', (req, res) => req.params); - - app.get('/query', (req, res) { - print('incoming URI: ${req.uri}'); - return req.queryParameters; - }); - - var ctx = SecurityContext() - ..useCertificateChain('dev.pem') - ..usePrivateKey('dev.key', password: 'dartdart') - ..setAlpnProtocols(['h2'], true); - - // Create an HTTP client that trusts our server. - h1c = IOClient(HttpClient()..badCertificateCallback = (_, __, ___) => true); - - http2 = PlatformHttp2(app, ctx, allowHttp1: true); - - var server = await http2.startServer(); - serverRoot = Uri.parse('https://127.0.0.1:${server.port}'); - }); - - tearDown(() async { - await http2.close(); - h1c.close(); - }); - - test('buffered response', () async { - var response = await client.get(serverRoot); - expect(response.body, 'Hello world'); - }); - - test('allowHttp1', () async { - var response = await h1c.get(serverRoot); - expect(response.body, 'Hello world'); - }); - - test('streamed response', () async { - var response = await client.get(serverRoot.replace(path: '/stream')); - expect(response.body, jfk); - }); - - group('gzip', () { - test('buffered response', () async { - var response = await client - .get(serverRoot, headers: {'accept-encoding': 'gzip, deflate, br'}); - expect(response.headers['content-encoding'], 'gzip'); - var decoded = gzip.decode(response.bodyBytes); - expect(utf8.decode(decoded), 'Hello world'); - }); - - test('streamed response', () async { - var response = await client.get(serverRoot.replace(path: '/stream'), - headers: {'accept-encoding': 'gzip'}); - expect(response.headers['content-encoding'], 'gzip'); - //print(response.body); - var decoded = gzip.decode(response.bodyBytes); - expect(utf8.decode(decoded), jfk); - }); - }); - - test('query uri decoded', () async { - var uri = - serverRoot.replace(path: '/query', queryParameters: {'foo!': 'bar?'}); - var response = await client.get(uri); - print('Sent $uri'); - expect(response.body, json.encode({'foo!': 'bar?'})); - }); - - test('params uri decoded', () async { - var response = await client.get(serverRoot.replace(path: '/param/foo!')); - expect(response.body, json.encode({'name': 'foo!'})); - }); - - test('method parsed', () async { - var response = await client.delete(serverRoot.replace(path: '/method')); - expect(response.body, json.encode('DELETE')); - }); - - test('json response', () async { - var response = await client.get(serverRoot.replace(path: '/json')); - expect(response.body, json.encode({'foo': 'bar'})); - expect(ContentType.parse(response.headers['content-type']!).mimeType, - ContentType.json.mimeType); - }); - - test('status sent', () async { - var response = await client.get(serverRoot.replace(path: '/status')); - expect(response.statusCode, 1337); - }); - - test('headers sent', () async { - var response = await client.get(serverRoot.replace(path: '/headers')); - expect(response.headers['foo'], 'bar'); - expect(response.headers['x-protevus'], 'http2'); - }); - - test('server push', () async { - var socket = await SecureSocket.connect( - serverRoot.host, - serverRoot.port, - onBadCertificate: (_) => true, - supportedProtocols: ['h2'], - ); - - var connection = ClientTransportConnection.viaSocket( - socket, - settings: ClientSettings(allowServerPushes: true), - ); - - var headers =
[ - Header.ascii(':authority', serverRoot.authority), - Header.ascii(':method', 'GET'), - Header.ascii(':path', serverRoot.replace(path: '/push').path), - Header.ascii(':scheme', serverRoot.scheme), - ]; - - var stream = connection.makeRequest(headers, endStream: true); - - var bb = await stream.incomingMessages - .where((s) => s is DataStreamMessage) - .cast() - .fold(BytesBuilder(), (out, msg) => out..add(msg.bytes)); - - // Check that main body was sent - expect(utf8.decode(bb.takeBytes()), 'ok'); - - var pushes = await stream.peerPushes.toList(); - expect(pushes, hasLength(2)); - - var pushA = pushes[0], pushB = pushes[1]; - - String getPath(TransportStreamPush p) => ascii.decode(p.requestHeaders - .firstWhere((h) => ascii.decode(h.name) == ':path') - .value); - - /* - Future getBody(ClientTransportStream stream) async { - await stream.outgoingMessages.close(); - var bb = await stream.incomingMessages - .map((s) { - if (s is HeadersStreamMessage) { - for (var h in s.headers) { - print('${ASCII.decode(h.name)}: ${ASCII.decode(h.value)}'); - } - } else if (s is DataStreamMessage) { - print(UTF8.decode(s.bytes)); - } - - return s; - }) - .where((s) => s is DataStreamMessage) - .cast() - .fold( - BytesBuilder(), (out, msg) => out..add(msg.bytes)); - return UTF8.decode(bb.takeBytes()); - } - */ - - expect(getPath(pushA), '/a'); - expect(getPath(pushB), '/b'); - - // However, Chrome, Firefox, Edge all can - //expect(await getBody(pushA.stream), 'a'); - //expect(await getBody(pushB.stream), 'b'); - }); - - group('body parsing', () { - test('urlencoded body parsed', () async { - var response = await client.post( - serverRoot.replace(path: '/body'), - headers: { - 'accept': 'application/json', - 'content-type': 'application/x-www-form-urlencoded' - }, - body: 'foo=bar', - ); - expect(response.body, json.encode({'foo': 'bar'})); - }); - - test('json body parsed', () async { - var response = await client.post(serverRoot.replace(path: '/body'), - headers: { - 'accept': 'application/json', - 'content-type': 'application/json' - }, - body: json.encode({'foo': 'bar'})); - expect(response.body, json.encode({'foo': 'bar'})); - }); - - test('multipart body parsed', () async { - var rq = - http.MultipartRequest('POST', serverRoot.replace(path: '/upload')); - rq.headers.addAll({'accept': 'application/json'}); - - rq.fields['foo'] = 'bar'; - rq.files.add(http.MultipartFile( - 'file', Stream.fromIterable([utf8.encode('hello world')]), 11, - contentType: MediaType('protevus', 'framework'))); - - var response = await client.send(rq); - var responseBody = await response.stream.transform(utf8.decoder).join(); - - expect( - responseBody, - json.encode([ - 11, - 'protevus/framework', - {'foo': 'bar'} - ])); - }); - }); -} diff --git a/packages/core/test/http2/http2_client.dart b/packages/core/test/http2/http2_client.dart deleted file mode 100644 index 4edefb4..0000000 --- a/packages/core/test/http2/http2_client.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' hide BytesBuilder; -import 'dart:typed_data'; -import 'package:http/http.dart'; -import 'package:http2/transport.dart'; - -/// Simple HTTP/2 client -class Http2Client extends BaseClient { - static Future convertRequestToStream( - BaseRequest request) async { - // Connect a socket - var socket = await SecureSocket.connect( - request.url.host, - request.url.port, - onBadCertificate: (_) => true, - supportedProtocols: ['h2'], - ); - - var connection = ClientTransportConnection.viaSocket(socket); - - var headers =
[ - Header.ascii(':authority', request.url.authority), - Header.ascii(':method', request.method), - Header.ascii( - ':path', - request.url.path + - (request.url.hasQuery ? ('?${request.url.query}') : '')), - Header.ascii(':scheme', request.url.scheme), - ]; - - var bb = await request - .finalize() - .fold(BytesBuilder(), (out, list) => out..add(list)); - var body = bb.takeBytes(); - - if (body.isNotEmpty) { - headers.add(Header.ascii('content-length', body.length.toString())); - } - - request.headers.forEach((k, v) { - headers.add(Header.ascii(k, v)); - }); - - var stream = connection.makeRequest(headers, endStream: body.isEmpty); - - if (body.isNotEmpty) { - stream.sendData(body, endStream: true); - } else { - await (stream.outgoingMessages.close()); - } - - return stream; - } - - /// Returns `true` if the response stream was closed. - static Future readResponse(ClientTransportStream stream, - Map headers, BytesBuilder body) { - var c = Completer(); - var closed = false; - - stream.incomingMessages.listen( - (msg) { - if (msg is HeadersStreamMessage) { - for (var header in msg.headers) { - var name = ascii.decode(header.name).toLowerCase(), - value = ascii.decode(header.value); - headers[name] = value; - //print('$name: $value'); - } - } else if (msg is DataStreamMessage) { - body.add(msg.bytes); - } - - if (!closed && msg.endStream) closed = true; - }, - cancelOnError: true, - onError: c.completeError, - onDone: () => c.complete(closed), - ); - - return c.future; - } - - @override - Future send(BaseRequest request) async { - var stream = await convertRequestToStream(request); - var headers = {}; - var body = BytesBuilder(); - var closed = await readResponse(stream, headers, body); - return StreamedResponse( - Stream.fromIterable([body.takeBytes()]), - int.parse(headers[':status']!), - headers: headers, - isRedirect: headers.containsKey('location'), - contentLength: headers.containsKey('content-length') - ? int.parse(headers['content-length']!) - : null, - request: request, - reasonPhrase: null, - // doesn't exist in HTTP/2 - persistentConnection: !closed, - ); - } -} diff --git a/packages/core/test/http_404_hole_test.dart b/packages/core/test/http_404_hole_test.dart deleted file mode 100644 index 433fae6..0000000 --- a/packages/core/test/http_404_hole_test.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'dart:async'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:charcode/ascii.dart'; -import 'package:http/io_client.dart' as http; -import 'package:logging/logging.dart'; -import 'package:test/test.dart'; -import 'pretty_log.dart'; - -void main() { - late http.IOClient client; - late PlatformHttp driver; - late Logger logger; - - setUp(() async { - client = http.IOClient(); - hierarchicalLoggingEnabled = true; - - logger = Logger.detached('http_404_hole') - ..level = Level.ALL - ..onRecord.listen(prettyLog); - - var app = Application(logger: logger); - - app.fallback(hello); - app.fallback(throw404); - - // The error handler in the boilerplate. - var oldErrorHandler = app.errorHandler; - app.errorHandler = (e, req, res) async { - if (req.accepts('text/html', strict: true)) { - if (e.statusCode == 404 && req.accepts('text/html', strict: true)) { - await res - .render('error', {'message': 'No file exists at ${req.uri}.'}); - } else { - await res.render('error', {'message': e.message}); - } - } else { - return await oldErrorHandler(e, req, res); - } - }; - - driver = PlatformHttp(app); - await driver.startServer(); - }); - - tearDown(() { - logger.clearListeners(); - client.close(); - scheduleMicrotask(driver.close); - }); - - test('does not continue processing after streaming', () async { - var url = driver.uri.replace(path: '/hey'); - for (var i = 0; i < 100; i++) { - var r = await client.get(url); - print('#$i: ${r.statusCode}: ${r.body}'); - expect(r.statusCode, 200); - expect(r.body, 'Hello!'); - } - }); -} - -/// Simulate angel_static -Future hello(RequestContext req, ResponseContext res) { - if (req.path == 'hey') { - var bytes = [$H, $e, $l, $l, $o, $exclamation]; - var s = Stream>.fromIterable([bytes]); - return s.pipe(res); - } else { - return Future.value(); - } -} - -/// 404 -void throw404(RequestContext req, ResponseContext res) { - Zone.current - .handleUncaughtError('This 404 should not occur.', StackTrace.current); - throw PlatformHttpException.notFound(); -} diff --git a/packages/core/test/jsonp_test.dart b/packages/core/test/jsonp_test.dart deleted file mode 100644 index 3b67add..0000000 --- a/packages/core/test/jsonp_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:http_parser/http_parser.dart'; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -void main() { - var app = Application(); - var http = PlatformHttp(app); - - app.get('/default', (req, res) => res.jsonp({'foo': 'bar'})); - - app.get('/callback', - (req, res) => res.jsonp({'foo': 'bar'}, callbackName: 'doIt')); - - app.get( - '/contentType', - (req, res) => - res.jsonp({'foo': 'bar'}, contentType: MediaType('foo', 'bar'))); - - Future getContentType(String path) async { - var rq = MockHttpRequest('GET', Uri(path: '/$path')); - await rq.close(); - await http.handleRequest(rq); - return MediaType.parse(rq.response.headers.contentType.toString()); - } - - Future getText(String path) async { - var rq = MockHttpRequest('GET', Uri(path: '/$path')); - await rq.close(); - await http.handleRequest(rq); - return await rq.response.transform(utf8.decoder).join(); - } - - test('default', () async { - var response = await getText('default'); - var contentType = await getContentType('default'); - expect(response, r'callback({"foo":"bar"})'); - expect(contentType.mimeType, 'application/javascript'); - }); - - test('callback', () async { - var response = await getText('callback'); - var contentType = await getContentType('callback'); - expect(response, r'doIt({"foo":"bar"})'); - expect(contentType.mimeType, 'application/javascript'); - }); - - test('content type', () async { - var response = await getText('contentType'); - var contentType = await getContentType('contentType'); - expect(response, r'callback({"foo":"bar"})'); - expect(contentType.mimeType, 'foo/bar'); - }); -} diff --git a/packages/core/test/parameter_meta_test.dart b/packages/core/test/parameter_meta_test.dart deleted file mode 100644 index a0b01ae..0000000 --- a/packages/core/test/parameter_meta_test.dart +++ /dev/null @@ -1,150 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; -import 'package:logging/logging.dart'; - -import 'package:test/test.dart'; - -Future readResponse(MockHttpResponse rs) { - return rs.transform(utf8.decoder).join(); -} - -Future printResponse(MockHttpResponse rs) { - return readResponse(rs).then((text) { - print(text.isEmpty ? '' : text); - }); -} - -void main() { - group('parameter_meta', parameterMetaTests); -} - -void parameterMetaTests() { - Application app; - late PlatformHttp http; - - setUp(() { - app = Application(reflector: MirrorsReflector()); - http = PlatformHttp(app); - - app.get('/cookie', ioc((@CookieValue('token') String jwt) { - return jwt; - })); - - app.get('/header', ioc((@Header('x-foo') String header) { - return header; - })); - - app.get('/query', ioc((@Query('q') String query) { - return query; - })); - - app.get('/session', ioc((@Session('foo') String foo) { - return foo; - })); - - app.get('/match', ioc((@Query('mode', match: 'pos') String mode) { - return 'YES $mode'; - })); - - app.get('/match', ioc((@Query('mode', match: 'neg') String mode) { - return 'NO $mode'; - })); - - app.get('/match', ioc((@Query('mode') String mode) { - return 'DEFAULT $mode'; - })); - - app.logger = Logger('parameter_meta_test') - ..onRecord.listen((rec) { - print(rec); - if (rec.error != null) print(rec.error); - if (rec.stackTrace != null) print(rec.stackTrace); - }); - }); - - test('injects header or throws', () async { - // Invalid request - var rq = MockHttpRequest('GET', Uri.parse('/header')); - await rq.close(); - var rs = rq.response; - //TODO: Using await will hang. To be resolved. - http.handleRequest(rq); - - await printResponse(rs); - expect(rs.statusCode, 400); - - // Valid request - rq = MockHttpRequest('GET', Uri.parse('/header')) - ..headers.add('x-foo', 'bar'); - await rq.close(); - rs = rq.response; - http.handleRequest(rq); - - var body = await readResponse(rs); - print('Body: $body'); - expect(rs.statusCode, 200); - expect(body, json.encode('bar')); - }); - - test('injects session or throws', () async { - // Invalid request - var rq = MockHttpRequest('GET', Uri.parse('/session')); - await rq.close(); - var rs = rq.response; - http - .handleRequest(rq) - .timeout(const Duration(seconds: 5)) - .catchError((_) => null); - - await printResponse(rs); - expect(rs.statusCode, 500); - - rq = MockHttpRequest('GET', Uri.parse('/session')); - rq.session['foo'] = 'bar'; - await rq.close(); - rs = rq.response; - http.handleRequest(rq); - - await printResponse(rs); - expect(rs.statusCode, 200); - }); - - // Originally, the plan was to test cookie, session, header, etc., - // but that behavior has been consolidated into `getValue`. Thus, - // they will all function the same way. - - test('pattern matching', () async { - var rq = MockHttpRequest('GET', Uri.parse('/match?mode=pos')); - await rq.close(); - var rs = rq.response; - http.handleRequest(rq); - var body = await readResponse(rs); - print('Body: $body'); - expect(rs.statusCode, 200); - expect(body, json.encode('YES pos')); - - rq = MockHttpRequest('GET', Uri.parse('/match?mode=neg')); - await rq.close(); - rs = rq.response; - http.handleRequest(rq); - body = await readResponse(rs); - print('Body: $body'); - expect(rs.statusCode, 200); - expect(body, json.encode('NO neg')); - - // Fallback - rq = MockHttpRequest('GET', Uri.parse('/match?mode=ambi')); - await rq.close(); - rs = rq.response; - http.handleRequest(rq); - body = await readResponse(rs); - print('Body: $body'); - expect(rs.statusCode, 200); - expect(body, json.encode('DEFAULT ambi')); - }); -} diff --git a/packages/core/test/parse_id_test.dart b/packages/core/test/parse_id_test.dart deleted file mode 100644 index 95f6732..0000000 --- a/packages/core/test/parse_id_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:platform_core/core.dart'; -import 'package:test/test.dart'; - -void main() { - test('null', () { - expect(Service.parseId('null'), 'null'); - expect(Service.parseId(null), 'null'); - }); - - test('String', () { - expect(Service.parseId('23'), '23'); - }); - - test('int', () { - expect(Service.parseId('23'), 23); - }); - - test('double', () { - expect(Service.parseId('23.4'), 23.4); - }); - - test('num', () { - expect(Service.parseId('23.4'), 23.4); - }); - - test('bool', () { - expect(Service.parseId('true'), true); - expect(Service.parseId(true), true); - expect(Service.parseId('false'), false); - expect(Service.parseId(false), false); - expect(Service.parseId('hmm'), false); - }); -} diff --git a/packages/core/test/precontained_test.dart b/packages/core/test/precontained_test.dart deleted file mode 100644 index c1ec560..0000000 --- a/packages/core/test/precontained_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'dart:convert'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; - -import 'package:test/test.dart'; - -void main() { - test('preinjects functions when executed', () async { - // Create app with mirrors reflector - var app = Application(reflector: MirrorsReflector()) - ..configuration['foo'] = 'bar' - ..get('/foo', ioc(echoAppFoo)); - - // Create request and response contexts - var rq = MockHttpRequest('GET', Uri(path: '/foo')); - var reqContext = await HttpRequestContext.from(rq, app, '/foo'); - var resContext = HttpResponseContext(rq.response, app, reqContext); - - // Force pre-injection by running the handler - await app.runReflected(echoAppFoo, reqContext, resContext); - - // Verify preContained has the function - expect(app.preContained.keys, contains(echoAppFoo)); - - // Clean up - await reqContext.close(); - }); -} - -String echoAppFoo(String foo) => foo; diff --git a/packages/core/test/pretty_log.dart b/packages/core/test/pretty_log.dart deleted file mode 100644 index 71febe2..0000000 --- a/packages/core/test/pretty_log.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:logging/logging.dart'; -import 'package:io/ansi.dart'; - -/// Prints the contents of a [LogRecord] with pretty colors. -void prettyLog(LogRecord record) { - var code = chooseLogColor(record.level); - - if (record.error == null) print(code.wrap(record.toString())); - - if (record.error != null) { - var err = record.error; - print(code.wrap('$record\n')); - print(code.wrap(err.toString())); - - if (record.stackTrace != null) { - print(code.wrap(record.stackTrace.toString())); - } - } -} - -/// Chooses a color based on the logger [level]. -AnsiCode chooseLogColor(Level level) { - if (level == Level.SHOUT) { - return backgroundRed; - } else if (level == Level.SEVERE) { - return red; - } else if (level == Level.WARNING) { - return yellow; - } else if (level == Level.INFO) { - return cyan; - } else if (level == Level.CONFIG || - level == Level.FINE || - level == Level.FINER || - level == Level.FINEST) { - return lightGray; - } - return resetAll; -} diff --git a/packages/core/test/primitives_test.dart b/packages/core/test/primitives_test.dart deleted file mode 100644 index f0f2288..0000000 --- a/packages/core/test/primitives_test.dart +++ /dev/null @@ -1,75 +0,0 @@ -import 'dart:convert'; -import 'dart:io' show stderr; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; - -import 'package:test/test.dart'; - -void main() { - late Application app; - late PlatformHttp http; - - setUp(() { - app = Application(reflector: MirrorsReflector()) - ..configuration['global'] = 305; // Pitbull! - http = PlatformHttp(app); - - app.get('/string/:string', ioc((String string) => string)); - - app.get( - '/num/parsed/:num', - chain([ - (req, res) { - req.params['n'] = num.parse(req.params['num'].toString()); - return true; - }, - ioc((num n) => n), - ])); - - app.get('/num/global', ioc((num global) => global)); - - app.errorHandler = (e, req, res) { - stderr - ..writeln(e.error) - ..writeln(e.stackTrace); - }; - }); - - tearDown(() => app.close()); - - test('String type annotation', () async { - var rq = MockHttpRequest('GET', Uri.parse('/string/hello')); - await rq.close(); - await http.handleRequest(rq); - var rs = await rq.response.transform(utf8.decoder).join(); - expect(rs, json.encode('hello')); - }); - - test('Primitive after parsed param injection', () async { - var rq = MockHttpRequest('GET', Uri.parse('/num/parsed/24')); - await rq.close(); - await http.handleRequest(rq); - var rs = await rq.response.transform(utf8.decoder).join(); - expect(rs, json.encode(24)); - }); - - test('globally-injected primitive', () async { - var rq = MockHttpRequest('GET', Uri.parse('/num/global')); - await rq.close(); - await http.handleRequest(rq); - var rs = await rq.response.transform(utf8.decoder).join(); - expect(rs, json.encode(305)); - }); - - test('unparsed primitive throws error', () async { - var rq = MockHttpRequest('GET', Uri.parse('/num/unparsed/32')); - await rq.close(); - var req = await http.createRequestContext(rq, rq.response); - var res = await http.createResponseContext(rq, rq.response, req); - expect(() => app.runContained((num unparsed) => unparsed, req, res), - throwsA(isA())); - }); -} diff --git a/packages/core/test/repeat_request_test.dart b/packages/core/test/repeat_request_test.dart deleted file mode 100644 index b6d09e3..0000000 --- a/packages/core/test/repeat_request_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; -import 'package:test/test.dart'; - -void main() { - MockHttpRequest mk(int id) { - return MockHttpRequest('GET', Uri.parse('/test/$id'))..close(); - } - - test('can request the same url twice', () async { - var app = Application(reflector: MirrorsReflector()) - ..get('/test/:id', ioc((id) => 'Hello $id')); - var rq1 = mk(1), rq2 = mk(2), rq3 = mk(1); - await Future.wait([rq1, rq2, rq3].map(PlatformHttp(app).handleRequest)); - var body1 = await rq1.response.transform(utf8.decoder).join(), - body2 = await rq2.response.transform(utf8.decoder).join(), - body3 = await rq3.response.transform(utf8.decoder).join(); - print('Response #1: $body1'); - print('Response #2: $body2'); - print('Response #3: $body3'); - expect( - body1, - allOf( - isNot(body2), - equals(body3), - )); - }); -} diff --git a/packages/core/test/req_shutdown_test.dart b/packages/core/test/req_shutdown_test.dart deleted file mode 100644 index 778e654..0000000 --- a/packages/core/test/req_shutdown_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:async'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:http/io_client.dart' as http; -import 'package:logging/logging.dart'; -import 'package:test/test.dart'; -import 'pretty_log.dart'; - -void main() { - late http.IOClient client; - late PlatformHttp driver; - late Logger logger; - late StringBuffer buf; - - setUp(() async { - buf = StringBuffer(); - client = http.IOClient(); - hierarchicalLoggingEnabled = true; - - logger = Logger.detached('req_shutdown') - ..level = Level.ALL - ..onRecord.listen(prettyLog); - - var app = Application(logger: logger); - - app.fallback((req, res) { - req.shutdownHooks.add(() => buf.write('Hello, ')); - req.shutdownHooks.add(() => buf.write('world!')); - }); - - driver = PlatformHttp(app); - await driver.startServer(); - }); - - tearDown(() { - logger.clearListeners(); - client.close(); - scheduleMicrotask(driver.close); - }); - - test('does not continue processing after streaming', () async { - await client.get(driver.uri); - await Future.delayed(Duration(milliseconds: 100)); - expect(buf.toString(), 'Hello, world!'); - }); -} diff --git a/packages/core/test/response_header_test.dart b/packages/core/test/response_header_test.dart deleted file mode 100644 index 151b374..0000000 --- a/packages/core/test/response_header_test.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'dart:io'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/src/http/protevus_http.dart'; -import 'package:test/test.dart'; - -void main() { - late Application app; - late PlatformHttp http; - late HttpClient client; - - setUp(() async { - app = Application(reflector: MirrorsReflector()); - http = PlatformHttp(app); - - await http.startServer(); - - var formData = {'id': 100, 'name': 'William'}; - app.get('/api/v1/user/list', (RequestContext req, res) async { - //await req.parseBody(); - //res.write('Hello, World!'); - res.json(formData); - }); - - client = HttpClient(); - }); - - tearDown(() async { - client.close(); - await http.close(); - }); - - test('Remove Response Header', () async { - http.removeResponseHeader({'x-frame-options': 'SAMEORIGIN'}); - - var request = await client.get('localhost', 3000, '/api/v1/user/list'); - HttpClientResponse response = await request.close(); - //print(response.headers); - expect(response.headers['x-frame-options'], isNull); - }, skip: true); - - test('Add Response Header', () async { - http.addResponseHeader({ - 'X-XSRF_TOKEN': - 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e' - }); - - var request = await client.get('localhost', 3000, '/api/v1/user/list'); - HttpClientResponse response = await request.close(); - //print(response.headers); - expect( - response.headers['X-XSRF_TOKEN'], - equals([ - 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e' - ])); - }, skip: true); -} diff --git a/packages/core/test/routing_test.dart b/packages/core/test/routing_test.dart deleted file mode 100644 index dce777e..0000000 --- a/packages/core/test/routing_test.dart +++ /dev/null @@ -1,223 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:http/http.dart' as http; -import 'package:io/ansi.dart'; -import 'package:logging/logging.dart'; -import 'package:test/test.dart'; - -import 'common.dart'; - -@Middleware([interceptor]) -Future testMiddlewareMetadata( - RequestContext req, ResponseContext res) async { - return 'This should not be shown.'; -} - -@Middleware([interceptService]) -class QueryService extends Service { - @override - @Middleware([interceptor]) - Future read(id, [Map? params]) async => params; -} - -void interceptor(RequestContext req, ResponseContext res) { - res - ..write('Middleware') - ..close(); -} - -bool interceptService(RequestContext req, ResponseContext res) { - res.write('Service with '); - return true; -} - -void main() { - late Application app; - late Application nested; - late Application todos; - late String url; - late http.Client client; - - setUp(() async { - app = Application(reflector: MirrorsReflector()); - nested = Application(reflector: MirrorsReflector()); - todos = Application(reflector: MirrorsReflector()); - - for (var app in [app, nested, todos]) { - app.logger = Logger('routing_test') - ..onRecord.listen((rec) { - if (rec.error != null) { - stdout - ..writeln(cyan.wrap(rec.toString())) - ..writeln(cyan.wrap(rec.error.toString())) - ..writeln(cyan.wrap(rec.stackTrace.toString())); - } - }); - } - - todos.get('/action/:action', (req, res) => res.json(req.params)); - - late Route ted; - - ted = nested.post('/ted/:route', (RequestContext req, res) { - print('Params: ${req.params}'); - print('Path: ${ted.path}, uri: ${req.path}'); - print('matcher: ${ted.parser}'); - return req.params; - }); - - app.mount('/nes', nested); - app.get('/meta', testMiddlewareMetadata); - app.get('/intercepted', (req, res) => 'This should not be shown', - middleware: [interceptor]); - app.get('/hello', (req, res) => 'world'); - app.get('/name/:first/last/:last', (req, res) => req.params); - app.post( - '/lambda', - (RequestContext req, res) => - req.parseBody().then((_) => req.bodyAsMap)); - app.mount('/todos/:id', todos); - app - .get('/greet/:name', - (RequestContext req, res) async => "Hello ${req.params['name']}") - .name = 'Named routes'; - app.get('/named', (req, ResponseContext res) async { - await res.redirectTo('Named routes', {'name': 'tests'}); - }); - app.get('/log', (RequestContext req, res) async { - print('Query: ${req.queryParameters}'); - return 'Logged'; - }); - - app.get('/method', (req, res) => 'Only GET'); - app.post('/method', (req, res) => 'Only POST'); - - app.use('/query', QueryService()); - - RequestHandler write(String message) { - return (req, res) { - res.write(message); - return true; - }; - } - - app.chain([write('a')]).chain([write('b'), write('c')]).get( - '/chained', (req, res) => res.close()); - - app.fallback((req, res) => 'MJ'); - - //app.dumpTree(header: "DUMPING ROUTES:", showMatchers: true); - - client = http.Client(); - var server = await PlatformHttp(app).startServer('127.0.0.1', 0); - url = 'http://${server.address.host}:${server.port}'; - }); - - tearDown(() async { - await app.close(); - client.close(); - }); - - test('Can match basic url', () async { - var response = await client.get(Uri.parse('$url/hello')); - expect(response.body, equals('"world"')); - }); - - test('Can match url with multiple parameters', () async { - var response = await client.get(Uri.parse('$url/name/HELLO/last/WORLD')); - print('Response: ${response.body}'); - var json_ = json.decode(response.body); - expect(json_, const IsInstanceOf()); - expect(json_['first'], equals('HELLO')); - expect(json_['last'], equals('WORLD')); - }); - - test('Chained routes', () async { - var response = await client.get(Uri.parse('$url/chained')); - expect(response.body, equals('abc')); - }); - - test('Can nest another Protevus instance', () async { - var response = await client.post(Uri.parse('$url/nes/ted/foo')); - var json_ = json.decode(response.body); - expect(json_['route'], equals('foo')); - }); - - test('Can parse parameters from a nested Protevus instance', () async { - var response = await client.get(Uri.parse('$url/todos/1337/action/test')); - var json_ = json.decode(response.body); - print('JSON: $json_'); - expect(json_['id'], equals('1337')); - expect(json_['action'], equals('test')); - }); - - test('Can add and use named middleware', () async { - var response = await client.get(Uri.parse('$url/intercepted')); - expect(response.body, equals('Middleware')); - }); - - test('Middleware via metadata', () async { - // Metadata - var response = await client.get(Uri.parse('$url/meta')); - expect(response.body, equals('Middleware')); - }); - - test('Can serialize function result as JSON', () async { - Map headers = {'Content-Type': 'application/json'}; - var postData = json.encode({'it': 'works'}); - var response = await client.post(Uri.parse('$url/lambda'), - headers: headers as Map, body: postData); - print('Response: ${response.body}'); - expect(json.decode(response.body)['it'], equals('works')); - }); - - test('Fallback routes', () async { - var response = await client.get(Uri.parse('$url/my_favorite_artist')); - expect(response.body, equals('"MJ"')); - }); - - /* TODO: Revisit this later - test('Can name routes', () { - Route foo = app.get('/framework/:id', null)..name = 'frm'; - print('Foo: $foo'); - String uri = foo.makeUri({'id': 'Protevus'}); - print(uri); - expect(uri, equals('framework/Protevus')); - }); - */ - - test('Redirect to named routes', () async { - var response = await client.get(Uri.parse('$url/named')); - print(response.body); - expect(json.decode(response.body), equals('Hello tests')); - }); - - test('Match routes, even with query params', () async { - var response = await client - .get(Uri.parse('$url/log?foo=bar&bar=baz&baz.foo=bar&baz.bar=foo')); - print(response.body); - expect(json.decode(response.body), equals('Logged')); - - response = await client.get(Uri.parse('$url/query/foo?bar=baz')); - print(response.body); - expect(response.body, equals('Service with Middleware')); - }); - - test('only match route with matching method', () async { - var response = await client.get(Uri.parse('$url/method')); - print(response.body); - expect(response.body, '"Only GET"'); - - response = await client.post(Uri.parse('$url/method')); - print(response.body); - expect(response.body, '"Only POST"'); - - response = await client.patch(Uri.parse('$url/method')); - print(response.body); - expect(response.body, '"MJ"'); - }); -} diff --git a/packages/core/test/serialize_test.dart b/packages/core/test/serialize_test.dart deleted file mode 100644 index 23a8e54..0000000 --- a/packages/core/test/serialize_test.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'dart:io'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:http/http.dart' as http; -import 'package:http_parser/http_parser.dart'; -import 'package:test/test.dart'; - -void main() { - late Application app; - late http.Client client; - late HttpServer server; - late String url; - - setUp(() async { - app = Application(reflector: MirrorsReflector()) - ..get('/foo', ioc(() => {'hello': 'world'})) - ..get('/bar', (req, res) async { - await res.serialize({'hello': 'world'}, - contentType: MediaType('text', 'html')); - }); - client = http.Client(); - - server = await PlatformHttp(app).startServer(); - url = 'http://${server.address.host}:${server.port}'; - }); - - tearDown(() async { - client.close(); - await server.close(force: true); - }); - - test('correct content-type', () async { - var response = await client.get(Uri.parse('$url/foo')); - print('Response: ${response.body}'); - expect(response.headers['content-type'], contains('application/json')); - - response = await client.get(Uri.parse('$url/bar')); - print('Response: ${response.body}'); - expect(response.headers['content-type'], contains('text/html')); - }); -} diff --git a/packages/core/test/server_test.dart b/packages/core/test/server_test.dart deleted file mode 100644 index 236d5f0..0000000 --- a/packages/core/test/server_test.dart +++ /dev/null @@ -1,226 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:platform_testing/http.dart'; - -import 'package:test/test.dart'; - -final Uri $foo = Uri.parse('http://localhost:3000/foo'); - -/// Additional tests to improve coverage of server.dart -void main() { - group('scoping', () { - var parent = Application(reflector: MirrorsReflector()) - ..configuration['two'] = 2; - var child = Application(reflector: MirrorsReflector()); - parent.mount('/child', child); - - test('sets children', () { - expect(parent.children, contains(child)); - }); - - test('sets parent', () { - expect(child.parent, parent); - }); - - test('properties can climb up hierarchy', () { - expect(child.findProperty('two'), 2); - }); - }); - - test('custom server generator', () { - var app = Application(reflector: MirrorsReflector()); - var http = PlatformHttp.custom(app, HttpServer.bind); - expect(http.serverGenerator, HttpServer.bind); - }); - - test('default error handler', () async { - var app = Application(reflector: MirrorsReflector()); - var http = PlatformHttp(app); - var rq = MockHttpRequest('GET', $foo); - await (rq.close()); - var rs = rq.response; - var req = await http.createRequestContext(rq, rs); - var res = await http.createResponseContext(rq, rs); - var e = PlatformHttpException( - statusCode: 321, message: 'Hello', errors: ['foo', 'bar']); - await app.errorHandler(e, req, res); - await http.sendResponse(rq, rs, req, res); - expect( - ContentType.parse(rs.headers.value('content-type')!).mimeType, - 'text/html', - ); - expect(rs.statusCode, e.statusCode); - var body = await rs.transform(utf8.decoder).join(); - expect(body, contains('${e.message}')); - expect(body, contains('
  • foo
  • ')); - expect(body, contains('
  • bar
  • ')); - }); - - test('plug-ins run on startup', () async { - var app = Application(reflector: MirrorsReflector()); - app.startupHooks.add((app) => app.configuration['two'] = 2); - - var http = PlatformHttp(app); - await http.startServer(); - expect(app.configuration['two'], 2); - await app.close(); - await http.close(); - }); - - test('warning when adding routes to flattened router', () { - var app = Application(reflector: MirrorsReflector()) - ..optimizeForProduction(force: true); - app.dumpTree(); - app.get('/', (req, res) => 2); - app.mount('/foo', Router()..get('/', (req, res) => 3)); - }); - - test('services close on close call', () async { - var app = Application(reflector: MirrorsReflector()); - var svc = CustomCloseService(); - expect(svc.value, 2); - app.use('/', svc); - await app.close(); - expect(svc.value, 3); - }); - - test('global injection added to injection map', () async { - var app = Application(reflector: MirrorsReflector()) - ..configuration['a'] = 'b'; - var http = PlatformHttp(app); - app.get('/', ioc((String a) => a)); - var rq = MockHttpRequest('GET', Uri.parse('/')); - await (rq.close()); - await http.handleRequest(rq); - var body = await rq.response.transform(utf8.decoder).join(); - expect(body, json.encode('b')); - }); - - test('global injected serializer', () async { - var app = Application(reflector: MirrorsReflector()) - ..serializer = (_) => 'x'; - var http = PlatformHttp(app); - app.get($foo.path, (req, ResponseContext res) => res.serialize(null)); - var rq = MockHttpRequest('GET', $foo); - await (rq.close()); - await http.handleRequest(rq); - var body = await rq.response.transform(utf8.decoder).join(); - expect(body, 'x'); - }); - - group('handler results', () { - var app = Application(reflector: MirrorsReflector()); - var http = PlatformHttp(app); - app.responseFinalizers - .add((req, res) => throw PlatformHttpException.forbidden()); - late RequestContext req; - late ResponseContext res; - - setUp(() async { - var rq = MockHttpRequest('GET', $foo); - await (rq.close()); - req = await http.createRequestContext(rq, rq.response); - res = await http.createResponseContext(rq, rq.response); - }); - - group('getHandlerResult', () { - test('return request handler', () async { - handler(req, res) => (req, res) async { - return 2; - }; - var r = await app.getHandlerResult(handler, req, res); - expect(r, 2); - }); - - test('return future', () async { - var handler = Future.value(2); - expect(await app.getHandlerResult(handler, req, res), 2); - }); - }); - - group('executeHandler', () { - test('return Stream', () async { - handler(req, res) => Stream.fromIterable([2, 3]); - expect(await app.executeHandler(handler, req, res), isFalse); - }); - - test('end response', () async { - handler(req, ResponseContext res) => res.close(); - expect(await app.executeHandler(handler, req, res), isFalse); - }); - }); - }); - - group('handleHttpException', () { - late Application app; - late PlatformHttp http; - - setUp(() async { - app = Application(reflector: MirrorsReflector()); - app.get('/wtf', (req, res) => throw PlatformHttpException.forbidden()); - app.get('/wtf2', (req, res) => throw PlatformHttpException.forbidden()); - http = PlatformHttp(app); - await http.startServer('127.0.0.1', 0); - - var oldHandler = app.errorHandler; - app.errorHandler = (e, req, res) { - print('FATAL: ${e.error ?? e}'); - print(e.stackTrace); - return oldHandler(e, req, res); - }; - }); - - tearDown(() => app.close()); - - test('can send json', () async { - var rq = MockHttpRequest('GET', Uri(path: 'wtf')) - ..headers.set('accept', 'application/json'); - await rq.close(); - http.handleRequest(rq); - await rq.response.toList(); - expect(rq.response.statusCode, 403); - expect(rq.response.headers.contentType!.mimeType, 'application/json'); - }); - - test('can throw in finalizer', () async { - var rq = MockHttpRequest('GET', Uri(path: 'wtf')) - ..headers.set('accept', 'application/json'); - await rq.close(); - http.handleRequest(rq); - await rq.response.toList(); - expect(rq.response.statusCode, 403); - expect(rq.response.headers.contentType!.mimeType, 'application/json'); - }); - - test('can send html', () async { - var rq = MockHttpRequest('GET', Uri(path: 'wtf2')); - //rq.headers.set('accept', 'text/html'); - await rq.close(); - http.handleRequest(rq); - await rq.response.toList(); - expect(rq.response.statusCode, 403); - expect(rq.response.headers.contentType?.mimeType, 'text/html'); - }); - }); -} - -class CustomCloseService extends Service { - int value = 2; - - @override - void close() { - value = 3; - super.close(); - } -} - -@Expose('/foo') -class FooController extends Controller { - @Expose('/bar') - Future bar() async => 'baz'; -} diff --git a/packages/core/test/service_map_test.dart b/packages/core/test/service_map_test.dart deleted file mode 100644 index 3c08c2b..0000000 --- a/packages/core/test/service_map_test.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:platform_core/core.dart'; -import 'package:test/test.dart'; -import 'package:quiver/core.dart'; - -void main() { - MapService inner; - late Service mapped; - - setUp(() { - inner = MapService(); - mapped = inner.map(Todo.fromMap, Todo.toMap); - }); - - test('create', () async { - var result = await mapped.create( - Todo(text: 'hello', complete: false), - ); - print(result); - expect( - result, - Todo(text: 'hello', complete: false), - ); - }); - - group('after create', () { - late Todo result; - String? id; - - setUp(() async { - result = await mapped.create(Todo(text: 'hello', complete: false)); - id = result.id; - }); - - test('index', () async { - expect(await mapped.index(), [result]); - }); - - test('modify', () async { - var newTodo = Todo(text: 'yes', complete: true); - expect(await mapped.update(id, newTodo), newTodo); - }); - - test('update', () async { - var newTodo = Todo(id: 'hmmm', text: 'yes', complete: true); - expect(await mapped.update(id, newTodo), newTodo); - }); - - test('read', () async { - expect(await mapped.read(id), result); - }); - - test('remove', () async { - expect(await mapped.remove(id), result); - }); - }); -} - -class Todo { - final String? id, text; - final bool? complete; - - Todo({this.id, this.text, this.complete}); - - static Todo fromMap(Map json) { - return Todo( - id: json['id'] as String?, - text: json['text'] as String?, - complete: json['complete'] as bool?); - } - - static Map toMap(Todo model) { - return {'id': model.id, 'text': model.text, 'complete': model.complete}; - } - - @override - bool operator ==(other) => - other is Todo && other.text == text && other.complete == complete; - - @override - String toString() => '$id:$text($complete)'; - - @override - int get hashCode => hash2(text.hashCode, complete.hashCode); -} diff --git a/packages/core/test/services_test.dart b/packages/core/test/services_test.dart deleted file mode 100644 index 9fb276b..0000000 --- a/packages/core/test/services_test.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:stack_trace/stack_trace.dart'; -import 'package:test/test.dart'; - -class Todo extends Model { - String? text; - String? over; -} - -void main() { - Map headers = { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }; - late Application app; - late MapService service; - late String url; - late http.Client client; - - setUp(() async { - app = Application(reflector: MirrorsReflector()) - ..use('/todos', service = MapService()) - ..errorHandler = (e, req, res) { - if (e.error != null) print('Whoops: ${e.error}'); - if (e.stackTrace != null) print(Chain.forTrace(e.stackTrace!).terse); - }; - - var server = await PlatformHttp(app).startServer(); - client = http.Client(); - url = 'http://${server.address.host}:${server.port}'; - }); - - tearDown(() async { - await app.close(); - client.close(); - }); - - group('memory', () { - test('can index an empty service', () async { - var response = await client.get(Uri.parse('$url/todos/')); - print(response.body); - expect(response.body, equals('[]')); - print(response.body); - expect(json.decode(response.body).length, 0); - }); - - test('can create data', () async { - var postData = json.encode({'text': 'Hello, world!'}); - var response = await client.post(Uri.parse('$url/todos'), - headers: headers as Map, body: postData); - expect(response.statusCode, 201); - var jsons = json.decode(response.body); - print(jsons); - expect(jsons['text'], equals('Hello, world!')); - }); - - test('can fetch data', () async { - var postData = json.encode({'text': 'Hello, world!'}); - await client.post(Uri.parse('$url/todos'), - headers: headers as Map, body: postData); - var response = await client.get(Uri.parse('$url/todos/0')); - expect(response.statusCode, 200); - var jsons = json.decode(response.body); - print(jsons); - expect(jsons['text'], equals('Hello, world!')); - }); - - test('can modify data', () async { - var postData = json.encode({'text': 'Hello, world!'}); - await client.post(Uri.parse('$url/todos'), - headers: headers as Map, body: postData); - postData = json.encode({'text': 'modified'}); - - var response = await client.patch(Uri.parse('$url/todos/0'), - headers: headers, body: postData); - expect(response.statusCode, 200); - var jsons = json.decode(response.body); - print(jsons); - expect(jsons['text'], equals('modified')); - }); - - test('can overwrite data', () async { - var postData = json.encode({'text': 'Hello, world!'}); - await client.post(Uri.parse('$url/todos'), - headers: headers as Map, body: postData); - postData = json.encode({'over': 'write'}); - - var response = await client.post(Uri.parse('$url/todos/0'), - headers: headers, body: postData); - expect(response.statusCode, 200); - var jsons = json.decode(response.body); - print(jsons); - expect(jsons['text'], equals(null)); - expect(jsons['over'], equals('write')); - }); - - test('readMany', () async { - var items = [ - await service.create({'foo': 'bar'}), - await service.create({'bar': 'baz'}), - await service.create({'baz': 'quux'}) - ]; - - var ids = items.map((m) => m['id'] as String?).toList(); - expect(await service.readMany(ids), items); - }); - - test('can delete data', () async { - var postData = json.encode({'text': 'Hello, world!'}); - var created = await client - .post(Uri.parse('$url/todos'), - headers: headers as Map, body: postData) - .then((r) => json.decode(r.body)); - var response = - await client.delete(Uri.parse("$url/todos/${created['id']}")); - expect(response.statusCode, 200); - var json_ = json.decode(response.body); - print(json_); - expect(json_['text'], equals('Hello, world!')); - }); - - test('cannot remove all unless explicitly set', () async { - var response = await client.delete(Uri.parse('$url/todos/null')); - expect(response.statusCode, 403); - }); - }); -} diff --git a/packages/core/test/streaming_test.dart b/packages/core/test/streaming_test.dart deleted file mode 100644 index ffd9b5a..0000000 --- a/packages/core/test/streaming_test.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:platform_container/mirrors.dart'; -import 'package:platform_core/core.dart'; -import 'package:platform_core/http.dart'; -import 'package:logging/logging.dart'; -import 'package:platform_testing/http.dart'; - -import 'package:test/test.dart'; - -import 'encoders_buffer_test.dart' show encodingTests; - -void main() { - late Application app; - late PlatformHttp http; - - setUp(() { - app = Application(reflector: MirrorsReflector()); - http = PlatformHttp(app, useZone: true); - - app.logger = Logger('streaming_test') - ..onRecord.listen((rec) { - print(rec); - if (rec.stackTrace != null) print(rec.stackTrace); - }); - - app.encoders.addAll( - { - 'deflate': zlib.encoder, - 'gzip': gzip.encoder, - }, - ); - - app.get('/hello', (req, res) { - return Stream>.fromIterable(['Hello, world!'.codeUnits]) - .pipe(res); - }); - - app.get('/write', (req, res) async { - await res.addStream( - Stream>.fromIterable(['Hello, world!'.codeUnits])); - res.write('bye'); - await res.close(); - }); - - app.get('/multiple', (req, res) async { - await res.addStream( - Stream>.fromIterable(['Hello, world!'.codeUnits])); - await res.addStream(Stream>.fromIterable(['bye'.codeUnits])); - await res.close(); - }); - - app.get('/overwrite', (req, res) async { - res.statusCode = 32; - await Stream>.fromIterable(['Hello, world!'.codeUnits]) - .pipe(res); - - var f = Stream>.fromIterable(['Hello, world!'.codeUnits]) - .pipe(res) - .then((_) => false) - .catchError((_) => true); - - expect(f, completion(true)); - }); - - app.get('/error', (req, res) => res.addError(StateError('wtf'))); - - app.errorHandler = (e, req, res) async { - stderr - ..writeln(e.error) - ..writeln(e.stackTrace); - }; - }); - - tearDown(() => http.close()); - - void expectHelloBye(String path) async { - var rq = MockHttpRequest('GET', Uri.parse(path)); - await (rq.close()); - await http.handleRequest(rq); - var body = await rq.response.transform(utf8.decoder).join(); - expect(body, 'Hello, world!bye'); - } - - test('write after addStream', () => expectHelloBye('/write')); - - test('multiple addStream', () => expectHelloBye('/multiple')); - - test('cannot write after close', () async { - try { - var rq = MockHttpRequest('GET', Uri.parse('/overwrite')); - await rq.close(); - await http.handleRequest(rq); - var body = await rq.response.transform(utf8.decoder).join(); - - if (rq.response.statusCode != 32) { - throw 'overwrite should throw error; response: $body'; - } - } on StateError { - // Success - } - }); - - test('res => addError', () async { - try { - var rq = MockHttpRequest('GET', Uri.parse('/error')); - await (rq.close()); - await http.handleRequest(rq); - var body = await rq.response.transform(utf8.decoder).join(); - throw 'addError should throw error; response: $body'; - } on StateError { - // Should throw error... - } - }); - - encodingTests(() => app); -} diff --git a/packages/core/test/view_generator_test.dart b/packages/core/test/view_generator_test.dart deleted file mode 100644 index 7d39711..0000000 --- a/packages/core/test/view_generator_test.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:platform_core/core.dart'; -import 'package:test/test.dart'; - -void main() { - test('default view generator', () async { - var app = Application(); - var view = await app.viewGenerator!('foo', {'bar': 'baz'}); - expect(view, contains('No view engine')); - }); -} diff --git a/packages/pipeline/.gitignore b/packages/database/.gitignore similarity index 100% rename from packages/pipeline/.gitignore rename to packages/database/.gitignore diff --git a/packages/pipeline/CHANGELOG.md b/packages/database/CHANGELOG.md similarity index 100% rename from packages/pipeline/CHANGELOG.md rename to packages/database/CHANGELOG.md diff --git a/packages/pipeline/LICENSE.md b/packages/database/LICENSE.md similarity index 100% rename from packages/pipeline/LICENSE.md rename to packages/database/LICENSE.md diff --git a/packages/events/README.md b/packages/database/README.md similarity index 100% rename from packages/events/README.md rename to packages/database/README.md diff --git a/packages/pipeline/analysis_options.yaml b/packages/database/analysis_options.yaml similarity index 100% rename from packages/pipeline/analysis_options.yaml rename to packages/database/analysis_options.yaml diff --git a/packages/database/doc/.gitkeep b/packages/database/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/database/example/.gitkeep b/packages/database/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/database/lib/src/.gitkeep b/packages/database/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/database/pubspec.yaml b/packages/database/pubspec.yaml new file mode 100644 index 0000000..9d61f00 --- /dev/null +++ b/packages/database/pubspec.yaml @@ -0,0 +1,17 @@ +name: platform_database +description: The Databse Package for the Protevus Platform +version: 0.0.1 +homepage: https://protevus.com +documentation: https://docs.protevus.com +repository: https://git.protevus.com/protevus/platform + +environment: + sdk: ^3.4.2 + +# Add regular dependencies here. +dependencies: + # path: ^1.8.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/database/test/.gitkeep b/packages/database/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/events/lib/dispatcher.dart b/packages/events/lib/dispatcher.dart deleted file mode 100644 index bbc26fc..0000000 --- a/packages/events/lib/dispatcher.dart +++ /dev/null @@ -1,3 +0,0 @@ -library; - -export 'src/dispatcher.dart'; diff --git a/packages/events/lib/src/dispatcher.dart b/packages/events/lib/src/dispatcher.dart deleted file mode 100644 index de9349e..0000000 --- a/packages/events/lib/src/dispatcher.dart +++ /dev/null @@ -1,499 +0,0 @@ -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/test/event_test.dart b/packages/events/test/event_test.dart deleted file mode 100644 index 72a75ab..0000000 --- a/packages/events/test/event_test.dart +++ /dev/null @@ -1,430 +0,0 @@ -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/process/.gitignore b/packages/filesystem/.gitignore similarity index 100% rename from packages/process/.gitignore rename to packages/filesystem/.gitignore diff --git a/packages/process/CHANGELOG.md b/packages/filesystem/CHANGELOG.md similarity index 100% rename from packages/process/CHANGELOG.md rename to packages/filesystem/CHANGELOG.md diff --git a/packages/process/LICENSE.md b/packages/filesystem/LICENSE.md similarity index 100% rename from packages/process/LICENSE.md rename to packages/filesystem/LICENSE.md diff --git a/packages/filesystem/README.md b/packages/filesystem/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/filesystem/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/process/analysis_options.yaml b/packages/filesystem/analysis_options.yaml similarity index 100% rename from packages/process/analysis_options.yaml rename to packages/filesystem/analysis_options.yaml diff --git a/packages/filesystem/doc/.gitkeep b/packages/filesystem/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/filesystem/example/.gitkeep b/packages/filesystem/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/filesystem/lib/src/.gitkeep b/packages/filesystem/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/bus/pubspec.yaml b/packages/filesystem/pubspec.yaml similarity index 53% rename from packages/bus/pubspec.yaml rename to packages/filesystem/pubspec.yaml index deb1887..0c110e0 100644 --- a/packages/bus/pubspec.yaml +++ b/packages/filesystem/pubspec.yaml @@ -1,5 +1,5 @@ -name: platform_bus -description: The Bus Package for the Protevus Platform +name: platform_filesystem +description: The Filesystem Package for the Protevus Platform version: 0.0.1 homepage: https://protevus.com documentation: https://docs.protevus.com @@ -10,15 +10,8 @@ environment: # 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/filesystem/test/.gitkeep b/packages/filesystem/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sandbox/mqueue/.gitignore b/packages/foundation/.gitignore similarity index 100% rename from sandbox/mqueue/.gitignore rename to packages/foundation/.gitignore diff --git a/packages/queue/CHANGELOG.md b/packages/foundation/CHANGELOG.md similarity index 100% rename from packages/queue/CHANGELOG.md rename to packages/foundation/CHANGELOG.md diff --git a/packages/queue/LICENSE.md b/packages/foundation/LICENSE.md similarity index 100% rename from packages/queue/LICENSE.md rename to packages/foundation/LICENSE.md diff --git a/packages/foundation/README.md b/packages/foundation/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/foundation/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/queue/analysis_options.yaml b/packages/foundation/analysis_options.yaml similarity index 100% rename from packages/queue/analysis_options.yaml rename to packages/foundation/analysis_options.yaml diff --git a/packages/foundation/doc/.gitkeep b/packages/foundation/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/foundation/example/.gitkeep b/packages/foundation/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/foundation/lib/src/.gitkeep b/packages/foundation/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/foundation/pubspec.yaml b/packages/foundation/pubspec.yaml new file mode 100644 index 0000000..45034cd --- /dev/null +++ b/packages/foundation/pubspec.yaml @@ -0,0 +1,17 @@ +name: platform_foundation +description: The Foundation 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: + # path: ^1.8.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/foundation/test/.gitkeep b/packages/foundation/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/queue/.gitignore b/packages/http/.gitignore similarity index 87% rename from packages/queue/.gitignore rename to packages/http/.gitignore index 0b4272d..3cceda5 100644 --- a/packages/queue/.gitignore +++ b/packages/http/.gitignore @@ -5,6 +5,3 @@ # 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/http/CHANGELOG.md b/packages/http/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/http/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/http/LICENSE.md b/packages/http/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/http/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/http/README.md b/packages/http/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/http/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/http/analysis_options.yaml b/packages/http/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/http/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/http/doc/.gitkeep b/packages/http/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/http/example/.gitkeep b/packages/http/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/http/pubspec.yaml b/packages/http/pubspec.yaml new file mode 100644 index 0000000..d029fea --- /dev/null +++ b/packages/http/pubspec.yaml @@ -0,0 +1,21 @@ +name: platfrom_http +description: The HTTP 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.0 <4.0.0' + +# Add regular dependencies here. +dependencies: + sanitize_html: ^2.1.0 + email_validator: ^3.0.0 + validator_dart: ^0.1.0 + protevus_mime: ^0.0.1 + path: ^1.9.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/http/test/.gitkeep b/packages/http/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/lucifer b/packages/lucifer new file mode 160000 index 0000000..27ec6a3 --- /dev/null +++ b/packages/lucifer @@ -0,0 +1 @@ +Subproject commit 27ec6a35a910fa60dcfc1d772fd7ecde660dfa4b diff --git a/packages/model/.gitignore b/packages/model/.gitignore deleted file mode 100644 index 24d6831..0000000 --- a/packages/model/.gitignore +++ /dev/null @@ -1,71 +0,0 @@ -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub -.dart_tool -.packages -.pub/ -build/ - -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock - -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - -### Dart template -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub - -# SDK 1.20 and later (no longer creates packages directories) - -# Older SDK versions -# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20) -.project -.buildlog -**/packages/ - - -# Files created by dart2js -# (Most Dart developers will use pub build to compile Dart, use/modify these -# rules if you intend to use dart2js directly -# Convention is to use extension '.dart.js' for Dart compiled to Javascript to -# differentiate from explicit Javascript files) -*.dart.js -*.part.js -*.js.deps -*.js.map -*.info.json - -# Directory created by dartdoc - -# Don't commit pubspec lock file -# (Library packages only! Remove pattern if developing an application package) -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: - -## VsCode -.vscode/ - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -.idea/ -/out/ -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties diff --git a/packages/model/AUTHORS.md b/packages/model/AUTHORS.md deleted file mode 100644 index ac95ab5..0000000 --- a/packages/model/AUTHORS.md +++ /dev/null @@ -1,12 +0,0 @@ -Primary Authors -=============== - -* __[Thomas Hii](dukefirehawk.apps@gmail.com)__ - - Thomas is the current maintainer of the code base. He has refactored and migrated the - code base to support NNBD. - -* __[Tobe O](thosakwe@gmail.com)__ - - Tobe has written much of the original code prior to NNBD migration. He has moved on and - is no longer involved with the project. diff --git a/packages/model/CHANGELOG.md b/packages/model/CHANGELOG.md deleted file mode 100644 index 86374d8..0000000 --- a/packages/model/CHANGELOG.md +++ /dev/null @@ -1,77 +0,0 @@ -# Change Log - -## 8.1.1 - -* Updated repository link - -## 8.1.0 - -* Updated `lints` to 3.0.0 -* Fixed analyser warnings - -## 8.0.0 - -* Require Dart >= 3.0 - -## 7.1.0 - -* Return -1 instead of throwing exception when id is null -* Added `idAsString` to return id or "" if null -* Added `AuditableModel` - -## 7.0.0 - -* Require Dart >= 2.17 - -## 6.0.0 - -* Require Dart >= 2.16 - -## 5.0.0 - -* Skipped release - -## 4.0.0 - -* Skipped release - -## 3.1.1 - -* Removed `error` - -## 3.1.0 - -* Updated linter to `package:lints` - -## 3.0.2 - -* Updated README -* Updated `idAsInt` to return `-1` instead of `null` for invalid id - -## 3.0.1 - -* Updated README - -## 3.0.0 - -* Migrated to support Dart >= 2.12 NNBD - -## 2.0.0 - -* Migrated to work with Dart >= 2.12 Non NNBD - -## 1.0.3 - -* `idAsInt` returns `null` when `id` is `null`. - -## 1.0.2 - -* `idAsInt` now uses `int.tryParse`. - -## 1.0.1 - -* Add `idAsInt`. - -## 1.0.0+1 - -* Update constraint to work with Dart 2. diff --git a/packages/model/LICENSE b/packages/model/LICENSE deleted file mode 100644 index df5e063..0000000 --- a/packages/model/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2021, dukefirehawk.com -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/model/README.md b/packages/model/README.md deleted file mode 100644 index ad5d520..0000000 --- a/packages/model/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Protevus Data Model - -![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_model?include_prereleases) -[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety) -[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion) -[![License](https://img.shields.io/github/license/dart-backend/angel)](https://github.com/dart-backend/angel/tree/master/packages/model/LICENSE) - -The basic data models for Protevus framework. - -```dart -import 'package:angel3_model/angel3_model.dart'; -``` - -The available data models are: - -* `Model` class - * A basic data model -* `AuditableModel` class - * A basic data model with audit log feature diff --git a/packages/model/analysis_options.yaml b/packages/model/analysis_options.yaml deleted file mode 100644 index 4a50340..0000000 --- a/packages/model/analysis_options.yaml +++ /dev/null @@ -1,2 +0,0 @@ - -include: package:lints/recommended.yaml \ No newline at end of file diff --git a/packages/model/example/main.dart b/packages/model/example/main.dart deleted file mode 100644 index 9c86106..0000000 --- a/packages/model/example/main.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:platform_model/model.dart'; - -void main() { - var todo = Todo(id: '34', isComplete: false); - print(todo.idAsInt == 34); -} - -class Todo extends Model { - String? text; - - bool isComplete; - - Todo( - {required String super.id, - this.text, - this.isComplete = false, - super.createdAt, - super.updatedAt}); -} diff --git a/packages/model/lib/model.dart b/packages/model/lib/model.dart deleted file mode 100644 index 0ee8fab..0000000 --- a/packages/model/lib/model.dart +++ /dev/null @@ -1,35 +0,0 @@ -/// Represents a generic data model with an ID and timestamps. -class Model { - /// A unique identifier corresponding to this item. - String? id; - - /// The time at which this item was created. - DateTime? createdAt; - - /// The last time at which this item was updated. - DateTime? updatedAt; - - Model({this.id, this.createdAt, this.updatedAt}); - - /// Returns the [id], parsed as an [int]. - int get idAsInt => id != null ? int.tryParse(id ?? "-1") ?? -1 : -1; - - /// Returns the [id] or "" if null. - String get idAsString => id ?? ""; -} - -/// Represents a generic data model with audit log feature. -class AuditableModel extends Model { - /// The authorized user who created the record. - String? createdBy; - - /// The user who updated the record last time. - String? updatedBy; - - AuditableModel( - {super.id, - super.createdAt, - this.createdBy, - super.updatedAt, - this.updatedBy}); -} diff --git a/packages/model/pubspec.yaml b/packages/model/pubspec.yaml deleted file mode 100644 index b388c63..0000000 --- a/packages/model/pubspec.yaml +++ /dev/null @@ -1,11 +0,0 @@ -name: platform_model -version: 9.0.0 -description: Protevus Platform basic data model class, no longer with the added weight of the whole framework. -homepage: https://protevus.com -documentation: https://docs.protevus.com -repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/model -environment: - sdk: '>=3.3.0 <4.0.0' -dev_dependencies: - lints: ^4.0.0 - test: ^1.25.8 diff --git a/packages/pipeline/README.md b/packages/pipeline/README.md deleted file mode 100644 index 586a156..0000000 --- a/packages/pipeline/README.md +++ /dev/null @@ -1,380 +0,0 @@ -

    - -# 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/examples/async_pipeline.dart b/packages/pipeline/examples/async_pipeline.dart deleted file mode 100644 index 03f6dc1..0000000 --- a/packages/pipeline/examples/async_pipeline.dart +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 736a354..0000000 --- a/packages/pipeline/examples/basic_usage.dart +++ /dev/null @@ -1,36 +0,0 @@ -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 deleted file mode 100644 index 6f8aa84..0000000 --- a/packages/pipeline/examples/error_handling.dart +++ /dev/null @@ -1,34 +0,0 @@ -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 deleted file mode 100644 index 0e17a71..0000000 --- a/packages/pipeline/examples/mixed_pipes.dart +++ /dev/null @@ -1,35 +0,0 @@ -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 deleted file mode 100644 index 9b73f9f..0000000 --- a/packages/pipeline/lib/pipeline.dart +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index ce796a0..0000000 --- a/packages/pipeline/lib/src/conditionable.dart +++ /dev/null @@ -1,16 +0,0 @@ -/// 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 deleted file mode 100644 index 37d9d68..0000000 --- a/packages/pipeline/lib/src/pipeline.dart +++ /dev/null @@ -1,241 +0,0 @@ -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 deleted file mode 100644 index 2b45e7f..0000000 --- a/packages/pipeline/lib/src/pipeline_contract.dart +++ /dev/null @@ -1,9 +0,0 @@ -/// 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/test/laravel_pipeline_test.dart b/packages/pipeline/test/laravel_pipeline_test.dart deleted file mode 100644 index 0fcdeaa..0000000 --- a/packages/pipeline/test/laravel_pipeline_test.dart +++ /dev/null @@ -1,258 +0,0 @@ -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 deleted file mode 100644 index ae67501..0000000 --- a/packages/pipeline/test/pipeline_test.dart +++ /dev/null @@ -1,106 +0,0 @@ -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/README.md b/packages/process/README.md deleted file mode 100644 index 757f4c9..0000000 --- a/packages/process/README.md +++ /dev/null @@ -1 +0,0 @@ -

    \ No newline at end of file diff --git a/packages/process/examples/basic_process/main.dart b/packages/process/examples/basic_process/main.dart deleted file mode 100644 index 8415927..0000000 --- a/packages/process/examples/basic_process/main.dart +++ /dev/null @@ -1,36 +0,0 @@ -// 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 deleted file mode 100644 index 7950162..0000000 --- a/packages/process/examples/process_pipeline/main.dart +++ /dev/null @@ -1,37 +0,0 @@ -// 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 deleted file mode 100644 index f8f21e4..0000000 --- a/packages/process/examples/process_pool/main.dart +++ /dev/null @@ -1,37 +0,0 @@ -// 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 deleted file mode 100644 index 1559db1..0000000 --- a/packages/process/examples/web_server_with_processes/main.dart +++ /dev/null @@ -1,67 +0,0 @@ -// 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 deleted file mode 100644 index cb29244..0000000 --- a/packages/process/examples/web_server_with_processes/views/index.mustache +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - Angel3 Process Example - - -

    Run a Process

    -
    - - -
    - - -
    - -
    -
    - - - - diff --git a/packages/process/lib/angel3_process.dart b/packages/process/lib/angel3_process.dart deleted file mode 100644 index 1965d4a..0000000 --- a/packages/process/lib/angel3_process.dart +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 4049683..0000000 --- a/packages/process/lib/src/process.dart +++ /dev/null @@ -1,250 +0,0 @@ -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 deleted file mode 100644 index 5166698..0000000 --- a/packages/process/lib/src/process_helper.dart +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index f2d48b6..0000000 --- a/packages/process/lib/src/process_manager.dart +++ /dev/null @@ -1,148 +0,0 @@ -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 deleted file mode 100644 index 449c708..0000000 --- a/packages/process/lib/src/process_pipeline.dart +++ /dev/null @@ -1,50 +0,0 @@ -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 deleted file mode 100644 index 67b323f..0000000 --- a/packages/process/lib/src/process_pool.dart +++ /dev/null @@ -1,62 +0,0 @@ -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 deleted file mode 100644 index c762c94..0000000 --- a/packages/process/lib/src/process_service_provider.dart +++ /dev/null @@ -1,24 +0,0 @@ -/* 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 deleted file mode 100644 index b837bae..0000000 --- a/packages/process/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index ab3a7eb..0000000 --- a/packages/process/test/process_test.dart +++ /dev/null @@ -1,80 +0,0 @@ -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 deleted file mode 100644 index ab82810..0000000 --- a/packages/process/test/process_test_extended.dart +++ /dev/null @@ -1,102 +0,0 @@ -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/README.md b/packages/queue/README.md deleted file mode 100644 index 757f4c9..0000000 --- a/packages/queue/README.md +++ /dev/null @@ -1 +0,0 @@ -

    \ No newline at end of file diff --git a/packages/queue/lib/queue.dart b/packages/queue/lib/queue.dart deleted file mode 100644 index 585829f..0000000 --- a/packages/queue/lib/queue.dart +++ /dev/null @@ -1,75 +0,0 @@ -/// 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 deleted file mode 100644 index 09b1301..0000000 --- a/packages/queue/lib/src/job_queued_event.dart +++ /dev/null @@ -1,70 +0,0 @@ -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 deleted file mode 100644 index 35fc590..0000000 --- a/packages/queue/lib/src/job_queueing_event.dart +++ /dev/null @@ -1,72 +0,0 @@ -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 deleted file mode 100644 index 2233816..0000000 --- a/packages/queue/lib/src/queue.dart +++ /dev/null @@ -1,396 +0,0 @@ -// 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 deleted file mode 100644 index 348ad79..0000000 --- a/packages/queue/lib/src/should_be_encrypted.dart +++ /dev/null @@ -1,18 +0,0 @@ -/// 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 deleted file mode 100644 index d6da8d5..0000000 --- a/packages/queue/lib/src/should_queue_after_commit.dart +++ /dev/null @@ -1,22 +0,0 @@ -/// 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 deleted file mode 100644 index f251ac6..0000000 --- a/packages/queue/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 5c9e0de..0000000 --- a/packages/queue/test/queue_test.dart +++ /dev/null @@ -1,317 +0,0 @@ -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/reflection/LICENSE b/packages/reflection/LICENSE deleted file mode 100644 index f7a8ccc..0000000 --- a/packages/reflection/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 The Reflection Authors - -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/packages/reflection/README.md b/packages/reflection/README.md deleted file mode 100644 index 7e30aa7..0000000 --- a/packages/reflection/README.md +++ /dev/null @@ -1,167 +0,0 @@ -# Dart Pure Reflection - -A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation without using `dart:mirrors` or code generation. - -## Features - -- ✅ Works on all platforms (Web, Mobile, Desktop) -- ✅ No dependency on `dart:mirrors` -- ✅ No code generation required -- ✅ Pure runtime reflection -- ✅ Type-safe property access -- ✅ Method invocation with argument validation -- ✅ Constructor invocation support -- ✅ Comprehensive error handling - -## Installation - -Add this to your package's `pubspec.yaml` file: - -```yaml -dependencies: - reflection: ^1.0.0 -``` - -## Usage - -### Basic Setup - -1. Add the `@reflectable` annotation and `Reflector` mixin to your class: - -```dart -import 'package:reflection/reflection.dart'; - -@reflectable -class User with Reflector { - String name; - int age; - final String id; - - User(this.name, this.age, {required this.id}); -} -``` - -2. Register your class and its constructors: - -```dart -// Register the class -Reflector.register(User); - -// Register constructors -Reflector.registerConstructor( - User, - '', // Default constructor - (String name, int age, {String? id}) { - if (id == null) throw ArgumentError.notNull('id'); - return User(name, age, id: id); - }, -); -``` - -### Reflecting on Types - -```dart -final reflector = RuntimeReflector.instance; - -// Get type metadata -final userType = reflector.reflectType(User); -print('Type name: ${userType.name}'); -print('Properties: ${userType.properties.keys.join(', ')}'); -print('Methods: ${userType.methods.keys.join(', ')}'); -``` - -### Working with Instances - -```dart -final user = User('john_doe', 30, id: 'usr_123'); -final userReflector = reflector.reflect(user); - -// Read properties -final name = userReflector.getField('name'); // john_doe -final age = userReflector.getField('age'); // 30 - -// Write properties -userReflector.setField('name', 'jane_doe'); -userReflector.setField('age', 25); - -// Invoke methods -userReflector.invoke('someMethod', ['arg1', 'arg2']); -``` - -### Creating Instances - -```dart -// Using default constructor -final newUser = reflector.createInstance( - User, - positionalArgs: ['alice', 28], - namedArgs: {'id': 'usr_456'}, -) as User; - -// Using named constructor -final specialUser = reflector.createInstance( - User, - constructorName: 'special', - positionalArgs: ['bob'], -) as User; -``` - -## Error Handling - -The package provides specific exceptions for different error cases: - -- `NotReflectableException`: Thrown when attempting to reflect on a non-reflectable type -- `ReflectionException`: Base class for reflection-related errors -- `InvalidArgumentsException`: Thrown when providing invalid arguments to a method or constructor -- `MemberNotFoundException`: Thrown when a property or method is not found - -```dart -try { - reflector.reflect(NonReflectableClass()); -} catch (e) { - print(e); // NotReflectableException: Type "NonReflectableClass" is not marked as @reflectable -} -``` - -## Complete Example - -See the [example](example/reflection_example.dart) for a complete working demonstration. - -## Limitations - -1. Type Discovery - - Properties and methods must be registered explicitly - - No automatic discovery of class members - - Generic type information is limited - -2. Performance - - First access to a type involves metadata creation - - Subsequent accesses use cached metadata - -3. Private Members - - Private fields and methods cannot be accessed - - Reflection is limited to public API - -## Design Philosophy - -This package is inspired by: - -- **dart:mirrors**: API design and metadata structure -- **fake_reflection**: Registration-based approach -- **mirrors.cc**: Runtime type handling - -The goal is to provide a lightweight, cross-platform reflection system that: - -- Works everywhere Dart runs -- Requires minimal setup -- Provides type-safe operations -- Maintains good performance -- Follows Dart best practices - -## Contributing - -Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting pull requests. - -## License - -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/packages/reflection/example/reflection_example.dart b/packages/reflection/example/reflection_example.dart deleted file mode 100644 index 9e2044d..0000000 --- a/packages/reflection/example/reflection_example.dart +++ /dev/null @@ -1,172 +0,0 @@ -import 'package:platform_reflection/reflection.dart'; - -@reflectable -class User with Reflector { - String name; - int age; - final String id; - bool _isActive; - - User(this.name, this.age, {required this.id, bool isActive = true}) - : _isActive = isActive; - - // Guest constructor - User.guest() - : name = 'guest', - age = 0, - id = 'guest_id', - _isActive = true; - - bool get isActive => _isActive; - - void deactivate() { - _isActive = false; - } - - void birthday() { - age++; - } - - String greet([String greeting = 'Hello']) => '$greeting, $name!'; - - @override - String toString() => - 'User(name: $name age: $age id: $id isActive: $isActive)'; -} - -void main() { - // Register User class for reflection - Reflector.register(User); - - // Register properties - Reflector.registerProperty(User, 'name', String); - Reflector.registerProperty(User, 'age', int); - Reflector.registerProperty(User, 'id', String, isWritable: false); - Reflector.registerProperty(User, 'isActive', bool, isWritable: false); - - // Register methods - Reflector.registerMethod( - User, - 'birthday', - [], - true, // returns void - ); - Reflector.registerMethod( - User, - 'greet', - [String], - false, // returns String - parameterNames: ['greeting'], - isRequired: [false], // optional parameter - ); - Reflector.registerMethod( - User, - 'deactivate', - [], - true, // returns void - ); - - // Register constructors - Reflector.registerConstructor( - User, - '', // default constructor - (String name, int age, {required String id, bool isActive = true}) => - User(name, age, id: id, isActive: isActive), - parameterTypes: [String, int, String, bool], - parameterNames: ['name', 'age', 'id', 'isActive'], - isRequired: [true, true, true, false], - isNamed: [false, false, true, true], - ); - - Reflector.registerConstructor( - User, - 'guest', - () => User.guest(), - ); - - // Create a user instance - final user = User('john_doe', 30, id: 'usr_123'); - print('Original user: $user'); - - // Get the reflector instance - final reflector = RuntimeReflector.instance; - - // Reflect on the User type - final userType = reflector.reflectType(User); - print('\nType information:'); - print('Type name: ${userType.name}'); - print('Properties: ${userType.properties.keys.join(', ')}'); - print('Methods: ${userType.methods.keys.join(', ')}'); - print('Constructors: ${userType.constructors.map((c) => c.name).join(', ')}'); - - // Create an instance reflector - final userReflector = reflector.reflect(user); - - // Read properties - print('\nReading properties:'); - print('Name: ${userReflector.getField('name')}'); - print('Age: ${userReflector.getField('age')}'); - print('ID: ${userReflector.getField('id')}'); - print('Is active: ${userReflector.getField('isActive')}'); - - // Modify properties - print('\nModifying properties:'); - userReflector.setField('name', 'jane_doe'); - userReflector.setField('age', 25); - print('Modified user: $user'); - - // Invoke methods - print('\nInvoking methods:'); - final greeting = userReflector.invoke('greet', ['Hi']); - print('Greeting: $greeting'); - - userReflector.invoke('birthday', []); - print('After birthday: $user'); - - userReflector.invoke('deactivate', []); - print('After deactivation: $user'); - - // Create new instances using reflection - print('\nCreating instances:'); - final newUser = reflector.createInstance( - User, - positionalArgs: ['alice', 28], - namedArgs: {'id': 'usr_456'}, - ) as User; - print('Created user: $newUser'); - - final guestUser = reflector.createInstance( - User, - constructorName: 'guest', - ) as User; - print('Created guest user: $guestUser'); - - // Demonstrate error handling - print('\nError handling:'); - try { - userReflector.setField('id', 'new_id'); // Should throw - id is final - } catch (e) { - print('Expected error: $e'); - } - - try { - userReflector - .invoke('unknownMethod', []); // Should throw - method doesn't exist - } catch (e) { - print('Expected error: $e'); - } - - // Demonstrate non-reflectable class - print('\nNon-reflectable class:'); - try { - final nonReflectable = NonReflectable(); - reflector.reflect(nonReflectable); - } catch (e) { - print('Expected error: $e'); - } -} - -// Class without @reflectable annotation for testing -class NonReflectable { - String value = 'test'; -} diff --git a/packages/reflection/lib/reflection.dart b/packages/reflection/lib/reflection.dart deleted file mode 100644 index 9985942..0000000 --- a/packages/reflection/lib/reflection.dart +++ /dev/null @@ -1,8 +0,0 @@ -/// A lightweight cross-platform reflection system for Dart. -library reflection; - -export 'src/reflector.dart'; -export 'src/metadata.dart'; -export 'src/annotations.dart'; -export 'src/exceptions.dart'; -export 'src/types.dart'; diff --git a/packages/reflection/lib/src/annotations.dart b/packages/reflection/lib/src/annotations.dart deleted file mode 100644 index 5831426..0000000 --- a/packages/reflection/lib/src/annotations.dart +++ /dev/null @@ -1,216 +0,0 @@ -import 'metadata.dart'; - -/// Registry of reflectable types and their metadata. -class ReflectionRegistry { - /// Map of type to its property metadata - static final _properties = >{}; - - /// Map of type to its method metadata - static final _methods = >{}; - - /// Map of type to its constructor metadata - static final _constructors = >{}; - - /// Map of type to its constructor factories - static final _constructorFactories = >{}; - - /// Registers a type as reflectable - static void registerType(Type type) { - _properties[type] = {}; - _methods[type] = {}; - _constructors[type] = []; - _constructorFactories[type] = {}; - } - - /// Registers a property for a type - static void registerProperty( - Type type, - String name, - Type propertyType, { - bool isReadable = true, - bool isWritable = true, - }) { - _properties[type]![name] = PropertyMetadata( - name: name, - type: propertyType, - isReadable: isReadable, - isWritable: isWritable, - ); - } - - /// Registers a method for a type - static void registerMethod( - Type type, - String name, - List parameterTypes, - bool returnsVoid, { - List? parameterNames, - List? isRequired, - List? isNamed, - }) { - final parameters = []; - for (var i = 0; i < parameterTypes.length; i++) { - parameters.add(ParameterMetadata( - name: parameterNames?[i] ?? 'param$i', - type: parameterTypes[i], - isRequired: isRequired?[i] ?? true, - isNamed: isNamed?[i] ?? false, - )); - } - - _methods[type]![name] = MethodMetadata( - name: name, - parameterTypes: parameterTypes, - parameters: parameters, - returnsVoid: returnsVoid, - ); - } - - /// Registers a constructor for a type - static void registerConstructor( - Type type, - String name, - Function factory, { - List? parameterTypes, - List? parameterNames, - List? isRequired, - List? isNamed, - }) { - final parameters = []; - if (parameterTypes != null) { - for (var i = 0; i < parameterTypes.length; i++) { - parameters.add(ParameterMetadata( - name: parameterNames?[i] ?? 'param$i', - type: parameterTypes[i], - isRequired: isRequired?[i] ?? true, - isNamed: isNamed?[i] ?? false, - )); - } - } - - _constructors[type]!.add(ConstructorMetadata( - name: name, - parameterTypes: parameterTypes ?? [], - parameters: parameters, - )); - _constructorFactories[type]![name] = factory; - } - - /// Gets property metadata for a type - static Map? getProperties(Type type) => - _properties[type]; - - /// Gets method metadata for a type - static Map? getMethods(Type type) => _methods[type]; - - /// Gets constructor metadata for a type - static List? getConstructors(Type type) => - _constructors[type]; - - /// Gets a constructor factory for a type - static Function? getConstructorFactory(Type type, String name) => - _constructorFactories[type]?[name]; - - /// Checks if a type is registered - static bool isRegistered(Type type) => _properties.containsKey(type); -} - -/// Marks a class as reflectable, allowing runtime reflection capabilities. -class Reflectable { - const Reflectable(); -} - -/// The annotation used to mark classes as reflectable. -const reflectable = Reflectable(); - -/// Mixin that provides reflection capabilities to a class. -mixin Reflector { - /// Register this type for reflection. - /// This should be called in the class's static initializer. - static void register(Type type) { - if (!ReflectionRegistry.isRegistered(type)) { - ReflectionRegistry.registerType(type); - } - } - - /// Register a property for reflection. - static void registerProperty( - Type type, - String name, - Type propertyType, { - bool isReadable = true, - bool isWritable = true, - }) { - ReflectionRegistry.registerProperty( - type, - name, - propertyType, - isReadable: isReadable, - isWritable: isWritable, - ); - } - - /// Register a method for reflection. - static void registerMethod( - Type type, - String name, - List parameterTypes, - bool returnsVoid, { - List? parameterNames, - List? isRequired, - List? isNamed, - }) { - ReflectionRegistry.registerMethod( - type, - name, - parameterTypes, - returnsVoid, - parameterNames: parameterNames, - isRequired: isRequired, - isNamed: isNamed, - ); - } - - /// Register a constructor for reflection. - static void registerConstructor( - Type type, - String name, - Function factory, { - List? parameterTypes, - List? parameterNames, - List? isRequired, - List? isNamed, - }) { - ReflectionRegistry.registerConstructor( - type, - name, - factory, - parameterTypes: parameterTypes, - parameterNames: parameterNames, - isRequired: isRequired, - isNamed: isNamed, - ); - } - - /// Checks if a type is registered for reflection. - static bool isReflectable(Type type) => ReflectionRegistry.isRegistered(type); - - /// Gets property metadata for a type. - static Map? getPropertyMetadata(Type type) => - ReflectionRegistry.getProperties(type); - - /// Gets method metadata for a type. - static Map? getMethodMetadata(Type type) => - ReflectionRegistry.getMethods(type); - - /// Gets constructor metadata for a type. - static List? getConstructorMetadata(Type type) => - ReflectionRegistry.getConstructors(type); - - /// Gets a constructor factory for a type. - static Function? getConstructor(Type type, String name) => - ReflectionRegistry.getConstructorFactory(type, name); -} - -/// Checks if a type is registered for reflection. -bool isReflectable(Type type) => Reflector.isReflectable(type); diff --git a/packages/reflection/lib/src/exceptions.dart b/packages/reflection/lib/src/exceptions.dart deleted file mode 100644 index 38ac136..0000000 --- a/packages/reflection/lib/src/exceptions.dart +++ /dev/null @@ -1,32 +0,0 @@ -/// Base class for all reflection-related exceptions. -class ReflectionException implements Exception { - /// The error message. - final String message; - - /// Creates a new reflection exception with the given [message]. - const ReflectionException(this.message); - - @override - String toString() => 'ReflectionException: $message'; -} - -/// Thrown when attempting to reflect on a type that is not marked as [Reflectable]. -class NotReflectableException extends ReflectionException { - /// Creates a new not reflectable exception for the given [type]. - NotReflectableException(Type type) - : super('Type "$type" is not marked as @reflectable'); -} - -/// Thrown when a property or method is not found during reflection. -class MemberNotFoundException extends ReflectionException { - /// Creates a new member not found exception. - MemberNotFoundException(String memberName, Type type) - : super('Member "$memberName" not found on type "$type"'); -} - -/// Thrown when attempting to invoke a method with invalid arguments. -class InvalidArgumentsException extends ReflectionException { - /// Creates a new invalid arguments exception. - InvalidArgumentsException(String methodName, Type type) - : super('Invalid arguments for method "$methodName" on type "$type"'); -} diff --git a/packages/reflection/lib/src/metadata.dart b/packages/reflection/lib/src/metadata.dart deleted file mode 100644 index 69c7c77..0000000 --- a/packages/reflection/lib/src/metadata.dart +++ /dev/null @@ -1,258 +0,0 @@ -import 'exceptions.dart'; - -/// Represents metadata about a parameter. -class ParameterMetadata { - /// The name of the parameter. - final String name; - - /// The type of the parameter. - final Type type; - - /// Whether this parameter is required. - final bool isRequired; - - /// Whether this parameter is named. - final bool isNamed; - - /// The default value for this parameter, if any. - final Object? defaultValue; - - /// Any attributes (annotations) on this parameter. - final List attributes; - - /// Creates a new parameter metadata instance. - const ParameterMetadata({ - required this.name, - required this.type, - required this.isRequired, - this.isNamed = false, - this.defaultValue, - this.attributes = const [], - }); -} - -/// Represents metadata about a type's property. -class PropertyMetadata { - /// The name of the property. - final String name; - - /// The type of the property. - final Type type; - - /// Whether the property can be read. - final bool isReadable; - - /// Whether the property can be written to. - final bool isWritable; - - /// Any attributes (annotations) on this property. - final List attributes; - - /// Creates a new property metadata instance. - const PropertyMetadata({ - required this.name, - required this.type, - this.isReadable = true, - this.isWritable = true, - this.attributes = const [], - }); -} - -/// Represents metadata about a type's method. -class MethodMetadata { - /// The name of the method. - final String name; - - /// The parameter types of the method in order. - final List parameterTypes; - - /// Detailed metadata about each parameter. - final List parameters; - - /// Whether the method is static. - final bool isStatic; - - /// Whether the method returns void. - final bool returnsVoid; - - /// Any attributes (annotations) on this method. - final List attributes; - - /// Creates a new method metadata instance. - const MethodMetadata({ - required this.name, - required this.parameterTypes, - required this.parameters, - required this.returnsVoid, - this.isStatic = false, - this.attributes = const [], - }); - - /// Validates the given arguments against this method's parameter types. - bool validateArguments(List arguments) { - if (arguments.length != parameterTypes.length) return false; - - for (var i = 0; i < arguments.length; i++) { - final arg = arguments[i]; - if (arg != null && arg.runtimeType != parameterTypes[i]) { - return false; - } - } - - return true; - } -} - -/// Represents metadata about a type's constructor. -class ConstructorMetadata { - /// The name of the constructor (empty string for default constructor). - final String name; - - /// The parameter types of the constructor in order. - final List parameterTypes; - - /// The names of the parameters if they are named parameters. - final List? parameterNames; - - /// Detailed metadata about each parameter. - final List parameters; - - /// Any attributes (annotations) on this constructor. - final List attributes; - - /// Creates a new constructor metadata instance. - const ConstructorMetadata({ - this.name = '', - required this.parameterTypes, - required this.parameters, - this.parameterNames, - this.attributes = const [], - }); - - /// Whether this constructor uses named parameters. - bool get hasNamedParameters => parameterNames != null; - - /// Validates the given arguments against this constructor's parameter types. - bool validateArguments(List arguments) { - if (arguments.length != parameterTypes.length) return false; - - for (var i = 0; i < arguments.length; i++) { - final arg = arguments[i]; - if (arg != null && arg.runtimeType != parameterTypes[i]) { - return false; - } - } - - return true; - } -} - -/// Represents metadata about a type. -class TypeMetadata { - /// The actual type this metadata represents. - final Type type; - - /// The name of the type. - final String name; - - /// The properties defined on this type. - final Map properties; - - /// The methods defined on this type. - final Map methods; - - /// The constructors defined on this type. - final List constructors; - - /// The supertype of this type, if any. - final TypeMetadata? supertype; - - /// The interfaces this type implements. - final List interfaces; - - /// Any attributes (annotations) on this type. - final List attributes; - - /// Creates a new type metadata instance. - const TypeMetadata({ - required this.type, - required this.name, - required this.properties, - required this.methods, - required this.constructors, - this.supertype, - this.interfaces = const [], - this.attributes = const [], - }); - - /// Gets a property by name, throwing if not found. - PropertyMetadata getProperty(String name) { - final property = properties[name]; - if (property == null) { - throw MemberNotFoundException(name, type); - } - return property; - } - - /// Gets a method by name, throwing if not found. - MethodMetadata getMethod(String name) { - final method = methods[name]; - if (method == null) { - throw MemberNotFoundException(name, type); - } - return method; - } - - /// Gets the default constructor, throwing if not found. - ConstructorMetadata get defaultConstructor { - return constructors.firstWhere( - (c) => c.name.isEmpty, - orElse: () => throw ReflectionException( - 'No default constructor found for type "$name"', - ), - ); - } - - /// Gets a named constructor, throwing if not found. - ConstructorMetadata getConstructor(String name) { - return constructors.firstWhere( - (c) => c.name == name, - orElse: () => throw ReflectionException( - 'Constructor "$name" not found for type "$type"', - ), - ); - } -} - -/// Represents metadata about a function. -class FunctionMetadata { - /// The parameters of the function. - final List parameters; - - /// Whether the function returns void. - final bool returnsVoid; - - /// The return type of the function. - final Type returnType; - - /// Creates a new function metadata instance. - const FunctionMetadata({ - required this.parameters, - required this.returnsVoid, - required this.returnType, - }); - - /// Validates the given arguments against this function's parameters. - bool validateArguments(List arguments) { - if (arguments.length != parameters.length) return false; - - for (var i = 0; i < arguments.length; i++) { - final arg = arguments[i]; - if (arg != null && arg.runtimeType != parameters[i].type) { - return false; - } - } - - return true; - } -} diff --git a/packages/reflection/lib/src/reflector.dart b/packages/reflection/lib/src/reflector.dart deleted file mode 100644 index 27a2864..0000000 --- a/packages/reflection/lib/src/reflector.dart +++ /dev/null @@ -1,258 +0,0 @@ -import 'dart:core'; -import 'package:meta/meta.dart'; - -import 'annotations.dart'; -import 'exceptions.dart'; -import 'metadata.dart'; - -/// A pure runtime reflection system that provides type introspection and manipulation. -class RuntimeReflector { - /// The singleton instance of the reflector. - static final instance = RuntimeReflector._(); - - RuntimeReflector._(); - - /// Creates a new instance of a type using reflection. - Object createInstance( - Type type, { - String constructorName = '', - List positionalArgs = const [], - Map namedArgs = const {}, - }) { - // Check if type is reflectable - if (!isReflectable(type)) { - throw NotReflectableException(type); - } - - // Get type metadata - final metadata = reflectType(type); - - // Get constructor - final constructor = constructorName.isEmpty - ? metadata.defaultConstructor - : metadata.getConstructor(constructorName); - - // Validate arguments - if (!_validateConstructorArgs(constructor, positionalArgs, namedArgs)) { - throw InvalidArgumentsException(constructorName, type); - } - - try { - // Get constructor factory - final factory = Reflector.getConstructor(type, constructorName); - if (factory == null) { - throw ReflectionException( - 'Constructor "$constructorName" not found on type $type', - ); - } - - // Create a map of named arguments with Symbol keys - final namedArgsMap = {}; - for (var entry in namedArgs.entries) { - namedArgsMap[Symbol(entry.key)] = entry.value; - } - - // Apply the function with both positional and named arguments - return Function.apply(factory, positionalArgs, namedArgsMap); - } catch (e) { - throw ReflectionException( - 'Failed to create instance of $type using constructor "$constructorName": $e', - ); - } - } - - /// Validates constructor arguments. - bool _validateConstructorArgs( - ConstructorMetadata constructor, - List positionalArgs, - Map namedArgs, - ) { - // Get required positional parameters - final requiredPositional = constructor.parameters - .where((p) => p.isRequired && !p.isNamed) - .toList(); - - // Get required named parameters - final requiredNamed = - constructor.parameters.where((p) => p.isRequired && p.isNamed).toList(); - - // Check required positional arguments - if (positionalArgs.length < requiredPositional.length) { - return false; - } - - // Check positional args types - for (var i = 0; i < positionalArgs.length; i++) { - final arg = positionalArgs[i]; - if (arg != null && i < constructor.parameters.length) { - final param = constructor.parameters[i]; - if (!param.isNamed && arg.runtimeType != param.type) { - return false; - } - } - } - - // Check required named parameters are provided - for (var param in requiredNamed) { - if (!namedArgs.containsKey(param.name)) { - return false; - } - } - - // Check named args types - for (var entry in namedArgs.entries) { - final param = constructor.parameters.firstWhere( - (p) => p.name == entry.key && p.isNamed, - orElse: () => throw InvalidArgumentsException( - constructor.name, - constructor.parameterTypes.first, - ), - ); - - final value = entry.value; - if (value != null && value.runtimeType != param.type) { - return false; - } - } - - return true; - } - - /// Reflects on a type, returning its metadata. - TypeMetadata reflectType(Type type) { - // Check if type is reflectable - if (!isReflectable(type)) { - throw NotReflectableException(type); - } - - // Get metadata from registry - final properties = Reflector.getPropertyMetadata(type) ?? {}; - final methods = Reflector.getMethodMetadata(type) ?? {}; - final constructors = Reflector.getConstructorMetadata(type) ?? []; - - return TypeMetadata( - type: type, - name: type.toString(), - properties: properties, - methods: methods, - constructors: constructors, - ); - } - - /// Creates a new instance reflector for the given object. - InstanceReflector reflect(Object instance) { - // Check if type is reflectable - if (!isReflectable(instance.runtimeType)) { - throw NotReflectableException(instance.runtimeType); - } - - return InstanceReflector._(instance, reflectType(instance.runtimeType)); - } -} - -/// Provides reflection capabilities for object instances. -class InstanceReflector { - final Object _instance; - final TypeMetadata _metadata; - - /// Creates a new instance reflector. - @protected - InstanceReflector._(this._instance, this._metadata); - - /// Gets the value of a property by name. - Object? getField(String name) { - final property = _metadata.getProperty(name); - if (!property.isReadable) { - throw ReflectionException( - 'Property "$name" on type "${_metadata.name}" is not readable', - ); - } - - try { - final instance = _instance as dynamic; - switch (name) { - case 'name': - return instance.name; - case 'age': - return instance.age; - case 'id': - return instance.id; - case 'isActive': - return instance.isActive; - default: - throw ReflectionException( - 'Property "$name" not found on type "${_metadata.name}"', - ); - } - } catch (e) { - throw ReflectionException( - 'Failed to get property "$name" on type "${_metadata.name}": $e', - ); - } - } - - /// Sets the value of a property by name. - void setField(String name, Object? value) { - final property = _metadata.getProperty(name); - if (!property.isWritable) { - throw ReflectionException( - 'Property "$name" on type "${_metadata.name}" is not writable', - ); - } - - try { - final instance = _instance as dynamic; - switch (name) { - case 'name': - instance.name = value as String; - break; - case 'age': - instance.age = value as int; - break; - default: - throw ReflectionException( - 'Property "$name" not found on type "${_metadata.name}"', - ); - } - } catch (e) { - throw ReflectionException( - 'Failed to set property "$name" on type "${_metadata.name}": $e', - ); - } - } - - /// Invokes a method by name with the given arguments. - Object? invoke(String name, List arguments) { - final method = _metadata.getMethod(name); - if (!method.validateArguments(arguments)) { - throw InvalidArgumentsException(name, _metadata.type); - } - - try { - final instance = _instance as dynamic; - switch (name) { - case 'birthday': - instance.birthday(); - return null; - case 'greet': - return arguments.isEmpty - ? instance.greet() - : instance.greet(arguments[0] as String); - case 'deactivate': - instance.deactivate(); - return null; - default: - throw ReflectionException( - 'Method "$name" not found on type "${_metadata.name}"', - ); - } - } catch (e) { - throw ReflectionException( - 'Failed to invoke method "$name" on type "${_metadata.name}": $e', - ); - } - } - - /// Gets the type metadata for this instance. - TypeMetadata get type => _metadata; -} diff --git a/packages/reflection/lib/src/types.dart b/packages/reflection/lib/src/types.dart deleted file mode 100644 index 11cff67..0000000 --- a/packages/reflection/lib/src/types.dart +++ /dev/null @@ -1,19 +0,0 @@ -/// Represents the void type in our reflection system. -class VoidType implements Type { - const VoidType._(); - - /// The singleton instance representing void. - static const instance = VoidType._(); - - @override - String toString() => 'void'; -} - -/// The void type instance to use in our reflection system. -const voidType = VoidType.instance; - -/// Extension to check if a Type is void. -extension TypeExtensions on Type { - /// Whether this type represents void. - bool get isVoid => this == voidType; -} diff --git a/packages/reflection/pubspec.lock b/packages/reflection/pubspec.lock deleted file mode 100644 index 101471f..0000000 --- a/packages/reflection/pubspec.lock +++ /dev/null @@ -1,402 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77" - url: "https://pub.dev" - source: hosted - version: "73.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.2" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a" - url: "https://pub.dev" - source: hosted - version: "6.8.0" - args: - dependency: transitive - description: - name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 - url: "https://pub.dev" - source: hosted - version: "2.6.0" - async: - dependency: transitive - description: - name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 - url: "https://pub.dev" - source: hosted - version: "2.12.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5" - url: "https://pub.dev" - source: hosted - version: "1.11.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" - url: "https://pub.dev" - source: hosted - version: "4.1.1" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf - url: "https://pub.dev" - source: hosted - version: "0.7.1" - lints: - dependency: "direct dev" - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - macros: - dependency: transitive - description: - name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" - url: "https://pub.dev" - source: hosted - version: "0.1.2-main.4" - matcher: - dependency: transitive - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - meta: - dependency: "direct main" - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 - url: "https://pub.dev" - source: hosted - version: "1.1.3" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" - url: "https://pub.dev" - source: hosted - version: "1.12.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test: - dependency: "direct dev" - description: - name: test - sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" - url: "https://pub.dev" - source: hosted - version: "1.25.8" - test_api: - dependency: transitive - description: - name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" - url: "https://pub.dev" - source: hosted - version: "0.7.3" - test_core: - dependency: transitive - description: - name: test_core - sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" - url: "https://pub.dev" - source: hosted - version: "0.6.5" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" - url: "https://pub.dev" - source: hosted - version: "14.3.1" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" - url: "https://pub.dev" - source: hosted - version: "0.1.6" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.5.0 <4.0.0" diff --git a/packages/reflection/pubspec.yaml b/packages/reflection/pubspec.yaml deleted file mode 100644 index e5feb62..0000000 --- a/packages/reflection/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: platform_reflection -description: A lightweight cross-platform reflection system for Dart -version: 0.1.0 -environment: - sdk: '>=3.0.0 <4.0.0' - -dependencies: - meta: ^1.9.0 - -dev_dependencies: - lints: ^2.1.0 - test: ^1.24.0 diff --git a/packages/reflection/test/reflection_test.dart b/packages/reflection/test/reflection_test.dart deleted file mode 100644 index 469309a..0000000 --- a/packages/reflection/test/reflection_test.dart +++ /dev/null @@ -1,236 +0,0 @@ -import 'package:platform_reflection/reflection.dart'; -import 'package:test/test.dart'; - -@reflectable -class Person with Reflector { - String name; - int age; - final String id; - - Person(this.name, this.age, {required this.id}); - - // Guest constructor - Person.guest() - : name = 'Guest', - age = 0, - id = 'guest'; - - // Constructor with optional parameters - Person.withDefaults(this.name, [this.age = 18]) : id = 'default'; - - void birthday() { - age++; - } - - String greet(String greeting) { - return '$greeting, $name!'; - } - - static Person create(String name, int age, String id) { - return Person(name, age, id: id); - } -} - -// Class without @reflectable annotation for testing -class NotReflectable { - String value = 'test'; -} - -void main() { - group('RuntimeReflector', () { - late RuntimeReflector reflector; - late Person person; - - setUp(() { - // Register Person as reflectable - Reflector.register(Person); - - // Register properties - Reflector.registerProperty(Person, 'name', String); - Reflector.registerProperty(Person, 'age', int); - Reflector.registerProperty(Person, 'id', String, isWritable: false); - - // Register methods - Reflector.registerMethod( - Person, - 'birthday', - [], - true, - ); - Reflector.registerMethod( - Person, - 'greet', - [String], - false, - parameterNames: ['greeting'], - ); - - // Register constructors - Reflector.registerConstructor( - Person, - '', - (String name, int age, {required String id}) => - Person(name, age, id: id), - parameterTypes: [String, int, String], - parameterNames: ['name', 'age', 'id'], - isRequired: [true, true, true], - isNamed: [false, false, true], - ); - - Reflector.registerConstructor( - Person, - 'guest', - () => Person.guest(), - ); - - Reflector.registerConstructor( - Person, - 'withDefaults', - (String name, [int age = 18]) => Person.withDefaults(name, age), - parameterTypes: [String, int], - parameterNames: ['name', 'age'], - isRequired: [true, false], - isNamed: [false, false], - ); - - reflector = RuntimeReflector.instance; - person = Person('John', 30, id: '123'); - }); - - group('Type Reflection', () { - test('reflectType returns correct type metadata', () { - final metadata = reflector.reflectType(Person); - - expect(metadata.name, equals('Person')); - expect(metadata.properties.length, equals(3)); - expect(metadata.methods.length, equals(2)); // birthday and greet - expect(metadata.constructors.length, - equals(3)); // default, guest, withDefaults - }); - - test('reflect creates instance reflector', () { - final instanceReflector = reflector.reflect(person); - - expect(instanceReflector, isNotNull); - expect(instanceReflector.type.name, equals('Person')); - }); - - test('throws NotReflectableException for non-reflectable class', () { - final instance = NotReflectable(); - - expect( - () => reflector.reflect(instance), - throwsA(isA()), - ); - }); - }); - - group('Property Access', () { - test('getField returns property value', () { - final instanceReflector = reflector.reflect(person); - - expect(instanceReflector.getField('name'), equals('John')); - expect(instanceReflector.getField('age'), equals(30)); - expect(instanceReflector.getField('id'), equals('123')); - }); - - test('setField updates property value', () { - final instanceReflector = reflector.reflect(person); - - instanceReflector.setField('name', 'Jane'); - instanceReflector.setField('age', 25); - - expect(person.name, equals('Jane')); - expect(person.age, equals(25)); - }); - - test('setField throws on final field', () { - final instanceReflector = reflector.reflect(person); - - expect( - () => instanceReflector.setField('id', '456'), - throwsA(isA()), - ); - }); - }); - - group('Method Invocation', () { - test('invoke calls method with arguments', () { - final instanceReflector = reflector.reflect(person); - - final result = instanceReflector.invoke('greet', ['Hello']); - expect(result, equals('Hello, John!')); - - instanceReflector.invoke('birthday', []); - expect(person.age, equals(31)); - }); - - test('invoke throws on invalid arguments', () { - final instanceReflector = reflector.reflect(person); - - expect( - () => instanceReflector.invoke('greet', [42]), - throwsA(isA()), - ); - }); - }); - - group('Constructor Invocation', () { - test('creates instance with default constructor', () { - final instance = reflector.createInstance( - Person, - positionalArgs: ['Alice', 25], - namedArgs: {'id': '456'}, - ) as Person; - - expect(instance.name, equals('Alice')); - expect(instance.age, equals(25)); - expect(instance.id, equals('456')); - }); - - test('creates instance with named constructor', () { - final instance = reflector.createInstance( - Person, - constructorName: 'guest', - ) as Person; - - expect(instance.name, equals('Guest')); - expect(instance.age, equals(0)); - expect(instance.id, equals('guest')); - }); - - test('creates instance with optional parameters', () { - final instance = reflector.createInstance( - Person, - constructorName: 'withDefaults', - positionalArgs: ['Bob'], - ) as Person; - - expect(instance.name, equals('Bob')); - expect(instance.age, equals(18)); // Default value - expect(instance.id, equals('default')); - }); - - test('throws on invalid constructor arguments', () { - expect( - () => reflector.createInstance( - Person, - positionalArgs: ['Alice'], // Missing required age - namedArgs: {'id': '456'}, - ), - throwsA(isA()), - ); - }); - - test('throws on non-existent constructor', () { - expect( - () => reflector.createInstance( - Person, - constructorName: 'nonexistent', - ), - throwsA(isA()), - ); - }); - }); - }); -} diff --git a/packages/route/.gitignore b/packages/route/.gitignore deleted file mode 100644 index 24d6831..0000000 --- a/packages/route/.gitignore +++ /dev/null @@ -1,71 +0,0 @@ -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub -.dart_tool -.packages -.pub/ -build/ - -# If you're building an application, you may want to check-in your pubspec.lock -pubspec.lock - -# Directory created by dartdoc -# If you don't generate documentation locally you can remove this line. -doc/api/ - -### Dart template -# See https://www.dartlang.org/tools/private-files.html - -# Files and directories created by pub - -# SDK 1.20 and later (no longer creates packages directories) - -# Older SDK versions -# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20) -.project -.buildlog -**/packages/ - - -# Files created by dart2js -# (Most Dart developers will use pub build to compile Dart, use/modify these -# rules if you intend to use dart2js directly -# Convention is to use extension '.dart.js' for Dart compiled to Javascript to -# differentiate from explicit Javascript files) -*.dart.js -*.part.js -*.js.deps -*.js.map -*.info.json - -# Directory created by dartdoc - -# Don't commit pubspec lock file -# (Library packages only! Remove pattern if developing an application package) -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: - -## VsCode -.vscode/ - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -.idea/ -/out/ -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties diff --git a/packages/route/AUTHORS.md b/packages/route/AUTHORS.md deleted file mode 100644 index ac95ab5..0000000 --- a/packages/route/AUTHORS.md +++ /dev/null @@ -1,12 +0,0 @@ -Primary Authors -=============== - -* __[Thomas Hii](dukefirehawk.apps@gmail.com)__ - - Thomas is the current maintainer of the code base. He has refactored and migrated the - code base to support NNBD. - -* __[Tobe O](thosakwe@gmail.com)__ - - Tobe has written much of the original code prior to NNBD migration. He has moved on and - is no longer involved with the project. diff --git a/packages/route/CHANGELOG.md b/packages/route/CHANGELOG.md deleted file mode 100644 index 34b37d6..0000000 --- a/packages/route/CHANGELOG.md +++ /dev/null @@ -1,98 +0,0 @@ -# Change Log - -## 8.1.1 - -* Updated repository link - -## 8.1.0 - -* Updated `lints` to 3.0.0 -* Fixed analyser warnings - -## 8.0.0 - -* Require Dart >= 3.0 -* Updated `build_web_compilers` to 4.0.0 -* Updated `http` to 1.0.0 - -## 7.0.0 - -* Require Dart >= 2.17 - -## 6.0.0 - -* Updated to 2.16.x - -## 5.2.0 - -* Updated `package:build_runner` -* Updated `package:build_web_compiler` - -## 5.1.0 - -* Updated to use `package:belatuk_combinator` -* Updated linter to `package:lints` - -## 5.0.1 - -* Updated README - -## 5.0.0 - -* Migrated to support Dart >= 2.12 NNBD - -## 4.0.0 - -* Migrated to work with Dart >= 2.12 Non NNBD - -## 3.1.0+1 - -* Accidentally hit `CTRL-C` while uploading `3.1.0`; this version ensures everything is ok. - -## 3.1.0 - -* Add `Router.groupAsync` - -## 3.0.6 - -* Remove static default values for `middleware`. - -## 3.0.5 - -* Add `MiddlewarePipelineIterator`. - -## 3.0.4 - -* Add `RouteResult` class, which allows segments (i.e. wildcard) to -modify the `tail`. -* Add more wildcard tests. - -## 3.0.3 - -* Support trailing text after parameters with custom Regexes. - -## 3.0.2 - -* Support leading and trailing text for both `:parameters` and `*` - -## 3.0.1 - -* Make the callback in `Router.group` generically-typed. - -## 3.0.0 - -* Make `Router` and `Route` single-parameter generic. -* Remove `package:browser` dependency. -* `BrowserRouter.on` now only accepts a `String`. -* `MiddlewarePipeline.routingResults` now accepts -an `Iterable`, instead of just a `List`. -* Removed deprecated `Route.as`, as well as `Router.registerMiddleware`. -* Completely removed `Route.requestMiddleware`. - -## 2.0.7 - -* Minor strong mode updates to work with stricter Dart 2. - -## 2.0.5 - -* Patch to work with `combinator@1.0.0`. diff --git a/packages/route/LICENSE b/packages/route/LICENSE deleted file mode 100644 index df5e063..0000000 --- a/packages/route/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2021, dukefirehawk.com -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/route/README.md b/packages/route/README.md deleted file mode 100644 index 6d1dd01..0000000 --- a/packages/route/README.md +++ /dev/null @@ -1,136 +0,0 @@ -# Protevus Route - -![Pub Version (including pre-releases)](https://img.shields.io/pub/v/angel3_route?include_prereleases) -[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety) -[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion) -[![License](https://img.shields.io/github/license/dart-backend/angel)](https://github.com/dart-backend/angel/tree/master/packages/route/LICENSE) - -A powerful, isomorphic routing library for Dart. - -`angel3_route` exposes a routing system that takes the shape of a tree. This tree structure can be easily navigated, in a fashion somewhat similar to a filesystem. The `Router` API is a very straightforward interface that allows for your code to take a shape similar to the route tree. Users of Laravel and Express will be very happy. - -`angel3_route` does not require the use of [Protevus 3](https://pub.dev/packages/angel3_framework), and has minimal dependencies. Thus, it can be used in any application, regardless of framework. This includes Web apps, Flutter apps, CLI apps, and smaller servers which do not need all the features of the Protevus framework. - -## Contents - -- [Protevus Route](#platform-route) - - [Contents](#contents) - - [Examples](#examples) - - [Routing](#routing) - - [Hierarchy](#hierarchy) - - [In the Browser](#in-the-browser) - - [Route State](#route-state) - - [Route Parameters](#route-parameters) - -## Examples - -### Routing - -If you use [Protevus](https://pub.dev/packages/angel3_framework), every `Protevus` instance is a `Router` in itself. - -```dart -void main() { - final router = Router(); - - router.get('/users', () {}); - - router.post('/users/:id/timeline', (String id) {}); - - router.get('/square_root/:id([0-9]+)', (n) { - return { 'result': pow(int.parse(n), 0.5) }; - }); - - // You can also have parameters auto-parsed. - // - // Supports int, double, and num. - router.get('/square_root/int:id([0-9]+)', (int n) { - return { 'result': pow(n, 0.5) }; - }); - - router.group('/show/:id', (router) { - router.get('/reviews', (id) { - return someQuery(id).reviews; - }); - - // Optionally restrict params to a RegExp - router.get('/reviews/:reviewId([A-Za-z0-9_]+)', (id, reviewId) { - return someQuery(id).reviews.firstWhere( - (r) => r.id == reviewId); - }); - }, middleware: [put, middleware, here]); - - // Grouping can also take async callbacks. - await router.groupAsync('/hello', (router) async { - var name = await getNameFromFileSystem(); - router.get(name, (req, res) => '...'); - }); -} -``` - -The default `Router` does not give any notification of routes being changed, because there is no inherent stream of URL's for it to listen to. This is good, because a server needs a lot of flexibility with which to handle requests. - -### Hierarchy - -```dart -void main() { - final router = Router(); - - router - .chain('middleware1') - .chain('other_middleware') - .get('/hello', () { - print('world'); - }); - - router.group('/user/:id', (router) { - router.get('/balance', (id) async { - final user = await someQuery(id); - return user.balance; - }); - }); -} -``` - -See [the tests](test/route/no_params.dart) for good examples. - -## In the Browser - -Supports both hashed routes and pushState. The `BrowserRouter` interface exposes a `Stream onRoute`, which can be listened to for changes. It will fire `"NULL"` whenever no route is matched. - -`angel3_route` will also automatically intercept `` elements and redirect them to your routes. - -To prevent this for a given anchor, do any of the following: - -- Do not provide an `href` -- Provide a `download` or `target` attribute on the element -- Set `rel="external"` - -## Route State - -```dart -main() { - final router = BrowserRouter(); - // .. - router.onRoute.listen((route) { - if (route == null) - throw 404; - else route.state['foo'] = 'bar'; - }); - - router.listen(); // Start listening -} -``` - -For applications where you need to access a chain of handlers, consider using `onResolve` instead. You can see an example in `web/shared/basic.dart`. - -## Route Parameters - -Routes can have parameters, as seen in the above examples. Use `allParams` in a `RoutingResult` to get them as a nice `Map`: - -```dart -var router = Router(); -router.get('/book/:id/authors', () => ...); - -var result = router.resolve('/book/foo/authors'); -var params = result.allParams; // {'id': 'foo'}; -``` diff --git a/packages/route/analysis_options.yaml b/packages/route/analysis_options.yaml deleted file mode 100644 index 572dd23..0000000 --- a/packages/route/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:lints/recommended.yaml diff --git a/packages/route/example/main.dart b/packages/route/example/main.dart deleted file mode 100644 index dc351a1..0000000 --- a/packages/route/example/main.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'dart:math'; - -import 'package:platform_route/route.dart'; - -void main() { - final router = Router(); - - router.get('/whois/~:user', () {}); - - router.get('/wild*', () {}); - - router.get('/ordinal/int:n([0-9]+)st', () {}); - - print(router.resolveAbsolute('/whois/~thosakwe').first.allParams); - print(router.resolveAbsolute('/wild_thornberrys').first.route.path); - print(router.resolveAbsolute('/ordinal/1st').first.allParams); - - router.get('/users', () {}); - - router.post('/users/:id/timeline', (String id) {}); - - router.get('/square_root/:id([0-9]+)', (String n) { - return {'result': pow(int.parse(n), 0.5)}; - }); - - // You can also have parameters auto-parsed. - // - // Supports int, double, and num. - router.get('/square_root/int:id([0-9]+)', (int n) { - return {'result': pow(n, 0.5)}; - }); - - router.group('/show/:id', (router) { - router.get('/reviews', (id) { - return someQuery(id).reviews; - }); - - // Optionally restrict params to a RegExp - router.get('/reviews/:reviewId([A-Za-z0-9_]+)', (id, reviewId) { - return someQuery(id).reviews.firstWhere((r) => r.id == reviewId); - }); - }); -} - -SomeQuery someQuery(id) => SomeQuery(); - -class SomeQuery { - List get reviews => [ - SomeQueryReview('fake'), - SomeQueryReview('data'), - ]; -} - -class SomeQueryReview { - final String id; - - SomeQueryReview(this.id); -} diff --git a/packages/route/lib/browser.dart b/packages/route/lib/browser.dart deleted file mode 100644 index 29268eb..0000000 --- a/packages/route/lib/browser.dart +++ /dev/null @@ -1,225 +0,0 @@ -import 'dart:async' show Stream, StreamController; -import 'dart:html'; -import 'package:path/path.dart' as p; - -import 'route.dart'; - -final RegExp _hash = RegExp(r'^#/'); -final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)'); - -/// A variation of the [Router] support both hash routing and push state. -abstract class BrowserRouter extends Router { - /// Fires whenever the active route changes. Fires `null` if none is selected (404). - Stream> get onResolve; - - /// Fires whenever the active route changes. Fires `null` if none is selected (404). - Stream> get onRoute; - - /// Set `hash` to true to use hash routing instead of push state. - /// `listen` as `true` will call `listen` after initialization. - factory BrowserRouter({bool hash = false, bool listen = false}) { - return hash - ? _HashRouter(listen: listen) - : _PushStateRouter(listen: listen); - } - - //BrowserRouter._() : super(); - - void _goTo(String path); - - /// Navigates to the path generated by calling - /// [navigate] with the given [linkParams]. - /// - /// This always navigates to an absolute path. - void go(List linkParams); - - // Handles a route path, manually. - // void handle(String path); - - /// Begins listen for location changes. - void listen(); - - /// Identical to [all]. - Route on(String path, T handler, {Iterable middleware}); -} - -abstract class _BrowserRouterImpl extends Router - implements BrowserRouter { - bool _listening = false; - Route? _current; - final StreamController> _onResolve = - StreamController>(); - final StreamController> _onRoute = StreamController>(); - - Route? get currentRoute => _current; - - @override - Stream> get onResolve => _onResolve.stream; - - @override - Stream> get onRoute => _onRoute.stream; - - _BrowserRouterImpl({bool listen = false}) : super() { - if (listen != false) this.listen(); - prepareAnchors(); - } - - @override - void go(Iterable linkParams) => _goTo(navigate(linkParams)); - - @override - Route on(String path, T handler, {Iterable middleware = const []}) => - all(path, handler, middleware: middleware); - - void prepareAnchors() { - final anchors = window.document - .querySelectorAll('a') - .cast(); //:not([dynamic])'); - - for (final $a in anchors) { - if ($a.attributes.containsKey('href') && - $a.attributes.containsKey('download') && - $a.attributes.containsKey('target') && - $a.attributes['rel'] != 'external') { - $a.onClick.listen((e) { - e.preventDefault(); - _goTo($a.attributes['href']!); - //go($a.attributes['href'].split('/').where((str) => str.isNotEmpty)); - }); - } - - $a.attributes['dynamic'] = 'true'; - } - } - - void _listen(); - - @override - void listen() { - if (_listening) { - throw StateError('The router is already listening for page changes.'); - } - _listening = true; - _listen(); - } -} - -class _HashRouter extends _BrowserRouterImpl { - _HashRouter({required bool listen}) : super(listen: listen) { - if (listen) { - this.listen(); - } - } - - @override - void _goTo(String uri) { - window.location.hash = '#$uri'; - } - - void handleHash([_]) { - final path = window.location.hash.replaceAll(_hash, ''); - var allResolved = resolveAbsolute(path); - - if (allResolved.isEmpty) { - // TODO: Need fixing - //_onResolve.add(null); - //_onRoute.add(_current = null); - _current = null; - } else { - var resolved = allResolved.first; - if (resolved.route != _current) { - _onResolve.add(resolved); - _onRoute.add(_current = resolved.route); - } - } - } - - void handlePath(String path) { - final resolved = resolveAbsolute(path).first; - - //if (resolved == null) { - // _onResolve.add(null); - // _onRoute.add(_current = null); - //} else - if (resolved.route != _current) { - _onResolve.add(resolved); - _onRoute.add(_current = resolved.route); - } - } - - @override - void _listen() { - window.onHashChange.listen(handleHash); - handleHash(); - } -} - -class _PushStateRouter extends _BrowserRouterImpl { - late String _basePath; - - _PushStateRouter({required bool listen}) : super(listen: listen) { - var $base = window.document.querySelector('base[href]') as BaseElement; - - if ($base.href.isNotEmpty != true) { - throw StateError( - 'You must have a element present in your document to run the push state router.'); - } - _basePath = $base.href.replaceAll(_straySlashes, ''); - if (listen) this.listen(); - } - - @override - void _goTo(String uri) { - final resolved = resolveAbsolute(uri).first; - var relativeUri = uri; - - if (_basePath.isNotEmpty) { - relativeUri = p.join(_basePath, uri.replaceAll(_straySlashes, '')); - } - - //if (resolved == null) { - // _onResolve.add(null); - // _onRoute.add(_current = null); - //} else { - final route = resolved.route; - var thisPath = route.name ?? ''; - if (thisPath.isEmpty) { - thisPath = route.path; - } - window.history - .pushState({'path': route.path, 'params': {}}, thisPath, relativeUri); - _onResolve.add(resolved); - _onRoute.add(_current = route); - //} - } - - void handleState(state) { - if (state is Map && state.containsKey('path')) { - var path = state['path'].toString(); - final resolved = resolveAbsolute(path).first; - - if (resolved.route != _current) { - //properties.addAll(state['properties'] ?? {}); - _onResolve.add(resolved); - _onRoute.add(_current = resolved.route); - } else { - //_onResolve.add(null); - //_onRoute.add(_current = null); - _current = null; - } - } else { - //_onResolve.add(null); - //_onRoute.add(_current = null); - _current = null; - } - } - - @override - void _listen() { - window.onPopState.listen((e) { - handleState(e.state); - }); - - handleState(window.history.state); - } -} diff --git a/packages/route/lib/route.dart b/packages/route/lib/route.dart deleted file mode 100644 index 8cd7ae4..0000000 --- a/packages/route/lib/route.dart +++ /dev/null @@ -1,5 +0,0 @@ -library platform_route; - -export 'src/middleware_pipeline.dart'; -export 'src/router.dart'; -export 'src/routing_exception.dart'; diff --git a/packages/route/lib/src/grammar.dart b/packages/route/lib/src/grammar.dart deleted file mode 100644 index ecacb58..0000000 --- a/packages/route/lib/src/grammar.dart +++ /dev/null @@ -1,327 +0,0 @@ -part of 'router.dart'; - -class RouteGrammar { - static const String notSlashRgx = r'([^/]+)'; - //static final RegExp rgx = RegExp(r'\((.+)\)'); - static final Parser notSlash = - match(RegExp(notSlashRgx)).value((r) => r.span?.text ?? ''); - - static final Parser regExp = - match(RegExp(r'\(([^\n)]+)\)([^/]+)?')) - .value((r) => r.scanner.lastMatch!); - - static final Parser parameterName = - match(RegExp('$notSlashRgx?' r':([A-Za-z0-9_]+)' r'([^(/\n])?')) - .value((r) => r.scanner.lastMatch!); - - static final Parser parameterSegment = chain([ - parameterName, - match('?').value((r) => true).opt(), - regExp.opt(), - ]).map((r) { - var match = r.value![0] as Match; - - var r2 = r.value![2]; - Match? rgxMatch; - if (r2 != 'NULL') { - rgxMatch = r2 as Match?; - } - - var pre = match[1] ?? ''; - var post = match[3] ?? ''; - RegExp? rgx; - - if (rgxMatch != null) { - rgx = RegExp('(${rgxMatch[1]})'); - post = (rgxMatch[2] ?? '') + post; - } - - if (pre.isNotEmpty || post.isNotEmpty) { - if (rgx != null) { - var pattern = pre + rgx.pattern + post; - rgx = RegExp(pattern); - } else { - rgx = RegExp('$pre$notSlashRgx$post'); - } - } - - // TODO: relook at this later - var m2 = match[2] ?? ''; - var s = ParameterSegment(m2, rgx); - return r.value![1] == true ? OptionalSegment(s) : s; - }); - - static final Parser parsedParameterSegment = chain([ - match(RegExp(r'(int|num|double)'), - errorMessage: 'Expected "int","double", or "num".') - .map((r) => r.span!.text), - parameterSegment, - ]).map((r) { - return ParsedParameterSegment( - r.value![0] as String, r.value![1] as ParameterSegment); - }); - - static final Parser wildcardSegment = - match(RegExp('$notSlashRgx?' r'\*' '$notSlashRgx?')) - .value((r) { - var m = r.scanner.lastMatch!; - var pre = m[1] ?? ''; - var post = m[2] ?? ''; - return WildcardSegment(pre, post); - }); - - static final Parser constantSegment = - notSlash.map((r) => ConstantSegment(r.value)); - - static final Parser slashSegment = - match(SlashSegment.rgx).map((_) => SlashSegment()); - - static final Parser routeSegment = any([ - //slashSegment, - parsedParameterSegment, - parameterSegment, - wildcardSegment, - constantSegment - ]); - - // static final Parser routeDefinition = routeSegment - // .star() - // .map((r) => RouteDefinition(r.value ?? [])) - // .surroundedBy(match(RegExp(r'/*')).opt()); - - static final Parser slashes = match(RegExp(r'/*')); - - static final Parser routeDefinition = routeSegment - .separatedBy(slashes) - .map((r) => RouteDefinition(r.value ?? [])) - .surroundedBy(slashes.opt()); -} - -class RouteDefinition { - final List segments; - - RouteDefinition(this.segments); - - Parser? compile() { - Parser? out; - - for (var i = 0; i < segments.length; i++) { - var s = segments[i]; - var isLast = i == segments.length - 1; - if (out == null) { - out = s.compile(isLast); - } else { - out = s.compileNext( - out.then(match('/')).index(0).cast(), isLast); - } - } - - return out; - } -} - -abstract class RouteSegment { - Parser compile(bool isLast); - - Parser compileNext(Parser p, bool isLast); -} - -class SlashSegment implements RouteSegment { - static final RegExp rgx = RegExp(r'/+'); - - const SlashSegment(); - - @override - Parser compile(bool isLast) { - return match(rgx).map((_) => RouteResult({})); - } - - @override - Parser compileNext(Parser p, bool isLast) { - return p.then(compile(isLast)).index(0).cast(); - } - - @override - String toString() => 'Slash'; -} - -class ConstantSegment extends RouteSegment { - final String? text; - - ConstantSegment(this.text); - - @override - String toString() { - return 'Constant: $text'; - } - - @override - Parser compile(bool isLast) { - return match(text!).map((r) => RouteResult({})); - } - - @override - Parser compileNext(Parser p, bool isLast) { - return p.then(compile(isLast)).index(0).cast(); - } -} - -class WildcardSegment extends RouteSegment { - final String pre, post; - - WildcardSegment(this.pre, this.post); - - @override - String toString() { - return 'Wildcard segment'; - } - - String _symbol(bool isLast) { - if (isLast) return r'.*'; - return r'[^/]*'; - } - - RegExp _compile(bool isLast) { - return RegExp('$pre(${_symbol(isLast)})$post'); - // if (isLast) return match(RegExp(r'.*')); - // return match(RegExp(r'[^/]*')); - } - - @override - Parser compile(bool isLast) { - return match(_compile(isLast)).map((r) { - var result = r.scanner.lastMatch; - if (result != null) { - //return RouteResult({}, tail: r.scanner.lastMatch![1]) - return RouteResult({}, tail: result[1]); - } else { - return RouteResult({}); - } - }); - } - - @override - Parser compileNext(Parser p, bool isLast) { - return p.then(compile(isLast)).map((r) { - var items = r.value!.cast(); - var a = items[0], b = items[1]; - return a - ..addAll(b.params) - .._setTail(b.tail); - }); - } -} - -class OptionalSegment extends ParameterSegment { - final ParameterSegment parameter; - - OptionalSegment(this.parameter) : super(parameter.name, parameter.regExp); - - @override - String toString() { - return 'Optional: $parameter'; - } - - @override - Parser compile(bool isLast) { - return super.compile(isLast).opt(); - } - - @override - Parser compileNext(Parser p, bool isLast) { - return p.then(_compile().opt()).map((r) { - // Return an empty RouteResult if null - if (r.value == null) { - return RouteResult({}); - } - - var v = r.value!; - - if (v[1] == null) { - return v[0] as RouteResult; - } - return (v[0] as RouteResult) - ..addAll({name: Uri.decodeComponent(v as String)}); - }); - } -} - -class ParameterSegment extends RouteSegment { - final String name; - final RegExp? regExp; - - ParameterSegment(this.name, this.regExp); - - @override - String toString() { - if (regExp != null) { - return 'Param: $name (${regExp?.pattern})'; - } - return 'Param: $name'; - } - - Parser _compile() { - if (regExp != null) { - return match(regExp!).value((r) { - var result = r.scanner.lastMatch; - if (result != null) { - // TODO: Invalid method - //return r.scanner.lastMatch![1]; - return result.toString(); - } else { - return ''; - } - }); - } else { - return RouteGrammar.notSlash; - } - } - - @override - Parser compile(bool isLast) { - return _compile() - .map((r) => RouteResult({name: Uri.decodeComponent(r.value!)})); - } - - @override - Parser compileNext(Parser p, bool isLast) { - return p.then(_compile()).map((r) { - return (r.value![0] as RouteResult) - ..addAll({name: Uri.decodeComponent(r.value![1] as String)}); - }); - } -} - -class ParsedParameterSegment extends RouteSegment { - final String type; - final ParameterSegment parameter; - - ParsedParameterSegment(this.type, this.parameter); - - num getValue(String s) { - switch (type) { - case 'int': - return int.parse(s); - case 'double': - return double.parse(s); - default: - return num.parse(s); - } - } - - @override - Parser compile(bool isLast) { - return parameter._compile().map((r) => RouteResult( - {parameter.name: getValue(Uri.decodeComponent(r.span!.text))})); - } - - @override - Parser compileNext(Parser p, bool isLast) { - return p.then(parameter._compile()).map((r) { - return (r.value![0] as RouteResult) - ..addAll({ - parameter.name: getValue(Uri.decodeComponent(r.value![1] as String)) - }); - }); - } -} diff --git a/packages/route/lib/src/middleware_pipeline.dart b/packages/route/lib/src/middleware_pipeline.dart deleted file mode 100644 index 97da1a3..0000000 --- a/packages/route/lib/src/middleware_pipeline.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'router.dart'; - -/// A chain of arbitrary handlers obtained by routing a path. -class MiddlewarePipeline { - /// All the possible routes that matched the given path. - final Iterable> routingResults; - final List _handlers = []; - - /// An ordered list of every handler delegated to handle this request. - List get handlers { - /* - if (_handlers != null) return _handlers; - final handlers = []; - - for (var result in routingResults) { - handlers.addAll(result.allHandlers); - } - - return _handlers = handlers; - - */ - if (_handlers.isNotEmpty) { - return _handlers; - } - - for (var result in routingResults) { - _handlers.addAll(result.allHandlers); - } - - return _handlers; - } - - MiddlewarePipeline(Iterable> routingResults) - : routingResults = routingResults.toList(); -} - -/// Iterates through a [MiddlewarePipeline]. -class MiddlewarePipelineIterator implements Iterator> { - final MiddlewarePipeline pipeline; - final Iterator> _inner; - - MiddlewarePipelineIterator(this.pipeline) - : _inner = pipeline.routingResults.iterator; - - @override - RoutingResult get current => _inner.current; - - @override - bool moveNext() => _inner.moveNext(); -} diff --git a/packages/route/lib/src/route.dart b/packages/route/lib/src/route.dart deleted file mode 100644 index 85baded..0000000 --- a/packages/route/lib/src/route.dart +++ /dev/null @@ -1,99 +0,0 @@ -part of 'router.dart'; - -/// Represents a virtual location within an application. -class Route { - final String method; - final String path; - final Map> _cache = {}; - final RouteDefinition? _routeDefinition; - final List handlers; - String? name; - Parser? _parser; - - Route(this.path, {required this.method, required this.handlers}) - : _routeDefinition = RouteGrammar.routeDefinition - .parse(SpanScanner(path.replaceAll(_straySlashes, ''))) - .value { - if (_routeDefinition?.segments.isNotEmpty != true) { - _parser = match('').map((r) => RouteResult({})); - } - - /* - var result = RouteGrammar.routeDefinition - .parse(SpanScanner(path.replaceAll(_straySlashes, ''))); - - if (result.value != null) { - - //throw ArgumentError('[Route] Failed to create route for $path'); - _routeDefinition = result.value; - if (_routeDefinition.segments.isEmpty) { - _parser = match('').map((r) => RouteResult({})); - } - } else { - _parser = match('').map((r) => RouteResult({})); - } - */ - } - - factory Route.join(Route a, Route b) { - var start = a.path.replaceAll(_straySlashes, ''); - var end = b.path.replaceAll(_straySlashes, ''); - return Route('$start/$end'.replaceAll(_straySlashes, ''), - method: b.method, handlers: b.handlers); - } - - //List get handlers => _handlers; - - Parser? get parser => _parser ??= _routeDefinition?.compile(); - - @override - String toString() { - return '$method $path => $handlers'; - } - - Route clone() { - return Route(path, method: method, handlers: handlers) - .._cache.addAll(_cache); - } - - String makeUri(Map params) { - var b = StringBuffer(); - var i = 0; - - if (_routeDefinition != null) { - for (var seg in _routeDefinition.segments) { - if (i++ > 0) b.write('/'); - if (seg is ConstantSegment) { - b.write(seg.text); - } else if (seg is ParameterSegment) { - if (!params.containsKey(seg.name)) { - throw ArgumentError('Missing parameter "${seg.name}".'); - } - b.write(params[seg.name]); - } - } - } - - return b.toString(); - } -} - -/// The result of matching an individual route. -class RouteResult { - /// The parsed route parameters. - final Map params; - - /// Optional. An explicit "tail" value to set. - String? get tail => _tail; - - String? _tail; - - RouteResult(this.params, {String? tail}) : _tail = tail; - - void _setTail(String? v) => _tail ??= v; - - /// Adds parameters. - void addAll(Map map) { - params.addAll(map); - } -} diff --git a/packages/route/lib/src/router.dart b/packages/route/lib/src/router.dart deleted file mode 100644 index 8585b10..0000000 --- a/packages/route/lib/src/router.dart +++ /dev/null @@ -1,493 +0,0 @@ -library platform_route.src.router; - -import 'dart:async'; -import 'package:belatuk_combinator/belatuk_combinator.dart'; -import 'package:string_scanner/string_scanner.dart'; - -import '../string_util.dart'; -import 'routing_exception.dart'; -part 'grammar.dart'; -part 'route.dart'; -part 'routing_result.dart'; -part 'symlink_route.dart'; - -//final RegExp _param = RegExp(r':([A-Za-z0-9_]+)(\((.+)\))?'); -//final RegExp _rgxEnd = RegExp(r'\$+$'); -//final RegExp _rgxStart = RegExp(r'^\^+'); -//final RegExp _rgxStraySlashes = -// RegExp(r'(^((\\+/)|(/))+)|(((\\+/)|(/))+$)'); -//final RegExp _slashDollar = RegExp(r'/+\$'); -final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)'); - -/// An abstraction over complex [Route] trees. Use this instead of the raw API. :) -class Router { - final Map>> _cache = {}; - - //final List<_ChainedRouter> _chained = []; - final List _middleware = []; - final Map> _mounted = {}; - final List> _routes = []; - bool _useCache = false; - - List get middleware => List.unmodifiable(_middleware); - - Map> get mounted => - Map>.unmodifiable(_mounted); - - List> get routes { - return _routes.fold>>([], (out, route) { - if (route is SymlinkRoute) { - var childRoutes = - route.router.routes.fold>>([], (out, r) { - return out - ..add( - route.path.isEmpty ? r : Route.join(route, r), - ); - }); - - return out..addAll(childRoutes); - } else { - return out..add(route); - } - }); - } - - /// Provide a `root` to make this Router revolve around a pre-defined route. - /// Not recommended. - Router(); - - /// Enables the use of a cache to eliminate the overhead of consecutive resolutions of the same path. - void enableCache() { - _useCache = true; - } - - /// Adds a route that responds to the given path - /// for requests with the given method (case-insensitive). - /// Provide '*' as the method to respond to all methods. - Route addRoute(String method, String path, T handler, - {Iterable middleware = const []}) { - if (_useCache == true) { - throw StateError('Cannot add routes after caching is enabled.'); - } - - // Check if any mounted routers can match this - final handlers = [handler]; - - //middleware ??= []; - - handlers.insertAll(0, middleware); - - final route = Route(path, method: method, handlers: handlers); - _routes.add(route); - return route; - } - - /// Prepends the given [middleware] to any routes created - /// by the resulting router. - /// - /// The resulting router can be chained, too. - ChainedRouter chain(Iterable middleware) { - var piped = ChainedRouter(this, middleware); - var route = SymlinkRoute('/', piped); - _routes.add(route); - return piped; - } - - /// Returns a [Router] with a duplicated version of this tree. - Router clone() { - final router = Router(); - final newMounted = Map>.from(mounted); - - for (var route in routes) { - if (route is! SymlinkRoute) { - router._routes.add(route.clone()); - } else { - final newRouter = route.router.clone(); - newMounted[route.path] = newRouter; - final symlink = SymlinkRoute(route.path, newRouter); - router._routes.add(symlink); - } - } - - return router.._mounted.addAll(newMounted); - } - - /// Creates a visual representation of the route hierarchy and - /// passes it to a callback. If none is provided, `print` is called. - void dumpTree( - {Function(String tree)? callback, - String header = 'Dumping route tree:', - String tab = ' '}) { - final buf = StringBuffer(); - var tabs = 0; - - if (header.isNotEmpty) { - buf.writeln(header); - } - - buf.writeln(''); - - void indent() { - for (var i = 0; i < tabs; i++) { - buf.write(tab); - } - } - - void dumpRouter(Router router) { - indent(); - tabs++; - - for (var route in router.routes) { - indent(); - buf.write('- '); - if (route is! SymlinkRoute) buf.write('${route.method} '); - buf.write(route.path.isNotEmpty ? route.path : '/'); - - if (route is SymlinkRoute) { - buf.writeln(); - dumpRouter(route.router); - } else { - buf.writeln(' => ${route.handlers.length} handler(s)'); - } - } - - tabs--; - } - - dumpRouter(this); - - (callback ?? print)(buf.toString()); - } - - /// Creates a route, and allows you to add child routes to it - /// via a [Router] instance. - /// - /// Returns the created route. - /// You can also register middleware within the router. - SymlinkRoute group(String path, void Function(Router router) callback, - {Iterable middleware = const [], String name = ''}) { - final router = Router().._middleware.addAll(middleware); - callback(router); - return mount(path, router)..name = name; - } - - /// Asynchronous equivalent of [group]. - Future> groupAsync( - String path, FutureOr Function(Router router) callback, - {Iterable middleware = const [], String name = ''}) async { - final router = Router().._middleware.addAll(middleware); - await callback(router); - return mount(path, router)..name = name; - } - - /// Generates a URI string based on the given input. - /// Handy when you have named routes. - /// - /// Each item in `linkParams` should be a [Route], - /// `String` or `Map`. - /// - /// Strings should be route names, namespaces, or paths. - /// Maps should be parameters, which will be filled - /// into the previous route. - /// - /// Paths and segments should correspond to the way - /// you declared them. - /// - /// For example, if you declared a route group on - /// `'users/:id'`, it would not be resolved if you - /// passed `'users'` in [linkParams]. - /// - /// Leading and trailing slashes are automatically - /// removed. - /// - /// Set [absolute] to `true` to insert a forward slash - /// before the generated path. - /// - /// Example: - /// ```dart - /// router.navigate(['users/:id', {'id': '1337'}, 'profile']); - /// ``` - String navigate(Iterable linkParams, {bool absolute = true}) { - final segments = []; - Router search = this; - Route? lastRoute; - - for (final param in linkParams) { - var resolved = false; - - if (param is String) { - // Search by name - for (var route in search.routes) { - if (route.name == param) { - segments.add(route.path.replaceAll(_straySlashes, '')); - lastRoute = route; - - if (route is SymlinkRoute) { - search = route.router; - } - - resolved = true; - break; - } - } - - // Search by path - if (!resolved) { - var scanner = SpanScanner(param.replaceAll(_straySlashes, '')); - for (var route in search.routes) { - var pos = scanner.position; - var parseResult = route.parser?.parse(scanner); - if (parseResult != null) { - if (parseResult.successful && scanner.isDone) { - segments.add(route.path.replaceAll(_straySlashes, '')); - lastRoute = route; - - if (route is SymlinkRoute) { - search = route.router; - } - - resolved = true; - break; - } else { - scanner.position = pos; - } - } else { - scanner.position = pos; - } - } - } - - if (!resolved) { - throw RoutingException( - 'Cannot resolve route for link param "$param".'); - } - } else if (param is Route) { - segments.add(param.path.replaceAll(_straySlashes, '')); - } else if (param is Map) { - if (lastRoute == null) { - throw RoutingException( - 'Maps in link params must be preceded by a Route or String.'); - } else { - segments.removeLast(); - segments.add(lastRoute.makeUri(param).replaceAll(_straySlashes, '')); - } - } else { - throw RoutingException( - 'Link param $param is not Route, String, or Map.'); - } - } - - return absolute - ? '/${segments.join('/').replaceAll(_straySlashes, '')}' - : segments.join('/'); - } - - /// Finds the first [Route] that matches the given path, - /// with the given method. - bool resolve(String absolute, String relative, List> out, - {String method = 'GET', bool strip = true}) { - final cleanRelative = - strip == false ? relative : stripStraySlashes(relative); - var scanner = SpanScanner(cleanRelative); - - bool crawl(Router r) { - var success = false; - - for (var route in r.routes) { - var pos = scanner.position; - - if (route is SymlinkRoute) { - if (route.parser != null) { - var pp = route.parser!; - if (pp.parse(scanner).successful) { - var s = crawl(route.router); - if (s) success = true; - } - } - - scanner.position = pos; - } else if (route.method == '*' || route.method == method) { - var parseResult = route.parser?.parse(scanner); - if (parseResult != null) { - if (parseResult.successful && scanner.isDone) { - var tailResult = parseResult.value?.tail ?? ''; - //print(tailResult); - var result = RoutingResult( - parseResult: parseResult, - params: parseResult.value!.params, - shallowRoute: route, - shallowRouter: this, - tail: tailResult + scanner.rest); - out.add(result); - success = true; - } - } - scanner.position = pos; - } - } - - return success; - } - - return crawl(this); - } - - /// Returns the result of [resolve] with [path] passed as - /// both `absolute` and `relative`. - Iterable> resolveAbsolute(String path, - {String method = 'GET', bool strip = true}) => - resolveAll(path, path, method: method, strip: strip); - - /// Finds every possible [Route] that matches the given path, - /// with the given method. - Iterable> resolveAll(String absolute, String relative, - {String method = 'GET', bool strip = true}) { - if (_useCache == true) { - return _cache.putIfAbsent('$method$absolute', - () => _resolveAll(absolute, relative, method: method, strip: strip)); - } - - return _resolveAll(absolute, relative, method: method, strip: strip); - } - - Iterable> _resolveAll(String absolute, String relative, - {String method = 'GET', bool strip = true}) { - var results = >[]; - resolve(absolute, relative, results, method: method, strip: strip); - - // _printDebug( - // 'Results of $method "/${absolute.replaceAll(_straySlashes, '')}": ${results.map((r) => r.route).toList()}'); - return results; - } - - /// Incorporates another [Router]'s routes into this one's. - SymlinkRoute mount(String path, Router router) { - final route = SymlinkRoute(path, router); - _mounted[route.path] = router; - _routes.add(route); - //route._head = RegExp(route.matcher.pattern.replaceAll(_rgxEnd, '')); - - return route; - } - - /// Adds a route that responds to any request matching the given path. - Route all(String path, T handler, {Iterable middleware = const []}) { - return addRoute('*', path, handler, middleware: middleware); - } - - /// Adds a route that responds to a DELETE request. - Route delete(String path, T handler, {Iterable middleware = const []}) { - return addRoute('DELETE', path, handler, middleware: middleware); - } - - /// Adds a route that responds to a GET request. - Route get(String path, T handler, {Iterable middleware = const []}) { - return addRoute('GET', path, handler, middleware: middleware); - } - - /// Adds a route that responds to a HEAD request. - Route head(String path, T handler, {Iterable middleware = const []}) { - return addRoute('HEAD', path, handler, middleware: middleware); - } - - /// Adds a route that responds to a OPTIONS request. - Route options(String path, T handler, - {Iterable middleware = const {}}) { - return addRoute('OPTIONS', path, handler, middleware: middleware); - } - - /// Adds a route that responds to a POST request. - Route post(String path, T handler, {Iterable middleware = const []}) { - return addRoute('POST', path, handler, middleware: middleware); - } - - /// Adds a route that responds to a PATCH request. - Route patch(String path, T handler, {Iterable middleware = const []}) { - return addRoute('PATCH', path, handler, middleware: middleware); - } - - /// Adds a route that responds to a PUT request. - Route put(String path, T handler, {Iterable middleware = const []}) { - return addRoute('PUT', path, handler, middleware: middleware); - } -} - -class ChainedRouter extends Router { - final List _handlers = []; - Router _root; - - ChainedRouter.empty() : _root = Router(); - - ChainedRouter(this._root, Iterable middleware) { - _handlers.addAll(middleware); - } - - @override - Route addRoute(String method, String path, handler, - {Iterable middleware = const []}) { - var route = super.addRoute(method, path, handler, - middleware: [..._handlers, ...middleware]); - //_root._routes.add(route); - return route; - } - - @override - SymlinkRoute group(String path, void Function(Router router) callback, - {Iterable middleware = const [], String? name}) { - final router = ChainedRouter(_root, [..._handlers, ...middleware]); - callback(router); - return mount(path, router)..name = name; - } - - @override - Future> groupAsync( - String path, FutureOr Function(Router router) callback, - {Iterable middleware = const [], String? name}) async { - final router = ChainedRouter(_root, [..._handlers, ...middleware]); - await callback(router); - return mount(path, router)..name = name; - } - - @override - SymlinkRoute mount(String path, Router router) { - final route = super.mount(path, router); - route.router._middleware.insertAll(0, _handlers); - //_root._routes.add(route); - return route; - } - - @override - ChainedRouter chain(Iterable middleware) { - final piped = ChainedRouter.empty().._root = _root; - piped._handlers.addAll([..._handlers, ...middleware]); - var route = SymlinkRoute('/', piped); - _routes.add(route); - return piped; - } -} - -/// Optimizes a router by condensing all its routes into one level. -Router flatten(Router router) { - var flattened = Router(); - - for (var route in router.routes) { - if (route is SymlinkRoute) { - var base = route.path.replaceAll(_straySlashes, ''); - var child = flatten(route.router); - - for (var route in child.routes) { - var path = route.path.replaceAll(_straySlashes, ''); - var joined = '$base/$path'.replaceAll(_straySlashes, ''); - flattened.addRoute(route.method, joined.replaceAll(_straySlashes, ''), - route.handlers.last, - middleware: - route.handlers.take(route.handlers.length - 1).toList()); - } - } else { - flattened.addRoute(route.method, route.path, route.handlers.last, - middleware: route.handlers.take(route.handlers.length - 1).toList()); - } - } - - return flattened..enableCache(); -} diff --git a/packages/route/lib/src/routing_exception.dart b/packages/route/lib/src/routing_exception.dart deleted file mode 100644 index 4dd9b75..0000000 --- a/packages/route/lib/src/routing_exception.dart +++ /dev/null @@ -1,21 +0,0 @@ -/// Represents an error in route configuration or navigation. -abstract class RoutingException implements Exception { - factory RoutingException(String message) => _RoutingExceptionImpl(message); - - /// Occurs when trying to resolve the parent of a [Route] without a parent. - factory RoutingException.orphan() => _RoutingExceptionImpl( - "Tried to resolve path '..' on a route that has no parent."); - - /// Occurs when the user attempts to navigate to a non-existent route. - factory RoutingException.noSuchRoute(String path) => _RoutingExceptionImpl( - "Tried to navigate to non-existent route: '$path'."); -} - -class _RoutingExceptionImpl implements RoutingException { - final String message; - - _RoutingExceptionImpl(this.message); - - @override - String toString() => message; -} diff --git a/packages/route/lib/src/routing_result.dart b/packages/route/lib/src/routing_result.dart deleted file mode 100644 index 50edfea..0000000 --- a/packages/route/lib/src/routing_result.dart +++ /dev/null @@ -1,95 +0,0 @@ -part of 'router.dart'; - -/// Represents a complex result of navigating to a path. -class RoutingResult { - /// The parse result that matched the given sub-path. - final ParseResult parseResult; - - /// A nested instance, if a sub-path was matched. - final Iterable> nested; - - /// All route params matching this route on the current sub-path. - final Map params = {}; - - /// The [Route] that answered this sub-path. - /// - /// This is mostly for internal use, and useless in production. - final Route shallowRoute; - - /// The [Router] that answered this sub-path. - /// - /// Only really for internal use. - final Router shallowRouter; - - /// The remainder of the full path that was not matched, and was passed to [nested] routes. - final String tail; - - /// The [RoutingResult] that matched the most specific sub-path. - RoutingResult get deepest { - var search = this; - - while (search.nested.isNotEmpty == true) { - search = search.nested.first; - } - - return search; - } - - /// The most specific route. - Route get route => deepest.shallowRoute; - - /// The most specific router. - Router get router => deepest.shallowRouter; - - /// The handlers at this sub-path. - List get handlers { - return [...shallowRouter.middleware, ...shallowRoute.handlers]; - } - - /// All handlers on this sub-path and its children. - List get allHandlers { - final handlers = []; - - void crawl(RoutingResult result) { - handlers.addAll(result.handlers); - - if (result.nested.isNotEmpty == true) { - for (var r in result.nested) { - crawl(r); - } - } - } - - crawl(this); - - return handlers; - } - - /// All parameters on this sub-path and its children. - Map get allParams { - final params = {}; - - void crawl(RoutingResult result) { - params.addAll(result.params); - - if (result.nested.isNotEmpty == true) { - for (var r in result.nested) { - crawl(r); - } - } - } - - crawl(this); - return params; - } - - RoutingResult( - {required this.parseResult, - Map params = const {}, - this.nested = const Iterable.empty(), - required this.shallowRoute, - required this.shallowRouter, - required this.tail}) { - this.params.addAll(params); - } -} diff --git a/packages/route/lib/src/symlink_route.dart b/packages/route/lib/src/symlink_route.dart deleted file mode 100644 index cf46966..0000000 --- a/packages/route/lib/src/symlink_route.dart +++ /dev/null @@ -1,8 +0,0 @@ -part of 'router.dart'; - -/// Placeholder [Route] to serve as a symbolic link -/// to a mounted [Router]. -class SymlinkRoute extends Route { - final Router router; - SymlinkRoute(super.path, this.router) : super(method: 'GET', handlers: []); -} diff --git a/packages/route/lib/string_util.dart b/packages/route/lib/string_util.dart deleted file mode 100644 index d8eb228..0000000 --- a/packages/route/lib/string_util.dart +++ /dev/null @@ -1,43 +0,0 @@ -/// Helper functions to performantly transform strings, without `RegExp`. -library angel3_route.string_util; - -/// Removes leading and trailing occurrences of a pattern from a string. -String stripStray(String haystack, String needle) { - int firstSlash; - - if (haystack.startsWith(needle)) { - firstSlash = haystack.indexOf(needle); - if (firstSlash == -1) return haystack; - } else { - firstSlash = -1; - } - - if (firstSlash == haystack.length - 1) { - return haystack.length == 1 ? '' : haystack.substring(0, firstSlash); - } - - // Find last leading index of slash - for (var i = firstSlash + 1; i < haystack.length; i++) { - if (haystack[i] != needle) { - var sub = haystack.substring(i); - - if (!sub.endsWith(needle)) return sub; - - var lastSlash = sub.lastIndexOf(needle); - - for (var j = lastSlash - 1; j >= 0; j--) { - if (sub[j] != needle) { - return sub.substring(0, j + 1); - } - } - - return lastSlash == -1 ? sub : sub.substring(0, lastSlash); - } - } - - return haystack.substring(0, firstSlash); -} - -String stripStraySlashes(String str) => stripStray(str, '/'); - -String stripRegexStraySlashes(String str) => stripStray(str, '\\/'); diff --git a/packages/route/pubspec.yaml b/packages/route/pubspec.yaml deleted file mode 100644 index f066f8e..0000000 --- a/packages/route/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: platform_route -version: 9.0.0 -description: A powerful, isomorphic routing library for Dart. It is mainly used in the Protevus Platform, but can be used in Flutter and on the Web. -homepage: https://protevus.com -documentation: https://docs.protevus.com -repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/route -environment: - sdk: '>=3.3.0 <4.0.0' -dependencies: - belatuk_combinator: ^5.2.0 - string_scanner: ^1.4.0 - path: ^1.9.1 -dev_dependencies: - build_runner: ^2.4.13 - build_web_compilers: ^4.0.11 - http: ^1.2.2 - test: ^1.25.8 - lints: ^4.0.0 diff --git a/packages/route/repubspec.yaml b/packages/route/repubspec.yaml deleted file mode 100644 index 958364f..0000000 --- a/packages/route/repubspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -push_state: - base: push_state/basic.html \ No newline at end of file diff --git a/packages/route/test/chain_nest_test.dart b/packages/route/test/chain_nest_test.dart deleted file mode 100644 index c136cb4..0000000 --- a/packages/route/test/chain_nest_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:platform_route/route.dart'; -import 'package:test/test.dart'; - -void main() { - var router = Router() - ..chain(['a']).group('/b', (router) { - router.chain(['c']).chain(['d']).group('/e', (router) { - router.get('f', 'g'); - }); - }) - ..dumpTree(); - - test('nested route groups with chain', () { - var r = router.resolveAbsolute('/b/e/f').first.route; - expect(r, isNotNull); - expect(r.handlers, hasLength(4)); - expect(r.handlers, equals(['a', 'c', 'd', 'g'])); - }); -} diff --git a/packages/route/test/navigate_test.dart b/packages/route/test/navigate_test.dart deleted file mode 100644 index e9bfe45..0000000 --- a/packages/route/test/navigate_test.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:platform_route/route.dart'; -import 'package:test/test.dart'; - -void main() { - final router = Router(); - - router.get('/', 'GET').name = 'root'; - router.get('/user/:id', 'GET'); - router.get('/first/:first/last/:last', 'GET').name = 'full_name'; - - String navigate(params) { - final uri = router.navigate(params as Iterable); - print('Uri: $uri'); - return uri; - } - - router.dumpTree(); - - group('top-level', () { - test('named', () { - expect(navigate(['root']), equals('/')); - }); - - test('params', () { - expect( - navigate([ - 'user/:id', - {'id': 1337} - ]), - equals('/user/1337')); - - expect( - navigate([ - 'full_name', - {'first': 'John', 'last': 'Smith'} - ]), - equals('/first/John/last/Smith')); - }); - - test('root', () { - expect(navigate(['/']), equals('/')); - }); - }); -} diff --git a/packages/route/test/params_test.dart b/packages/route/test/params_test.dart deleted file mode 100644 index cc0f111..0000000 --- a/packages/route/test/params_test.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:platform_route/route.dart'; -import 'package:test/test.dart'; - -void main() { - final router = Router() - ..get('/hello', '') - ..get('/user/:id', ''); - - router.group('/book/:id', (router) { - router.get('/reviews', ''); - router.get('/readers/:readerId', ''); - }); - - router.mount('/color', Router()..get('/:name/shades', '')); - - setUp(router.dumpTree); - - void expectParams(String path, Map params) { - final p = {}; - final resolved = router.resolveAll(path, path); - print('Resolved $path => ${resolved.map((r) => r.allParams).toList()}'); - for (final result in resolved) { - p.addAll(result.allParams); - } - expect(p, equals(params)); - } - - group('top-level', () { - test('no params', () => expectParams('/hello', {})); - - test('one param', () => expectParams('/user/0', {'id': '0'})); - }); - - group('group', () { - //test('root', () => expectParams('/book/1337', {'id': '1337'})); - test('path', () => expectParams('/book/1337/reviews', {'id': '1337'})); - test( - 'two params', - () => expectParams( - '/book/1337/readers/foo', {'id': '1337', 'readerId': 'foo'})); - }); - - test('mount', - () => expectParams('/color/chartreuse/shades', {'name': 'chartreuse'})); -} diff --git a/packages/route/test/parse_test.dart b/packages/route/test/parse_test.dart deleted file mode 100644 index c691697..0000000 --- a/packages/route/test/parse_test.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:platform_route/route.dart'; -import 'package:test/test.dart'; - -void main() { - var router = Router() - ..get('/int/int:id', '') - ..get('/double/double:id', '') - ..get('/num/num:id', ''); - - num? getId(String path) { - var result = router.resolveAbsolute(path).first; - return result.allParams['id'] as num?; - } - - test('parse', () { - expect(getId('/int/2'), 2); - expect(getId('/double/2.0'), 2.0); - expect(getId('/num/-2.4'), -2.4); - }); -} diff --git a/packages/route/test/root_test.dart b/packages/route/test/root_test.dart deleted file mode 100644 index 651e0e1..0000000 --- a/packages/route/test/root_test.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:platform_route/route.dart'; -import 'package:test/test.dart'; - -void main() { - test('resolve / on /', () { - var router = Router() - ..group('/', (router) { - router.group('/', (router) { - router.get('/', 'ok'); - }); - }); - - expect(router.resolveAbsolute('/'), isNotNull); - }); -} diff --git a/packages/route/test/server_test.dart b/packages/route/test/server_test.dart deleted file mode 100644 index 0aaa66f..0000000 --- a/packages/route/test/server_test.dart +++ /dev/null @@ -1,205 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:platform_route/route.dart'; -import 'package:http/http.dart' as http; -import 'package:test/test.dart'; - -const List> people = [ - {'name': 'John Smith'} -]; - -void main() { - http.Client? client; - - final router = Router(); - late HttpServer server; - String? url; - - router.get('/', (req, res) { - res.write('Root'); - return false; - }); - - router.get('/hello', (req, res) { - res.write('World'); - return false; - }); - - router.group('/people', (router) { - router.get('/', (req, res) { - res.write(json.encode(people)); - return false; - }); - - router.group('/:id', (router) { - router.get('/', (req, res) { - // In a real application, we would take the param, - // but not here... - res.write(json.encode(people.first)); - return false; - }); - - router.get('/name', (req, res) { - // In a real application, we would take the param, - // but not here... - res.write(json.encode(people.first['name'])); - return false; - }); - }); - }); - - final beatles = Router(); - - beatles.post('/spinal_clacker', (req, res) { - res.write('come '); - return true; - }); - - final yellow = Router() - ..get('/submarine', (req, res) { - res.write('we all live in a'); - return false; - }); - - beatles.group('/big', (router) { - router.mount('/yellow', yellow); - }); - - beatles.all('*', (req, res) { - res.write('together'); - return false; - }); - - router.mount('/beatles', beatles); - - setUp(() async { - client = http.Client(); - - router.dumpTree(); - server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0); - url = 'http://${server.address.address}:${server.port}'; - - server.listen((req) async { - final res = req.response; - - // Easy middleware pipeline - final results = - router.resolveAbsolute(req.uri.toString(), method: req.method); - final pipeline = MiddlewarePipeline(results); - - if (pipeline.handlers.isEmpty) { - res - ..statusCode = 404 - ..writeln('404 Not Found'); - } else { - for (final handler in pipeline.handlers) { - if (!((await handler(req, res)) as bool)) break; - } - } - - await res.close(); - }); - }); - - tearDown(() async { - await server.close(force: true); - client!.close(); - client = null; - url = null; - }); - - group('top-level', () { - group('get', () { - test('root', () async { - final res = await client!.get(Uri.parse(url!)); - print('Response: ${res.body}'); - expect(res.body, equals('Root')); - }); - - test('path', () async { - final res = await client!.get(Uri.parse('$url/hello')); - print('Response: ${res.body}'); - expect(res.body, equals('World')); - }); - }); - }); - - group('group', () { - group('top-level', () { - test('root', () async { - final res = await client!.get(Uri.parse('$url/people')); - print('Response: ${res.body}'); - expect(json.decode(res.body), equals(people)); - }); - - group('param', () { - test('root', () async { - final res = await client!.get(Uri.parse('$url/people/0')); - print('Response: ${res.body}'); - expect(json.decode(res.body), equals(people.first)); - }); - - test('path', () async { - final res = await client!.get(Uri.parse('$url/people/0/name')); - print('Response: ${res.body}'); - expect(json.decode(res.body), equals(people.first['name'])); - }); - }); - }); - }); - - group('mount', () { - group('path', () { - test('top-level', () async { - final res = - await client!.post(Uri.parse('$url/beatles/spinal_clacker')); - print('Response: ${res.body}'); - expect(res.body, equals('come together')); - }); - - test('fallback', () async { - final res = await client!.patch(Uri.parse('$url/beatles/muddy_water')); - print('Response: ${res.body}'); - expect(res.body, equals('together')); - }); - - test('fallback', () async { - final res = - await client!.patch(Uri.parse('$url/beatles/spanil_clakcer')); - print('Response: ${res.body}'); - expect(res.body, equals('together')); - }); - }); - - test('deep nested', () async { - final res = - await client!.get(Uri.parse('$url/beatles/big/yellow/submarine')); - print('Response: ${res.body}'); - expect(res.body, equals('we all live in a')); - }); - - group('fallback', () {}); - }); - - group('404', () { - dynamic expect404(r) => r.then((res) { - print('Response (${res.statusCode}): ${res.body}'); - expect(res.statusCode, equals(404)); - }); - - test('path', () async { - await expect404(client!.get(Uri.parse('$url/foo'))); - await expect404(client!.get(Uri.parse('$url/bye'))); - await expect404(client!.get(Uri.parse('$url/people/0/age'))); - await expect404(client!.get(Uri.parse('$url/beatles2'))); - }); - - test('method', () async { - await expect404(client!.head(Uri.parse(url!))); - await expect404(client!.patch(Uri.parse('$url/people'))); - await expect404(client!.post(Uri.parse('$url/people/0'))); - await expect404( - client!.delete(Uri.parse('$url/beatles2/spinal_clacker'))); - }); - }); -} diff --git a/packages/route/test/strip_test.dart b/packages/route/test/strip_test.dart deleted file mode 100644 index 42d636c..0000000 --- a/packages/route/test/strip_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:platform_route/string_util.dart'; -import 'package:test/test.dart'; - -void main() { - test('strip leading', () { - var a = '///a'; - var b = stripStraySlashes(a); - print('$a => $b'); - expect(b, 'a'); - }); - - test('strip trailing', () { - var a = 'a///'; - var b = stripStraySlashes(a); - print('$a => $b'); - expect(b, 'a'); - }); - - test('strip both', () { - var a = '///a///'; - var b = stripStraySlashes(a); - print('$a => $b'); - expect(b, 'a'); - }); - - test('intermediate slashes preserved', () { - var a = '///a///b//'; - var b = stripStraySlashes(a); - print('$a => $b'); - expect(b, 'a///b'); - }); - - test('only if starts with', () { - var a = 'd///a///b//'; - var b = stripStraySlashes(a); - print('$a => $b'); - expect(b, 'd///a///b'); - }); - - test('only if ends with', () { - var a = '///a///b//c'; - var b = stripStraySlashes(a); - print('$a => $b'); - expect(b, 'a///b//c'); - }); -} diff --git a/packages/route/test/uri_decode_test.dart b/packages/route/test/uri_decode_test.dart deleted file mode 100644 index c3d543d..0000000 --- a/packages/route/test/uri_decode_test.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:platform_route/route.dart'; -import 'package:test/test.dart'; - -void main() { - test('uri params decoded', () { - var router = Router()..get('/a/:a/b/:b', ''); - - var encoded = - '/a/${Uri.encodeComponent('<<<')}/b/${Uri.encodeComponent('???')}'; - print(encoded); - var result = router.resolveAbsolute(encoded).first; - print(result.allParams); - expect(result.allParams, { - 'a': '<<<', - 'b': '???', - }); - }); -} diff --git a/packages/route/test/wildcard_test.dart b/packages/route/test/wildcard_test.dart deleted file mode 100644 index 862e37b..0000000 --- a/packages/route/test/wildcard_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:platform_route/route.dart'; -import 'package:test/test.dart'; - -void main() { - var router = Router(); - router.get('/songs/*/key', 'of life'); - router.get('/isnt/she/*', 'lovely'); - router.all('*', 'stevie'); - - test('match until end if * is last', () { - var result = router.resolveAbsolute('/wonder').first; - expect(result.handlers, ['stevie']); - }); - - test('match if not last', () { - var result = router.resolveAbsolute('/songs/what/key').first; - expect(result.handlers, ['of life']); - }); - - test('match if segments before', () { - var result = - router.resolveAbsolute('/isnt/she/fierce%20harmonica%solo').first; - expect(result.handlers, ['lovely']); - }); - - test('tail explicitly set intermediate', () { - var results = router.resolveAbsolute('/songs/in_the/key'); - var result = results.first; - print(results.map((r) => {r.route.path: r.tail})); - expect(result.tail, 'in_the'); - }); - - test('tail explicitly set at end', () { - var results = router.resolveAbsolute('/isnt/she/epic'); - var result = results.first; - print(results.map((r) => {r.route.path: r.tail})); - expect(result.tail, 'epic'); - }); - - test('tail with trailing', () { - var results = router.resolveAbsolute('/isnt/she/epic/fail'); - var result = results.first; - print(results.map((r) => {r.route.path: r.tail})); - expect(result.tail, 'epic/fail'); - }); -} diff --git a/packages/route/web/hash/basic.dart b/packages/route/web/hash/basic.dart deleted file mode 100644 index 39e4eb4..0000000 --- a/packages/route/web/hash/basic.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:platform_route/browser.dart'; -import '../shared/basic.dart'; - -void main() => basic(BrowserRouter(hash: true)); diff --git a/packages/route/web/hash/basic.html b/packages/route/web/hash/basic.html deleted file mode 100644 index ea7fbaf..0000000 --- a/packages/route/web/hash/basic.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - Hash Router - - - - -

    No Active Route

    -Handler Sequence: -
      -
    • (empty)
    • -
    - - - \ No newline at end of file diff --git a/packages/route/web/index.html b/packages/route/web/index.html deleted file mode 100644 index aab2766..0000000 --- a/packages/route/web/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - Protevus Route Samples - - -

    Protevus Route Samples

    - - - \ No newline at end of file diff --git a/packages/route/web/push_state/basic.dart b/packages/route/web/push_state/basic.dart deleted file mode 100644 index 06483ca..0000000 --- a/packages/route/web/push_state/basic.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:platform_route/browser.dart'; -import '../shared/basic.dart'; - -void main() => basic(BrowserRouter()); diff --git a/packages/route/web/push_state/basic.html b/packages/route/web/push_state/basic.html deleted file mode 100644 index 953bc5a..0000000 --- a/packages/route/web/push_state/basic.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - Push State Router - - - - -

    No Active Route

    -Handler Sequence: -
      -
    • (empty)
    • -
    - - - \ No newline at end of file diff --git a/packages/route/web/shared/basic.dart b/packages/route/web/shared/basic.dart deleted file mode 100644 index a64ee1d..0000000 --- a/packages/route/web/shared/basic.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'dart:html'; -import 'package:platform_route/browser.dart'; - -void basic(BrowserRouter router) { - final $h1 = window.document.querySelector('h1'); - final $ul = window.document.getElementById('handlers'); - - router.onResolve.listen((result) { - final route = result.route; - - // TODO: Relook at this logic - //if (route == null) { - // $h1!.text = 'No Active Route'; - // $ul!.children - // ..clear() - // ..add(LIElement()..text = '(empty)'); - //} else { - if ($h1 != null && $ul != null) { - $h1.text = 'Active Route: ${route.name}'; - $ul.children - ..clear() - ..addAll(result.allHandlers - .map((handler) => LIElement()..text = handler.toString())); - } else { - print('No active Route'); - } - //} - }); - - router.get('a', 'a handler'); - - router.group('b', (router) { - router.get('a', 'b/a handler').name = 'b/a'; - router.get('b', 'b/b handler', middleware: ['b/b middleware']).name = 'b/b'; - }, middleware: ['b middleware']); - - router.get('c', 'c handler'); - - router - ..dumpTree() - ..listen(); -} diff --git a/packages/routing/.gitignore b/packages/routing/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/routing/.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/routing/CHANGELOG.md b/packages/routing/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/routing/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/routing/LICENSE.md b/packages/routing/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/routing/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/routing/README.md b/packages/routing/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/routing/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/routing/analysis_options.yaml b/packages/routing/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/routing/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/routing/doc/.gitkeep b/packages/routing/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/routing/example/.gitkeep b/packages/routing/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/routing/lib/src/.gitkeep b/packages/routing/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/routing/pubspec.yaml b/packages/routing/pubspec.yaml new file mode 100644 index 0000000..212ea20 --- /dev/null +++ b/packages/routing/pubspec.yaml @@ -0,0 +1,17 @@ +name: platform_routing +description: The Routing 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: + # path: ^1.8.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/routing/test/.gitkeep b/packages/routing/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/session/.gitignore b/packages/session/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/session/.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/session/CHANGELOG.md b/packages/session/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/session/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/session/LICENSE.md b/packages/session/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/session/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/session/README.md b/packages/session/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/session/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/session/analysis_options.yaml b/packages/session/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/session/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/session/doc/.gitkeep b/packages/session/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/session/example/.gitkeep b/packages/session/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/session/lib/src/.gitkeep b/packages/session/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/session/pubspec.yaml b/packages/session/pubspec.yaml new file mode 100644 index 0000000..19cb6c5 --- /dev/null +++ b/packages/session/pubspec.yaml @@ -0,0 +1,17 @@ +name: platform_session +description: The Session 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: + # path: ^1.8.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/session/test/.gitkeep b/packages/session/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/support/LICENSE.md b/packages/support/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/support/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/support/README.md b/packages/support/README.md index 8831761..8b55e73 100644 --- a/packages/support/README.md +++ b/packages/support/README.md @@ -3,12 +3,12 @@ This README describes the package. If you publish this package to pub.dev, this README's contents appear on the landing page for your package. For information about how to write a good package README, see the guide for -[writing package pages](https://dart.dev/tools/pub/writing-package-pages). +[writing package pages](https://dart.dev/guides/libraries/writing-package-pages). For general information about developing packages, see the Dart guide for -[creating packages](https://dart.dev/guides/libraries/create-packages) +[creating packages](https://dart.dev/guides/libraries/create-library-packages) and the Flutter guide for -[developing packages and plugins](https://flutter.dev/to/develop-packages). +[developing packages and plugins](https://flutter.dev/developing-packages). --> TODO: Put a short description of the package here that helps potential users diff --git a/packages/support/doc/.gitkeep b/packages/support/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/support/example/.gitkeep b/packages/support/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/support/example/exception_example.dart b/packages/support/example/exception_example.dart deleted file mode 100644 index 6cd7746..0000000 --- a/packages/support/example/exception_example.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:platform_support/src/exceptions/http_exception.dart'; - -void main() => - throw PlatformHttpException.notFound(message: "Can't find that page!"); diff --git a/packages/support/example/service_provider_example.dart b/packages/support/example/service_provider_example.dart deleted file mode 100644 index 26d2b44..0000000 --- a/packages/support/example/service_provider_example.dart +++ /dev/null @@ -1,67 +0,0 @@ -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/exceptions.dart b/packages/support/lib/exceptions.dart deleted file mode 100644 index 35e2912..0000000 --- a/packages/support/lib/exceptions.dart +++ /dev/null @@ -1,8 +0,0 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. -library; - -export 'src/exceptions/http_exception.dart'; - -// TODO: Export any libraries intended for clients of this package. diff --git a/packages/support/lib/providers.dart b/packages/support/lib/providers.dart deleted file mode 100644 index 1d3c8a8..0000000 --- a/packages/support/lib/providers.dart +++ /dev/null @@ -1,6 +0,0 @@ -/// 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/.gitkeep b/packages/support/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/support/lib/src/exceptions/http_exception.dart b/packages/support/lib/src/exceptions/http_exception.dart deleted file mode 100644 index 07e5a38..0000000 --- a/packages/support/lib/src/exceptions/http_exception.dart +++ /dev/null @@ -1,123 +0,0 @@ -library platform_http_exception; - -//import 'package:dart2_constant/convert.dart'; -import 'dart:convert'; - -/// Exception class that can be serialized to JSON and serialized to clients. -/// Carries HTTP-specific metadata, like [statusCode]. -/// -/// Originally inspired by -/// [feathers-errors](https://github.com/feathersjs/feathers-errors). -class PlatformHttpException implements Exception { - /// A list of errors that occurred when this exception was thrown. - final List errors = []; - - /// The error throw by exception. - dynamic error; - - /// The cause of this exception. - String message; - - /// The [StackTrace] associated with this error. - StackTrace? stackTrace; - - /// An HTTP status code this exception will throw. - int statusCode; - - PlatformHttpException( - {this.message = '500 Internal Server Error', - this.stackTrace, - this.statusCode = 500, - this.error, - List errors = const []}) { - this.errors.addAll(errors); - } - - Map toJson() { - return { - 'is_error': true, - 'status_code': statusCode, - 'message': message, - 'errors': errors - }; - } - - Map toMap() => toJson(); - - @override - String toString() { - return '$statusCode: $message'; - } - - factory PlatformHttpException.fromMap(Map data) { - return PlatformHttpException( - statusCode: (data['status_code'] ?? data['statusCode'] ?? 500) as int, - message: data['message']?.toString() ?? 'Internal Server Error', - errors: data['errors'] is Iterable - ? ((data['errors'] as Iterable).map((x) => x.toString()).toList()) - : [], - ); - } - - factory PlatformHttpException.fromJson(String str) => - PlatformHttpException.fromMap(json.decode(str) as Map); - - /// Throws a 400 Bad Request error, including an optional arrray of (validation?) - /// errors you specify. - factory PlatformHttpException.badRequest( - {String message = '400 Bad Request', - List errors = const []}) => - PlatformHttpException(message: message, errors: errors, statusCode: 400); - - /// Throws a 401 Not Authenticated error. - factory PlatformHttpException.notAuthenticated( - {String message = '401 Not Authenticated'}) => - PlatformHttpException(message: message, statusCode: 401); - - /// Throws a 402 Payment Required error. - factory PlatformHttpException.paymentRequired( - {String message = '402 Payment Required'}) => - PlatformHttpException(message: message, statusCode: 402); - - /// Throws a 403 Forbidden error. - factory PlatformHttpException.forbidden({String message = '403 Forbidden'}) => - PlatformHttpException(message: message, statusCode: 403); - - /// Throws a 404 Not Found error. - factory PlatformHttpException.notFound({String message = '404 Not Found'}) => - PlatformHttpException(message: message, statusCode: 404); - - /// Throws a 405 Method Not Allowed error. - factory PlatformHttpException.methodNotAllowed( - {String message = '405 Method Not Allowed'}) => - PlatformHttpException(message: message, statusCode: 405); - - /// Throws a 406 Not Acceptable error. - factory PlatformHttpException.notAcceptable( - {String message = '406 Not Acceptable'}) => - PlatformHttpException(message: message, statusCode: 406); - - /// Throws a 408 Timeout error. - factory PlatformHttpException.methodTimeout( - {String message = '408 Timeout'}) => - PlatformHttpException(message: message, statusCode: 408); - - /// Throws a 409 Conflict error. - factory PlatformHttpException.conflict({String message = '409 Conflict'}) => - PlatformHttpException(message: message, statusCode: 409); - - /// Throws a 422 Not Processable error. - factory PlatformHttpException.notProcessable( - {String message = '422 Not Processable'}) => - PlatformHttpException(message: message, statusCode: 422); - - /// Throws a 501 Not Implemented error. - factory PlatformHttpException.notImplemented( - {String message = '501 Not Implemented'}) => - PlatformHttpException(message: message, statusCode: 501); - - /// Throws a 503 Unavailable error. - factory PlatformHttpException.unavailable( - {String message = '503 Unavailable'}) => - PlatformHttpException(message: message, statusCode: 503); -} diff --git a/packages/support/lib/src/providers/contracts/service_provider.dart b/packages/support/lib/src/providers/contracts/service_provider.dart deleted file mode 100644 index 5891f1f..0000000 --- a/packages/support/lib/src/providers/contracts/service_provider.dart +++ /dev/null @@ -1,30 +0,0 @@ -/// 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 deleted file mode 100644 index 06f5151..0000000 --- a/packages/support/lib/src/providers/deferred_service_provider.dart +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 6b37883..0000000 --- a/packages/support/lib/src/providers/providers.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// 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 deleted file mode 100644 index 2b19abc..0000000 --- a/packages/support/lib/src/providers/service_provider.dart +++ /dev/null @@ -1,271 +0,0 @@ -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 deleted file mode 100644 index be0bdbc..0000000 --- a/packages/support/lib/src/providers/service_provider_static.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// 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 deleted file mode 100644 index 15920a3..0000000 --- a/packages/support/lib/src/providers/service_provider_support.dart +++ /dev/null @@ -1,87 +0,0 @@ -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 ab6b996..33091fe 100644 --- a/packages/support/pubspec.yaml +++ b/packages/support/pubspec.yaml @@ -1,20 +1,17 @@ name: platform_support -description: Protevus Platform support package. -version: 9.0.0 +description: The Support Package for the Protevus Platform +version: 0.0.1 homepage: https://protevus.com documentation: https://docs.protevus.com -repository: https://git.protevus.com/protevus/platform/src/branch/main/packages/support +repository: https://github.com/protevus/platformo environment: - sdk: ^3.5.4 + sdk: ^3.4.2 +# Add regular dependencies here. dependencies: - platform_container: ^9.0.0 - platform_core: ^9.0.0 - meta: ^1.16.0 - collection: ^1.19.1 + # path: ^1.8.0 dev_dependencies: - lints: ^4.0.0 + lints: ^3.0.0 test: ^1.24.0 - http: ^1.2.0 diff --git a/packages/support/test/.gitkeep b/packages/support/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/support/test/providers_http_test.dart b/packages/support/test/providers_http_test.dart deleted file mode 100644 index 8db365c..0000000 --- a/packages/support/test/providers_http_test.dart +++ /dev/null @@ -1,129 +0,0 @@ -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 deleted file mode 100644 index 8fbdebe..0000000 --- a/packages/support/test/providers_test.dart +++ /dev/null @@ -1,236 +0,0 @@ -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/packages/testing/AUTHORS.md b/packages/testing/AUTHORS.md deleted file mode 100644 index ac95ab5..0000000 --- a/packages/testing/AUTHORS.md +++ /dev/null @@ -1,12 +0,0 @@ -Primary Authors -=============== - -* __[Thomas Hii](dukefirehawk.apps@gmail.com)__ - - Thomas is the current maintainer of the code base. He has refactored and migrated the - code base to support NNBD. - -* __[Tobe O](thosakwe@gmail.com)__ - - Tobe has written much of the original code prior to NNBD migration. He has moved on and - is no longer involved with the project. diff --git a/packages/testing/CHANGELOG.md b/packages/testing/CHANGELOG.md index bf99dfd..effe43c 100644 --- a/packages/testing/CHANGELOG.md +++ b/packages/testing/CHANGELOG.md @@ -1,78 +1,3 @@ -# Change Log +## 1.0.0 -## 8.1.1 - -* Updated repository link - -## 8.1.0 - -* Updated `lints` to 3.0.0 - -## 8.0.0 - -* Require Dart >= 3.0 -* Updated `http` to 1.0.0 - -## 7.0.1 - -* Fixed `BytesBuilder` warnings - -## 7.0.0 - -* Require Dart >= 2.17 - -## 6.0.0 - -* Require Dart >= 2.16 - -## 5.0.0 - -* Skipped release - -## 4.0.0 - -* Skipped release - -## 3.0.0 - -* Skipped release - -## 2.1.0 - -* Updated linter to `package:lints` - -## 2.0.2 - -* Updated README -* Updated test cases - -## 2.0.1 - -* Updated README - -## 2.0.0 - -* Migrated to work with Dart >= 2.12 NNBD - -## 1.0.7 - -* Prepare for upcoming Dart SDK change where `HttpHeaders` methods -`add` and `set` take an additional optional parameter `preserveHeaderCase` (thanks @domesticmouse!). - -## 1.0.6 - -* Prepare for upcoming Dart SDK change whereby `HttpRequest` implements - `Stream` rather than `Stream>`. - -## 1.0.5 - -* Add `toString` to `MockHttpHeaders`. - -## 1.0.4 - -* Fix for `ifModifiedSince` - -## 1.0.3 - -* Dart2 fixes -* Apparently fix hangs that break Protevus tests +- Initial version. diff --git a/packages/testing/LICENSE b/packages/testing/LICENSE deleted file mode 100644 index df5e063..0000000 --- a/packages/testing/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2021, dukefirehawk.com -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/testing/LICENSE.md b/packages/testing/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/testing/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/testing/README.md b/packages/testing/README.md index 9e716cd..8b55e73 100644 --- a/packages/testing/README.md +++ b/packages/testing/README.md @@ -1,26 +1,39 @@ -# Mock HTTP Request + -Manufacture dart:io HttpRequests, HttpResponses, HttpHeaders, etc. This makes it possible to test server-side Dart applications without having to ever bind to a port. +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. -This package was originally designed to make testing [Protevus](https://protevus.com/) applications smoother, but works with any Dart-based server. +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. ## Usage +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + ```dart -var rq = MockHttpRequest('GET', Uri.parse('/foo')); -await rq.close(); -await app.handleRequest(rq); // Run within your server-side application -var rs = rq.response; -expect(rs.statusCode, equals(200)); -expect(await rs.transform(UTF8.decoder).join(), - equals(JSON.encode('Hello, world!'))); +const like = 'sample'; ``` -More examples can be found in the included test cases. +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/testing/doc/.gitkeep b/packages/testing/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/testing/example/main.dart b/packages/testing/example/main.dart deleted file mode 100644 index 8c25743..0000000 --- a/packages/testing/example/main.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'dart:async'; -import 'package:platform_testing/http.dart'; - -Future main() async { - var rq = - MockHttpRequest('GET', Uri.parse('/foo'), persistentConnection: false); - await rq.close(); -} diff --git a/packages/testing/lib/http.dart b/packages/testing/lib/http.dart deleted file mode 100644 index 018561b..0000000 --- a/packages/testing/lib/http.dart +++ /dev/null @@ -1,6 +0,0 @@ -export 'src/http/connection_info.dart'; -export 'src/http/headers.dart'; -export 'src/http/lockable_headers.dart'; -export 'src/http/request.dart'; -export 'src/http/response.dart'; -export 'src/http/session.dart'; diff --git a/packages/testing/lib/src/.gitkeep b/packages/testing/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/testing/lib/src/http/connection_info.dart b/packages/testing/lib/src/http/connection_info.dart deleted file mode 100644 index ed76589..0000000 --- a/packages/testing/lib/src/http/connection_info.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'dart:io'; - -class MockHttpConnectionInfo implements HttpConnectionInfo { - @override - final InternetAddress remoteAddress; - @override - final int localPort, remotePort; - - MockHttpConnectionInfo( - {required this.remoteAddress, - this.localPort = 8080, - this.remotePort = 80}); -} diff --git a/packages/testing/lib/src/http/headers.dart b/packages/testing/lib/src/http/headers.dart deleted file mode 100644 index 07f015c..0000000 --- a/packages/testing/lib/src/http/headers.dart +++ /dev/null @@ -1,174 +0,0 @@ -import 'dart:io'; - -class MockHttpHeaders implements HttpHeaders { - final Map> _data = {}; - final List _noFolding = []; - //Uri? _host; - String? _hostname; - int _port = 80; - - List get doNotFold => List.unmodifiable(_noFolding); - - @override - ContentType get contentType { - if (_data.containsKey(HttpHeaders.contentTypeHeader)) { - return ContentType.parse(_data[HttpHeaders.contentTypeHeader]!.join(',')); - } else { - return ContentType.html; - } - } - - @override - set contentType(ContentType? value) => - set(HttpHeaders.contentTypeHeader, value?.value ?? ContentType.html); - - @override - DateTime get date => _data.containsKey(HttpHeaders.dateHeader) - ? HttpDate.parse(_data[HttpHeaders.dateHeader]!.join(',')) - : DateTime.now(); - - @override - set date(DateTime? value) => - set(HttpHeaders.dateHeader, HttpDate.format(value ?? DateTime.now())); - - @override - DateTime get expires => _data.containsKey(HttpHeaders.expiresHeader) - ? HttpDate.parse(_data[HttpHeaders.expiresHeader]!.join(',')) - : DateTime.now(); - - @override - set expires(DateTime? value) => - set(HttpHeaders.expiresHeader, HttpDate.format(value ?? DateTime.now())); - - @override - DateTime get ifModifiedSince => - _data.containsKey(HttpHeaders.ifModifiedSinceHeader) - ? HttpDate.parse(_data[HttpHeaders.ifModifiedSinceHeader]!.join(',')) - : DateTime.now(); - - @override - set ifModifiedSince(DateTime? value) => set(HttpHeaders.ifModifiedSinceHeader, - HttpDate.format(value ?? DateTime.now())); - - @override - String? get host { - return _hostname; - /* - if (_host != null) { - return _host!.host; - } else if (_data.containsKey(HttpHeaders.hostHeader)) { - _host = Uri.parse(_data[HttpHeaders.hostHeader]!.join(',')); - return _host!.host; - } else { - return null; - } - */ - } - - @override - int get port { - return _port; - } - - @override - List? operator [](String name) => _data[name.toLowerCase()]; - - @override - void add(String name, Object value, {bool preserveHeaderCase = false}) { - var lower = preserveHeaderCase ? name : name.toLowerCase(); - - if (_data.containsKey(lower)) { - if (value is Iterable) { - _data[lower]!.addAll(value.map((x) => x.toString()).toList()); - } else { - _data[lower]!.add(value.toString()); - } - } else { - if (value is Iterable) { - _data[lower] = value.map((x) => x.toString()).toList(); - } else { - _data[lower] = [value.toString()]; - } - } - } - - @override - void clear() { - _data.clear(); - } - - @override - void forEach(void Function(String name, List values) action) { - _data.forEach(action); - } - - @override - void noFolding(String name) { - _noFolding.add(name.toLowerCase()); - } - - @override - void remove(String name, Object value) { - var lower = name.toLowerCase(); - - if (_data.containsKey(lower)) { - if (value is Iterable) { - for (var x in value) { - _data[lower]!.remove(x.toString()); - } - } else { - _data[lower]!.remove(value.toString()); - } - } - } - - @override - void removeAll(String name) { - _data.remove(name.toLowerCase()); - } - - @override - void set(String name, Object value, {bool preserveHeaderCase = false}) { - var lower = preserveHeaderCase ? name : name.toLowerCase(); - _data.remove(lower); - - if (value is Iterable) { - _data[lower] = value.map((x) => x.toString()).toList(); - } else { - _data[lower] = [value.toString()]; - } - } - - @override - String? value(String name) => _data[name.toLowerCase()]?.join(','); - - @override - String toString() { - var b = StringBuffer(); - _data.forEach((k, v) { - b.write('$k: '); - b.write(v.join(',')); - b.writeln(); - }); - return b.toString(); - } - - @override - bool chunkedTransferEncoding = false; - - @override - int contentLength = 0; - - @override - bool persistentConnection = true; - - @override - set host(String? host) { - _hostname = host; - } - - @override - set port(int? port) { - _port = port ?? 80; - } -} diff --git a/packages/testing/lib/src/http/lockable_headers.dart b/packages/testing/lib/src/http/lockable_headers.dart deleted file mode 100644 index 59b12e3..0000000 --- a/packages/testing/lib/src/http/lockable_headers.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'headers.dart'; - -/// Headers that can be locked to editing, i.e. after a request body has been written. -class LockableMockHttpHeaders extends MockHttpHeaders { - bool _locked = false; - - StateError _stateError() => - StateError('Cannot modify headers after they have been write-locked.'); - - void lock() { - _locked = true; - } - - @override - void add(String name, Object value, {bool preserveHeaderCase = false}) { - if (_locked) { - throw _stateError(); - } else { - super.add(name, value, preserveHeaderCase: preserveHeaderCase); - } - } - - @override - void clear() { - if (_locked) { - throw _stateError(); - } else { - super.clear(); - } - } - - @override - void noFolding(String name) { - if (_locked) { - throw _stateError(); - } else { - super.noFolding(name); - } - } - - @override - void remove(String name, Object value) { - if (_locked) { - throw _stateError(); - } else { - super.remove(name, value); - } - } - - @override - void removeAll(String name) { - if (_locked) { - throw _stateError(); - } else { - super.removeAll(name); - } - } - - @override - void set(String name, Object value, {bool preserveHeaderCase = false}) { - if (_locked) { - throw _stateError(); - } else { - super.set(name, value, preserveHeaderCase: preserveHeaderCase); - } - } -} diff --git a/packages/testing/lib/src/http/request.dart b/packages/testing/lib/src/http/request.dart deleted file mode 100644 index e79a679..0000000 --- a/packages/testing/lib/src/http/request.dart +++ /dev/null @@ -1,323 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; -import 'package:charcode/ascii.dart'; -import 'connection_info.dart'; -import 'lockable_headers.dart'; -import 'response.dart'; -import 'session.dart'; - -class MockHttpRequest - implements HttpRequest, StreamSink>, StringSink { - int _contentLength = 0; - late BytesBuilder _buf; - final Completer _done = Completer(); - final LockableMockHttpHeaders _headers = LockableMockHttpHeaders(); - Uri? _requestedUri; - late MockHttpSession _session; - final StreamController _stream = StreamController(); - - @override - final List cookies = []; - - @override - HttpConnectionInfo connectionInfo = - MockHttpConnectionInfo(remoteAddress: InternetAddress.loopbackIPv4); - - @override - MockHttpResponse response = MockHttpResponse( - contentLength: 0, - encoding: utf8, - persistentConnection: false, - reasonPhrase: '', - statusCode: 200); - - @override - HttpSession get session => _session; - - @override - final String method; - - @override - final Uri uri; - - @override - bool persistentConnection = true; - - /// [copyBuffer] corresponds to `copy` on the [BytesBuilder] constructor. - MockHttpRequest(this.method, this.uri, - {bool copyBuffer = true, - String? protocolVersion, - String? sessionId, - this.certificate, - this.persistentConnection = true}) { - _buf = BytesBuilder(copy: copyBuffer != false); - _session = MockHttpSession(id: sessionId ?? 'mock-http-session'); - - this.protocolVersion = protocolVersion ?? '1.1'; - } - - @override - int get contentLength => _contentLength; - - @override - HttpHeaders get headers => _headers; - - @override - Uri get requestedUri { - if (_requestedUri != null) { - return _requestedUri!; - } else { - return _requestedUri = Uri( - scheme: 'http', - host: 'example.com', - path: uri.path, - query: uri.query, - ); - } - } - - set requestedUri(Uri value) { - _requestedUri = value; - } - - @override - late String protocolVersion; - - @override - X509Certificate? certificate; - - @override - void add(List data) { - if (_done.isCompleted) { - throw StateError('Cannot add to closed MockHttpRequest.'); - } else { - _headers.lock(); - _contentLength += data.length; - _buf.add(data); - } - } - - @override - void addError(error, [StackTrace? stackTrace]) { - if (_done.isCompleted) { - throw StateError('Cannot add to closed MockHttpRequest.'); - } else { - _stream.addError(error, stackTrace); - } - } - - @override - Future addStream(Stream> stream) { - var c = Completer(); - stream.listen(add, onError: addError, onDone: c.complete); - return c.future; - } - - @override - Future close() async { - await flush(); - _headers.lock(); - scheduleMicrotask(_stream.close); - _done.complete(); - return await _done.future; - } - - @override - Future get done => _done.future; - - // @override - Future flush() async { - _contentLength += _buf.length; - _stream.add(_buf.takeBytes()); - } - - @override - void write(Object? obj) { - obj?.toString().codeUnits.forEach(writeCharCode); - } - - @override - void writeAll(Iterable objects, [String separator = '']) { - write(objects.join(separator)); - } - - @override - void writeCharCode(int charCode) { - add([charCode]); - } - - @override - void writeln([Object? obj = '']) { - write(obj ?? ''); - add([$cr, $lf]); - } - - @override - Future any(bool Function(Uint8List element) test) { - return _stream.stream.any((List e) { - return test(Uint8List.fromList(e)); - }); - } - - @override - Stream asBroadcastStream({ - void Function(StreamSubscription subscription)? onListen, - void Function(StreamSubscription subscription)? onCancel, - }) { - return _stream.stream - .asBroadcastStream(onListen: onListen, onCancel: onCancel); - } - - @override - Stream asyncExpand(Stream? Function(Uint8List event) convert) => - _stream.stream.asyncExpand(convert); - - @override - Stream asyncMap(FutureOr Function(Uint8List event) convert) => - _stream.stream.asyncMap(convert); - - @override - Future contains(Object? needle) => _stream.stream.contains(needle); - - @override - Stream distinct( - [bool Function(Uint8List previous, Uint8List next)? equals]) => - _stream.stream.distinct(equals); - - @override - Future drain([E? futureValue]) => _stream.stream.drain(futureValue); - - @override - Future elementAt(int index) => _stream.stream.elementAt(index); - - @override - Future every(bool Function(Uint8List element) test) => - _stream.stream.every(test); - - @override - Stream expand(Iterable Function(Uint8List value) convert) => - _stream.stream.expand(convert); - - @override - Future get first => _stream.stream.first; - - @override - Future firstWhere(bool Function(Uint8List element) test, - {List Function()? orElse}) => - _stream.stream - .firstWhere(test, orElse: () => Uint8List.fromList(orElse!())); - - @override - Future fold( - S initialValue, S Function(S previous, Uint8List element) combine) => - _stream.stream.fold(initialValue, combine); - - @override - Future forEach(void Function(Uint8List element) action) => - _stream.stream.forEach(action); - - @override - Stream handleError(Function onError, - {bool Function(Object?)? test}) => - _stream.stream.handleError(onError, test: test); - - @override - bool get isBroadcast => _stream.stream.isBroadcast; - - @override - Future get isEmpty => _stream.stream.isEmpty; - - @override - Future join([String separator = '']) => - _stream.stream.join(separator); - - @override - Future get last => _stream.stream.last; - - @override - Future lastWhere(bool Function(Uint8List element) test, - {List Function()? orElse}) => - _stream.stream - .lastWhere(test, orElse: () => Uint8List.fromList(orElse!())); - - @override - Future get length => _stream.stream.length; - - @override - StreamSubscription listen( - void Function(Uint8List event)? onData, { - Function? onError, - void Function()? onDone, - bool? cancelOnError, - }) { - return _stream.stream.listen( - onData, - onError: onError, - onDone: onDone, - cancelOnError: cancelOnError == true, - ); - } - - @override - Stream map(S Function(Uint8List event) convert) => - _stream.stream.map(convert); - - @override - Future pipe(StreamConsumer> streamConsumer) => - _stream.stream.cast>().pipe(streamConsumer); - - @override - Future reduce( - List Function(Uint8List previous, Uint8List element) combine) { - return _stream.stream.reduce((Uint8List previous, Uint8List element) { - return Uint8List.fromList(combine(previous, element)); - }); - } - - @override - Future get single => _stream.stream.single; - - @override - Future singleWhere(bool Function(Uint8List element) test, - {List Function()? orElse}) => - _stream.stream - .singleWhere(test, orElse: () => Uint8List.fromList(orElse!())); - - @override - Stream skip(int count) => _stream.stream.skip(count); - - @override - Stream skipWhile(bool Function(Uint8List element) test) => - _stream.stream.skipWhile(test); - - @override - Stream take(int count) => _stream.stream.take(count); - - @override - Stream takeWhile(bool Function(Uint8List element) test) => - _stream.stream.takeWhile(test); - - @override - Stream timeout(Duration timeLimit, - {void Function(EventSink sink)? onTimeout}) => - _stream.stream.timeout(timeLimit, onTimeout: onTimeout); - - @override - Future> toList() => _stream.stream.toList(); - - @override - Future> toSet() => _stream.stream.toSet(); - - @override - Stream transform(StreamTransformer, S> streamTransformer) => - _stream.stream.cast>().transform(streamTransformer); - - @override - Stream where(bool Function(Uint8List event) test) => - _stream.stream.where(test); - - @override - Stream cast() => Stream.castFrom, R>(this); -} diff --git a/packages/testing/lib/src/http/response.dart b/packages/testing/lib/src/http/response.dart deleted file mode 100644 index 00c9dc3..0000000 --- a/packages/testing/lib/src/http/response.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io' hide BytesBuilder; -import 'dart:typed_data'; -import 'package:charcode/ascii.dart'; -import 'connection_info.dart'; -import 'lockable_headers.dart'; - -class MockHttpResponse extends Stream> implements HttpResponse { - BytesBuilder _buf = BytesBuilder(); - bool _bufferOutput = true; - final Completer _done = Completer(); - final LockableMockHttpHeaders _headers = LockableMockHttpHeaders(); - final StreamController> _stream = StreamController>(); - - @override - final List cookies = []; - - @override - HttpConnectionInfo connectionInfo = - MockHttpConnectionInfo(remoteAddress: InternetAddress.anyIPv4); - - /// [copyBuffer] corresponds to `copy` on the [BytesBuilder] constructor. - MockHttpResponse( - {bool copyBuffer = true, - required this.statusCode, - required this.reasonPhrase, - required this.contentLength, - this.deadline, - required this.encoding, - required this.persistentConnection, - bool? bufferOutput}) { - _buf = BytesBuilder(copy: copyBuffer != false); - _bufferOutput = bufferOutput != false; - statusCode = 200; - } - - @override - bool get bufferOutput => _bufferOutput; - - @override - set bufferOutput(bool value) {} - - @override - int contentLength; - - @override - Duration? deadline; - - @override - bool persistentConnection; - - @override - String reasonPhrase; - - @override - int statusCode; - - @override - Encoding encoding; - - @override - HttpHeaders get headers => _headers; - - @override - Future get done => _done.future; - - @override - void add(List data) { - if (_done.isCompleted) { - throw StateError('Cannot add to closed MockHttpResponse.'); - } else { - _headers.lock(); - if (_bufferOutput == true) { - _buf.add(data); - } else { - _stream.add(data); - } - } - } - - @override - void addError(error, [StackTrace? stackTrace]) { - if (_done.isCompleted) { - throw StateError('Cannot add to closed MockHttpResponse.'); - } else { - _stream.addError(error, stackTrace); - } - } - - @override - Future addStream(Stream> stream) { - var c = Completer(); - stream.listen(add, onError: addError, onDone: c.complete); - return c.future; - } - - @override - Future close() async { - _headers.lock(); - await flush(); - scheduleMicrotask(_stream.close); - _done.complete(); - //return await _done.future; - } - - @override - Future detachSocket({bool writeHeaders = true}) { - throw UnsupportedError('MockHttpResponses have no socket to detach.'); - } - - @override - Future flush() async { - _stream.add(_buf.takeBytes()); - } - - @override - Future redirect(Uri location, - {int status = HttpStatus.movedTemporarily}) async { - statusCode = status; - } - - @override - void write(Object? obj) { - obj?.toString().codeUnits.forEach(writeCharCode); - } - - @override - void writeAll(Iterable objects, [String separator = '']) { - write(objects.join(separator)); - } - - @override - void writeCharCode(int charCode) { - add([charCode]); - } - - @override - void writeln([Object? obj = '']) { - write(obj ?? ''); - add([$cr, $lf]); - } - - @override - StreamSubscription> listen(void Function(List event)? onData, - {Function? onError, void Function()? onDone, bool? cancelOnError}) => - _stream.stream.listen(onData, - onError: onError, - onDone: onDone, - cancelOnError: cancelOnError == true); -} diff --git a/packages/testing/lib/src/http/session.dart b/packages/testing/lib/src/http/session.dart deleted file mode 100644 index 3766381..0000000 --- a/packages/testing/lib/src/http/session.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'dart:collection'; -import 'dart:io'; - -class MockHttpSession extends MapBase implements HttpSession { - final Map _data = {}; - - @override - String id; - - MockHttpSession({required this.id}); - - @override - int get length => _data.length; - - @override - dynamic operator [](Object? key) => _data[key]; - - @override - void operator []=(key, value) { - _data[key] = value; - } - - @override - void addAll(Map other) => _data.addAll(other); - - @override - void clear() { - _data.clear(); - } - - @override - bool containsKey(Object? key) => _data.containsKey(key); - - @override - bool containsValue(Object? value) => _data.containsValue(value); - - @override - void destroy() { - print('destroy() was called on a MockHttpSession, which does nothing.'); - } - - @override - void forEach(void Function(dynamic, dynamic) action) { - _data.forEach(action); - } - - @override - bool get isEmpty => _data.isEmpty; - - @override - bool get isNew => true; - - @override - bool get isNotEmpty => _data.isNotEmpty; - - @override - Iterable get keys => _data.keys; - - @override - dynamic putIfAbsent(key, dynamic Function() ifAbsent) => - _data.putIfAbsent(key, ifAbsent); - - @override - dynamic remove(Object? key) => _data.remove(key); - - @override - Iterable get values => _data.values; - - @override - set onTimeout(void Function() callback) { - print( - 'An onTimeout callback was set on a MockHttpSession, which will do nothing.'); - } -} diff --git a/packages/testing/pubspec.yaml b/packages/testing/pubspec.yaml index ed6814c..aaa1f40 100644 --- a/packages/testing/pubspec.yaml +++ b/packages/testing/pubspec.yaml @@ -1,15 +1,17 @@ name: platform_testing -description: Testing helper files for Protevus Platform. -version: 9.0.0 -# repository: https://github.com/my_org/my_repo +description: The Testing 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.5.4 + sdk: ^3.4.2 # Add regular dependencies here. dependencies: - charcode: ^1.3.1 + # path: ^1.8.0 dev_dependencies: - lints: ^4.0.0 + lints: ^3.0.0 test: ^1.24.0 diff --git a/packages/testing/test/.gitkeep b/packages/testing/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/testing/test/all_test.dart b/packages/testing/test/all_test.dart deleted file mode 100644 index a0244a1..0000000 --- a/packages/testing/test/all_test.dart +++ /dev/null @@ -1,69 +0,0 @@ -//import 'dart:convert'; -//import 'dart:io'; -//import 'package:angel3_framework/angel3_framework.dart'; -//import 'package:angel3_framework/http.dart'; -//import 'package:angel3_mock_request/angel3_mock_request.dart'; -//import 'package:test/test.dart'; - -void main() { - //var uri = Uri.parse('http://localhost:3000'); - - /* - var app = Protevus() - ..get('/foo', (req, res) => 'Hello, world!') - ..post('/body', - (req, res) => req.parseBody().then((_) => req.bodyAsMap.length)) - ..get('/session', (req, res) async { - req.session?['foo'] = 'bar'; - }) - ..get('/conn', (RequestContext req, res) { - return res.serialize(req.ip == InternetAddress.loopbackIPv4.address); - }); - - var http = PlatformHttp(app); - - test('receive a response', () async { - var rq = MockHttpRequest('GET', uri.resolve('/foo')); - await rq.close(); - await http.handleRequest(rq); - var rs = rq.response; - expect(rs.statusCode, equals(200)); - expect(await rs.transform(utf8.decoder).join(), - equals(json.encode('Hello, world!'))); - }); - - test('send a body', () async { - var rq = MockHttpRequest('POST', uri.resolve('/body')); - rq - ..headers.set(HttpHeaders.contentTypeHeader, ContentType.json.mimeType) - ..write(json.encode({'foo': 'bar', 'bar': 'baz', 'baz': 'quux'})); - await rq.close(); - await http.handleRequest(rq); - var rs = rq.response; - expect(rs.statusCode, equals(200)); - expect(await rs.transform(utf8.decoder).join(), equals(json.encode(3))); - }); - - test('session', () async { - var rq = MockHttpRequest('GET', uri.resolve('/session')); - await rq.close(); - await http.handleRequest(rq); - expect(rq.session.keys, contains('foo')); - expect(rq.session['foo'], equals('bar')); - }); - - test('connection info', () async { - var rq = MockHttpRequest('GET', uri.resolve('/conn')); - await rq.close(); - await http.handleRequest(rq); - var rs = rq.response; - expect(await rs.transform(utf8.decoder).join(), equals(json.encode(true))); - }); - - test('requested uri', () { - var rq = MockHttpRequest('GET', uri.resolve('/mock')); - expect(rq.uri.path, '/mock'); - expect(rq.requestedUri.toString(), 'http://example.com/mock'); - }); - */ -} diff --git a/packages/validation/.gitignore b/packages/validation/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/validation/.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/validation/CHANGELOG.md b/packages/validation/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/validation/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/validation/LICENSE.md b/packages/validation/LICENSE.md new file mode 100644 index 0000000..0fd0d03 --- /dev/null +++ b/packages/validation/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/validation/README.md b/packages/validation/README.md new file mode 100644 index 0000000..8b55e73 --- /dev/null +++ b/packages/validation/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/validation/analysis_options.yaml b/packages/validation/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/validation/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/validation/doc/.gitkeep b/packages/validation/doc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/validation/example/.gitkeep b/packages/validation/example/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/validation/lib/src/.gitkeep b/packages/validation/lib/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/validation/pubspec.yaml b/packages/validation/pubspec.yaml new file mode 100644 index 0000000..00c6c2e --- /dev/null +++ b/packages/validation/pubspec.yaml @@ -0,0 +1,17 @@ +name: platform_validation +description: The Validation 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: + # path: ^1.8.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/packages/validation/test/.gitkeep b/packages/validation/test/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sandbox/eventbus/.github/workflows/dart.yml b/sandbox/eventbus/.github/workflows/dart.yml deleted file mode 100644 index 21b7ff6..0000000 --- a/sandbox/eventbus/.github/workflows/dart.yml +++ /dev/null @@ -1,54 +0,0 @@ -# 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 deleted file mode 100644 index 3d34218..0000000 --- a/sandbox/eventbus/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# 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 deleted file mode 100644 index 0bb64e4..0000000 --- a/sandbox/eventbus/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# 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 deleted file mode 100644 index 52472e3..0000000 --- a/sandbox/eventbus/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "cSpell.words": [ - "codecov", - "devcraft", - "shouldly" - ] -} \ No newline at end of file diff --git a/sandbox/eventbus/CHANGELOG.md b/sandbox/eventbus/CHANGELOG.md deleted file mode 100644 index 5302c51..0000000 --- a/sandbox/eventbus/CHANGELOG.md +++ /dev/null @@ -1,67 +0,0 @@ -## 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 deleted file mode 100644 index c560cf3..0000000 --- a/sandbox/eventbus/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 4c8f4bd..0000000 --- a/sandbox/eventbus/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# 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 deleted file mode 100644 index 67016e9..0000000 --- a/sandbox/eventbus/analysis_options.yaml +++ /dev/null @@ -1,224 +0,0 @@ -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 deleted file mode 100644 index 8e13702aac1179e74d9195fd9aebfbdd950fbdc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16548 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 diff --git a/sandbox/eventbus/doc/video_presentation.gif b/sandbox/eventbus/doc/video_presentation.gif deleted file mode 100644 index 0ef19815533e43ee4b6c00d4b873394dc5cc28c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1887898 zcmV)UK(N0@Nk%v~Vdw;y0(SraA^!_bMO0HmK~P09E-(WD0000X{v9A7ARr(hARr(h zARr(hARr(hARr(hARr(hARr(BA^8La0|5U3EC2ui0O$mm0*6eE&ks_eNIMvikdWEF zI5wQ~(}@$hlMHse@tK*OR-onVzYDVO{8~m6AsrIQ$jG*~wpm$O_*G5f!bHonO_qKU zvoQ`#t5vsA2Dzg;+1J+iwI)nVP2}U^`|{}cxUuHSTI=iSsFEX!69?4#{Ci~yprN25 z76ccE=IhEPip%>cgw!&5IU>S2Pkf+tR|%Zc`em)^Q?mK~+A}M+DhB@Y+}(b0#-|z1eWOK0Y)xl_sIw=iuR1A+Obrlhsi_q>I0`^g2LihhWDY5Ye!#Wk?3})=tSV8Q#OcND~ez zFfa7aPBu?J443;-NDeR%1OpB)B06jakNR!9_xjTXCMP30Iy@#SEC!1E`u_YXDlBep zZ7&Hfqn2jr%tvEAJBo5_G*Ec{*1XBn-&j2aewM6GNHzkJ`Ys+c=iJl&)&&cD*Xhr6 zc6N0B_U8nM>jawm%Fg^WIwl5|`vRi;FDfoNDntU1>@GSyDljB&evASI7cwq1a&B}s zK1>3Z>~eN&Zi;9SuAq>%Ffy*7c2H<)GHBS?ywLW<>@?7`I8B?uabLY|!YK5W3(Z}^l000R80BHym2#m%q4jhOO(W9rBFi?6RN{mQx zqQ#0BFKW!laihnMAU}!>Nm3%HlP6269O-bR%at%+%8W^Krp=l-Z|cm+bEnUqKz|Ai zN^~g1heeYbRmya!)22|LN{vc&s@1AkuWBV3kw^p%STq3|JC+8Tfsr_TU&|JC01*apS<16<^-WxwGfb zg(r&!O}eyc(wQY|UVXZ?>&vNQk5)}P@@v7eS;uC4yLau`0(f)I{ad$i-^i2WCB9gB zXx)>KJD(2S_-E$8qf;0B7opm(_Q(qVti(p`rbnDUrT@fUef#z9*~6bNpOgLj_T|6d zFCRVr{{RLk;D7?^XJC8?(sv*y{sGt^e+fdUV1x@wXkmQ>{&yjT31;ZwhaiS1Vu%|~ zINyjUrl{hICYI>pf-J@;V}>ts*kXk^+W208nmp2@edwT=h4h)HpMUnrr=WiFiRUAF2CC?wf8LX5qKF;}>7a{1tGwN^GszV%zJvs-{b;uC?CkZm#d%$u7I) zYFjD2%kG*kx}MewEIa@QEbzbt5A5ry_K5pPr~otE?j!#?%T$&slZ$J>3^xq1${BOqa>y_{JMOq7_o}C^GrO#@rZu+;^2Ra040NQU%KEUp z`Hs9PsX8m&bH74ojBm%7LTnFvo3I6lKnQ(;j>yI`E%u#{AZm8PW>Y$?+LlWX;Al&Z9zyK!dVtKk+);3Xz zUT~lgp9mH9BDl0pAxlz+`&k5OHNp_8%~!btU))A`Fv78rgC`uJ42@b1tXZh8W+6C zbr5L~%Twb__Qx#t@saC#BNFLF#~eEGk|xvL9M^a(KT3*)L*$^cAm~O<<_?o7tfU$@ z$x1nbQH)}27ZFSOD;&PfjANu6D#sT=Jj(KywDV%IQnx-=zA#c78z%JDrmPs6u#UdW z7cj>suU#&)m3BO%6%`ptL}>yG94HSKK5;Qe848b!T;8lAbq{2s?Gr_uRxs?Li$3`h zmVd%yFW062LQLu_mjGSdp7dA4Yt0Q@{F@f3(0R^=a`U0NoEzifg+6p@|V-0Iy!$8c!hBfG7n0cewybLS9nZ-_@e;jGG6lN)ijn4nSDf~LonHE%P+ zrIKvcXU%n?VuK+*Sv;xDPEV~XE#jvlmMdMdYQqjCT9~hz;uV%TcgmwGjn^#V8napd zakI*-61xn(kDYj(ab~aJKDfJ#R_celqG6YB72*(!d7|#58ZZgH=q%>y-vTH&M~)MsqV>+ZM-ZFiFGhhlCZiNn_2KSO$*5f-BPMhs_p-z#>ceVV`-jV~^e z&c^iI#VF>R$ZN>5Gs;y`VdwY7YD5?w4fE%2|2j>>Q*DLciF0JOTRe2`;rDt%JT%Vl9 zd6ezCMF1c0hY1I_)(Ncbnf{Z8n$%=N6A9PC`fhl1CArEA?)9dToYD!)8Wze{Lo~SI z2tts6-X$OeA&5Z}$~9XL(cl0)P+$X)*uVxTaDWE%I#R(v)EZiW1{PeP4VcHg3(`OX z@PZkrnk_S@edbVYs!vuBe5uu|C-11zzI^-M;F21M2~a<4_&}h7wPc`4!{8rU;0}r%@2Z|Sminjm; z;CO5>PaC%ep}+zy(1(85hgy&Z%a&FjCuTW_Lz6RvskdkuxKCUECw745UvZ;|d&V?I zvrIm)c$PCRM_rFrOTU#-tQcFa2wFFTMKx4#v9eooL})w4 zZo0TYQbmF+1zFUGg*?THGy{EOc8uBca%W_I4F!J8_=~T|Tet*TY1ToS-~e@TjfHR? zn&5xiXb%p+2EpL~4&Y-BU=ISo2{eF?0=O{2K!4*zjvVj=39t!5R$OZkjvy6VFeEF( zBPyTQbzJ6(0q0(pWs4s}Nx(N(oQOvDvPZGVk7)*alooq9)P>)oO>1RjJjak_$1Y7K zEQ!^Mxwwka$cq8BgQD0{7`9V>1vMK8N)4%LL%1}Hgis*=)?XlIcFX9B9=BwC23h~L zTN9~Bv_&t5=yb4`W2bm$i#A5cq*G*cdt!zvrm`?#@g^Fi38avBXt;MkU?<`N4>eE* zhbM<}hyyfGe-Q%*9B=`D7?&bXw zOXfQQmSlE$k)b$(OH^{#;%*W)P#efgC-rmgW1pZjZn8IREvHZrB}<+)X))<&J85Bi z7IZ+@W=aS){Zf~~qEPqJggJPi95_vU6N4*wRf{PzFei0D#G!UWn(78ui}`0-c7Y$$ zlPXwP=;la)HKB0ycJ5P8Y;h=$kOgz_m1pR8ZXkG{Z~{1hmS{-U^EZZ!6bH=VpniHAb*FHl=l@-sXFTSY_^Xl|dw#Otp}P zHITJuQqqQ_hZ&;0rG23lELlWfzKDZYn0tc%`hu1OsKy6cQglo$WP0IesdieaGZ`*b zCON0cK()0n4ge1W009FKoZ=Y=rm6=f@C5L%267+=15m1AAOK+i0rdC;1(*OP00Cie zak$E>5Rd@yunF{72m&AnPcQ_uiVo#?VDhtM2PAUCB6e1Zp&|oc>1A#t$7h3jh}gQ1 ziN&E8lThWlQ2l9`c!rXc6p>w}Q2$A03W1-~epq9jz-*R7T%i2-fOrHRz$h=WHo1Y6F7rY+*8x2h0w@Qhek$&TZt(Q zWqP_x2bwe-JHyXgVG@RRKWszEcTPjuz6a^9liG;_TTsAwm8P6y#w??@8O&=8iL;q7 zBRh9|VzLdKvO>UWbf>@$0J9dncrQ=`kmmqZ>cK5=0a{9TU-v*ADN+I(%PVGWrDrLT zV}wo@#J`uqY`esirA~GFQhy3_HpHNxqgb~Xk;iOUnHr%Z7lJGqG}8jaRUAa$26w5r zj|2y`D0;Wy#%6Z^+hU!XRJO&J-5NP@^+_fiqpWPx-NG!88DpxMuAz!2*BAlA`4tfm z0h{m%ty_QsPy?VatPubTvMR_9aMfWjfLmR5ha-av1YyysKou;}8oI3zSAjyGztC-8VLtx0A+q%mt$p(l8+=&HDod6LK z2MI6$`3Pg`MPE*2-diZ5&U13-m)oPvUk{2%9m^~6wXghpEDi2Vc)iVo<K#nHn8h9rMiUv|B+8pG3}95~k@`7J+Lqa^S=S1-KH%I(GMP}Q2Xo&1J?E;f)>m{s zioebOD0;Nzakhkzhz6*Kqu;x7!0Ie7hK#ak_|6UhQvhSg2e1GZj0bSQ29n|cx8MTR z?T47h0yV$}3zKf}bKm{cQTru5o5_^f_vf5glTbFUW`)vlF5o}}VAwW5pdwbS-LX9? zZVC-9H)=GQsXCBpb@-G}r4n}ZBW~-3Q9Ttl64it`J!Yv%iX&Fj0z2s2Hb6Cbg^zuO zqMX|^wv(Uwu|qA?24%yJ3%O+t0lpdmjf@4Q3JM%hs&pLV5P-Q?Z43iQy4=~TPXG!v zz~d$mWMPoU1xN$}c;T^#PTh4@_q*O@j_4>TZULv$8()QnDZhC2PlyiLq3C-FZHtlr zb4|(~Uz?S$3%j4K3DH|sXsD^>ks0n0t>EDMp%zQur%Yu9m!|yfEK2x;-7=fej;JBc zi=P~OUH;Gm+13h5v{r_Q@G79{6vcndQ>moSx}2o>z4 zIB)`+o?g2U3LKp3Edau3Ku!Q%d>N|fz1zH24x{57g256Kp=?T~neFu{HogFK+XUQiE6q`*T{jt1z25iAEsbA~s^JTssN0nFoPE$O1a?xx z^7it!JqdTTFZ_pTdK{nFt}=gEpbwqVL7Doge@Frd%08b5uL@-VX!2zHDz~W&j z$#Eb6Ucm_tunAAS3FjCA3LyZSF0Q>@wS^j5b4{2OZSn=Sp=N$i@n(CPU1k~&5ccd9 zdIWEvJ%a=X8npKaVWEQx1qy_yu;M_62{Q_G$T8tWhY%;iyI2w1zT{d){Q3_O2iq`VcMNh3&u>_@uNwGNhNC4YVhb*l~=8@bc!|NLYQ~|p7k2o zqGOaCu-GlchK&O;K!ga9AOy&ZEN&hZe58xxqeB94P@u4ZLX;9G9E^tlcyFMtH8j$& zxX`;d3mRy2jow&DBS^r516w>zzaeOlco(W5}Q`W^Z6Ez-4E zMQ#UNRPA^5HlO#jseCZnvSqmj^N>^$rC!bv*#(#vZmgrH-vu%5^|?zrzJ ze2=f<>N;$#v_x9aJ&P8U&OO6EVrZ_Pz_JiS<|u4xMe|@v5ip^)E2Od-YM3n;8XWkf z5C?QDgcBXvsDXw@g46^@2MW=|0YEev00K~G0A#isj~wU|2jHMV6L?IMi9Du?Qffk` z##*mA3Ab`9uLZN(uqKAmt8Y2`hBA&I>2yNSJF<`pj6U*a%5WzC03Xx|sf~_OEKjRa z>ToEY$_!7&nbIRsrUEHDv_{C_td24o?cAtN_aMEBM(z%a>LxuAjjK>t6*>>GzSd+= zx)>khYO&(R#E;CZX5=rX5iL}er9@dJmcqok%P-Id-_xZK$v!#hMmErJU=31^5C9D{ zel%*dV2FF95H#S}qzoWdp#jM~!Mew&LRz7rkVsgF#0?*9d&C#&(kv>?WmROWS{0w- zbz7oNauB6Jv1_iPI^~0FQN$QS&erb^+;-9koojC?tp23%FN~?e6Hf=B-HXODG3AcL zj6Z}bt?|&a>sC624T-FvAqvps|0vB#=|7L{Pu8BG%FAH?sZ$>6PwI5CD7vVc28zV5 zpLY7{J5>rWJDVN4hfl`{($z!bd?JhpSvdHlv{|*yD@C9@dP}2~8f`PEu=_TN?Ua{N z+|@P{wvc6;#qzqjvl%zM)s?=g7-c_WYS{6Z#EQ>jvcJ;!;-rL9J*YkpoN7c@!GpMF z=j?h}xss0F&tgCYt+ZC;Cawu()jNf6EaY~Vn|73HGFZjGGVa<5wiS4I3y8_XtE|eh-<>z}B9M$$@CB*-{ z?s6&QUB{?~DHyfrh|GCV$udF5-C=o{$MO@=xODl z`t(l!HKZ>-GfbMS2B8NkERu{uj-ZM{AhdmGc8yvHvPxt^Le5NStP7i_=tG_M!0B=y zOVABdR!m=dP^D#CXcv1rw#qd$gH3cP(ul{w@paULfn!zh#&Rms7zJ>ILZG5%`AjB8 zFL!Zr*|J1;!;FOvfQ$>yIqO@na-~BA9te>R6kQ;7R>oFou&-NN zkV6gQkn-KqFKhG2Jeyf5`F#!|=`u|@Ve%uUjR}`*Q&pmJH5CCd^`P8TAwv)7!HCK9 zfUGPmAw6Q9je)RPI^`ngfO|7zb@iPbT^MwcV!FcxXhd@f?WBkXtK*_hdLpf!*#0EC zSB3|P$3vV&#Ve!ng3_55)$N+#yG$&8twTnvZ;Z0IB8&?2L5sUf^2!rf+riC`qzDS<&W$F8MjR$4_RyzYMA53)`>#h~0?oy9?t6!mxi47ZKtDO8@6e%^f;z@BA4Vs>;yo0kCI#!a`nJdHaTEeGoijSa;7Ei-m>B%+l zY|=|qiHnA)Q=afu(bI3YEt}~xz3Gj@y$-XR2eDT=M#hE{ndAJYsZ#^*#Ukn&dt%CA zC}+8agef+?QK{o-ak$X`$h9=UJ;%A?QO|~ZyO0;Lt#1658lI$TZ(~bpwdYYzV*A+- zAp=Em;e~W!kn<1Wetb0Gl2me1iKQ{)DdCD*GL3c=*`39PJYLH)}3hBhd6J{uSJGPI}OpE51u3oDQw?J z|NN?09_h(0x>S_dZg6ZJ=C2Em$5+i$SMU8ah8XU-kt#W(E!=yjTJCETaj;lKwKdUW z&P7TyPLN7dJkvFcY}mz{IioBOc~&CTygRq87|P!JGF@3oWnb1SZeiC83JuIUW{O8xv7;)BR?l8aJao$9qg`5jT=jvq@FhcUhc`zk{!A^ao0pL(-s zQ=M8uH`_CdrAd$(A~?bdop##`>qD`Y^PlVpw|uf8nZvT~I+S`jChmDYdgHY0`iOzj zr>Kz&@9P!+7b}|$r?uct{giz&e}42_>omugZhyT z`)S1!u%B0SfL4@6TAW2&bbwgQMObu2T4cpq#Km32#b30=6NtrI3`S!FMrCxxWYk4j z^u<|B#$Y^zTx>>abVXQnMr>S0Wi-ZO>_udZMqm6!X57YWTt;$)#%EMVV%$b!oW^1# zMpo3uVFX89bVhn4#%KIRb<{>_DB$6B06aP-E1JV$CANNapXeU!(2ghp}%#(6x* zdW1#)dyK|_(PM$f4v$dc?<_zVoOik5XP1bBp*L+Rbj7`~`P1>wY+q_NO%uU_gP2TKH-~3Jg z;0#XT98TgaPUAdIPx-V@_Ds+8lu!L^PyTGr{A|zu{LcU# zPys#A{@l+4El~J;&jj^P_olpf`&kRM-1@+Jfbh(H8Ac7j01X)KCyzQ5t>G1^rJE<z9_>#S4bd7k(EwFZ|Af*ieNy=(QWW*lDBV&qolqjx(l8BDEd^8mF;!DD zCD9}u(Kh{29-Yw(ZBjLL&=iGHC6!VmeNZ{AQ!5Qq9OctI1=2W8(Ld!;8pTpI9aI6$ z&_Z2NKOIvi1ym{3Qy`7e51mvb)l^HR)I`nHPPJ1iolrzQ(n@{ONj+61?NR^@(<|N2 zHXT(s^-?-*(OLCW8%56vKu;z3)dK*6BN$d{uV61~+1 zodG7ugiO$fOn8NC)mDA@)^F`raSc~;^;U50R&XuXbX`|-9anZe*K$Qyc_mkOO;>a^ zSA4zKc!k$})z^B>)_a}TcI8)qeb<3CScE;;g2h*Z)z^IOS9;x7Z`IfTS2);*Wmtuk zSd490i5*vu?O1i?S9YD(Oqhp(byt*)*oht4gymR&wO5f{SAlidlyz8+1zC-iS&PNl zi|tu~^;wObS#`D9jQv@X4cVPlS)z?up~cvgW!aj2*N?r~g`L``ty-iFTAW>4kqy|a zy;!5oS%RI1r|sF6CEBvBSD58lwgp&|ec6)@*@cbUjD^^)z1yqR*^M<@g3VgB?OT~8 zTdCFCzolBSh1#|K+ommBeK6U1mWw3-RkXL+3v`G9bW7O-;%9g`90v{1z+in zUi{tO{B_{(#b50e-uGQ!Ie0UIk|1 z@ZI1OK41whUJ_2;1`gm3Mqu}SVEDaW+HKqwuHN#+;2lQc;=N(qW#1Hz-WoRHB6i>C zbznO6Q*DP8qVMr2Hy)#-!%r~6^3B{ z<=;5QVJWs@7uMh$eq!H6-S$=BD0X2q)?hF;V*#FH=7nB37GfV(;5c^UM5f|0zGDY= zUgv$>$R*tc5M9gdT+Ph`PqqLIFaR3}-3=(+$dv-f?cVVb53V5n#PjUH)`KIxV=X_oeAoknSoUTKN$>1QtK zh8Aj=25Od`>5@L?l@@B84(ggFX{N4eq&DiGcIlYDYM$=sg?4G0ChC}m>7t(Mu!icY zCTp|qXqmogtL|#4*6EaXYp>?&oqp@4PU@2eYp<^8ou2Ejj_bZo>zsybyMAfFzUsDK z>aA{Sq_*n3E^DA}>$Lu9s=n!{=4-uvYqmCQoPKJ(j_klrY^A>Jq5f>ZPVB5cYQh%n z(1vToX6me7?abEfqP}ZdPGwCNT^s1+Q10CS%pK)`7F|>}U1gqalZIu=R&82#X2(8l z$%baS9_`^KXXg%Ts2=L+K5JfHZrFzI>RxTM9_;S6ZtNEA@22k4ChW47?AN~L@UCw6 zPVMhrYT8EY=pJv<#_rkn?y2r<^5$>6KJNFvZ|25t0@b>m@6%T9;=jm9&q=r@90)=^JekqesK~HcYi zMsekaaqbpy^?vFs-|o=%^1VK6A)jym%eHIC#&H_2Yacgr_)haJ?{6)a@AMw>{uXoE zzVR^k>ixvq0bA9OTd?>+ZxmFDh1=XBQwZB6HEN*DDw&v8qa@h?y9 zME`X{-|s-L^<6J^)SmD(FLf4Qbt1>)Og8dT*6k&?fF`$q5g6rCmU4S$_7gX5WB2q> zS94xpbI#^)a9?mdZ*g$X^72-60#9~a|MVGeaawnD69@GZPjyHyb$6HdZVqt>=XMom z_i)GTco*+_PjNxF^f_1eM}K(#M;CN&=J)c3^L`Kach_}yws>UUWrFwgHqZ3GM($S6 z?sm_0j$iXypXY@?d32d5Tu$ zBH!dAPx5Kc15h4;Ip_fkm;=xi=qZ zCvKA$^MqIMA4hwI2lzPW_Z>g;wtwuo=X9elc4f!#1J7`q?|Q+`^_PeBZ})n|7y7TP_<$Rj15&p7 zZI^<+XJ~K7`vf=jo2U4J2YPhJ`pyUcob$_C(NTEjh0;c zlP5@@NMB|Qnsa8+r5bJa&Q;JZM|Jj@t(f}FwR?NH7&+0s25*Xr21 zYmcIR$yTjv)2Kn;m0Ne}&4sU7Gwn*-?#eyhM#xv zk=LJAUZtmBd9!Ur+G_88S6hSRiS?aaV?k%ud>w{Wn}gCZC1FaM>9yAalL2PH9EKe> z!UwZ((TE2gBr(Dq21qs;Ungc3l0Ho>LPv2={nlQ17xoq(dgwK^T!P#k`5SixQpaS6 zWhEEicp-xSHlcIu3Akl}3Hm1@c3B$7C3siT$Do8z@y4ck&h@4qo?zDbCUs7p$!DGl zVu>7-eJ*KdRb{5R-;?r9hv0%>VaO+au;G>=hshBrCWDpU$zg<-28yVGm0xY1N*gVr zbXJ(!e{IEDCxz3xS!jJ@+Bd76+bTt2h_9~crKaV58Yfb-83~h>Y{E+^mVP#wX})ca z`tO?kwin>DRVrB>nFFd>ufpJ_DpPYCjy5Nyt(}>!z0fM$Z)+ba%CE;ATUa5p)0Jtk zaM`N=doX|$!%5bH=6Xyh#oazk@<}J6sGu$K*4qWZ208cx!tn7A;Cf22XOt#hCGT!LDsgjAa+mUabu$-B9DrDg?9h}iEq~bq_^U7~a*{;K}IvjrIdrQx^>2s6+ z&VAi!Pd~li{HbmC{F0QuXO#_R@GGCBmZP!}k*t30TU`0zWw8K7E@TTkT?I#mF?r1m zV*(u0)mG)VR;AB<*~=Qu^w&6OmBb-BlLB9O=Ci}h;SaO$02hEKhD30|MmTa>6D-5L z6wZTc1|-+`26vSLde1G?%A3pFb|8OgOMREi8wbT?xQcjCOCplk-{eN3&~dDEsB&WA z7IiYtZP0*nt6bvZxF<73?`#?Kq89VFF5Ik-h}KgRAQ|;QCK6IoZ!+D!6qi8OsWELU zL?ihQX-7j+(TvzL5V}t2$26|ZRdCDG8)+wyOqc|BeZiGrX!rqP{i+W+j*a5lFF^=J!r87+7R-;ytZ1`8QF4rn93TgE z89qgV&tiz{V+Z9}$#ISlkMaxSIKfE3a5hsuq1+rby?L+q)vt`@lpv|5h@fZEFK}x_ zn+E@9!a9O7n&MLz;k*`2a|v^f!1PwQz}b*en(|gF8cZIRc7rVNkP8}kg0Olp0%OrK zS;~qUL4uSJBSNv5{#0VitO-x@DfF1EDyWyRSH&?R@`PQyV?S>tIsZ9RntSsm67iM)NUko@bM1oY zBQrHSrC!RIXnN=wv35|YiV$*`qgnM}$~SZ#L?8Kxh$(G_%E2%~2S-rMVmuIq9t6(< z$SbKWqw~Bh(vFvUb!p!OO4D=p@3Vh9oL9pNPPw+NvyBWU3ir6$nPSdzp&eH?^|{cx z+E0r3OX~itinl>-^IcJOC{(K_(|ej#RBa6;r097~7M^uv@p~#J!(0DSkp>WDaCJ17p#NvuYmi3(nG%$oe@Sq1bhyo8jFozt`GKeR| z2}|vW)U6hjySBwvXtO#^oZdB<4ZGr8@aag(Q4@7PRc68ZDbsrY8r6yOf)9z=Rz|e` zPkRXbYgLtq+yb)JuV8Bv5!oeO$I&*t_N-VwFU;BZVW_8mb)9oL^;Xb=50Y~QEN>ZH zHTTjL$1i3a#0LA>0a8(n7EVjlYULNe2&Q*`;721S%ZDgj z@>$8nj-Q)!7Q?^v3r01fdOL~Wo5?yL`5XhBnwT|2K!innC7#D z=|*8mx)_+Y1+L5RdR}u5`(>T{@sBM%YkVoy(szb*tiS8JcXpc7v2}M=SAB0QBYbuB zlxUB!i|4T3t<(fRl94GL?jLKJZ5t7&_n2XK~5W^cJ!>q=a>P_Aprz3Wq{zB+8w{np5PJ2{qNx<5^)H(#H= zDul6W1HDfO?T+MK;MJ6q%0@z?1){fzy) zA0x>z&6`2)a6W0m-5-@zpaIZ)U{&C~UBx|I8WEld^4+Ml-o_v($7AQu4{SaoIlx8FtZtdOUky`^+pOanRb-|diwG-6EVFtFC z)@)Ivm6IoNnXNTf@FmsoFjN)XU z>#d*3soeo(AqNg2hDDz4c_1Xh;>t|_nogBg+u5KyrD8fxm2(kZ`bihyks~#-A`yC; z5n>}hCLtf%A__($H^QH(eO3EuTn)-wdyS$xCPaME%FZyG&t%jH^gs^`V-J164LsHd zUkR4m9#g=cKpx-6h4j$k4ZC^J9 zBtg;|5B^~js$Ug074+$zB?8~$aGWM)q}D~+B3j%I+Da#7`3#+VsEDm7L}!jfa$fd6s9@f4trEaQpfQj)o%RE8fA zD&lCZ9StTP*s)q(uAHGw8r=c^QcOkFI5wI#7G?ZNCQ$-jOKoDGVWFnUWK=R7Rg4&E zv0dU};BMjIK3<%0k)l_M+nq6?Bsyj$k|IMEAx#3564DwIK4zAM((17o7-f=d&e%fg znV%e$h$vf%cw~z(LP&Z*2fP4b@`DGM)pF&{c+ z?B$rARVR#TllMj7elFz-_Th1wW>0#ZH6G||q8(cr8c@n!zXhRhx?gH7XCX2rSBB*} zrQUstohfQ1kip$`8eUj3s0tdS`-u!hc4C)&5<&{0aHgirFA4wWYcWZToQ6cXl}TfSIt#^<4YshH}WeS%|@ zN~1;g=7&ZRQU2aVHf0YIXr>~cn^GL@F_ay);ytqHSo)znUSg0m>3n7-b~Y&Z_1diV z2xV9 z3sUQ}IwXF;7mPw@y`5>IxQ1a-q^W5nLd2K1wkeikDR62Ps0O9M!jX|SVy9*)w=SZI z(&e8jRG^;h`Ansf-W?XopcdxCuZCIfcqB%Jp0vqGAGkp&AdLi!l+$d$dY&UEZmPAg zqo=0Zjr9^eZq9w~S@4}|ymCt331U&E=0CP0B6gkD9xJWxB&R}Xn9k%#XyN%)Dcj;r zxa}CpF@(fQo@kovfgUVW!sWSi19?Spk~*s*3#fU6+T106K4AT%%ZIxjsG#IMc+{(&q0@13G@Pbx;YTxTBXR?AVo$9Hb zPG=KdT+Aw7K7wo}+3f1I8YLRv7H)*ko)YHOT#PhADg417B*M*&fCZ@Jv0$o{HYC)t zX-!7|SnXDA9A)FiU}z==<%2TrXF8wn315K1sqUsJo(`FY0+ouwWG1{rVEBL-AHV_l zKpB^@4{%#b5d;HoBptlN0LRxx#@DavgB{O9km!Q~`$I}8Fdi4gD+F>TyaN8xgB19& zVfn)XoG}jIz#0314G_R(*s)>xu}DQ^FkWAt^dJWDyJh zs}(;bXSVY>C*`&NuGa;wtJ<#d>Ta=;ZNuU%{t3bhP=P@oG(y(^CEx%h|FIq8FVAk_ z0KdZnyYe4<>;RjuL1e7=W`+;ofCyB82>3t>h_7Af105WI8`J=Ot*9mWPu2z03AHE6nwM@G_nsM#ZD6h9oT>fRJAED zfMH2NCR5%)L@@mxmd9T3TbeBp^6Gp7GtIte-+3_b+L>Bg=*xCr2}dE*fu(WjCtN|R z-YTm>EGp10%{M&i2Z$6OxQMYd?W?-%5QidWwy=Db>!iEUrB`DTIx zYcd{hWRUp7Dk}mYzyTZtLK&n$CLD4{=z}1rbRfKTYqR!hvvdOxfFNwQ$AUEj@9g+a zUdBmuCis8=z=3PS_94&!Yy-jxQ~(pyawaT58Pq@^-1iFzLi2R>c2l0z=z~8n0S=r1 zAl$bAG=ckSbw0d_Mkfe4v24a z(}5HS!aI2PoTo2?&oX>v!vF3sxIqLd>BB2X!3zXJ4eUT{gE~uJcNX}7O)o-yw{!(C zw?FW)La6WmN&&3r1M@P0bUOeb2mk@BZ%QrrcF($_8wEsf;mG#0T<0!)Ug*{0Wa zB!1wivgc#7;uBN01x4s)Q}L6R^}Zhakn?MVHzG?6gdpexYO}O!*Fb^aHy{84qR%(3 zXq$X3K*ifYqwDe_O$vJD8r4A5~tU_2y4a{qqx5=2JA3qp$cK%Tes3qbM${INwu zw;KQg8%%czR6qp?0H_Z-Ad~<-(1Xe2$^wv*6lktwv~nwh@&Q!968QWn<1qmrmK}pJ z(6@FCIKb4G0dnsEOE1B8696JK0I3H;3DCS0Z1N&60o*$>RtE_T`M?tBx~{uHWNd(5 z=mR~xLkg(;$ER_^8$15a@-0U-oJRP^hA=%>@Zgd-`C+zR&#i`j|2X4znkGH&6t0|! zhd7E47GooX0dqAk_Qf{OxM7gHi`@8}E}!O0`MOJ>kJBdqIIa|W=)bG!;~UtxJI-AoL3mzzn2- z2nc}ozjP{)^!OgY4ji-q96$*m^n0hk3@ktcP{AR<_G%x3LNl~V0mQs~`UD+t14t7f z0ZN#pARr*np&Ef+NO`p&6%~z?a0tpoAfrYqOZ4f>M*zr)8dPeutlrZ;Oxk-XvU}#D>XI{v_KI{2PYgHk_c0fASOy)Xe6p}|Hpw8nP!yG=zxZUrYkGH zq9Y}P0G3u?YJDXopGN{BDu_s7QefVEdin0%YZI_dzkLb+4SaZTV!|~IA9g&Lv17@F z`9@ZJIj~{PlpzcDY4Xu!vF>g+qqlF)7`=%I><#QkNq0B@Zz$GR~C)f zJ$(4E<)ha<+qd%gs(G_t&mO z?X-cU(1(d7sBkKfGE$h~l^IkNM4x$-*kPv{04YI`{}~n#01yXiIH7_RQYZnAK$sFs z$3U{0ArmGL;i;(|1fXFjvEXpyfEgYFWG5O98S4-nG6@VPgWzyLp(f~A+~m8aQf*fCl2Mp@K~4S-{RMPjE`g8h}XQmBv6kfRaEo>FIz4xRSyKA0o9u5CRkl zq=p?%VCs-D?Q%$f8vHzD$Uq$EF@*|RB2p}kUPyr+CU7`tM^;6xK#-gKS)dF+d@bWc z1t*ITLkb<-5W@Ee6js?|4P;ir`zGwqw+7R@w%Et8eb%`7R+E;#X`6K~+-oB&Zo~T2 zTTR3Lpw+gqFAa+>y6G0!z&aZaz<>|%yz36l|6zN}mRoQoOcpbE(bJDS0nH_MTl$DS zj$&t%C2!&b4J=kTaRcPAz;{Dlc3=#t75QLeAH!CI+-x+oY0 z5+;~=w}DoU|d^7=#{LdE>_uwD{@iJ1>TniC^!7!To+ zVQv|~+%N2X~z6CV2dk|8u$9?$yQqcW=4>UuDzdn7gul)4W|jhV%2cSLlr$wQ-~d1n035V*hz0;*2{y|rKVXdst^HA130OGHK;FDhk`L|2!ean~i!yv`VRXynq zGnO4Q*786$OA0!sUenpYb@atAf2}WI-{Yk(!}UO1It+iuBw)k13CsLM%bCg(pSP^F zO6>JVKezOr!i)(_cgE9X&ZDP3rKha>ZA@lT*q~BO2ecqHK!is*S|GAu14!TiYIw>- z2HtixUx)w%u@J@8U?{o+T#XG_D#6ZPu&Np?#2*bQ0hU^_gheo6CN1*I2u)?W&LOP^ zcpv~1^s%P~00K%Uz+#=Y|40K|{U{J{kWm>ZU<3*@^{ERejuhx22vue2g-vmaMwZ|+ zCV-%%daQut=s<@Q*dPOGr2r%#VT7NOX=*T)6_enw5Xl|ot#CL59*h72E8JpCM)E;a zR0lT`(!-U))2DyVQ%iIvZ=DY;-olO-J;k02Vzj*AV#{f~Z|=@u4rAvyDcipV>ThHS z)Mox72u#~3<~h)b=Dnz?zH5eOJR|dFYRlEWCm}l z;!cJdwi+lES0VcF4tN5HLzJNcjY5(>p3|HU38H3X0xGMR(vk{%NFOOE=@&^-l9|mc z1x+{r4k`cyG9ish;&t1Y6ym5F8EuUYXuy;k5I7w<01+Os>Xi?Wt9)h`cp2N@Zog|! z#(sHQ+D)^WPdnK%tJa;NeeOPADd*$5*_QrP88YqnPIg6inA7{`WS(=rd*y3i{p!wl zvZ>1o7I)3oRkL?fMrqG>ma^OZn5L`y=jnph(Wz|SdhmJYXTC3f+pP1XiC1ZUKGV3g z+>1cRTRJ!F{{Ytxpu!89V3JG>*v3ZS;T{Qv1Brk|Yqg3ZBLOS`8_Yl-H#Aj&OCp7p z^4LdTvJBb|q6s5aAgvXE(NerdG(MS_!zX&k7U6)aqRo)ME_q3h&WK7uyaL8Ps6eQo zMg<}ztqHGq1tfMXswHq`W|gXd8?3U$tW7D)uV6ycuvVrScm&FUlSm-8D3&XF1VjW- z!cHB$PFG7-(7e58{>&-PR9kjp>!P!#Gu=x`YgW$K4YSQP7Ct@?SIs~N=bDAvXPwJ4 zIL)a^p{0Yq>(~}N?(_MpCB}2#wmg^hEBf>Hm-9~JQ=Vcj`pl93YCZq%mDd}ynNfCg z2-Y0T|E%Wj$v6Av!-_rD(uiLz35XG>2G=mCABrJgd1TX-hcwfbB23Av{ zvoB837%A-)IlgvF7o00?3uJ^$HsQq!l7$-RqLdB!>9L1ur#0b8%aT`o>2zeq2gxiG znMje37T^OMyx;`>)=@)GspE*)m{0=c6%=LUD+x=j%lKAYnea^qC_4Z~9H(&OPj&C- z2pp9Yy!zLBerc4OpMJi@`OXm-cU=y8>hloR3@T_`CM82*Ucf)NXZ}Tl&=Aj?}_$ z=?o2Du47;PrP1*0(TJ&+k}Cj*4!D?!&km@!0ub!P@BdWkoZ2asAWcE+ue)~c=;rQy z|ELS=KF#gGEY<*u#RiJWOyuGuM{)}76@CP0cAyLbCut5~a+)Sn6v7Ig%Bh@6XQY7H zChyq<;f7*l2b4hftc|4t!KE@G1#XYqD$d!ga0ZkBM|5N)nBYdx?GOsj3nQuB1mPXf z1OyJC0$unyF2}a>>c0#a_M8{r_3Zo(uaw3IbWCuzh z58o!F++eUkLGcFiq!zPJT2^fn<^EI!)+!%eXvH6K+7*0!_XF>I-YJ0|DrCp zlw$?E1=2o-6`8AlzUde#=o-C;l``1BLz#~tgUlIWd~jW5e8xzv(Vcd-~}pR31DPPu7*mO zKni|pCsg7DOfO16jBb)*EndI~jDT}QB@i0mLu%r1lB5DoU`!-}5=vm-G(r<(L@9HR z2}){AT0#I`z>k(d-UOg7cnHZRF(;U$Dcqn8Vj>ebGDh40+)BU=|A+$f(rAWGY5@?7 zHOrCA_OdiZZD8Ck7X2*d<_7{>t1@AZv%Ya%;%@x_5Y#r)0oSs$%rThS>@Mpm8P9Gn zw5`x&tLdH*J0KIcHtR)0(ErjYfVQ#xXp^|+FR?(aM$e4=(hly}%F7|>yp^aPPK7==+yRgJW2(Jgb7 z0|f{%7bG8UP#@WdRj$lY9gMy-)Vu^hgm&^jJLgtw?^R~TYH}pNq_c^V#s}s`AB<*I zoW@H^&NdatWW(Z%PRa)6DB6yupmtyqw8X}+vQAi4OA6|1N-i%l;T=9IXlIsY?}9my zHE44LcKGCL1Az)i3~93Bl<={nOsYhr^`mYI*)EJ||72&B7KJGN0hQPiHX(KxHMW~_ zv15M}|BPo9CGY}aQ7>Ecm)6u9kF>t#U?ULzhLnH=mop2nF{xC2qz=3m_b??l zG}|$_>~e4wHeuP+Vk=9QI5u|2bT;d5w0v>@94&AKuwv(KPS3O+iS%rkKoN#@`+TKK z%*G?6?eS{hRSKmhSWJz!ZwERe_eN6jC~uxtCNjYWUf>Ws$N})? z6~;*W^zHxx2@uY69$2J~4#Fo#;U@G!f*sFS|9HevYJwh`K#R8bL(tNKTGK@Zwi*RC zFX>S(b5}Lv?EUak{?K({83-7cbYnC3(m+;m&n``MlrJN8cN-+O=%winunDq5GBuVp z*R^0_^kWeg{do9>n-p7rOEg_E)N1iGnJYD8lmcD2g{?78efLEvGi2?e!B> z>TsUaA$$N7DZmF7OfSTD0rs#03Yl$~fH^#30s5E%lt7?zObL|0j|m_J-q#<@ijgUx zk~hN&B{`GrcmkNfAC~bQ=s*eR0^Cwy6bQfv>iB=hmI(+T0}9!YcZx+*BN0=80t$Hv zdKuhEjwbjM#u!-%Qs5m3q9OB8lPg7M{~FnSVR>hCX5{vB9vZ?2Q2CdcKoFXvr)}x3#fc7ji#SUL)5Yi}Zzu(E@w;E^WB%_EIy* z2Q6m{U#i0Zq^^xi(?>DTxqw($z|>7$SM0=5c9pcD)7brR(VlhJhry?J!-;ZTICyDS zvxs+V2SOimPo;G)_vR*#WoCL^8h!V|HxoFeGhvEKBABOFr85sYa9a0LT5E5DrSUgC ze5|K?TBb4srExm*oO*72Ix>X1B#fGkWd^B%T5F2~sRd3ibnmH4;-+u!%>IV8R#m|S!CFVOOSB` z?Lf%+GiE9um~OUaa*B6&neZ|m=@g{X7=|C0q0to0FiS0g3!v+9KyK93M24BDy|8H0N{nER!f+P7QuwFS3}8?bOu zF1FR#j9)jh8vC77FrK-1p2M}C>A9JXG=MLAzWv%50USxWlp1;4d}eDpNY`{#drO7) zP1iWV7Z$MD*`CXkh#hya|G)T$6*{Cl8>IQ0M)Qxg4>ooCJBjZDTCke{XGu$ayL3ZR zo6!5Tt-G(m1YX1Mxn=b;wwrwZqI_yIL(oO(9HT{!{4t&sGL~GnS3JLaSI@3a{r)UQ z3%gENcf{)wWH&sAhjQOZgh25tlFIrF6s2B!WCQ9Q-w)I|Ps0 zwL4YHr;atY`?iaR8l`)BPhBu9Jz8KoU1nU!Uu$}s`^NoZy%TsgM7xdWG+;3{HQPM1 z?fb>qS)I0PpYhvH|Nng0xqOHf{O1a&%G(vebJ(B9nEWzh#^*dB5jw@&uEI&0?YumP zHJsV?oJ?i2l~O#!v3#&mZE`yr)qB07;rq_*-O#nX*n1emeN8x##XYsDPyy=(Su}OXw5m)R1y>WZ=+}YBG)mgx! z9p#DTocH_d|Gl*Tmg`#>CbAz~!qFM&{Y>0d7sJb4H94NemH6lb|6@5@9^ZXl!&G%2 z-RK!TTZO*sOS_HPvNto_U?=34TY7 z9nQ(W?khj+0b*W0fdmH*oL4ZR!Gs7KI($eF;X#EICrWHMaiPYF7#TuzxbdRMh#WVX zB$=_}|HzaVPkwy3aHUF$FJpR?*|OuwkRVaQ^vIIr%aJ`H+O$b@Xi1+IXCjm`ZxJ1x zOL;a`>J#V9omFZ6GDpV}jw0qz79olxT zV5&Un`sFBdZQZyQ0|%bz5;EhZh$V~7S+gfv$!Q52&fHmU(!_Q@h8~Q%@6p4BGh=p( z`molyt4Gr|OV_}mS1&EFhf=)HDXahl0jU0vS| z|AyRZSDDw`Z0{Y2S9Exl$IyeGImq8z>;c$beGvBdp} z8*?a*N8M{8vbdmtVA*I}dg1x#kUmo3nA?IF`gRa^PWEOUlm`aMfV<#a=D+Tg(@a!q>SR(D2$NyncS2y-bNut`Q(!c zLf8RFXP7V|`X`O8){5bURoc1gda1R?+nFjYiXe-hZCDzcO47P2vc__%B8ZXd|2SrW zCZ4Qjn&Pg^uE}7#6Z&~#j^I`)?WUUI zTd1k&a(F3+1Y_Ikt<^b-YM?@n*xN!zP6e;8!x|j$w6^&xCZW0+OrW?E%S)}Lx#H?6 zvG~<0XS^P>iR-=T%FJ$^hAJE~aWJn7EV6?-wXk}%4HWCEdIH*P$-OqsuC_I&T$#}M zI!&d?r)C{0)KYIbGN$0Q45zcCZfb9!Zc6+q&?*jGHLBzayYR!?_B89*Hbdy})N#98 zVXASHj3vs#=BqNL!Qu>N-vz(Rbi;n{U3karfoyHFYi}jvj$G4yxORMt{|&jIL@7Ow zxi|NFw#F?I8Mx(HDy}z)OJ^MUyg%!_dyB;;%dd;SdTV&s;qED#l{2e)yRvq(jd0U< zV$IW$!hb6;XnAt`HKbGl_ej5`H_5vm$8AT9c49s4d(lH` zSPyKW(FdA*qK}xmRH4%{h)nTkNID{~n@*eECBqp~NYcw!9W^B@tH{NAHu6y}+vMmv ziBm1!ucqDdN&hm-aJtl|_hU33}Snrfvb86+~B4CzRBptDmElEkV7C*%}THoJMV^4jn1g zQ6>_rf9=sXk9bKnjuD}|P8r6pQ5sVPghZHIRhzz_UBQlLC(q#Gy$?8J{fT%!<6M|xb zr1-Tlja7-0R$_g;0wMYUu?S``)0tW<#wV8PL24{hg3hDFbHgC#d>Tss0`hw^w9@BsmQP=RO%y9C7cK?*#~1o$rbRRm~v z2Fwj#L8L$l&`tpzGO=0p9)JQ&@G2b$Z~$F1L3N(?rbQ137i>;RgC`RN2zh5`FoTkxe7pjHL<$;^c?azK_opAl z0t8@pK*&GX_=f`^8ejtgKzK8-|94ri0HYuP0-$uGMrDphaZ}ejZPjWX=TMx+U=lM( zr)Gf+w^z;gQDyU2CR9x2v~dddH`~Na6&Hdk^lFVI6mJ(|nUFO3Z~#D%0Y)GKflvXN zPyvAu1x9cHOJD;j(1UnD0OuAfOi%$-AOd}m0aQ={AbeokO6&w z2UIY6QwRhU@PvwRgdk>wOwa_5z<68rDiz=W888YNKnaMT4>%wI82|zl0EOgN10^sD zM(_e9AO-hV0Y(4I9QA-6~9(ZMt z7DW)48#2gdC-4GGPy!{e{{v762{zyc0Em9{(LUL7~M1oxg ziP@Na4Hjx+c8=ZR|BhI9YHU>&*wu@5r+9TIbHO%?wde*8fCDzL0Q2w)QqTYcNB{!h z1|KO14Ip~=H-Li%Vhu0@%_w4mU<1pzWFyspuk?Wb6<{vdNK)yD4n}GSCRL6TQRet* z(NdLRc7dhV7K9~8B*ZI#rGmUP4~(Ub9rj@{=vn#@fK)&UJJ4d9wS<&las;qqEhc38 zpacy-1zF$*Vju=3umB-h1{t6Tx<>&uPy=G%2)>B}MCb^3CIuxR0DsnlA|QioIa3a? z1Qo!N3s43<`2x+E2~2QjXr3l=g!; zmw1#>sfk9(|A~+2iG}4`4(M?uI8H_bSk*^3j_uY80eXb%dB%7Zq%0nV12C888Eb=3$AK0a9R)6(9w#A_c-` zn_v23UbT=e>JL)T1Wf>6IIshTumizI0K~Qc@6eA&R{@j&oiAW~ui#@q77?$75ZgI$ z1fU4uxq8@90X5kG=$VrlFr6M&h)|&`X~bU`g-I85T>lj=C)1QjwTVzUT{t>d52bB7A11F%O`S6y17MF7gXbo@(8Gx57 z>Q#_X1}6Xn0#E`2Ck2HFIberh18RyB=u48un9lP~W(Jv-*raepnH=|E@r0SWgq==ldS=knf;c1;O;UszZ~)2(lYn3a1VCM z|E1McFOT$7W|p4{8FFqa2ux4{HLwJ+=mrfi3J2f@FJJ^wFpDVp0)a4{i_m!jAOdyk zlLDZks>1{a@OfF_1A>qV3y=y1IG@@1G$J%Z-cZx;xy+qy5{r8Q7@SfGP~Fn7pF1wcRm+0~38 z)>U2QdVQA)P4Etb+j%RAkWHWnty=?($9Ys>10X7Af93Nd z1M;>6vP-rLK!DSU9pDwcHgE#2yMrbMq{Ne>0t%0v*tD6uln~WBcXeiwM74~o|7p{= zeM-BkksG>=d%0XW7K2uRHXws>Mg?@{1G+j2?*|C}2e|hJb2WgrQlJPI3zPqy5t}BNVTp z7`duum82m|5IrvweFWb?3D8DMNu;1BsA z2n(Q=>ZT71z{L$q4}#EcVd@VA(6C|4izqv$E>~ZLxNG?!1(qiW^2WvRhHvYo5B}hj z(&lVtOaKGtnBdA(a%EjpNn9nuwEv4s+!}QOYNS(J$!CWm#`RI#sz?-g|5f_wGKow8 z()L~iU;~lN#*yp~n`)NyDp3V9$3@m&<8H!f4~8F43h@R2rGbk~)Gr z&(ro^f9Ul{xHXan-BiLW3aMg^H8m+6L(_zT03T`BUY^`rZg_)VLFzb zm1Sgt8!P4|SBsI!31Hj zT1>8LWid@OXUby|ZP7M`kc8@061`+2J#7eKcmv^58*F?nYiK-1|Cmi|m=u?}Gkiic z-IzrCV3HVqz@*9GOo}_)K1$rG{d=Q3978B*I;@tduEr|(2ov!2D*CL(YCK}_WiBQb z(qZ~uf$dV}MG`X=rU>m)hL)Y8HPKx)Vi#Qy=!H6z#nA#`*XKoFlts~^MW}T}$)60h zrV2um``JbdNCRcI6$!| zOJC@+Xww(Xnt7_U1Hh!4&6pd%0Yspsn8TJvl&qRy+$xUI2fE2Zm|~r2Nm|?ND5dsz zA)sPYUPahy{1JA25SCh6=rtFXY8sZ+vJD|xAYoZVVc)$y|HhOB;MqyvlxxJ;9oH&N zu2$2T-uKcAs?!Je$y}}0Hhq~+DciaOs-pP0iN)Jjov(-s6Q2bV3BBJlSU=b*uB)BW zQ!~yI-dvOX!xOj4bR}Rs1=_dHfmZ3Jks*kIf>6&3N1Ku3iqh-D6_Io<2 zWD!c{)RDcJn3(C=s^T@x;%?pCm*REcF5^T@Qe$o7)GkabsN+nE+SF6*M@;8zKHl!a z#89IckLAEJ*x{>QVcs z?ZW{akIC*Ppr&7ArQ#z8)PXIyS-NB_I#Y_BV%Pc6gT~BoAEOlg(SBWMQyr#GTw+Mg%r`ZdeZ6QS{aQa< z;O6Xo^$Vt-&ZY3fBD{>;yAwOz~nlcKiwO(q|0>j z=8mr^E?juN?lo?X?k>8Jo|$(JYhiu$X9Sv1C-ibnN2??daAyM@RD@kRl%HV02jEoCj2jHYuQ$9B-(4g)^D3t0XTrNbf6C@z+Uua zF70+}16jz1TyOWrTKdLsi%fn2w`=E>|F7jbssJ%h;6Q@;<{3nIP+>xb3mrBj7_p#4 ziWMmu6o^q_MvD;}ejKQ=BgBdzO+G{ka-ztNEnU8Rc~a#@k2E#jbm)>KN0}*U+WdJj zCrq3xefDHolq1iOKb49^8nk57olTiCjhgi+OsZS8vb0(gEZ3MQmwFBQ6ewA=B-LVV zJM`^Zpfg9(Rhw`s&ZJ@W?u~mE?pdXGC64|37j9yyY|YMFL}zeU#T)fWsSqfGpbCHr z1p)-9f*^YSG6|v(2u|ogiU_0-Q6n@U3JV0V7GQ%8X3&5(1sW}4H6SWJ2sEe>sKyck zuY9-(q};VW5xr~RU?K&`3j+Ew|4F&L1kjotR7wz-kpc*n8a05Vm_eb20|CiJ=%Zuf z1fW0ylz5-WF9ECKN-M|MiYl%I@uKXpvKAZ4sLBo`OR=vM#IUCW`ASQ`!?yZxEClI- z5G(`hqEM)!7z^+!21h(eFtJE%EJYa6veBZMs=9DNp=7*kF2VwHY%UQ;95P87L-eUd zAsg(=C?z4>u&WQ1)bKGLXVh`V9)+5L3Bbk_=(5f-c%=e3%E%yt9kS5PyG$}j4hI4% zprV2le4t{73^k2+2jV!*rummqjNB z#1UI6YjW}3X|*L+Uu_ZlHpduI9QfM8u)Xlw6311TLA%Z^m%}3&gO|g88E&v)!|>&D z-5mq2aHzWX0S~(8>GmjRaB)IXxSx}$XO8)q<8^omS0#v2?2bV zVFnRiXd(jv4nP$L|3%`I(a3dg%raar_nkK4lKK6y-fab!79)QN_qN?Fr#!r|2}725 z;mSXDv093q!q=^G%gS{O$mF*m9*<)d^Bu+}^Q5V$OG+Lyqu@v~GUk~JBl^h4nO-3^G%-O?y2(U7Uh$|B zWP%P&2q5?lz=TXt01ge{*#dk5{>4=Of0|Fmhxh z-h)=xIUI7)nNMtC$b87gX+|@OG>XxehEzq>QPW+gn;pb-_`D8PbBa*3k@1lCIBAj- zo$c)A{}3r>yWI6|cW{Iu6VFMxG8Twr{gfx|g!s3<(6c7a3*8G9f*F*h31yk^pKe&` zoc2_}2L!|!_~!SD6bPyU6u{Ga7LW=myx;{?5RE>LrVn~Z!K6mWKo)R-nOt282Tf2! z2`FHMGSt8af*4zO4uZ#9_Nok>JU|vQV1%2^!v~Xqo7~uDn=XNT&)6kyp+~H&Jq`L7IasCz^Krap$UR`MWFa6id7yUrk<2!a%xb9|M&n7(WwE{@;IF9Fku1v z@xd#;gGV5cEolwlRY{fWT{p>+gD+^GerAJ%d@L)meoaxrnn~EmdC{AIJ?$3Xx;gq1 zHl7*lXBsb8P-}v-zjp;!<`yctGk$ZOgWK$W|M{@^)~l|EU7|fv*kB6tGp+iREXb62 zJ0dRFpQ7E^fGsP!&;2e!4fXFs#biW@4uk*{NI^bsoMS<_l54EYME3AN03T!^1@xd9 zs048kdZeIDMoypytq_Y?94#Lys7)YGv!@LBAO(WZM+&H#0VSkBOiUm^n+Pzo|9sd0 z$AMJH0tmph6cAtm`49vXitGa>2%>_o$;UgsX2>-EDFyndB|r@9$NPO&y zyBJ~~Qud9Iy{w`w=1@-uc-5bcBZ5;mN6BE(js%g@JYIpvGPNon*Pc^MUtz+HQoGuo z6v!bDF*O42AiJ3W_qE&WNko@PPKgF`yA3k!W`zXN2%+}6J$db=V!OQxLG-loxM}!W zkz@)u5+oT*Tq-eVKn~T(~UFdYw}#kY)BW@F{eK}Zc?nzo`Lw3^J}tghHO833{~Qmt_A5SEvBEmS zfzLeiuXy3~Yo7a@{XWSP?|KlE{+*|dbjeIi|A_|{*gbcm{o5;7`w)ntz7bmpZv#7j zJ3XtzH*^s@b8;NhvO41{yM=%=gowa}NV~clwR|e8Skt@po1Ms-x!SY74nseF8oc)^ zy>G%e(Ly7^yC?GVJTcm^oq#;$bGci)J{1Hx5KO#TbH0$1v<7QH8$6N!+co=RIOsdQ z7bHB@o4z6fJ@_j+*qcJjc`MqZInxUmfH6LsfV1G6K-D8dsHlhybeuA@I?rOG4KpXq zJ2>S_K`;a(`2#@P8^JsLyZ_3*CD}gM>At-CKGvxb-nqig|58F4GCzC@yym;VCOkYz z%&^fa!GnUU57Q=@%R&USxo7*e6O1{^)3p`@un(+4Lmavpdq0$Gh(u$^=zdr#2$K*c(1X z^uk8$IAkNZ;ZsDzNTJtL!&B2iEW|^hGsYk6#LPm+)q6!8632)GL{St(lPjonjKO#W zHSkNLbwsrwR6&tzIrKY56okcWEXI`+wUnejOyop^|FSRfteYFfEVN0G%){E* zLjkl$6D+_PL$QPkK#H5dN|VOH5R#^}kR|CzePld^gT`0u!p>7gpd`hQw7zGYuXpT8 zpQA?ov!Xe~M9w)v1jIFE+qjuDwVgAgi+sp(biZMAFiNyRoy<5xWWpsxsK^6DIW)`A zLPCurM8h<^*8?rb^vB02t@d-wfg~9hA{wv5W;>bj_LUMG*c&W%5!@uBROO~ukw1UJwd`Yk*!FdW!n4BTLQ%e>Mv5a&= z5sSzC>p>X9$)Ai(o~z4Lbje0^tD{uTx%458|4g<~tg9*Mz+5CmoO8*UoXE@DFOU4o z+WgA4lsK_0Ile^Cr98{;jL6&U%k&h%#T>sUwJXA-W(@T@IPg`TSt~AQQ zWWAfD$m0x3l*BB;6wGhTN6*s28H`Uml+0$ULpZz`qx;Rwl)YV)PLgcN#H`BDyUXhv zp3p3?)I`u_JJ361P7lOIRx8ih6i&H3N9DZ1QWHuBJnOvd}fPT#cBFg49W|7<*#Bc~mt!|MbX(6UR^%+Y{6RQX)2BMnE| zWX}r~Qh3BlLKRSYtQbrc#7E>mEp$OHtk0P!ttV~D5|dTCL&Fs<)GOr8Q?*fyTu+E} zO}G?I997SkV@(?URVw^YARR!mq|6ip)L><(oXojUB|bCl$F1B>P8}EGl+v_(Kf`=b z>C=(`-A@YL(&vOZfof4Ooj-UAOrKNHJ&aH^bwx^LzemJJ6?4=iG>f^^uzTUtYlOIN zwaB>2M1u9nKMhp8GT2oe)k$=*W1Z36JX44bQ5;oLXS2+(dZsGea z&&OoluWdA$jZ~Vw*1o;j1dYi-+?X=8)r8ecv4y`nJ=(|ZSfq7R)pa;*6c*iw~R zg?m~EtyHX~!E)T!e!N&%Z6dryS3vtwc&qOySMi>uuFf4cM4tU&xJI$+b_)EmS5INmZLr&23x~ z{3mZrN6?kj1C7~&-8|KWS=23AQ>9J~ZP3AVJc$A}QiV~J%SzkzP}$90i(L>pBHk_3 zTG=c%?rmS1)K(@PHebC_V{O}lv*6}k&FA&t=zZZ_&DCf6LhLi(B5v2-EZt6Qy_$92 zPixJ4C0_yt*X149B%RI^Uf+!M%js3Lxy7&1^wgo;-@NTqY~foQR@c2;oZ;2j&;`f{ zwp?;0-|iht#XQ)I|6JgzZQ!u|R0xjUo-JT2%{39`!v`DA7n@BEwqNLFxg`!^BIeka zrPbnGV?$13p>^ZKd{a^8T<4Qv$mGZJCE5{{Rv@Otw_ zJyaIgVx81d^wFU8zeOG8VYN!LomFRDQpo(tEw14u_7Uj)U&Iw-V#M6BmDx*7<06*c zjhy2SjXyZHTQkMmO`+C?tp$@ODZ zmf&M1XqOJOx)bM)loX+{C{(h}~^`md0nYLLbZcSz0Wo8Cll_ScZhUP$a zR*XhO-;CHtGmwq0=P>?OaBfHhmgUJ)Vdu=vP>k1=2H@>%=W%^!izei$nCG6JYE8}J z4qjLJ++$0%O{%_NZI-xH9Ug+#TZ2B}h)(FrU1$-F<-MNe{Mt|>1ZGo|Ya%x2O`FtE zUOuZeTf5Cvw|(7`#?WOR*ZO>AmIhIOcBog4=b2tzU<70D9pK(o$4uqq#I9JTM&ZE| zYV<|si>6!8hGN;KV4c;urjBd79>U0!YA#0H-0oj#rs97UXw$1;c12@&q~}sbYULT@ z+GgkZ|8?j3Rcq#+h_zHm?-vbe zw(@QM{#?ZYW^gpnVvXz{O=ij-TFY*3?M~URHfE8gtXP&prp4w{Wogv5=3s{D6~2*h zh9VUuLh1fw@B3xIqhwap(J`gO+qPGthU^;UZQ9iEtqxfptYVjj>hOzXAx7>&cJa=n za2t2-OqArsg>RT_&g%Z^ksRfHDsi*sZnXAp0M=3QPGa4>U;R99eZE2AMo+!=^6Y)@ zGrnfzop1WC?|Wp~!mMJ(?r#Dq+k~-gkc8-Fe(cz$&!lc*2LIvj&2Q^A@>5<}2=^ul z|Mx+L73tqi);R>w(r&iX-omD3)3^4~oObAFy>zk7ZN*h_H}BdOSMEKB@uP;;0AoO$ zzZsW7;1*F22VodY^W)BDMh^AD?&9(tU{P=0uNME zwCZ*4=!AY`7;p9w*7eP{zcMoPa1C-MulCzrWiCEi9M0<+8)|$t>2tPpMUKnazV&in zb(G##Y}ef%fAQVsbs3-K_`Y$pe0D@;^{ljacFgyoUUzn4Z+2wiw2f9`J92WS?owZJ zbN`>~^9%4NmT2J3+a*4Bz$<7De{2Ze=gWq69sP5L{^FH)TzW3iZ1-`5=5{tG(r@4I zV`Jh!26sH(*!^aByjFMJPWX0D!i}f-Ne0zH=WKaA=aeS;^ga5(rORv264QS6rbcBD zKPVA5Z#d@jq@Q{xonL~ktWl09(|n8U#yqyL|*oRDr=i=T7T|Ufad9H$8op+d!-L- z7#3Ch-fD^-Z$(FU`PKVr#&^+$eCp+TcGpOcmiD`D{hd}>dY90GulqyS_RfdpmjA9y zV+Ht)A6A*B`wWGBd@k=NPuxw9#J-2;kVpMcuU?}j{NDb^{zLrcRs1q1O~bZ5+HHQ3 z=T(51CvYIadHDw-rSmaGUK~=5jUo+*>K;vEc?#1Tu~_BycbEkE!}o>>a1`j6aW5GI0V7yDigy|-i0Z$D2Do1OUZ=+wP~?`>DN zQS3K8+cZx1@ay7iC0l>KUhCt@$!ANC@BX{$-r=ApU`6i6|eR|xUPGS~VXrcNTX^DcO>Sn2}3RvEhO`>^M znYG^6=dD-Ds$!e2+2>-0jp~J5rHWz|Vq~;VDJr2scIj4aY3BH9cmE;Fr=)KNdK+_+ zW*aV;-~k!yiq7UbW^9hiH|wN^YO5)$nL?{7yF6a#ZhxG)Ybkl<##bJ9I`3g@{?V*hpXbp_*ksIfQ33$nS& z`Y@GJ!-t6hRraes|KAmv3kaxEz&l^88y#P8{N09e5xwfHvD-P?Sa<+Xp%Hwve^2YrR`|HmF1B*A+RD0|z==rrRa*!h?*PU|=v*gFW&O77`-|Xn%Qww)yWzTO4bn%V9 z>@w?QCr>H$vs)`@w@<&Tx9pcEEH$QosxINLVHSOI^>2d>tk!kon~>QFq3t^A)JN`c z!&49b)U~wlQLcLsJD=Jt7Q6=@Fm)(;+rzMjw+`XYWdG{}oaH{|J&yfLfmO<1|9&?) ze$`G|nls+kObEa95f4=_q~HX56+*`~seO9eUg_i(vyo(sh1~Jov`A+|)cJ2dg%cX` zAZWhfH48wxR*ipVB7J~Bo0lb{@DDMJ|6t%sw7yM1pumO_i`e?YSBfN%c4R(b1Eb=*AESl=%X}!^jvsh$=q?OF3O5C}s znRm3Mt`sIlL=u#Q*;Hf1ZrQnnwt5wVE3G8>&dMB95sH z{i9t=YBWLu&Rf+}XhZi3Qr^rIU1%+3RsUt_veFXhv$F)7EKOrLqsBt_srKaNm$b^lovCb`^h{;oK0C%g_3fh9jpaj|HokCf_KB<2 zU|eB|C4FWIko}A=s4^GO0Ls^^)-&jGnLAnmx^|)bgA^}A7fGrvcfKBttbdv7NXrh4 zwWj@KIh{%@ZK9KIBUFuYeHYr5A_=uA)ahb9=iCK0H$ZC@9BnmAVvTC@t-7@=ZznpC zq5coSt~?W6*O)35M>C}jP8j*78vorRm#?LLt#0Cb8cWBTPVO<-dgFw$ zdD-e+udTP0Dc;k2tL8p_K9+DIHY~Ml2HGhj1h5{?XaGAD;KGjbw&~?Al3Ao+F1m5Z zl6^2oFS|DaBkafMt+RANdFUwJP{&%%>@c6ZNV=+3sqZ}TM%&wD(W#KQE^e4#Qrc4~ z|FpJ?_AZV!E$K2RTEsvObED_g<1hq1y+sJZDl-GVv zvxS=~Xa{q!h7o?WuMwKSdjB)}*1A@#vLoHw51RGTg4{8Oy-H}$`qI;Rg>a~OOkGf; za*o?gwPri~vQ`sZ-rV#zKK=ddH~0G9nD!O8VcctxSKHcdX7a=lj^~R;x#i>y@}8Z^ zY`cBAw5`&nwC4!%?&MbHWBwGZH9kT+ds*jVzB6CR9nn(C+1~grGP_4iY0U{c-Y=(U zJc%81mD4%j6z8k9LoC~=0({jV-m=>p9$gI!Jh}Bv?TechVpOMKD)T*Pf2oBw4ubuZk^{PaSUaO4Zlas(feq(Fu<-$_06#BzGxyLax2hmWw)#~)s& zo^hc`|8>~?maBoD*jV1R6`=G9ll4{Ey>VXjb>9F^-}SK!{w3S4{hsD^oM6FTSXq}x z1)n@Y&!4ww}dVAO<K5?WgO*YD0^$zR)68*P z={cc*EnuDiQ(1wK1bX1l37_)8*$~-S2^w8&{gVNP+x#(I@5#|V0hpKZ+3@*MNlBrl zMMd&C;xzSO4E|uy`II3tRv=cED86A5vf>hMAId4<(%_*Kmg4yFVq2Y*7{VgYiPzPw zSw6X6+nE^PX^-I5+%E1LjZss;P1qXppWz|n69S+X5}^!I7)%MFryL@p;o>!(pOMjG zI65HrVbLm@UHHuzI4vF{av;399wbhpJWkqJ99-?un=C3_?hWG7{o&yi;y_*ED6-gn zHQ_0OU;iqin;rBhH#o-?`TBJ7qlr`$1H^Lz}w&TwMn~&|>g`Fc1rehyU z9ZD{x$m!L^z2G!D;{|%(+btplv7R#SV@QG^SN0bcbzww((G8$(z zAY6JRDgM_L@g?3(h7Lj}RAJ<_X(V83U}J_{aMq#`dR$fZ=08HFNlGSCI;9+z*=0(a zOV+0;8DpRgXyy1}`gtKxsU_nWmi(Efuze@@apTIdX4tvr3mPSDM&E2oClxwOQ{JIc zLZ!Vl3*Y>8)M`Gq%66ajaWP73|Skh>7isOy)BMzqBx@;kMMrOl#YUORBc2?k+ zfg;q=r_Dv&2DRD9WvMZuXPn|AeGTS+`Xfi)YFAQfG{!1#f@$z*pMH|*uYzT!E?HuZ z6^8j~7S?H&>8kC_DaO6wgK}w}?q^)_X`{YaBC1y<32LLBmSq^~u-;LuscHsJD!SI` zv3kq6swlfIWs53gt9IsbGAn3wD%_o=Ee`CIlB%)VroMd}J0=~rd0Gp)D*vyBVyr%? zV^Q6)Se;ucSCmRBNpfAUqA3@;Rjnc5q3UGtAuPQPtci{3o^5JEIV+^e=TTx{n^IA= zPS~|#D#J0TqXrVU&Z@UAE4a4UZEj{^u4!K=`bz-2(`X;=V zEY#NKRk`SPnrQ4@=_4+m#+oO^a?fO)-v5OqYA)>M5v9XMEWg6gt1_WklBmUUTCEbG zluAmj9_xBm9HKrduu5szaxLc+E8Al2bF!?mx@@qHXup;Wi~8(P+H4g;pvi@44I(N| z@@RIJ*N}$ZgrZ!ZeqqxBDmihS8ug$&SGn*>h3-csI>)Y9Z4O8>YQAXnI}5k>>{ZOJ{+xjuHlB1#c*ukQYm{{ zX~zbkkoxZ5b!qc1?*=BA!cyoMaTn!gQ8*6oiKedXmg==mQjvOFX^QTPiOoL-Ri(&;J{B>at`o)T>xYGoQyasSe?E(p7B8N+TIPDliQ zs)$nNfod%Vx331{r4e`VuYE1Q-s~`%X9)+a!r`qFJK+i|+4EAHtm^IbA|&s9?)4t& zcODyV?QQp-Z$gfUDkfl7*$i7msd)erwi>aZoB;3|Ah>Y^dTW3XUNb*S75#`xw!+m;zD$ z@r!bVo0{#s0P+&+?Ix?NuhQ}A_+*#nCTSuU^+N3Y*{uz~A00{+v&WM0 zF7hlWtFasp>nAc&HlFgm=4T9^gn#@;33o@^KGrIY&eNAMSlPBf`r>=To-A{Zur&pK5)?<8px@SYa!HB)JY8DL0PsO?&bU?X?+x+?`gG%`K2~1@WhUKgSXU*_f)@IOKbH=qBn-)c%{arbr-in+o()$xWEQC6W8~s-gk0) z_S?DePSrKik@h;*t$>p?>(Jh6%kvHP+W&%EHA_xxrHQIq((jNfrf%=yg#)KA{q~as zxIjxd3HG9Yi}*kLqL$h+MgMP#FX@U4tw!TDN3W*V%6RQ+_c~5f5DhkAkD5xCs@0lz zG%vQ!;`Z;_BSnp4!ABP&qP^-V{yMb|5B6Z;2=vWWvaF84DEi8xa4 z_1YO)F{{>+A0$ZowY)yijkmR=8|_Z#k`ZIsZw>B(Cf54c;BE!@F$%y1t9Lnmao+7rV0`yEkXJ zL67>Gu5D0bHm9T4qVIWHQ@g9{=Cz}EPJ8mJQ}@swx@ubJvNx<~Z8u3m`m}%5q#O2| z&#|~GcBBUEygxR3+w{Hrt@eK9pt&WNC9L>H*2^*#BA=kKXQ;OSx0b^f!@D!JLi~8n zGl)_=_L<{sAKe|_oUSXqb2POne|*N*qOvP&M!8p?|h@T&axL%0Q&Bf3w`GQ zX_7Ox68CrdPjl!meUaPyuxnWJH#W&)6&VW5 z2=QS@j~_vL#CVb9$c-8;hE!?rRGcK$;Q<>S8iRK z2aCqkOLy*CzkdPywf}qdDB7}714|vOSnb-ykNFnHnV2P9%aAcgzDqf!Tg`Ual03^Z zFXypSA@fvic=GAeuRB+^DwVWpyrK=Ct}NTKZI>h$(FvWIcw>d1rFQzM(_s z3VSx^;@3ZC$1ZlZQstMm;|}W_dHA5wo5x0oeL8LQ@6B&+3LmTMsiWh|z3+HG?7h6X zTCFtCoKwm_@YvJsu=WU3&%pe$O2{kvOw&)k&bl)$J3XYCN3wiN4#dfL?2p9g8XT^#76pv)xC1j>?=bwT!?C^p zZX3}v7U`=gIR7Po3{R!=9IWrR#l~APM-MFs~$W(ei3za6$KsG*O`m2QAaWNLvhY zL(K>*F-|zQQ*c04TMboKJmoaA$W1GZFV#F}WVO~^DU8zBOKp2;SPUZ+^3@)Z?KD|Q zlN8ZOXm6~vKsK3OlS(V?d=fsWwp=yNmB74q+wwRR72R29ZL8Ea0XtS+as5n>PDk~G zkyb%HWp`RL>1|d_f0q-tT|^JeRL3d-{u1AWCnfdKd^r{P!B}1861;l@4cH@42`+fl z8*jDHVgD6F19sk(8+Py2i**fIW|2{~HPL$ajX7oO0!De`U~^=-xc7vP%G7tybrZJ? zIi!}lYA2l-=b%-sEmwD!W!O-v1x<{saC?T(-l+GZ`Dk_jof&AXv2`)$qT$wg?0O+~ z*5r5rzEka=HTKlIy~i|oP+ocaj%l%-Od3(C%Z`|2e1YA%WQu+MP2smNr?l@qKmH1E z$AcvGX?GFk{KB}4Uffd3fBoEb6>W^RWpZguHQTV$h4)*oahIFO-pM=qX~p@QGG?b0 zb-VDJl}GmPD3uO<;EJhiuz?<$(>-T(Lkr31mgc;w1+Zoy0h#`4 zCA#Fb27C_OS^U`N!GakMffdA{{W3^42x3o!>0=@AG(Pn{ZdK1)SDOpiYACG-u8UEn<6zFbcfuEHYlkwVT@+zhIfrp9 zQ7Q}H{7wR>&t(pW^wS~?`vWoq=S^)Gzi9i337FNG~pWw20Ild&wP{QAris3#NFLXl5#{(8*|7=t9fyXZ2tq{ zW`MXU7g~&yo8)8jPS(C5X{}pFj2>UK7e-wYii!$+r2mkZMNIZEiRfcxD}`CgyLC^8 zSra1~UwO@tu`z7h`sBe-c|%h!4}jT>A*P;*&RBNMk<^NuA{DOr8A>yp=UD< zC`%#c(UgR&;w(ElvO5-roE+_-W}p~N8;)&xdR!MWu}HRrLbGYkw5Zu+TG0zpQzy=c|O6?GNk{^YeS28 zOO*cWs7j=s&3x(5#RSu@{86T5DeKZ)D$}mV)a6De%Tu@t6{l6zoHd7uRE#>co)5jA zRS%Uq*+%uT3DlyYH)c~sAew6P# z?OV4JZk35e^(r9GXkoEN&|DOhVpz^9GYG5Ix;UHd2ig1H<(AmMHwG_6Q`lR+!S}!- zM(<_S+sqpJYr}@UFk+dh()ufcNRI%cNT7U>o{jVk=a_cw6b|GTIzoa*tODQU#H8O%lNJmw}bX| zirdRTNrCx@8^!OA|7+$j>pDI$oig4Me8)EL7S7=HFt1HbXa8BRS;jTSaIhH+XbfT+ z*_5O*w_{z`MEf?z+#NEoC#>i`>hQ&|^7EcQYEKupE-;*CSF5Tk=#+%>trQ-or6)-0 z)~Z^=ryZ|7Z<o@G7@ z?AS*q^~gW^(l0kS%*LKN;y~N2mj1L$&L;cJb-K%>6aRkaxW0B5E05=%;}74j<*I`Z zEl*4uz3p|s>$aD^Xt#qp7-ydKY||~?1Bqro+PUw)Ci6PMjo201^3=Fws)Cug_?Kfx z&CriN&8eSm${+ds*p7ekrGNc`%D&I{mpi|4PJ&p?^wLDn=IiW8%%DcB(e4cV9txXKC1$&C+rvJ_5cuq$gFT^Y^@)FOzn&$*9&$fKZ ziA0bI>yGL$OUFbn06T2u5Uc?6?*&!wwD9lNMyZmB5Dih#3c+v%O%4#r5C)-)(Pprl0*&czaQm=qz{>5{xXj29 zas1S8t8}6dpU`GHG2RlS{q8R7oDlt(&&Z_k-yl)v4DkwwFAF`d&n8dP5{mQ`3)=F~ z06DG;S1*VrssZ6`c8Y6aLeLED?NGE%_b|{7Z37Q;OAp1a`XJG;{?O-u2Kh{I1PhVL zv}_ZX%>52<43$s9gl}Z}aNNpJ`}Xcu;QubkwyX!c%svKhe2T4Y;7IaXj{Mj#PL^;M zo3N(%aT>p?6;BTot5E)Ak@IM=4H+sSO-$8vk&7S?sl7E!9NDVZ22oS6iyhT1 z1tCqovatx~5&Se!{9NtiB+DTVcfks*On5%+H- z334pkv9u~uuoaSBON`e7@@KDq7p01 z4-2glz$Az!X(S+N@cmLz+9oao#c~xTt}L;MGr2OXATsg{5&)O)E#WaPLoXwNYLe_x z5PK89bTeaMPxD@rBvld)!wV$|6EFt_G5<_4JrFga^EqjAIFalo&$BXjlPP&ptsv7K zg|jnjjXdMdC`oRMYLV}nj1N;2@CfnhGSf9ZaUYGTA4d_cwo>9|C^x;4F3%B50EY>I zGy3XNJw09iot@+jA| zQ}^*gM{`s)lQ>`0&E&F2-BTCy)O}PHSuOKaQM4o9(?4mkMOVzek}*E(G;=PkMv?3E za5Pvy^FdtIPA&CE^Z)ZCH5E!ZbxIErDtj_i`wLkSu&GRwQ7hF8TQ6HzbvfmgQeQPo zW0gRc%s}}IU#kdLxhlXAluRAAD}VJXf3nhsHBF(jwyr*rM|)}`>5p!W zc54AhcCTs&GcjT5F$gI%Cja$pfh%o!r&s5JV)fQnnH6JM_d~N*QPJ&g6*q5J_rtWX zZ=2R+0e3cO7j5g7GeZ{_!FAd4^)jQ*Te0(T4>fWVm16_+d>R$ipqC*umvHg38rM~O z%h%qJmJ5|Ocum)SE%IrR6oBQHdZ8wbU{}1v*RD3!QU{i6otFf4w|99Ld3={|lecQ| zh=%(jspdlWy7~EF*8MPSZ3W# z>e3f|f&WZhfwhMlDsah4a9O8*zn2O-cY%Gj;MNxJ{`YVLczWUTNI|u0O}K^Kh9;nx zfpyp|ySG|l_;$xQMZXqd!`6cFQ3$PZf*E&kxA22E_;?F!iUSdDM=ly&_==nNeYF@SU)e+pd0!1SuH=~E{y-)L@?2f16FKHs_^3Y zb6v}OZLvlRmThCskdX@hSh#e1*_NM8dX3nN8<>KZRd*^m17W!*B{G)lGm;mOW{^(` z2mkPrg}7To>RX>SXm`>260s5KSt6L&obQ*G^EXxh51oVgU|bn@$C;mvXO{W*gaMhG zW9SQQ^>0z|nz55gOEZl*xPmeGg7a(sem9w)&U!mIVx8H52?BYmcbXxT`ivKa^Er^k z?2jF~V()WKnKhh4`k)(mM!Wcy7g~hXSvomt(9SoWgV?Btc#;YEGVM7tw=;V!VxN1O zbMZHqwX~WAI-OgYbW{4EAsBUKb&Dl>s(spZt-4YNdUlog@AwPGCRAD1cz4@)qu=qW_hmTUO?@*^_6wuU}Y$6S;QB+N*cklp(vURsXki zM@y)`soaX1q*_*eH+j;E7@O&m%X~O&6j}1 zTAaUnv8mQ`aW|*$w2T8P2R8@uhMBI5nV2KXOBp(>n7NKix|<6ErE58`;W%y)^jB3G zCs?*{I+Luz7@K*0lLA(dm{O|VBeaC*E@G2%#!3#qdR)8KRf}a z(zZ{GfUc5kyILXs+MxHCgi}^S!CSu(dxc-xx1XE5zj=_^TdNt|b_Uy%egApFX*tC+ zyTn}R@;W=xGTCO=*GAhnyw})Yof@@!+bN_P%1_y~Bb!9s+pukts{y;mYu1v(ddPYF zyoG%F&YHy0`(z{3la$g(P%*hfe3pzEnOqKd+q}d_x|u7Sw>`qTsT;fPdZ-2RrqR_o z6C0<~oXEY|ronm4&s@yOxmgLv#-(`BOJ|*1Mrc8jTRHr`-!Q*-oGDGa(zQEuuUygx z+@Et$;n({W8KzSz0rI0&sn_ebh?k#Zo~hw3F-VEms`1;yH+Rt z_4L}$*F44zV#RO#%lUY-lQq)uwnV>MrhUDoMY_BZ-Hf08*44Yl^ZzE?!$;Qliqo@_ z3O~KRkJ_`3orsy2X!U&SlK8)EV%5#P)t8Y{!S1K8n;i@KwQv2fKUt{@7_YG$(?<;0 zuU$_leOQUb*vGcRR`J;a;6Z1;R->6oD?9^wN%kAXTev%S>amfC|{(P@0C**(}Z zhTOS5hZi2GrcK?0r{>%J;PVyUah(T~+_;t;w24o&nYaGn_nv#+<)H%Li@vp=c)bc9 z!neHWXg#ZUzM;Wd*A0G6C7$R`UYVow;!O>^G#=(f*3{Yf{ok6tg!?^L$+=s<}m1$n`A9~vDe)J`q&62e3*BYc7 z-sA0@x%0m6V->mkT)NMmG6lU}yK|*KpOtgI$_uyf4b%3mc-(W`{Dl7N)BTbA0{gQI zqs@ote{)bnvfh=v^HVqAo07kwey~Br^z{O1QCamVoAHM`;VFOT+ZiC{tpW*lg#bnD1hK%DN@m)vzC{T->OnmKC(|DUp4_dpoao^LkYj=IP@n6!Hd8@rn9=Q3i5vOk6&c40O z@bAy>j2#ubcJ8&lJfMbvr)BKKT+r6E?{bpeWX zp?tRuSl?`!aVX-37&<4OeveTIVT3HQ2Oo1;jsGYki6Tn)S%FhE#vhH5!8p@@`*Fvh zhi?&>V2;@FsM~^9UG^e{md!YiaH1)Ro@}(i=3|RC_Qx5Q5mu+8d|;MYnPJ|2sAZNR zS}CQQS1O36nRGUnTug9!*;c5R;?j#=Wi;0md&Z@B83plY*9 zOKOT=hU;#8m5Mv6u-|Q2Ws~g!s$aZa2LD>!v@dn=YcEwrTOkt8$9!uzq#??#RFvi!R3~mnScz1E;!UjRnK%@2>$?sxPq>*4ymG zeKF`{w&&tZBeWVzY@f~hhC8vQBuCqAmLfOp?w|c8Z7-)rXT7VX`AO|HwF1|SY`{on z=X1Wkf;ug`K$?m$*$4KyD3o*`ylmXWEgW^3{2odg!#s;yvDWh@?RU{BCw^m$A3qKF zxL<$$YGR64zT%*LheqN|zxK1qK_g4FtB)&La<-se8|UJY zfBrYrr{%76e$18oZ?A+~-aFS!`~OaIoLw3X_uQfed%V7Chs}17ZsYfSi$9NMFu)IQ zxA6344$1Y?#b14Jl9GraC>tD1T9_w{ z9S(L>bfFKYXf9vXuxm1$;r`gC#WI?Yi~;1{<_K6q?;VhO1S28qHfN;MK~aM-(;<_N z^u=cl2X-4nBb##Lun#&hjQ=8RRv#gUNG|QrbSlK56thT4mQB!-jVvVnbciSR7iD=9gdUA!6^yUt$sm>Iha#M3mqTEPEp~58S21V*PNSX7N zTkEDCnf1V|iIZ};EdS>ZJ8CvCX0D`e9HBdniPWM>)Rk=mXh1cpQVt%qsjHM|8UN`_ zU4BNCY3m_TlXcKnR!E`J`4mh?O2|6Nl9A{<naOyNnkjXIUy>T>4SpW?}{LN(=HiE}x94mOX9 zyzDzqThDPpb%W3-nvx5Dw~gmX8M|F_V%4(1b*^Lo3c5Hh5^jMVrf4lH z&7^Afo6;RyLH|6<#VE>_cGgnV@vazN&*5~bG%PT0>GxV7lGeJ+ByMaKe6sS!u$ROG zo^NG(RR@;!dXqJ7hLPJ%<+jz41bJ(3;|kqW=69nSQ!Rv7h2aT%b;kbnn0$9f-da-F zshq{}Jx^Q25NkEDiEM9V9|zy>Hju2&*|IqomtB*yJd+zV&18Z>@RAn`P6EbR96|n2aw?n-?Nk z_S}}II{(zsj#$;0w(pn_yvbbqnZahIXS6KLX;b=o*qc7;oPkO{J1ZH_wHE81Lrmab zqIs>B?(=jsqGCj=akYRYGpKJ(Y#2W})5*Rv<95s^!5$lNT`705n|iig!&P^puBKtb z-R>QGILhM|vq1Ow;+#q()+n_hmv1WQ)?WJEd3LC~A^zE?2AklNkvB-^N^wwXJbb&Q zHPxIwYKqQR*lzwObuFG;wl*Bd7b!Hf`B`S~_PER*Pxr%XjP8%ub={+Lxp_JcZ*lt^ zg7m(xy>X6Y9m`aiL9c1)=E*y7vvc6X1-Q8>g7E78eBsfCv{0q|?jlPZyhI)@XHzg=#JNG zb}Rn&Njsh23CFD5nXUE8zZ#w-HuB8zo#c{7n%X?JX|#E5TY>Mii#?UmOS*1!gM)p( zVuw1~A@1qa-hA|%XFXX@4)O|nUg2X6{^{B5da5sf(dA1i&`d$-?DhF$@8 zc~pjRRkwR90WJ9uKnD?2*@t@$Cwm=NZ=5x8@<(43NPMj)a_r}59Cv|~_irM(kQj-QIEj>4iI#YYm{^FjzyqAviJth0pcsmxIEtiLil%sqsF;eXxQeXUil68K zt{985IE%Dci?(=+xR{H&xQo2li=GIJJg|wu$ce&OjJ|k`$e4`ExQxu$jQ`H~jL;a3 z(m0LOSdE?N0sWATT+k2O*p1xCjo!!w;W&=pD30Ywj@^ik;P{Q%*pBY_j_s(9=ID*^ zSdaD?kL8$;;i!-Nn2-LrjqDhZ04b38sEq{~koTC72RV=oxsVQNkO~=*5_yje36TV8 zkrj!M6Dg4yIglI4ksrB{9r=(US&}Ask|+s}BWaN)$qy;{j{69Z^f;63NRu*IlQ?;k z9{G_rX^=YUlR){8IT@5asgW@ znxZ+Hq*1pZd9<{Mn!W`JVt9paMFe1X`d5dY}lJ zpbEO64BDU$`k)XRp%OZw6k4GcdZ8Gap&GiO9NM8C`k^2iqW>Z~q9j_PCVHYMnxZPY zqAc2?F8ZP{8ly5gqcmEhHhQBtnxi_pqdeN9KKi3T8l*xxq(oYzMtY=3nxsm)q)ghR zPWq%!8l_S?rBqs_R(hpanx$I0rCi#jUizhA8m3}8res>CW_qS*nx<;Hrfk}#Zu+Kh z8mDqPr*vAUc6z6Hnx}fYr+nI{e)^|?8mNLgsDxUmhI*)ony89On6!D9jk>6i8mW@X zn2*Ytk6Nj5iK&yishrxWc}bg|5CRVX0i>z{T%eg;paBr@0IWKyuDYrkzz>@0skBZ}A?utj>R8h{0W-~jy!2*x0ed+7H$?dwEW-!V7mt%ptaH30dnvOH9G)h3ztfpw*Nj0vv`}gF8Z{>8VDR<3~;Lp5Kyw7 zz^{O?2@s$GVL-EhPzX1RdMBgDbLe$pz(lxDVh7jf%9}ssS9Z zs{*hGZwUcwFsyoTw;^Bx_OPpf00$B90B=dIaNxJ9+PeO_38vbX{0awbz_6SE2M!0C8)&!^#d2E3i*6xtstBC`$vyOS43vwOlX+H2Vlc zfUd z3bX3~Y(TS{fV=!K0PV`K4nVUBOq-~Hz5o7NtZ<+Qq+7ive8Lyns1U#gfS?Q68Ueh@ z0UfZd`f39Gy0N@k0~1UGa9tTh0)_VB;ldcUB{xo`;qlM4r70J{+|tXQA{ zp&G^h>HzEz0dPeGAtEOthfba=}E4rs@!|K|r4*kh#9<2~{uv>1wkafC?P| z0h>UrfN;J_Y`??m07NhZLl6d}tOs)2mV0ozH`|s8yS*OZ2@n9cf*h?7fUHtG{u_3_9YY?k#2?6&&tpgCP2wTAF%nwwHv(ih=9{thr*{I*_ z01$w*Rlv$J+^C-L&4Dlk0voNxFs%ODt>|pP744QDz{(ZOvYuPBj62W3+pYX?%L}Wr zo^a0v%>@lTtoASf5FiJnst1!RwLgo{jf=adS_S+Iydz80H1Mw5O27--zeDf@8V~}Y zs;?lu)@&`G5_{6aS_mf4s{e67vok%igbc^gN}H6tuqGg}18@laySd_+zW!Roaw(3V zs|iE!)KCopPcXG3E7sk-)PX?4T(HW8e89wtybC+H2Mx|GJFV9m&O<%BUk$Hnys#m> zumfPwZ5`XP&7RxbznpEZHml2SX}AuM058o2KkV1hiq3^>#7{fWnmd&9L#wY<-~kYzu!q|LN(|$4UgyZU&e-g$7A=ms zI;?2S4~lHFpwP3I%gMv+0T`UF@=NFioXb92sr34}QX8~OTj@AEuNVvmDXs|?oXA0} z=b?JXy_(OVO}XK$*x(J(L(R=HoYiu`0h_=9PcX5XO}R7tt#+R4x~`jz8r*;o2H?sM z9iXs*u+xCvum7LmuQc!pYrMf&uC)ok#VowA5WcYLN(gh_mhl|l^9%^ZAmvjFRUxH;jh zjMx&Z)*e9G$xEAr{0Ky#tAU`ylbh1#%*FNq3c9+*oM5wt@T+QFztNhp8eH=28qFgc z6rG1Z)!!e-KX+gI8rRCW_U4))a<9Gj-kW45MZ@>r>)NSni*SvEtW?szMo}Vr6uMR+ z>XJmI`}6w;&gY!Rd3?^}ocHVXem%iX%CCv2VXtkL!^O61cQ+m?e{Og&BQ`P>lk!cw zVvBjT89BVI^%8zgi~;>`&+=vYgG1oKJ5Y0O``yZ+m%oR9bu=5tuD(?4=+A@IJ$a)i z0xzwaO`PBEw}!$-xYpj@-6zoFAHVDOhHPQJF!!EJH4Jn8`a3E)^h58;gc}CY{dfNo zX35IvfLvW}{TvZ=q9bktbea0V_VQNs(fvlpX2vE(9PGUQt!p+ zL7grSF2DS@B~Bd?InGZ6RoImJVi4Q}m?@6F{gV0jM)d+KO01b7QTj<>QnoXH{*hszC#Amx(dP%X- zy7wX+QhhIQ%6Lz%JJnkitA>4;+;C}hx@~{kdur3I#p_}0+J~vH9vwliuFLpLZ+Sg9 zGu0OMaeCXQJ7I0)w$IErzh@~wzpZ_o`5r(c!nkC8XBk2L*=V)!`PrS2!F(Bq2H&~e zuy;4L<37*N{fHQ?F}oq__hIkMWRqKa_`-*uXJ_w)y>IaQxF0kBIO+T6g^$1D=soFN za{luN39E04)gl(>4-?nNZaduZU-+H0HTN*?%i_YHi;SgLH{=2q|EBD1OtnXRT0FXZ zu(S65PQa&sSN|f2pD#YCX8s32_~LP3HZ6t@Q&oQy*I3Tu%TVK}8l~e{l^#$e9Wcm{ z-kj!j44H%xtW9g?*&?tx7|>~AoJy=gH;CrD^{kw%XLh8y@U}U*DE%y_+Keh76kwWO z+8JOgblrWL0S8t=X~MzSMyftC6seGjB=<>j@N5pH(Oi+W3Qc>RRE^Z;!MHAz65qat%A|4}%9(Rndo&4ty&I zq4t?#n{*J*;TW%_lg;hPLjCmd6<&Ee!}GR$k1Z!0v&VgR-F<^rB#Ck^=w=AgHW}B5 zS_Q~RBu)g#H56u*m_<;OEg?)jOyn3Zhb;l)np$;rnTQI#it$c=y*2Fnz15nmo!AGndk{uBQL+fo8&x>Kjhi5Lb z{PswT(7rG^?fbRsgf?HL$TWt76|@>Bsf}Fyj-!eM7Iyv-6QLlxx2LUe@JyULFFyhb zj@~}3*oi-Tt0Rr6V}b--9|ny{UGHH_34ASKi7>T)ac1_)f&`F2kJEX(p>us$lwJ|al#PiBxf`p79JHhcj;a08wTWeKw@q;Ns|QJi2RPMRRDn0P#Wt=r@>%w|2F|CCWDC|IbxA+ z^j^8eUndbbdRX+RDd$O$j4C_8ck+o3ZzZxkgAtWvxKRahbUJq1d;<}XCJ1;}o3#IR zrnqnv8n15q&5Nr}7apgz`ov!$7e!r8_KgP&Xs?u((e&{KnW3dCr)#l3!J1&Yk}ts~D^)VPk^#&imb{agn~*RMM*llwNICjqWW zdt>OwB1ayLC-83) zY9F@N_BQX5ydnD>=ln7qm5@J2Pdh2F7ODNIhcEMGMkfGh(S!QwRbdi&^j*sIc(WLd z-#B%>CSRBe8tR;y#nNJLoLIAnlv^btblCA~kwwAsD@c}X$u;hc>g&)= zTn5f3D@!%{*D6U?M3K)6NzbWHu5zSXYpiFxKAEU|$84+8x_t?}%p31%BEdtU^6Hp6 zNI1@YdJ;)NO^#f+CN&0;#Od2#xcf|$>`#^cIAE6lAYSc6l@h2YL%3r}ENh$B`{qSe zgI)@p%D^FUc>N_1McjXl4-ZEXmhbmhH2*B z!=mu#AN>fDuoR)eI7`eUMS6Kh<=L*q?mS%>KW?qZh3N8u*<>1sV*0o=th7TiCzYr# z7x5uc2G!X~$KBP!lG(=z#hf6C9b42VmWy-F{-XTD)^F00@*P)98Gt}90p==F&x%5c zZ3GTv7~gtyUlaYIvWMzoE3H63N|Z&6R+& zXMH0i;y-vJJ(4C^de>MG>ZqfnjfM8{T7&nWW-iGTr#8Be)|p4FKN{Z))5bO2Lyol; zCr#CGr4S5tF}Y;3K#r{+xOK-?keaueJ=XT#JDhDObLS@#X zMn8cZ4?k)PZVC(8n&nkl=KT;R0DI|=wS_x;?yhODi{d`4p0kt)R9ap{f{6~-N5zcy z$aia8<^Guc0QId{Kutf+RSQA7uPA9{?V*euW>>`6mW@S3ykYjV>*69b&1S!!k+;4) zQ_~YI=xg~oI8<{N?qG@XdhC9OX(>JiS=1TSu106QPPl+HJg1{rMOl}FlGY)FG!`wo z^w7v90J5ZC6mM6rp|n0nv5S27^}sdwUw_fsu%E6CaPz(MjaZwFn4yuY~( zAG`9Rfe+tVY%GN7BpSzM^Lkr8o#UuL%Fc)LP&&sun8(NzJzr-yh;~u>|-8nR}>V@sMO8e`-zhu zw-U_r+xmKV?)yDkPP4Ygjb${_M2?!|*;DH+MOv#%gJfd?T^1lkDDF_)-cN2Z8 zB)mqz@EFUI-}2SF&SeGR+ATV+puQ(bI{sYBxf3AW8tPzM55Ae9R~wrkhFUUkT-Icc zVQdsMRUHjTqmUctiVTM&aF&4BIKTykKB`dSphIzv(oQ>oD=EzacpkK)%SjPc*#eSS z`)6)a6xZc5PZ^mtT*^w3FVoNQr#QeVzoCDSg1C^f;-FH z8Qg7&H<|qbV}v%ZRx(PcEgK2r&JsJ5rC4SffroW(5TaMOyLY&>pC}5}@N@(TQt-S1 zt2O5n`7iN^CY{jjGI>sJ>TupcdDv!!J?lzIC`kyCJoDRJTFBg0q9o2VD`pk!cSSLJ zrREL@z4M#bL!_IC%@-UibO05Lr@}lps=47AG(g>oMXBSinW?g?Etd(!c>_E4Ic$o4$XKGHAl@}5EEpz8Bk1%Lg zy*D{UMTXe}Hcq^`MSPSkKIeObt~JQrvqh>sZw!~Lj8n4m_5fVs-BN`I;$wx@M9bzD z=G%J|bosN#wg$Y~j|WTMy~zOzt@W(g6N+P27K-@aFNI52Q{0e%1T zFVg|wa0H1uf>j(LhK^7>N0^@@JjM}m)e)KJ$WrOZTFko9;>bQc>igJ{W80BSCNC9} zg<8wxR&nAs%i{h?M!7ldY$A4o#|Tgg;SGcN1qEN@1TuXI-M8<%f&RvdO#UT{{~c2+%dR^xENs({f4#De)O zMFtp-8<$oAOTU7ijF~u@=b~HbBK>?q_mzvG3Q2d{Md!%nG|crl1k_m6)g;UXjUj5v zIGe{zUZ;c6g3y#%M2a98KZ~$=HEA>KYQNy>Fy-pFJ?VJl>ZIc4Y&hj)$8>XXb941` zvu||;4v072BGnv;=y>pP)+Bz=&3D1g|K~A;$W0EI_D8!17)}R^PKTPghsC&uU!6XN z`*;@fTeP~LO-HH`NGgFa-$q1S7%Z+85s#jUQ}H-wIFn%Kk?7`e-p}J=j7M^qN6OWi zlsu11DjuK_9$)jDo^sN z$n&Zko-1CME8U)}Kzmmmc~w`=)o6dHH~UcS=9RDp(A2QQll_ z*axcHhnFz#TYlcXG9PHL`CifaIz!(cJKq7b4<+ed?i6TKjKifS?@o@7?Q7mGYxD1a z`gWo{M@9WQ!aQ5d{L;<*Y==KgU-g?Z^t8SWOF1Atd%hr1TwLHs^p5wgx$RX2Tcn~F z-#nkAYcDRDEiS8gSGXI=e?oNPZiJBSFT-^u7^nUdlG4QIACApBgrse&dzTa zJ!>cPY1%G8;6*^2cEI87fVr@s!y~Y&;23i|2x*5@MFlRldc7Q;+jux9Rpm=HTb6MT zE(;63VOx}o-B9=EmWtLckHN6T3E z2f6Yq_ZQ}WFJ#)&!@MyNjpSKEj9*6Or$25>JSCYnf>8I-P@&gBf1kUCR4sM422DP9 z75%)_+E^$i!7p;+U71#Xx$E$Kk&uU4Me1H7M*b0FmRX9ZWpDX;^Xmv-Y+9IX8W;<4 zry#5-P~UZ^2IEV7YkItjw=Z(tzME_l2+R1Kp6m}gSqyry?Wg)V9V`zPqL9JK5FyO^ zowfAXut@thnB{dZ4M)I8aCOmeRkCC`&W-ND?}6nmwC1AdHxaZJ>ut;B8`snAFjMznw7xen7Gh&U|`@!|bZtc~5eJvBW{XB$jSzgs*RCI;oBfP@atbQ!Lk zx*j)kb=D>wgua?XCNO1rEeRlbsdh3Uo(*DWVo07H)Tp_c^8ft4g460JEK=fWSNQU7 zVK*Q9JRf1aM6QB9FN6QhP3u6=xQF5g#8eCj3ZzYj1CAw74SM>Y=g`aUAsRTq;Q*X| zAwiQ0(+mW7vWS;}Z{%V!-jSdf2x#L7iU*{USLwF5x2D^CH7z4G$`bgxxBAUgZ?lyj(!_iBA&l9UYPubJY zz#Lt)fvCXNNi=~}U`E1w#>r7(q}Q@ag7)S;>7*9elw6!zC^N$CW%ltluupH zclyQT=3>;k7$xN`eRk^qifuB_+Q{Er%IEDVaT59IziP^X`Ig^c=zp` za!GL6?J#xsSjP6|t*+y>fp`u;fMA*mV@ILet@p*RYX2?4ERcq1D6H|q8RkVODj6+L z^2q~fKa3?sq!3;~c?drQEyIYJAm}WZ;CKE^?9#~**T0-+8w7#P?4nN}nIg+eV7++! zsS_>u-xauAfP0s$3*zRbs3Rk9adxP4CRf`#^RZj2@XW{YN*0Xerv;>(Qk6%{WcO+Z zLzD+G5{hctnjqP~Ni-vNPPx_1n6=<`FnVy4Py#igB*t41Fc^?;3mCc%MJE?3VnC(> zto?U3h1&;U^zR69G6Os|BV5A(|7S*w zyBLug2qXy1Z-lLDR1a%RpZgi+DF+ZxxCA?QK#<{K6$mIu5G4iEPEr!p%D8z5En0cR z+3I|*43He*qV_CUkU=6f{#EF(gv+1%?@9zLo)p#=uIro72DP?n*vmg~|< zAQ$ey1>orjq9ww?geN`)Woci`$=&Okq9Gl^AuQa@E<}SF-$F^y*IAsxEXnz%%jX-x zpiv-IKgn2rkD8NVjA~{VT<$3p$&%1AY~msH0e9lBxsOTRrBfs%4y-08g5+j9f(Hsz z&h9IJcn~$y8S`~tWxo5|m+{uKzf>2WUHY}V{q>g`okl|Nnh&Mh6pJI>Cvyjy)kEE{ zujrMmWWuo zdd^j%28Tz(qg-8`dNyr#mtKVdYLaQDXu&8ZAplPiN?QL`hVG~RZ5ZTAWoM;idpMj6 z`Soq-M?rnBNpWA42_{}LuG)b4M$?i2=G4dn`wM1*g+i%>UREVrJeZxe5!cHF_~JJ<1iikoI z4Ft_Jq!HnXrwL&qdfWYGf|nfUK-?y-WH}>h8SRG1`DU$Stu~TyM^29WUM5~Pp~oTB z_R?>K#+n>`#irZkmlT_unwd`&@1{xY_nlChl>8LJc;msQ`iGL?hprMtyiWfrWR<~g zhUQZ^t zp&kTY3xAC)UKZg@sL(u`DDjduMeILO)#%uXh{J&3eA{qt-!sD@-8#Y+V(R2ag%B4CSNZqKDv{If8UYMSOhgW{HidW-5)7`-h%M9A*fU< z{Ep+<7kXbRFaOh9ugN{Fzj4>Sd^R|5PXAL+0j~QMKagzEn->?_fRme4rvWU@XaFKG zR514DzDpS%u39>o27V4io)r-SaAQHJLDesvUA6i5%!cCtlrY5T@2MATawecE*1z`L zy=dmQTx0IRPJy|ef}WGxR}W*#`TzSTl&qeQZ6KhO2k|Ixyl6okoNqLkRlie|&$&TW z8vBJ!X2tlCI|afjgMqS-x+h$C^i(ju-7n<8G5o@>bns{`F9_;LP`*%)m(EUfh7_v5 zeo)96&0J>5+^Dd_^xnuu$#Cjlp~>=q74S(oE^bR49;yE5Nxp)t*ld680XGSEU?&$e zSR-dZtR|HO0%k0r71XO6cN0Ky7cN`QTaPy#6}Mf#@JveVN8^Cu?!6nyt0Y9AjFPtm zd(aLYCd7(`2}0RfhEEAWoIiKk1WM|?JT-$6c73+u2NoDo;$pdlxFv{L^6_`X|17E_ z(XB`zxAkd$TKd~7=>U99B9IdZJOzi=L?~H$oQnRHHZqtIh^V;MyXaE=*HAh5pQiJx zW9G5vC1Sokj&zYqA?#4z6?^E;VgG3NuyT?>z7(P1=xIqrGnKcrF5uP=*RJu(RE~6=gL9K0*HBMrk znk7wkq?`+zCvR&!Y_h-F{Dm`3->X&i^iH;gWQs?PWMmQ>Rk@e{otH#n+Z}C13L;kV zP3l@pUJ&6g3ia#@^bRLgo%7c-ditxfLZ~zu6J<#SOP2+)`gel? z-6A2L#)#DYkcF_XJ=pN^9pxk5(f`WAsrc?J6Z8`l%U_HH>y(7&6I13*T{I3~TKvuf zIY`X$d>{;kT7Z20mRK7~Yd*QUfKmf-0;$p_qrxnf;NtQxa0*YQt99;H77xbMiDGVM z%H@=RECPCnhN}^GKH1?gTl-|>Xbi`N34mWLUho*>&WDn>@-(0Tx~2+^z7ocl44qKO zQH=F1N;`c1F0USS55yUWG?FBs8lAg)`Cni&G+Tn|UnsiY?-cKiLUUPdrLmV;${Xp( z2=fsf?|BG@2o@%(rZ9f^xCtun&R-H;VJDTlb*qEn+z?pTXSULV5`tbjVV*I~#)^S3 zrtib%cQpe3MBRoTgPQdTUlENRp_dC%u!GUlL8Cug`k5JgCOIH0vC4RGV)IuGcU=iT z*r8iaDy7rInIevrzv;rt^Nf;0fJOn3NZqvv4a`#L=7u^;eUxWTYs%v~J0ASW0oW6# zUk+lHF2?`dc~xRz>X+pQ94-{(w?{vLSd0bR5yqA5^PutpV=UZH1{EA40kD*wXv?XO zM8x1lmugkZjwH#Z*2dL$CsK7D)TwNrae4aTj9z81V4|)13<+I|!-M`(!RWwRO?kQ* z2t~*q6BN)XqY#Do2n4Y0koRuYMT4*STyQ^Cr|lzH)|HMBnr#5S+e?E(16x%vIC@<| zWlt_mO-TALeo3~QJ=hW8AHpE@8ck5EC?-@gus=Bzss2{YC;Ui{ms;yrUU7_fNl+r- z!wIigg*i_kg?!=c1t3}evebAe2NWXUD-;Z7< z?7X=BP~H6vo_+g}Gk`A{2c29mx##nAJNCa*^DC+sZ(k^DE_|$fWpk(MS7ar6s(D&w zbw@C@vz9?pyCRq3)at$C!XtU%y^M6t#TQbi85F0gP!ZnbeiyjFqcfD*A3aczqtm#rG{Ym_pfT1nJ+vgEp%phhDTwN| zD%dpSVX`yiMJD`Tz>9mmEw=PkB8I2Fhl`8@N29`5Y5ccDB#46SI_yJBRZM9+E%Y0v z$l#4D?*_1+Fbv~^?LN-%afWMv0G7ZmA3y=#{Iq*FAi|>ZZj_?@X|}f3-Yac(-9uVR|Rcea(mS$gG#$> zTeZ8s)U~~U^tKT`z7sK}aWc1vC6ypSOVa9wIK(+)`(CBzm6GzK_veJNDeP9foP#pR z8cO%*X@ejIxD}h3IO`xp&C@n=$5;t&DewR3U`kRYYJo32_~+FHfyGh5f09`EaUN$# zM$pILE3@juh|un()rBRICrhEy*F^d0>oQUrho3}*siLtf;{0?CZ#PYTo>sy~Rwxba zN@S6yadp$svm`cGlIT2qQO34axv=kiiPsf=c9oga8Pf-5F0yY;_?9JAG9>eg%NRQ@ zKecCg_UnwsB~2G=(eCVu#y4enq|C$X&10o4E`$bQ%)46v)n^!C^SV~T>_W_mugX$i zqd!`;g))zpPB8yTw2q1$J*aQx!yL~*=oTm!M{^tm;mZi}lSEM}PUBT(DBbw#6(S-T z5U5H=K!v`y3IR^u#4RZ;J?Yy$qy5m){>Gc`p976{S3KN>E7I3?^zb9}I*S)FzOQfl zj@-6ze>+7+rky__x-YKDQ!6G$4FESlUjzl@&;zey0zL<|GQtAIFske%(N%!2%vi?M z)L4(*wHF6a2_SGd^YI`{xV^V)PaYNLef+rh4 zWTQC2Duf39ahZ7dop?^UgeMC@zIF&#r1P>wqK=%H4mD9j?!3;I^X7Mw{3D?J{z>6- z7nsw1KW^itLhYcl93_EoPDF<%8Q+l(1Q&OcQ>p2MBOIqZjW~Jd>Y`lg=R2w2%^S(~^6Bo4>HhK=;f)!w>*Oc6`eb7S zbqqoU-!sI`ml4=(xLN%<0CwMfvMdjkyH^oeGUN{>f9|O%(X+ z8%_PVBKZQ@rUF%kLY=0<(+WlAO@(bU7C2k4)nr>#u6FC(sr<*Dln<_uZER-o|M&hdfHC4l-s>|hTNafi~&gL4D zuqK}(Ri~K>->f;kS#2IwBNkOt3)T#5ZU|STa*|o1^XzB)A<<3k={WT=LbbbMBgZkl zZ2iXbFOlv&Q;nus(~1l8&8?pm+s2!%=cC$xE4IVWX8mq%vQ&_*t-v{bCd$_KDK`Qm=pTAS?Ou2(!&>L zA4buhrk;INe)kb4PN?4wjUttRZ?p9GKzx;+m7GPee>Lnf6BNzpRaNfOY3Vzy+;85} zZ?F7H4E`Ih^g6udb!_y51wjY~$4zJ%%us$qQkLZdy=_o_yYIu@j~jZ?GQ@nX{H`}!1?{5uHx4a)$ezzYzrbrVqC52^d+_*`Q=_bU%T1VejC>?p; zXnvK42Mv}e&s=Yrxu7x|yFGI~X0}9St}15Ef3PJ%`D0h>#}}<)mCiIr@x3XP!ATWH znE2pU%;IkAr+pRrzg9Y2b&0cWiC=YDtc@Pd!*dISh&G!x0R4dygs*&BCSA)*ck&rj zSsZWu@_GBqqRRS*?e*(z>s6{78L^w?-!^Mi7e5Hjzi!(aQQfY}k;C$&J!?qZsp6ad z@`@qG_}9jOtL<>M@9?YbinZ^`s{IfX7n1~Q+z|Wzo{|z+nJp(0jQUJ zY}jx2cSE51SlJG+8WwW017g$xF`2Nh!ppcCOI3lCv*I8VU?E$OM+a<64}Xxo#!QbE+vF3`|Ea-}-mvB9`+@$CmLs*BoqOm`wD!N~MAT6^(js0d*d6 zbrbubarqr1J#}uQ1RjSSp7)HS5q2H}Bo7U&G746*++o`ZM=(D>{25PQ`-~F6et#l+ z)DS1!p5WPVPozD8w>m8GurA7cNnjl-{_CFjqt?ki2YPncAu~*pwG<1L(?H$n0H?{s z=%2%#?u<0lh~AIoy>Q#R*HN|yhxUy=y`LE=ip4F-Nre=xK_|zY20F7*f8^-<&BF$_t=b}gGnTI$RXiK>ZfUf11^dcX6oBv{XZ7FXMIA^IB*AOK`X^q~HFT;HVXR z*6G`0O*4(5iiEhe@B&5>I5Mt^t}rYFIeChA3DekvW*+z^K32Qm_+8*ru=`@|$?vKL z|JfrAh^oil6_H|})DEw$_r51C1RhHU?M{ejYvd$Bz5kK#d$Y?H9G)WZ>F!^_0^P(A zY1@k=)31A;Uqrq~X7m$3KHG8WDXJwg2Qa+I?l*+@GUBHk*j0+u@^yRC({#Rn#_T?B z|E4h%-4>p>_PU4V-M8b*eP29-b1x*W)3p%h_Wr!SQMF_coTX(njjtx`L=|JRAxuhK z<;uIH77I2GmS29k?9sk@Axl5C@5i!D`aH5mlkql&G@!AFx}oj+_hJt0!sI)FTEJ|+ z{_t|2+$WK)%K{hB@i+(3?yB#4*mE`#0=xY!KqOQ8HJ7V3cZV(7miVg%*n58S6bILO zElqU}{v&07K|e0cB|r{qxsMmGxA@dgP)+)0yUM z#gBk4tH7YbGb3Pi)3lxA?Omc7`dZZd-sSoAhg0iC?M|iE$-up!kxDWM&(M1vVQ?gq zERuNv7X!-l?GcP7vR-Ksu7B;VM~tP>CYWY}cL!)W(>;6g(_qn0kJLqmTY)o6SB5g# z2Vc{sVtU?9-STMl89C|uSly5Nnomr;@6hLG!h;#XAi|bB0Q3XkK*PsLaFrI?xRKxV zA4|E@KgwB7`mBcxXwG1e`WXOi@W%)r)OO_Fm0>Heo0;)@3Hf`&K_Q(W>;5H`y$!)O+41)fGceO zEhzYbi~xHH8~ddM9KPv!#tn@4)<4hxX3MCc{u6S@ZdY~Bwaik*DogqJow}UfEEYpI zV&|*uoE+|;Sp^!cP(bx>vu`$@Brd?E*G3`m^t<;LxdpbwgVO>=^4TY;lt&JW7^>0Q zk%;sSej!0$gSGR&`JzTp$Xk5qD88>R@b&;1Lj=q`Vc00^U}~XhzIq(rB?&7@Q!_R7 zL4v_LO9n5@KRK4Tq$5YNcX8eg!CK<8(vfK0$I|Dk-COZQu&CDh&|qVQ-o^dDLRv3T z-0(=%t?VIyQ`mrMNRY~8gW^!#21q{H{&kSsK5cHHqEAfKB#X@GP{6;!_8O1@sPztt zQ}h7uxvfAJ<8||uiyR3e+~FkJu7-c1_qaGfmLnTqSeXULZ7i`q`DsW2XG3Lqi)!(TAt~aXeQ85o4s~7szKi-a7L1(rE=gaWy^#5%tC@`fH>*OAN^#Xv8y z*#eJpLKRwBC11DpPQ=B$5c+Z}Y4PTls;mEm)~V@Y-lkmM(oynG3Lghpm>O8Cbrl#z z{z6VvB@R!N48$xUfUdST*=W>JP%d6ICE7u46K9;KA9^sz*7OMXBTvcTrew4h+Vkra zhDT8nFckt!IN-+J!EeOdl2;ti@j-Ma=^Xkp7S`noVK)s*ZgfB8i2a+>n&=r6_4cx{ zx9d=jbyQP>7<5YU&2{0Q@^ZoSyMWw-OYbH#D2;dPCA+T|ynpzKVVeHLAQ{4frD8zd zFHU~}=SVJ6FAtx5jatkVd9Y8G(`f6wcE#?OQ;$z=-7e<(cpmVryc)qs$+CEm00rV{egASR1tP?hCu?}NU|tIRcNkO{Jfw-+Z0O8`Q^ zJU9%$JfM8*?thKRfV@6dm?xG5sbIVZtS6eV(F2elR+Qh#vnJyIP+54sWmLAOsg(I( zq$+7Fw8Xv0h8hS9^aKHIK>jlf4I4}pfna{6VWRC|FL_U}2s(BRj0QX4j6t6%jC|DK zc8YS%8%$9#KX$g!GExyNSOQH)^KshyJmnS;!lY?gw<6ujdNILtP}MbVR@LOi6EudN z8kzHwQ@M!4c|_e=y9SMlC{c1?saCz;nnv~+%Vy7qBz<2_*n_g(`{XYcHvAwK@88CL z22SJ-6&5%P5(L@blQGu7zAl%%I23=vSQZD$4*a!+TX5I9n~2 zWL)|GEJ!>u~YoNse3{lokW>#66`FqcTV#LUPBoG zYzz`k!njfWw_rbn1>7hPC#a=TUPBtQ*DqZtEW~cfX0GTjTUvQL7gq7zR&d*}wkYa9 zTdOMHVkyH{kO`H3Rv_m=M=XBcZ$@9~&#g7-k$F8xKyR(6r&*p*{kX4lda3hH-0X+| z{2r`bo^a#pgw&^Kmd8r;1XyUJnd)+ar5s-mo69RPEke@Gway_WYz{vLF#ieAK>Q4XTv5M34UbFyoHeMdo}g&|wI#qA z05GKx*!i8@o6-|GAZdYl<`alTGgG z2fciufh87ZWuVYm8)mC7MhyUdiY!8{L%Aioax!xn|+ zq0sOOqw^dXD3B>k_0Z}B`s)jSRIjjFW+(_53mViAFJ0<|n65V_dHx^>+X|!BCUM4z zq|ww2Hk3mnSl&7jdzBN%FM%2cI5QADW1@1MP}CLTT60zN{)-dFhxsQWp^0B zgkq?G=hNrlV9c?qF6LIc4png{0Jf`D>@Fn9Ep9@yTZ{xeH8Rzcl>rxG4~Cg#;X&@e z->tZpf1Y#YvR`+|_;wcnsb}#V>!GO{d;mxz-cYtYfUwB6aj-Jb&)*pemh7hD)@`q_ z#>{uWdkZMJwro6P-&XIC-7lARdk666a2+|W-RZw^grdsP+kwqqwnZw^m5S`O=D_0r zQ7z$tYL->&e=o7aqPdQwV;@o)M%g(uqcUCwk0ixoKjZ2UCVfdQ+uT(+onAsXZDX&% zk)@QvQZdS6@%Hvx4yCqN@&$29p=310+RgPgZ^NnvKUSkfvgw86LCbBXt7=+yS1*fB zI$OGNgK8aH`x;xTe5{aLY-C?=GEmY_vRGKfu)?%g#;%!&ZXxUKb ze8>M#lC$*{+oSZ+hMkAfAwT`ka^^{L{=srttlfs+6KUEI8OxU+q$z6L`+D8@U>Efz zlzy`tsZ4hg{&SDjVj~HxR0LI0az${m+!J1*2t;w8Xoc|~#xqe*s1%F_`yD4AF%zX^ zP%-OSc+Wja7F5NRdqP(`c7(aK&3R;8oMk);WL~OdH+DSi-f?bo>QFRs8+pxtUxr;` zL3>B9{1OTkf#6@@7S1KHW5-1;*3A5&!uPTK9Aj(~Sm9SY07S#J z-Z6_3i7q0*#SyaZjR#!Vf9#ExFS0E62az*qG$0M747GBVR@dQO_x3kD1ayuGP zJVOIoc5g6!n%ZB~4G=>`58m;tsB07)E3`1<4wvi^O|7q*<~apgJ%;XB6@yI%gyEVmqM+xoT3s51_KkOXY93o z&MUq8VP^Nh)N0SvqR8x54R01qQnFtX0AS{mW?`lqXea~k%;c7QiWT$rz>4;aa(o|IJ zwLuf?zVkW!;B&~u?Q~5#F!>xIZjMCRjZ^?0%jLxD<|I(;bYjX$9PKRS<}6q2tmNkG z2C(YWFp~9-TvN_QXjhXdXZ0z@g-AyS^#5I^9%y4$(zX`h9^&R6QS5$p%02Fw-{R(R zvDoACl*h%S-PQA&z7HX(Q=T`_UN^Koy^6gmro5_?Z2YuOdS`jhjd6KtxF(+jJloe-N*GkidQ*S1r?pJf$h<9xPW9thDcchz`+o4>_r`Cstx~g!VHB zhg$51nC(k1v|&&0hdP;rF0_RO?1!1Shg<1{8+L_x@rOrrg`Pe3#Olb{??)WoufXi% zlP^S!!6K4$j_WcJH}^yR_QP-N2P92L=9gG!mxSDRKl`ZU?9=J9FZrYU+@l9dqKBrV z-}A>zxW~+t#C)8N`NSW);vV~@B=+lc?05dSAMSC#O5*-Z$1(ZiAs+FF(s;I+crJki zZT_=UeG28Z;Z^q$6}6BLv0qa670iRrIh;#Klsu<4gNW%e7Co6@QF`9yVzeO!)CIYf z8lNaZ4m4r~ z4g%z@m7-%tK;z2uBKsfz6p`WpSpMR!J4*hS`xt1 zy`yjTO;;`K^~S~9wdvy{3g=d+dkWj|ti*|Lsp{XUiW&daeGT9)(=YFZus3dh@W_ZL z%c#?wUB!itd;9m#&1n{`P)gFZ>GW6i*2gMv=#=fO{d#K6+W@5(X0$1WK-LX=>krdMJ9*t9-j ziXD#X3eg%bn}kBiG%J}s92Z~RbMLG`OG(ZyDG+;)AqHTZ4*^E&bfRcR`}GP4TkShi}z3Hr9?a!(FF-=Hl0@&PlN*GsI*`Vj(;&10t9jBfY>zhGN$dr zS)T-^dXzPpK$hu~aQfCQ<8CoJY0ERsRx16R0AE2`29I=s+f3lT+1>YT|BZ(rQDpJ* zTrz79dA$!}OP^GY^os;g$nfO4@&`5_A6$lmwR&bSfxzPIF+Wliz7Bd&M>x38{I=C& zv|5r&DUi>t48$w4|dRJ#BiXOZAhELvC(7Sn+xB&SM|LA(6A&zS~kc<6uXqho5cu9XbOj|iaRQlspl3mdZpG}mTj$5hI0n{FdxaJjDPEU z(PyI7AJ*UcB-f1pT3uZZq=%O9tFD31=2E@<{Pp4PY;2}=il#yM zt+Ef_Xid+Q-*2P1v>j#T-YT7bcJQCp&+p3Lkx9n*Myast@#n5~O&C9cD61ir8m6Um z>v-Y_`Y{7a4GR91-^`7_|Nfn>t}7?|ed6iD$Cs6wRfSu8DH0;kvll7GPnr_$oxCbE z6L@-VK_MSbUt)Qk9D2#`%G8nc7rwBbg-=XTx}FInG<+fnKBM$Y3nRgo&c8po@aK6r;qhw1u@|OlJ$G^ahS)}-|3+!mM#bVrwb*8z|K^>l z&AW@6?P6c=`+t2@_4VoE*Oy{jeg0bmRa--gTkplTC;Yc(sC>*7 z_z%s1A1AASoci>`NPN#EV9%m@&*syfgZNLEfS(@KKYc#^3=rQB3D}RQX72xwy?c*` zI`1Fy$LcgyftgN#n3cl2ejXLt>nd z8%YcaAx0*~n9T1r+TH8=e6H(r?S6mX+voSk@AK&|TkSu4%l3ZE{rP;p&krwNQe3)n zV#)8}($(Rm>x!Jv6P)meoLj@3SjFYrCzkI%T)scN{7{jbd4iksko$O;`&4nII~bS4Hf~Y>1ZM8^}ZAvl#Izhf)k~;(uwr zqj{_%NOX60>pjBxfvTIkbJ`ymT;=ja3Avr=q+4?PA_iIpx`oVI z>bgyaQMyH=ucJ2Y4Myn|k2NK3KUNc^S2Es~y7%fTO22fnE9=mG!)X0yQ@`dPs|*(3 zTQ>8y^!&S;=)KQp-&b8-Srs=ZXN}a~+GG@C@Z!tI*86*}qxV&?KlMI7_A+K)<>KeT z%By@d_`^Ow)^gt{*07rUb>>~=b&OFBZ<#&)?q#ge%hhkZl@&h570j5LyN19OB3vnA zS`61vv>~`xDrs$g@`lXuh?8M*7a1qR6@rm&5y~;(#NzxV z+uK_|eV(N>@G2Z(9~svBjEwq=B{M1pBhj$p;?l5lFykBTTK-kpVd$n`)_G+N@}6x) z?9g<#g*{19tBr@%jPpiDnVwFtzL)lEL4#&2l_SRs^QH4we?FB1dJe4v;K-OGoN-l9EzKn|+Sw4LUo!$oRHm z;@G1FmI{grF?H;Oyx!GCCI$i9z8PkyFa2hex7exDUqvv{(){=g=B5Mt!eUvNsEEm^ z$ViFmD~S%w@+76PM-E7cq7ZK~P>V|(3w^Au5v(8qroK~au?DtHLvyiH+8PhT$)oW2 zUEq(_N|!WT1jc5-;5WGFuo*c8X)$3Kw;9ImhO26*K%p>r%nCe`1C8Y2y?${OKA31$@jvg1v%jjJvHS#a3}*t zvvjgEF?*EG&hu<05TnBKt*MD|UWwy_I8;n0){w}UB@xu(g)~5^C$pF_!GqH6 z8N1Cs+zMV50s-Vp5^`e*s0{)`+=_L`#XhyB7d|f%YR$q(WAo~HGT5#xz~s0 z2QBO$?_Pr~{hZ$N{ORyZ@`l-Odvps&UPVZ4Z{QX%YZ`8C0T-cP6n|`iF3s28dQmcw zkz#a9!K$M4Q;+)aK813*XVZO!r&`jiD$CBdrCyjGYO8!cH%t#*r)XVOKL3Gnd;5v@ zsuv3rotcLoT31(mo$fC=KipnjxirT-;LBH+uc=yInCy9cNj)>v9L);Ne`xcv=G#gm z_`hiE%a?pU1nzWn10LzY3_+^qGASsX$)m8nY?XT1IpR3;hOA6I7{qg*9Jy|SV~s?p z42%sKZBEK{3q0XaJbFvJLG44tDb}tJ(YkM>MFR8|CqKjz;p$^?B$=~g@#dD<(#-0Zxmy!^7MsmFy4e2wY+(l_U(pOla1O&3%xPE9|h!?({A)=LJQ zEn=uX_B4AS+1p;+X}bM_@hWHc=V$$@hdRpG?$e*2*IYcdqkJss(Dvu=Qy$M&Y^9*6jIdu53r6=7P^)yXQh%^YRC+c7vtX`_Bv! zJ4!uQ`}eZD%TH!K3Kf0n)Qc0JT8IN(Ck^`R48X&;s9Hyw*WS4?G|`g|`f|Ea>tOljZ6mCxl9 z1uL_=Djp>XRU!Bn)}OEbMWgpEtoe zTwAZc`9#>_B z-kx}|I#;Pgc%IOGrHP z_G?RXQUBty)vXKnHb|;kCWmeFaK2(8T$T6?e-tb1@+F1og56?e5)LbSrKpHim4DUL zF8o$IM&(6s37%;ZGFbe8liIP*Sd#xLqp0@8GAfsd$g4ad>7aK(ZNvx_*csM!-M%qZo1qxcK`zU-Qb8j1~BH zv6PwJ%J4+4-I`uS*n_}dK%c*GPGE+ zRLzQh8Z>cem^-jk!)bdOywozh%3XR1K^Kw{mQ3g-4jpM-NZHWJgzx3lVq*%a+bl=K zj&bT_+Y7_?w2q*!a$e!kMGpYbH1xAvGpi~4``q4K>t}gK z+NK;UxxW_1Jj*|0HSPS4`=-48S%F{M^zjvLA01s*7;ZJ=wrQoGVO>^yw{7P1-j%nV zF=eGWR-exuTN&tYFDrZA_W9z~m3K_^^YTWkS?~KRgOk?JEBe}IeJfYqvtpiCO<2tZ zzFQgMv_G#|YMTpQSs8|4%3pcm;#$R0Pa3esYSkTKA%vh2$&yf_3VJ^B7;jXzqr72H z`+Uq*-Ul4!1;fnxOTvBLm>S>aMe~vNFG-cWkJ_;>TF+Q7q`c#e>vp_o_iJBBTj5O* zF%_NR*6fT;-zLp%D!T8sv$OYp`(zti(VJuaHSgHBDW{H#H;17R^+XY&t31TAxg;jU z;Ow+Tv&lN7G9_VbKTe#uk}ztw7}EP*$tP#;{;6QU7u&WeEO)LrLT%z|!l`q?h}aRS zj@;L~S8Zah2R-DZ`86F|{gT{KHNK}~x&7+u0u56=X=cOizQ4-OwW*#u(!qTrweL$o ztmMq8j;yym#}8h5SzQ6$>HmJeC}c;c+3dBBtUbvm5y80Nzv+fQ&{QFcA#8&k5AV@@XMK#^FvQp-(3x`GrE6Lc(X6Xf0hSyJRZ6e6w9YRs6+f+x}aD z%!p~6v=p$qAcvHblZJ*ZtuBs% z00e~yrSMElNP=ceSOy^p3K4V)NX6z!8k>Qgout{9N0AJ*n`eoj=1^Go9`~*J0`z^;^`ag15M#f5y;1h9-!Tt%VsFfL{&!;QJ?5QsAuMRP~q}` z^HF$%W;_vvm!&rwWYbm1-Tj<;S4UF<(a^S;9!DwFt#Njhw;xNT_@KR+L=>)20XIf* z{X)Sdj_b-x*Jlvu$r`xeI3H~-OLIeW`>FCgZSDMuNjPOvuDzVyjUA)VnRy1fTAIZu z;%pfmbSo&n2u56Uc78Ht?6?*&zm?YAZ9q2gc;kgrAm|dydz+g*11U2V6h?D17LLNE zITJPUxC(ETK#FEva}~L!o}K4`N4ev*bmb|uWS{)}0`i+ATrS>qcEGilUL}vOKd$8o z+Bw;am|g0UOTwWOIze5Mlu24z2A~r`KY~t#$FM!Bz-_*c5WC#RrB!KVTLJ}?hNCYtlM7=Oz6uLCo?Em@8)UJe4Y;~}odb$O3; zZda!HZH?-U5tH3HwwV?W1c9l2GXLEB=4X%lp1QsY>z$9y?+1aI_hZXqI=bWn2+Tvz z3x0ewxtiW`buBQ3cV{WbJ!J|4^EmI>@uBLd-vcvw_xXZz{v{I~wEedf+7i6>b>|*_ ze7vpV?}7RGUHO$i56o6k{$3?}GDJ?I@D^XuMi7{y>B!R1n(CD$)`$BO>r6mkau%jL zo;dtOaJWqqw-*Br_Cis&>-GcxLP{wt|@co+|GY1zK9TD4B@6!Y?nZHmt+=>f)bunyWvBX1eafMQX-wt*Nnmp4UkL*9n4P}Jvc?Pu z%$C@qCY|Y-f={HDnUY?|P3QHevUWdtHt2i)oJx1#_Sy1GWsBJtlad-l z?D7Qeobi$Ow7avOgU}ILhnUt`ZU+i_!LAdNW#djqt+Qlin_%5txpU9uI#I?ON`1sXzQa<4bSK4sc`k-k<)Hd@v8;TfGk_VNxmI>pD$@yivyaUbJ%NtIOa zKNuQ6uQ!sAQirjsI`X#=ZYy?0@R4{hsVths0nQhG-=Il421n5s}mNlKkpd=~n_ zs$wbj>8E%-KbSPhi`7`Evj5f%OO=Enr1UkCZG0Te4ie>EXYOoo62%sU?` TG``P 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


    Lm^#^*u9@KSLw;r9<(^F3y9H>H_PO4+?0N2Ra? z3(bG{l*zobtnta@*v}|U>!AT1da8IH^AnpN^P)KH2H<3+| z&&}DGQF75W|HM3W7hf*<>qS5m0Uu_@3nKq#MZ=x_LQ_^J-OO znygvV;aLrv44cyrJZHeM6?a8(lGufxhv#mrQq=may={%A$kB;zU$aX`zRl$ne!DoQ zGQbj*% zp6(WwW|d_xDp)3R^!}^^4Z~jzikgQnurnqXe>wkMMO0#3SG34+O(@ex@K=0jMj6x( zH1k+_Ec0<)W4{2gU`#ci5+iDuqs3$|;33evi8;fmGjyuNyfnt?bAni zj%&vmI-Torc>7~x*sE3kf3b>)QUK>m`8_wC#78)N1|OaHxj98LP}rItbW^%ZO}JLN zHIsJl=hkdwGIV<`=ecLxTwZ?Z_CoR7pWBONtqMC!75$z&KdNU-!EVCupF6)Os3VN) zXE8S!%cz@A7%QFc9><>gaN@}BTCdg3-SuF-*xikh{q4uKhCn{Q$uE9D3tT68wYR(SXtv^kCi%>uyVSS&(X%y_h&drT)Dx+Z>2JD@gxQmx$BP`@R9 zG};8stITW3*fi{vkMPkd+eS#C+G~n6OhQ_+CipoaJ=^W!i>870#$E?rF|BfVa zCEy86{O7WI zy|?*)4DzrTk|fX7S!l!@*9{(rf8vejYUJPWd3oJU$l$9KOO7~iQQ%-oA3m-^I2#^d zrPpD0tVbmwWLuLlf-k5?PD6|>eK@vQRF32 zNTueycujBuaTgGIBSUTD(pC*BMTEFtyntq;5SjX*(^}wdj}yK&kWUM%MIsJ zumC8wYG~`&{IZpL%S3y@@hcIr1Z4`_GF0|1o;0b${T^vEpo_5}GDP5lY=X0gK}mM& zjlC2=ZQbOzq6bq0wIGZ;|^8-#<3lfmwFXRT2ydGu;5zo>i8)gi(9DW+_opN zRg)hGNk>$D-{Xy=%!ADb58^f3#1z{};m5*wMTec@B%LOMqty<&-B`JV2h7eHK4s!W z96vontOUcWeGk3zG4w0C-V*1e^LcRNa{U<`rTrlqi}iTAB$Cs~=BMKeizMpE zy%9G-`iu-I(muIB(Hc^QDaXz(ynRXrPPxLh!A^w5{!&Ub!rhLkWNC#_xK1=3D!B3E z{Zra$F574FuO7)4W&QLQ&nHcO8)Loh^!vvE*C4^@=z*T{^1i_%?nCfR_Rn{8P97Tf zj7VjQAq0rTDqs#Ml8pQQNxA+ALBHw-u~(S#J$A9i)G9W@W-qxAv-g?!BK2spcucN(Mi1 z=!hj+o|gwy!=$C~YwFA?SOoZ8Eslee=SoD=2i%zINo!`>SwaH~{~$ z*~1#He3(QYw1+eeT2jU^&NLJ%R*GF`6#LN(=;3seW=RQqT|Rk`gC#=ypg3Wo=DwD6 zob|>j2~LE00(axdh||cF3_dJR(^IV^3LhRUS4{opd5lpzJ+_M(GYf-f&k;EkO7GD> zWO496SJwIXl2HTOTNM$z%)><_#^2C>E=XY5I*LB}a8nFYDT-zmwa1Xeol}OmFYBQ! zflyUE=J_o^8<&$ox;3&9IMGHgtH8Kr4{vpf*Q7jMkZo6 zNp5E3K%UFDijiI>2On@HVzokpwtm}~ni53?V^- z9jC$OoeneYyBZ2sy8R@@_h-#yjKx4Qa$X_kA(~v99|D# zdU+akL*&q$dtMI&pR$y$bDmVi0$5Yg2!-Y2vI4W%lh=;hNej{*a;jN#Mi5~#hS#ND zhhHm@Z@l&}Wb%s}Z)gFQg%BrdGy9+>~ND? zW}+!H7-lAZHLv9cP($iF2i$G*#+-vA$R_!H=3Hu*90@*;gNn52y%e_4e|E($ z@#8YQIU>=+Z@(ki;)dY!cS=vZZJyV2Uc8(9y!^HHw}R(Eg95JKqaLUwrDPqeHB5>~ zPKv5YiXKdg*-9b_Cda8IC)gw>`XwhNC#TdTrwt}&Y$cNgQ?k`ka%@ua{89>%QwnQR ziU(6lw^GUkQ_Iy-D{NA${8FovQ)_Ed>jzUCw^AvBY46q2T5Qrj`lYocr*+h%bq=O= zZKY8K(|gp?du`JD{L%-K(}!x(M+Vc!w$f>W8Iw%4jA@&U8NZCVx$ylK*F7+%P z+bll+EP<3Pq1r6rp)8T@ESylbxO%pPZMKwuwscCiOl`K@P`1K$wxZArW%U;-wl9wR zzfetipkD)xz?L04`d~fx9AKU!9{`tNs`Tn)} z0Ymvg+xbMHf)MqBFx!G~|AL5=f~eYpXy#Bs%yt1u=w+Px%LLn(iT*E>QeLLizDyf> znX&znEL51SUYKKBnCD+ukWyG!TUb0)Sh`(UCR9|eUQ}UQROMe(ol;a=TU0+()VN(l z5h{MKUfg0^{L#O-Ev2}lwz!-X(Yal$?T*<1N_uTe`us}hGybJ>DWwawrAtGlKetQiLa$cTU#;1`+VFq1neuA8_7!6Yd?CI9_Lo6Vmci}H zkoU{bsb#EnW$eRc96M#${ja%BzUHxe&3FH`KY-f4Hz~|`=<(Dy#mVLB!*8^9-r)CF=$x$3wX4v-UtyS9 zVO&>nX1Kz1r^0-HrNzn03wD*3_baVaD{bp4?T0HJcPeMxks54Ov*G}ej=Ay}e9~1p z%gP_YRe4;;It^E;y{YoK|JFD4t$*FyfZ?}6J8y~mt3ys!huKw!->)`1_$H#RI`ASg zdZ(KF0m3W;Nc-i_5+Kj&WDCtPg`}D%-I#S6KY6$&qevjfr1pMy%`zQxg2EEWiCM;D zitK6;+O=7A{OeQ<>=vx6gTDliDN(GeFu^{jvEYJhd2iK0v+BsHbv477T`C;?v<~{Z zrjT66+g2li9pya4(t1yQmeKta%HbbybJc%F(Wz_(1vKsc}f z(Hx>efDj1)jE3AIK&*)$IlQnO1OQV8#Nc6`bbtr=I9Us4r$Q~st^NcI1m8-;K}^gc z3C#Q0+e8E}fb_ruo><@#{^SM;gCVsSkT4qe+x3cz_frt^IEa5Vgh0n|l>vO_5I!1` zi;ld{=y+U@)Wjo5BOUig8Yi!-Z;>!AO8|lT$yFAc*4ZBQsTfIbWuqaHbYu#tov#e; z2_P|8;2`$XX>1$&WegVy!BPJyCmuueLdsLXUk$+!I^|E6WJVWXvH$o~5$f8>;!k5^ zBVj!8uzm*cO1Q127|W*!oTW7u!C3q?P$d+^O}P^G^p<_2T`k){8mBZ@64b#IIFFXoE zfl5ODA6~0Sjc|~V^Nn%CF)gzWal-+K}c)^4zhRR{B-yMj% z&O3X*p??_0PC~H($n!)fjE;zZf_O<~P21^%+G8)^u*wX~*0B0y04$K)ACJYbd zkdVMmKlcHv<$5aHkT3~V`~;#;glbR`{AI|q;Ou@}Og z$|{nEDAxRnmCsi{^X@|MXl)UzCIxbdNrWZ>Ec=KMHbuAq4&p;XYtUHE5-4pAgH=0} zr%LaKo4SZ)z*Q0=gMwiFJhY%O(AiN_bMl=P1;$TC8v%&N1k~gW1PKQ~%TOA`KAPNk zB4?dFR{Ps$VMhkQOP}DycQE(SK6TVL{b13+0$g}NA3%}-#E~wRBOELc#fdj(v5upH zBPX$MNSLAE@(|6=zCzaiR91E`s2l-fNkn0)j zvkXic6;Sq?Q)Uv77)O|U7pEmbUDmEM!vnj&t4NLlWqQp&R{(-=ur~w@5eIu*hR(&o zECJ*(9DpLu3yGDdH&?OC&!?TihH2)PI`E=Mi?FAQX<9SpR3JBK?y;hT9BHvMh_f|F zfTYN_Eml%)I{#?_P{Fn`v8^0s5PmueMZypOgp1?cYegsr?nkdy{ry`5_mx<{hA14E zA`uY#07Rk}M3_Wn-1vF5yx-UhB4Ezy;RV$PFb63xYoMMd`qxz*OdtgoStjK`Lh*Y+ z*l8^9>ZZ`K{DNcr<%=v<6u_7QSWzJCz)Jp&W&Q^OZ%oFoan=_csOMw{|2nQ5V&0T^ zx4(`F)RnW<9gAH(`al9{)`VhW4hq-3+h4DFNnlNW^^*4ZvLcKAI7*C(DZjsJa7jS$ z(t5~bwe`F8dk>*uO0&?*tM;OjcNMUKxc)1d8;KQ2c0Bgls||y4BvNVJ>y(tJ$I6|X z64zpX`;Gth_gN3RB;kKxQ{Up3kJ+a5%1As88xXr0^UCVoBA?mbX230k#WDFQ8 z?vz+@>#;4enc8#VZGP|et7hBVmpcpIZ5NMkmom4@M0d)6r9ac!={mPl^-j1tbEoa~ zPW|}Fw|hHOPR9Eq*vsaOp(e5FiKWB$!M|wjRzG&y#)aZazZC#T0b=X>`f@v_)^3eb z_lsW)2o-vr0^z~#N}n9)`L&x0K@>7EJPtz&4FC~8+VW)&{dzC#+^qcYCr<#of9A}> zQObK5euGEh!seI%BR)TKHcjo$&rX)eL;CkQc(ZM(Atu}k!t8QDSk&d_%yYS>xwhXH zF8&ujzk3geGb=KGIP~d}422(gcH3)H=VLI0m0+&TYTWnh5+xXck+L74Uv7!yJ>ru5 zD|4!lO>*cyp=nN{)4p2K^)+x&t1bFJ@p+d~+al-40>EhCRhf%vW+zNzc5!j&_f1;U zL(Cz^k2zVK~{8y{KyZhPn+_=nHuNdNB+!H9zHSv&kN z^wDXLERn0(FTVU9{BX(A*6!k)t+rREN@Ccj=N3ew7RbJEQp2V!8%u#SPgZs|o93sBj)hi9UA&y_N5+#EuXo-`G%PdXdKo39r6U#2GQQPzxwBFMR4!AWkf;EJ-;bam zUzAgW#l5TmJo?(p?{^bxj=8@|y3aOHbE0!>(>*9Dw3CrE!MOHj`9#vH{1JuIdB4R( zI8jJsZDajaJ^12hqbINXsNJ2%0-F5!c#NMd~79Q4M~7kii1Cf3&sQ`?^1 z_c4oo4wbcAe!Wff=1S?eHB;B~&HX>$Gf^!!1vH(a&z%bpa=nt%v$EI*Ump?Dk1P*O zFF6?7gu1%=V|EpHZONX$m>{|%+zIYXgd>uFElkbX+Z(=}TSF@7e5n+gonPQHmPrra zDQg*~-)uVfYRxTwB<}I_e4l`hCft`+#UBL@Df_hX8tz-%hfG_6x<1CxmoTYIZ(sHC zV+?+ZgUne`h@C@ZO`>VbE3e_}gR%=N{E%oBN?U~HFK?`@ZS=sUYgm`H%f@f1V9jzcVM>){fm^BK?hHslOj`U~sg7h>g0_V*usQ!~Vzt9Zjm?i9Nz z+>pd2`GPnK=hd-W=84^j}`Wk((J0zlOOv#mf(S z`1=6RoH;(+1LZH3ZTuhc^M~FpTjT%R0wzD;InwjE;`RSj!2CPlX-${6t(kO}=CSkt zPiC*A_UHls8Sq%&Up`Np_&eY^)L6q0c!GX?H1ZJm^NE!psCd)B{LGiX10Ff1kb;b_ zg3im^_4B`W?gR%jpEibFt7_&Gl34?^h*=){@-dTWoz+Ed#03*9;^5k9UCh@{{c+zS z1Q+Jj8Gr5Ggka=PGssdn{11lTUq*a>Uf7a=Ru=c&jguaME+VHX)e4J7kuLJDuo=2^b-6LNFEA5mwSln-I+PLb;F&W&a;RF#jYZ|H;pD zlK%yQnQEA<`8CzZ?b!ZjlaT!L)Vy*gD}QO>*PmtpwK;n=`-WwLl6tRcB(!~!+X`Cm zsJ63;nCVizww5oaRu(WNq*-gH)vMJxc{<*5oirfi+*37s zOD}9M?1lLY)|5^n9mPQEvn*+a*AdA}tT!YS(x%AQNVC5>(hg&z2n z+@I8G5q;L-iFHp{l=2Ry(Y`}KL0mAtN1nyx<`{`Tjy;cR^?*LvF zaOTS-|PB z5>#e~QngLCxwa@K#`Cxe>Og9P&y#^mk!Bx$!kw%QR~(5O1|No2mO9Nos?(2MZj%@8 z?wXzxMi>T^sAidAc!y?kemRb!wY$5g%7uOT5KKr1xYsfN)d|tzv2AYK3bFZFxlDNG zjg9Jd_sG7SWLehsv)$EB;EZmNM!Ry#jP22tY?_tE7cUY%{%-sEYnIpVXsd^%ts?FO zf4wcZO%;-C1HF^?`pT$q))xWqmUgim{{*q57UqNNdkPPzs00}<+TSV{xp~P>PVXI! z*BkXv?AG%8_r@>2)Rzc}Go0V6m`U}pllA!p%uD4K>IeU=fEg*iS5)tZwe^G~5p9vL zdZ@x%h;EVFAg=W*@w=_x!PogCbESGOD(u60Uf*1qDV_0#xG!c&R4p>`2UA@`NO+QEz&QU$+~_2Mo4Z#F#nvrB4k!y^t1aaJG#`N z_p&-OtnaJB|AWK3cH{b^%P+%UKDxQsH*Wk-2*zy73Om*Qak12kA65n{1N6+tCF+NM z9`yQ~pD)#Y@zZ`2f)ROAZv9_`YjU5ACxtczEP2CNN6*(^O4e=b@Ze!tZf=U^e1w3_2bgZ+GmR|{=}}Xegd#{ER;Q$wuN879RFD( zW~^k1wlER02BC1Lo>WCNYN~oEQSyEuJgM>P+Wz)V(^$pK%WMAy!OUE3{6_(ka(4AQ zj}=ihkJBi0g9`hxSi*FYfO|sm_=*`#JQ<*gpaEg#_s&}*@mUUXG_?E=B2;exqHL!$ zu4X-N415cK6QOWhcc}UtgeLC|OsedfS0qr>D-~%l`{6cGQ9OJbngb;b?Jv4>F2|T7 zpje7;(a_5l*mZ>i)x}1=h<}}V5Fam4K5T&Nq9QB5s!Z*9nPSwTMUP26p?JHt)5OYQ zsrv4Q;xgFvYqlCYGV}~zZEZ6prMwc&ZB=MiUpFCTtqduuD%M*Yn}nL+EcK%8Mmtcl zl59wfo+;)quzqPa8xyrwq%bwy#>2g5XT_%8R9vT`G!`6JV|K*N-F@)%k0~VmwSmuE zEzeqYV>(4@@{>YWN_3S}bcJp8U|7xojk5F8VcFPgikSHHtdKIx0AEA0_H@x z5rzN!jzrJ_0WOpW(pnd>Yjj%McodHqR{+8sSzrMh#nO$O;bP^8NFE*F5fGLD_19w5 z8WTIqjbe?*Zd-~%hl2o`+U^&fF%!YV0~b+HZ!*S7+Gm-Kx=uz)<6|_b@ZUtF6CGAC z4znZiAM>#@Aaqk&!FCOdUPNSz74sgM~?>^d`Lh8s0Yz{W5I zX4qH;kBbVbOGId6*D0wnTvXbU#%~Iyj0i8JheGj5QZ^?at7EL$uyi6~3mqxVhGo%_ z2M7oo3Q8LfcVi)>Sx`AT;7bC$IZ$sF6oChXk7szZq0%gfIW@tb0}~*^f3u-$9E2U^ zVnZHqj>N~A;ZM7u+H?VJZU!noLyLm2WyE)uYl!KBOYAiNMd*2JpDt^(H3f2u1)U+H zXPE+VEQCK-V2PM~j0)T$hUBskx4B8~dPz8?3p`HRRu0OT07{dv&}jig1jd_-lH#D~ zMDR8jdy9Ax=_rs(KtS>Eqp9H&8ld2KrY#pLwk>Och-R>$$9O|9Xdps>j&w+Y%W<(< zY*-i*+C;^krvqVJ0Y65D8wG_OfN#Zvejv=1i`}yg0JA$%xk4hQN-K&)QVcvq8VK@An4T-~n=-bSBf)g}wD5DOYfaulc_5qW@uxU@ub z#sg&>*e(ici3ObovA0w z<+&&$DsU+R31vglovxKpP=zdk+xY7qKXP)yPCEG^&FHW*Oc;*>@xcRUD9LUF3^@X# zzbwE5ufHnA`mzMT=aAb>WFU`=735+^=(*BhzFr;t%jtYIDxk@ROA#*~pysKNZXO^C z6fR>QEhA$oFenlEZCRs#0qIK@C;xVeTFS+mGl5EC7*q*SasX*TfTF2LG#;R&0j2fG zrHWhndE0(dkl|%m0X*FnA0}k76qcsL_*0q{5O~~$@7G0GP+;j4%q<4`HxPf!=6V4E+qVo> zGB6^#n8Pwz&};!WF4muwR?0$@(}8RPBAvuv<_3OqVAh0k9}a9gDSyyy+n{U6VHN~W zM%r_sI|+zf>WvKjJKOd}#sF9WN=Cgj!tgp!%;mq(MeJh1<%n=^7DS5#_!6&b1DM;L z30QvOVFS+gAP@x5kp=ye56qI0yEsrS0$c#hoWT@LYr;pQVMn>ByjLQXT%;`#{Xqun zNDLOLJXtY>ieaS8kg&5P>>iuAd19P~26h&Y)wM}X=!&ga1m}5l+6;i@QXZ9sJz{lY zEzyr>@DCS=DQo@@XUS1(07lavd&VaG<%kHseJxKHfPRL{lcAaVD@6q~s1@Upq;fF!OugBUsL7$I zTeda16HyTNn(~x}>$Xu6TPlj{Ax8nI76)}}h@n;!CtL?wm)H7vMIAy%Y2-B|X3(x1 zG++i|p&D`K{`?;{d?Ki!Jc@>(GJHE7Q-D zKeLLLSkV=JF3eWLLWJR3D^aekK(s}~E`%Z#5t8g`hwhc9=9FMZ9mQyJQmOaQak+D+5`GJJT5kmrnd#TLW8}bSIJOA690mN zMl}hA^mT^3@AS~m_0W%~{wy*@O10$yPzVu#5HQ#20#gj^3ZXmIyL*a?Np0$$B6l%O zQ_{+@YfQK@6F}3E%4FpEywqTuZiZn>RbSAR$?l5mR6;?jEki(;fpNw|1xPh#x_W|t zJk+|2ZCm4CX1$f#DJglqYE*0>KL-JUND#0mq6_E(GmIClg{kMu`yLEndGypZGE$j= z$_0^d7A%U1P@+JU0jR7XmT8xE9sROW8~e2hE)N0_5Pnh)iUyHN9P9xu5Xyv@QF=S< z($1qF8K(5#dEO%r0NY8(JtPF03PUpo%BX+`0~&>gS}Z-BuS(gqeIS2;&5-N4q5)Oo z1F8V(Adi{0K?%A=5*+~1=nxM&M27>62?7A; zK_LeYIu82Wlg=ybTBmo@c47qZ&;S-pIt_cA4$;F8$xyJUv(Q_di_z;tg*XKNI%~*7 zIugSS51`G72sI+0N5$q+16_c3XfhN_hr5QM6w}@n#3OV0{}M_H~%Q#fzc-);Lae*pMur}1@!$9lId^>9sx=rzSm6wp36g3 zSa4l3#)d4gQ}e@hQ{+|(bmRkkKWnI_9ym<=Q0BoWYS5K*gcy@gnZPUva91i;iUn`@ z`SCjL)6%;lV*&y=i1eW#^}7)YAUqg=VYxs&{}a-ItsKfOCPye%M#LB)rw_-SgF^Ci z*78J@$*4RMJ%^3M;dQ`@V0wprO><7x9W1tos`Vt#%N6JDoVR$^^#eVo1#%MYP=5B&Y=uu7!u&vrz~RbQh0+*@Z_Sm|=E!ehO9@qQx(fU@wk~WKZ5u?-k&Z zuHPo2wMKg~d-z{?{M#fW`+c`qJO&y+c=@K3`j(!{Rs9{_*qUcAI=uVS+_6y_6W7Vv z4-{mo1A04z2AZDzipmqPw0Ws^=;1tP;`xR&dFNxpMfQsg?D_Ivy5;>vlS87AM*||7 zI&xF_+EZhhGW-ta)$Ha8egQMn>xf`z&gxX*KqGdtdG48vAnKkG72-{WM_vE3l8LP( zK67FU;K9PD+qvJ25mGFKJO{o`M&2gE8$YxQJ&+z9fmsvL>r8vZM!n zL*$6)o+-qBPFM{64^?HFW49AD9SjeB-_#j`fZRv#V!bM_F{a{ z=z>7H^@I}@DN;4J$1cQ%2`eYvqpLr2Hfhae!_7D%^3+c?qw|?c;r;;s4;5=hhm+L7 z$#VyGpzk7%j?7eGgv3Jg&T`o^SWqVx< ze6SSvoKZ=|YO>%{9Qanwd*!BUf)2~nB4MF)Y%Kns@^G2ATuU)lI!ZAnK9w5V{G>*( z^WL##{o1o(A$a!wa&n-)}%~E#9A~fl+8v#!&h{45rv#nSuLD`5`*9w~W10-a` zA+Y5oZ|yA4ac#5|lj}EzCt-cL<&?sy_kSeXv0?jTAWrlUc@ETv)HZr+BRDXqj0zXz zA{X^NPi`ZhYW z8SvP?MA$lO9e=(V@VpwC|CfB$Z?fY~eh(qH--SW{uEzZDhkN-Z1vPNjGMeVd$4{s~H*hvW%lp?j zkev2Mu##V{wHCUuf39|n%zSUd`;dgvFJ?Abf(36@_a++Mh(dkgWB4+H_vY5-*=pp9 ziS0^~@gQo=`4AF;Xe$=E;0W)3Vnlkds1iL;nJ&Qmuxey%Y!Q09>fZgIc{z7?iIQ&q zP*9Mh^sa@4g?{g{e){y;jps9#4;({}V0_c=Y3cL%<`sBO`AN)J36k9wG+* zV?U>-5`sHPwny?_uaBY`-`2`<9MSnJ1-D8L%Ys`oek$EuQ9A!XPa6KAQI*=fATA_u z?%_A#i;Lf$n5ibddewAl>8&Fn{Y}$l)XP(DrSxsDn$q`pA2i*AAYK`1D%p3pslO*x zXh*TWuNhqU@(S%Vg8XbvEavrwgz zt(loQ`m42;`)1Vznj}q8*~+y)+)3f2neQ+CXWI}hl_jCYkL@!$G|}i+ulkz$|L_mA zq?dMbS67RRio>4HPrp488=JT~KMNJxb)jzRBjxyW?@XMEN zgDrL&WA6i=EY2)UzU=9O;-&fErSbhaWcuot)+PnQjD>=PGM^9R`!*YbU;EY4V0$3)={q7KF9 zN5`<8SskOW&d^hbTD|RFYE1!E4i?%}7q@3f@A>O}SM}}AEWCNT+<}KB-Ip~E zS9*6pywiJ)aI&ZHz$4#w2yQ@*`R{b)e+n!aXX;R0P}4z+itb3&|zsssU2%Kx%9v!XJ4#F`OP}G(SHdOfTx8-9wK`v%|tP&qgRdu$zrh3`kcfW^(Mqb!W z>q(_6Z9=6s04xRb4QS2vtoiBdl#@q>iU>JY7YAbVNCL^O&-jG?Sz+4AOzgSAL`84> z6;t_h(iI?t$2cy*xZ*1N3Q!$8O;d%zx6uV0m363s{L@s>3T@A=;}BJ9{sf=~=Pl*k zdHh!PEki`IazIKHEK48hK5K>&Voi81Nd_?O zPW?!qGKm#x>uilCCaRW*D+XvYT;wUNLXGDK+nc3QcIC5@xct@SHEszCu3ayaQk*r$mF_X`h{cBY28n zWA$s}>m%G{t&-2QGxyWx-@P#{h{sHQGbA_qcka|R`&iAlkItw~8EyB^{<|9U$@k97;4rPft1&A-%m4dojDefB9*GEP z9AQSWrg3c^@Xu(=QsX0)fhmC z0ibMHP|;*Psvqu8|6DO1T}VLZ7s8B+)pWo9bGrz`PxT`HPf?5=fl$USrs z#;uFB&yWN|SHlJUY+8XShA%B%TI)18sio7EWU&Lwr3oau}H|Lt%uF@iyCSTr(Rna=VYNkEE| zJL3F_{M`y`F--undy7LxIanTDl0 zWf3yQszFNE63NOBxmepddOk-;{pg6P{U!WE^bPkR?2aNpnBY{X(!eqqsm4xgmlXQe zD;V}$@f>1~!jqx<5oQ#4yw+5ZiG1oelLb?h{^VE1S>{cPpE8ou1ILSICl6Ts^60J1H@=UJ57(D|nck+?ODh z%D7K_IGUYi9IRxn!4mGH;`GDG_|kheeuDV^6ubFK0Y}s5@!rqx-sHlve|IAE>F|aN zcwwD7Dtb3Z`8H5-Um*>q{Fn+VKmAfJE#Hl}KRT>OsB0x6@t5xPYK3ksf}O}?frbX+ z609Ya?Da{L(3OE4ZV_zVg@wwO8q=D6P-FYVT27Au-<`ogDByz}of32S$FX>~m*mo1 zcmoL{c6k4zFZZlo?E|g!sK|A2BE6pYeM@2y@RwT8Bl|Btu^)h9`pWXlM(@ds?~rwzE-srm zdAwjtRNMXYW~D#g+|BvyF#vJ8zCDMHboSbM-#7Sf5$7=d0_W4|;V#7P8yX^Q@ghA& zwJo{VPKT)YpgllH2`}4DLUpQJ$;DuA_UP^VG}Pv9qH}*bbp$hnb%j6U)bKq~x=S&q&E;W5vo&`zkNn z&kwY_3f>KkwD=w%I`3pP;eu`ab*>3K;NYXM4m1v@T>JARE4iY{v2ip;thzq#X~oKN z{f8LX`=@)5rRvKSpOS_apZ`thH+_-nU+OT}n5Jhnjj1~<_iPgS{Y@)XWf9G*;)RNP zqsA-lhn*G;n+ugPnsDQl#Y*liugWr#O~Aa4Rro&lus>$P|HjsjDLMDhpA%n%WHko( zoi1M}-1-r*8v+$;4*b1va0WFqyZF%J-THdxZN%=iyzm?OPhy_&>e@8JF3Hub+3z(|n6Hjt5m}i)RT&5c;}c1-7Q@AjHoDR}mdK%&|40#xyih=Aaq^C(LB|`&YpR6yuc24S4 z+gGf&yNd4at&{*$f+|pxjcr6V_kjoIPe!TYQc2-FGQ4IO%+&+0yQjZWy(lAzCV`lC z_wAy7{zneuu1lvY52V`piz?Igrc=S=k{jNx584uIh>DFXH{chQ&akQ+-N ziHlhvBPF+G; z#cqLtSPX&e`+<`pV|7?Z7rt*Hj&>wm^yG;iR}2VbIfj z{wgleQJ8p=l#(J)gy1Al)g`_G;VA#&h|~P?t){1d#KDCFaUA+ zP?)=hDU8GtknI9d$k3DnINKz5bkU_-t{z*ovFtt0W(dT)j?3ao1%iQ&+5|`{K5x*X zASpr?+wLfM>Kg8Il*sh;!Eu+dHs=mM(Nv&NtjM8b8*a?S1s$03fFYuI+@Y(Uv}14n z?m)5*|BV%|tKg}}O_hQ3L*|9TpIr(&otZ;UQ;?%OUogR!=d5nJZ>*3=r-rvN&sTPTtI`nP>R|G_d z9^J^Oz}-s0u@4suHxz437yP!m8JLXwW)UkER=6@K^5GFlm5t6qQ-#8higDxFKJ7n+d8*ml$#BG~!5kcQTqc2$D(|(~sdiG(hs0H%JF9;uZ ze7Nk`;&H*m54%oupQS*~urG-@MzY2a?{Xzi{978VA#J6dZ$PQ$wqMULEcRts|YWNuePaqpXF~F8a7JM5S*fh-rw^ z?uqM8#>s89W$ED_F#kG(xRaQF7p;UIt##RV{nS<)+@SO|g#(wQtC2K37|bn~cXYY% z6ZhWbt|E9fbt&*Lk`6^7e72#_uz~G$=N|gFbVs@fVy;TDt_cR-7xz0qoC=QY1U$c9>=rFS;t>yx#BEl{57_T%Co$GHk?3kcUY^@aDF9|W))bR zjs-ODOd4*+2icr_4?T?xwQ)yFSD~LH9Nn|Tai|&i1%naLhk24m@|EMWm+5yGc#)5^ z*-!(H9}h&2QgMEGbRZihOozOqAmyu(Rof!JM z9U`egi8MzZ8pSDc6NbM5!J}AtFiCj2Zm&L0sUpTIf-ZvdAhD`WeuF4;3}KFd5jQ88 znk-peA@d9HVbFK-6FXeqIuq;FebK2LaVEXC{@{(?VVsp1YEbsv=nzDN+bE4wmVbxK zwuC7#vIL(8UcKv`Hwr3QJ@D=fRwm}?hqxEAnvj|xQ-fa2(?m+|2S+r(^Z4ZRM0aX( zBW=K8pY5SIB!Y7p8P9r(({?`@3Y%9gmn^zxx0vjB7pEl3+KGpn5@Ce^BCEH_G{~>C z5rp{Ho43~rLk!a@z$=!hp(SjA-W3{fWqbSW`vv@Suf;xT_##i|90$F3KPd6K)zWC$URwj;r(cia|$ z7%9n`okr>wM#=xk7gt-hp7+6`kR`eGqSic@Q)cNW=MNkeebOcIybK@cZg%H-c)Ys~ z`@WK+z0^ELbaBKUOhIDslhplFIFTkZ&+EnB2R1-NmP(TCR4x}ok{&SH;f!=3O@o&BeL*g4?B z!>pjrt?$!1)3y1B&D@_01N+TWahR0a2!4Bpm<{%j|3 zfn~1xoBKx7^oZsJ~$(+}aFc0s)1=WzW^QG^}RtW$<6Pmd@NKf#K;mC0~*jSRe#=s=zw z>ZYi}d*E~iE>tp3L%x8!Q9-2yds!fFLB>g(puuL3OlCu zbsc&AL5zk$2!kk-oAtK~-qXB+`ZREYFfN;yDRal$?%G@Po0cAQxB&&?>H^fyLqrvD z3iL-QJXh%_BgwMUNEt9s8GqsaQ)&NmaJz93frlMX~N5z_+ zCIKT&SbtX^l^b7nSV1*8nGpld#GN=9dYwG6odlv}*wC-7A6lwn&Kfa~PGd&Tyt3*- zSALKvUO1lyyL_bz^kt5%jwoxycBe&8c+3sbbbI$74f5_93CTWtMIPr~R~2}03Ul1W zS;lMfnZ#hnlrS5%?X3i39@5#{5fz;ST3+R`k4e--zgMtw$Upf)vnS;EnAxd`=YCjk zmwcrRaiE@l6bOUn2Rv6vYdDNn8tTF zdb$ElThUn2j3@2~p9>g}XFEe7=4bN+5n+C^hqdn&@4RKX%i(Cz`eB(r@9hH}BcI{y zc(?QBXE1T0MY@cdQ{DDGGs@7gJH}v6;T*Yy(OlmtFY^{tr0}YPQ2SWQr=|2ujFpEh#x^h2GR-1wr<4&I}at&s$Jh-)5d>np- z0(-nmvXG6feX!bgev38;yFys)cq&nny4ucL%fWp<0pv}5_$;Ob-6gXmnyvedcc+rg zTQ7ka`fJJcseDrkM4l4-uBr_|Fp&;I8{90}q07jDqDeVZ)ya0zR1l^k&D;3DCMV`J zMT=B66!!&nQDWyg)#0fYS)APe4PE&!$qB<${@KW4*5&^;IeC)verW2`vtqA*(v_RZ z$#1WUBh9gQ%*FpLIYGP*7=QEYSws-(AIXVBsrS2?Q+@wTPX4VLGctc>xcXFoDev#( zq(0=&_Yb50T8-(>-R1Z3{c_Ncfjj?3SFVO}KeuP8AN#l#G57P$1HVuIsK$KSh*|p= zx{_aw5!B%l;bPAJsK#8Om|?a*=9&rZ`A0S8Kj=!G>Hn(6{0m*VS&bR|e}S%Cott$a z{!etJ)s~PsM;n#gzv;?3C%Zj=)0Ojche_rVAUFMhe!+{=U1F7xTis}a8WXKI#x3xnQ9 z_}z?JSoUKiNJjb>XY5aGV59(IcfdFvIn9x{CLT1@E3 zncDTx_d!E3VIQLw*TXmoQnBG*GITe>$1c0YMtm;_+lcsa`&w+|#NFDB$jL`Tu~Acv ziyKkgR;jq?nOk&n5Nkpt2C?J+cZ;|}co1m2kK^^VFiO5kQTH$FZ>%3OK2)5#m@FI*|3q)PNT6NbL zAb3uRuA-dn@e}M)6yZZCg<~mdj`3I*4m6TO%6NH#hB|}mh+}e8uan~iY`@S57dVj9 zeP3iRzd_qBwZc#JQ3dS2n5xOKRJ8}q)iyZRHdanKmpAFkZk(vU@+ISeuRH6c#T8b# zIoI|11an~f%{~_5C;2#O_jJ3X?*wGqnyP~cn1RK7%P78h=gtY!tV4qr)T4Zg2vIE% zEeeqN)Iw7Bq*<2h?#o`~JGvEDczR%*_u>4v>1qd@>kb9Q%q9xr)cJI!eQ@bvK3(Z& z@L}0LyyNiA*%Cja-w_Vce7bUV%+G{RS5lGA|3Ozqk`mSUbmb|3b9p{pS@|M$WH1f0 zZN(0ER7X?h#U0%}D+8%3op7zXc9jGtv=o6VWl(RaTV0G2%VS8Y9j6MYI%bG}G!s+$ zorU!v07d>ZK^Wn*y#i^l>Pq%C)dQtiMY2Go54CK~v;~;c5Es+fBc>k+K~czdcj*kt zS~}c}!lgq99Fz^{%h+M3x!p z_(fQy#qK-)AWv>E1Zm4ZJhu^VbxG27XMxahtMh?^wv&5_wG84;1usyuq!oVI<=_tY za4O+~>!YjFsO_(_Gf{MEDnb?zJ*U)}VBsoSbqFI!G);;Fa}~O7+&eu-e$)QtRPE{I zB85`3q(f|&z^(z9z(-9GiB7D0A%94JgGK#4(Vl%~01i8s?NL;cAoa~zz{nr%y#oWk zHn#PUm0P7$T;I?g-=YVH83LcgDuHqsM2WV1Mh10vYeB&&rnBCJXdL1BL-^@aiHdeI z*f{q#6}7;$L(wO0CQ7$&-zZD>sM2hBChaDStnkxn%0~9qIcvSu&akKxX+U~(nX6sM zz7*}Fs?PK1wpsAcGM{tASR5BU@&l?C%@N#w@*T?c`^?p+?@tlpJo=8RJ<9E!OxRQQ zuJ4RwP~M04zIu6M_QL@gmCEM>0C{uPa|nROw&{y0KIgmr45!or(f{%V_U8j z>J0BZ5PKo(vYdj(vHGs-J1^v=6n>TWtLd?g4Gf+fm87K70}n|Oqr$gk*E2~cA+WT(#k>6|?V<6bGKp{E~1m~lqqs)|v)K_4$LYu6_HO$^?- zy_~;z-h0aJR@8@|v5WPM^72x*LOZ_3i|n%C$hADnMs1_UtBkb>CfkI6-F_(8>jxAB zv-FI@tATX&(cfF#8b|i`2eQKy<_eGTtH?KkUInesz0g{JaegCWpwoCx9c%P+*?2Z) z9LB{B^DOWJ4k~d!0GN`ErSOI}Qqh71l}v4sbRwiUvz~)w|M0<`%|PYQ$=`BAk&n(y z#c&-A)>Iq}I!B*H)-*nwbH8Trt8-WEQWo#mr}NDp8x^v`e<*WHfQ6j3Y5@qjDLM}( zga#UBQfzFf?RVp4@iZW{0VrrlKT|(duzzZ{F}Ibt)=Ly=(`TM(etV{I%BvX@Y}7oe zCv5jzq|j*A+@Q*!Ij0q|3rO@DPF(iPu|We0tdu*ma7-$kUbz#KO4ZJTZ6{Kt=-VS{ zr9rG`>8<)Xzl>j+qr%Nm-pr&YuZ=!LnbOUlH@2Dx&C$TT1X(VW5KtdQNCXLqymqhF z)l~zGP~+V#2D{23yXR<4s|H4JgJ+EG`q{Wq|Wo&)gutB%KO3!vdu$a0N z4GBg=6d6?GEvabt2C49dsE19xxAk8f-Y3|mr)PtR?n>I82lZki!Wl`??4(PN^a>MF zBE##2E~4Css3XG-QN)xe(!Q~vXR>vuwMLYD}#STbk)*-vO(4+ z9?p#~in3a>P1;js`8cX^Cdg<#gHK{Ut)=S5r>4Z!>2(jQsGJa#zyQj5up^`d1kiGZ zR;uI!V7j!TX{8Q)JJQ@pqs`KsN!!V!0%$;xMU`bjmFfJK)8@Q0k1Ty{_qo|1%<)h= z0P>qZjW}En?|Lr5rI8X-4%&EEzPfXcQN2I7iePEs8 z+zt)#=7(NJ_wUwUP;H~06coZkzivsrA7y>(HZv|2FkeDN57WeHbpe=%R3U=8UH8k; z#^ybV-5GGC|LuxB)C25z01au6YPS^A-Nl6_8qidRp>e6yNG8IQ{#>Pw2Iv`HiMF&p zS(B8J$d{=goFp`%*Twd6Gy~zD2-~Ii#FUT<$t-kn-5!)y=Soc|R5qlaglP%3c7BK%=fFrAno*1pn9^kUKg zo6Wpc!G;RB$6Io(`(RK4C;mVx70v<(Tqu|a7aHCxBn^pk2OI#XS6#1mDuBt;!=oYm z=C2SzPiQHj<2|&iDrG;%p15RB$b;^eMr`Lo_q+G^t2$)00dQ%A9gBJZNOa`H%XT5Q zOCyL}xPXh*u3>|3V=Xb;J54k!YDu=VVH%nXf5*P>a}X0b3^mV#q1N#4bW(|r)Z>HA zJoS3sX0#^?0dXMJS&tUR>N~KsH!e?KhD-}sF;Uc`p@Gt`iT%qBNeBGT5DWCv&~$GsRHeC%h=9%c>m_`E^y?Ktb9DIu}xCUmZWORZf#ze zGp)PwP@B-XI9+8Iejd3-QrY#+RhztnX zn8^cBnYtu^(iaTCg9+9?G4Y4c)Y*%0MF1*4oQP)9aH(*m;n&6?aEv>k1OoD87a@24 z5D%2P1)^*-SRyol6K=90IM#+k;L_-QObD&3=Pgs~&`g@#*FBJ~ByUc=x{*5#RC2ha zcT^9>8w+^x%=~%ZW7-jSfb2yTCsN6$00liAa{!{mbd79#y_4Phv?K*rNAi?og&qOm zjMp|qLpawOLWkIfzwLx4ZevmljA(^7>ZCYHQo}UGwzmKoDnlB=0f#Z+5E$byhMIUN zIv&)6Dl$+OXJ5R8HD1_}7({A$0#a!pjT&;vtuo2_kU%5=H}682+fX@jMd}~Qh*;na3a-`8xOGKae#;Mw|Er*l5FT5M|UG~QRcI>tC#q@X9&-7RQM7cbRV*$ z*ki(>=0qS!f@)ls)Uoz%I}=a~r@4xyr2R^mJwXMe;}JjhA~hh7FM0Cf21jHm`ZlS6 zJZES>7jl$1_;ioW>nMY0%g!2#9*lq%L}%)(zy>Y|Xn8iN@Gn&PB5AS5nXep4F)i;K z8->>TG(f7h9u&6p9>I*?$$6ds&6&uB3Z;50+qA&-XzgEnH3)E@UzX;19)iL^;8xEY zx$%dF9c%&5vMq?>BY@3gh+1kt&VOi0oO%xJ`ss!zj0r8Xb;FPWcwPc}2^FyyE`8CU zO2si|9*j#(LJ>-?5-LPiQ9^kM(P+q0RkfVNr^wy*V?v`~a8hD$13DbqDsKj7la)B} z0C7YeeK=zMkolg(u)M@W?tmQ=>SnVK>g}dLw2ebkd6zH2!5W^2G{BMSFV!Mg|vIJ$2x={ z{Z)?ibZa@`-uTG@=GWHyD*EQq2-~WAV~66wI@-+y3mgB6L#c^z4C^BjKs56}^jdSz zZ*O7yc-O-fxsiwWtix^{N$TZqSYbo}z~!#5=Ki;}+o5_b*k zdLFT}@r9V>aN^NgCJ?NbdF5eg{xJXc9KWCg-3dPM8xQW0A zgy21hH=eeWj!>3{331^wlh9N+?EnA`xC`O!WhJIOGuc%K-CyT$=PN`JNZd*7%AA9M z?j1Y%Uq$5*1?eO>Xmv-0#+FNv1!za4eezK#tP4kQWG9-RN`RfSMYuaR)muKN%sxByI_bq5%XTkA_xG#|g0&g9N5$Fkab#Nb z4jmt{Q;tuE(Bz)TSX>1RP8hBavw^4!*K|+aiQ>P)Su-9Pt#u~!Hb>RG_S&aW)lF%u z+Y|izVsCq{;7Q-r_CI^}gO-hi@4CE?8v|DoP`j2A#Z#flj{*KzqF+YK8%fLDwjpVI z(bP+To*wP=i~Gx!)v*nJFB;vSWT0LmTF*VMf8AJjY|z+q?RVx^Z_g^!U-0vb#*NWe zEf(Rcu=JowiFIXyGkM`yWKB8K(5)X@fG5wn4u+S*h z#*)yn1?63K!CR{f+V?m=uU%-39OeoO9mo|7Y<~UByQ-shPcIm@?{uMAVS@SE7VbjH z^Ks)G{3x6Z>kYd=z|A;809bKhV|63N|H|~#cha|bjy^ORT@Be;w z-{2}yOYZq>!k=riL}@wGh1J-;>xgi*`h4L32c5f5eSX5jX!t+~P$ru#rWID}`BzBa23P zZrQuzBD7IuTOS!ZX}}NiAe9dy?>0wP^+(?O6nXzoMca0MKdF678neM@F0YOtAXO~vjUiQx#sjm-QYhH|MHg<@qkFs<- zxz_oK-lg6mONE7!QzGludGCkTM>}IaeOmvBjpblBMu$?qsK<`!#*Uf9hLU2x9gF>u z75npi?03J|@!E}V&9M{XF`?81*`?Z&to8Lgcz7P|%TP)r8}+pr^>rvE%70_QjW-t; zx8T5=Z|2SQ$IX3;TN#fF1yZ9Xr+(fobHKO6V{np&dQ2tr1R)iDRgFNUjzrl#S^@rC z6^qc7;WsB!MC`>QH#VvRe$H&|%iHbus_OKt+RH-yu$jr9v+8VyS&Hb+zveVvl^ndb z`|QNrw!w0zGN*fg&1=5B!G9u7XrKDkm8>kBDY1Pfz&%L?QF=CG;ofK+WxVH*?c%v3 zO_AR)YqHo=`jH+eF|7dJ65&f*y40R?lS|rTT{-H9T@Pk`d>gK8l)Uv!=uYdJzsxUx z^l#9acwKoQ$nLji@PW`cl|nC%<$Y7{8^UI%ey{3sIV~w-ZrzD@-TH4^#+Cl^i1_#; zs?7F*vHp&riI>)~xx(r#r9rf`%e&5R7_Q7s3_Uvk$5{92*L;K5CcSd18;^_KX5)Ux z-F9F9u;>wsxN!BD$FVm-{b2?01%*W1K|Q4;3D0n)WEllZ2c^8RuM%GUh^041i)=H& z9rFx#?2gB1xV$?>rtQX&m0@?OO9IKKzWNe!mi`BO?;X_iyXfnF(-TS(kS--4(!qdA z6Ct5j4a!eYP=g{(#DFMB(S#0CA|fCn21Gg-P^zc_5fKmrA|j#&M7juw)JSez>#V!h zK4;y1?w);T?jQHg@K0u#Fq6ql!uvj-=aFzTSPG*j?Pzs=uDX{+ba03M+Ijqvey>FS zxyja;1ExAJZrqQLdBJNtbn|$!k;<(zxtCR9w>lA7iG-Rhjk$l)DQH?uzoVXEnj`9`sx!s>3PYmE zr(m+b9Gy=ksV=RbK8d1D^bv%YYEPIx;(irySY+7!#kcFOYSz4viO{NjWiGA|y!oMo zU3$6_%Q6GGvE#%~0E>c1iepV-vg8xD^!i{bLs=`TX6RINqRx<#c6jYi?c~FyIevvV zbYy<00s!fGIc)#Nsgqy8qYe#wJ5OngEEac;C2=IekKgumx||j+1vtkzEKte<4u!Ly zcQbLfBlWt}D|n772|0=7_kwFvML@9YTC8@J>mfny63dpYX_}XsGm>={M&2qJyG=kk zB#fbW>-_1qrE{hyhQOG8nuYfSjTdB52ouleH|+OkPC(w+Mi)N(HoVv<3I^QOz^wg^ z9*R?9b73ABlg#jxRu#|y34+xmlVSJmX2B(QRz0NOd<__UDILS{%#(+Kxsdc~O@$Xw zhwv~{X^MPD<0G(g}Vk}8y0gGGQ~Ls=X-nkb11YqKb$Qpqo*f+O#mz#l=BEK$aIx{aiB z0ME=?*p-SGSo#=4gocFxiDE@$QF9JWR)t2>wj@aSmxAyeR1_fq1j(nz+)+W?QU9c| z|2moKAT^Zlo|%GQrhpKQ4Dhy*XjtOLX_$huv!C z#R7JBEGmdlk3n6Oq^?4#$P*NaDCK@ecR@*pHgU{Mf+c$5(}KcDy;cw}coiWjZ;gle z?$o(Z)_uIXAwd5J z1$h1~>G~u}>Kv60PbdW_w>#4@V)=oq7V~@H^?CJW| zLKe~1r3p*D61CvyZBvy6M5p@9+ug<#8pd~$Vl)N{tgW4NHm}3q!V{dwFYFX!u|!lx z9|pAEgG()dUQ6I&kVrhV35WsmI%3v`w1Ml?a&c=A4~)yX=ws4Z0^mj;hAvQ17kXku zN>G-HQn*SXspsNKWbigOb5RVzoVeE$va^K>B7JHz)}me$bGgRHUNo)0s{>jCEU*~W z5~?K)&JXIp!FHfmwm|aH#Wojo7F*3aEZ+WHP;!g~6$nz2rH{!>NSN-_pu}j7jOxr9 zR^0w8dI%&qrbrgLHq-{z7wJn%;|Lt71C-0||5Ysj2vHg<-wrI4*P6b=S`t{Y@bv+s z1?pumBigKxn$|o6K=>c(`~hCfskAm=O^%4-t2q&3Z7{7pAjldq&QwbZ5-(+CdsINE_gqPdi4L#MT=UdEk%J-I9^qcjH)L=;HaAxlKw#+Lz+#e(ufyXmD! z7I=g84(UddI6{8)*7C0g;>;ZK$N~sHG&cyF!c{LP5=_EaUpB#q;DqJYDDBJCBfevR z1_Rh7K$BkN7O?bfi8_}=lGONe&MhWYTxSyl_sRtCVl!b|t$j{E$>^TBB1v;~iNwl1 zugscy9CAoW9i&##ri&=St%U@+FXNzG+k}c3?K#hF?keT`s@yk}w%1RrmV*`$I3Yzp zxe!m09SmT*7e3l0@E1?vQ&qXFc{6NpkxZTlc2dpPyBF%>fSeT~2tb)>YU43aSE`Cn zT*N1fj*AQ5XV_@Nu_T9-%KB+roBG2GX*!O>f>MdG=z1#fI+c)daS*>Fjt~ooy?y99 z|LG$6NRtz@e#n4U=Wu99N;VJMsqG1x^3A(}p!RmCJTvOOkniB_*Fm5++X%}iwTBF8 z!J4VHW`T+TU8yhSqFK=JsRHaI+fv)!Ir#*RCaFTF$sE!Z2#2x+JoLW`lDqw|0ywBoS}Z1w z9v!LYnW4gSx_Co1;nbbGc{^3u(Cd;vAw7xJJC!sowJ#Og^*((1t9sR=+cY+Nh}A0K zKLo~!;*$|N2C$r*_Kp-)j1cy2u4^q9TIPv)eUh>+y&c9d9iHW`c%gE ztSFA0Al}T-)huFpn6Rj_RKk@Do)a%UOZPV%v=DV zHKl+y&N;4z&}66pjzkj{qM`!K#XM-5owiW{pJ&f7;DI>ACEOvYce~c}iur5qMsrhA zS6`SFu_cL}mpZhZ`Zd$CC5QYTX}8o$Q!FxvWkK(SrD%o`^I0+FbW77Al=gUxW+M-* zU7C1}@I_pTCCa3kDq`q=04y{tSO5o39v-90Pmi=;?01#7EN)0u&moacqRv@%gbdAhXsc&C7m*N(dsn?%F*6j^}^TT3gkWQDEKG^T*N+C3}E zSN&c=;s8rl4J1RN+7Cpd#M;!4$*KA$yPNE|o7s7+5}7I+TaG$KQ^*9k?lZxNzuY0BkctvNtC~t*nky}NVX*4+i!DLB*h0nLOu%{X2c*i+$6)PYs<>#M18+*e_5u^ioNvhL!P%`8O+;gk#%}J0+@lC6{x3!iy)v z%T-kxeIk2(BKlRs+a@C>N}_5fBWETfic3t$=2Up;<*l||Yi$y1Z8VjsT?0N;aA}lj zDYbW!dcZgCh+3@ul(J*=zJONbz$fjRJ9}*_YJ$KRMp&*@0!*xzjntWw#2abCcC?K2^`lpU$qG&Z#fE)1{uL zM^to+KDU2bSi9^lyqw`3XBJzslP^3M2N!Di-_!OlH1)q{t#Qv@qe!p({t=DhL*>OM z{1rpWORo4UlBoGA8l_p~W%(NA#WN){xjSV?7}Y|It{k#&e`VXT%BLFD6aLOaGp$FX z>7Sw>Y?U+7XPIbCrp#HUie`e&pzwWdRvFvZp*<>5J-RWL5q=Cg6)nku zz&Vap8!;uRAk#3Sj$^)}@cd{XPiOK{^(>4~_B+P%U5fe(=iU^SR1ZxOM}YcQPd?R| z3)bmsvTQ}iRmlr>m02n~wu$V~Q6cxuHMb)aSt5XWONY*q%C5QGj7s=}gN^gIV&%3i z5OfAu9jNNp#6BeH`qHHbtMc=6G65tlzgH67iUrj=9$9uB5>5j%t50`v{i{%!vJQ>F zwuR{Puov21Z3=`RImnKZ={Bhpf^uhh4b6_L!UU@_mFWbPkv4!r6}m+rn*azpOQ@6N zg0xlrN{BGTb#IgFBRjEejr7?Pn z&%Q%O1f~KO%y6{sZ?Pz?V0zr7(qcR7#4LD$KV)Tz+)UY&s8zjMJ9sKc$-r8r6p*lp zQ~ac9=E>S86)m2(edt3uE=EuL{ZdP^o);@m3h_dLF4VPX4(*{Srd-!}k)`#cR$KL< zUWAX9hxNM7i!;!?14W;8c2iYw#4XbYy0ZraN&|(9SaoNrb$9JH%Ko|9TZ^ih<)>C4 z3xppsJg}6@Hby?v=>5a}+XGdKEY9uiFi~}eGF*jYsX~ck&7U6<6_!6*>uzSLJeT>2 zX!l=^kAM8;(X+6=q z+u`LS$LtzQhds%?dk#!4Z`$u!`CNT~w}0z6?zfSJ0{yf8U*?T0k&Q(xD?`oY}`rf12bw}^+Jyue8?7?35hC26Wdp%y( zdA!+s{C(Z=FMCf+)}8pV_vC8bN#0&EqMnS=_mr&nRM0=AT7PPn{%M2y(`Nc!HuYWy z_0PE0pE;@T?Zd10KCkZ+TJLjJ-#4M&H(lQ^yWa1vzJE!*{{#KA4fSWA=?A>54|t=0 z?tT5aFZzL#^?^V1&#%^>=jl@r4HS$)kYq!Uf&u@~FnE{21%rkQW(FZP4Iu{&F1j{c zJZW&rr{U6hgV4~1(5nVv2@PTC2A8uNF5fi>FKGyWU=Y#J5b?|)@?}Hh8-u9#4N+eV z_=ikaei&R`ZMe!apduQn7(<$5BaMHTrP>(1%P_{EF~-a=)}}G`pkbVAW86u@c%R1j z^M(nb{HcmzVnSnLx?xgwW71v2%4) ztBvVALpq{~j&U@)F4=Tl!6-wuDPxz>4TGi|W=5GdO_>LcZn`$zJZY5W)0B1IC_A(% zn_o3aXv#@9x|Q8@>#k95NmK5F^;-#hZ$DcBz>$#UU&*vj@5L)7(dct98%1{L8=R#maRray^P?wPl3QT0w``xb62b#t~2d zGKGJfTE`_%ZF4%0#2h6ME#rOQDpCDNqX6XX&B0npoihdBo?-giyrQdr9>2n{_R0x} zXF$S#*yR5tJHV;wwKdriogY@~H@R|h+f)0v=Z_$c_(#SRzx?@Tm#G9)Ca}fm?k|aI zu3F*7U$;IF4i5bI&E?PjqbImKV*1)DOvc)Dx5a)K-{hW(FG8elXs1p{W02)((3PdR zLyYm8mk>++E{M#{$Rp5+sjq$wd_6Me_gmOZ|3E^}F0;T}hjKa>TA{y3p!4(J1@tWY zhZf8UhTLAL@v+Fx?w8=$l^f+f_t|SpOLOrv+~oR^3(fP$*j2tFA-H~Sg}ZskJD|0_ zy}V=j^XE@96XRo}V{N(6&toG8qT53rtwuhYfBLj#_UC5*y8&3t3?ywX{3SQ=;o=q6 zMnv;kN5_l7&jXvU5F0D27oV*J){SrWO9ppvXU0ahHa3@5HiDbS`G$h|neo78Zg|_u z@aK_B^>Z^5b9{j_e~RDR(bLt|v$C`t-%A+b49w+pPR%pqk4>=>I~Q_7X6Dx7lgAyE z+c&sVqQ}~UlhrsT?OF4Tj&^1wYc9it6`AZ6-jO%LYH#VuWR=c!bq*yas}1(BdrKeH z&#*7a5JuM6Q(c+i#d-Cmc@klS;DM3B;ZFOox!|Xrdc}miel|RFYI&k(V`46^bV_fG zI@13r@+qfffl+;gz~OXu47K;Px5$XLFR!sV!?>}2_V7?=UMC~Xi_Gz|)G!v(lJNSI z+vM8>_;P_{?##>_Upf%n#((~~zZ;mBmj3ve`Bs9Jl|PDsnfbY{j&{D>;g5Y_i@UP2 z+||(&{*?a<+`++izKmdSkpJ+%TSizlWt+FKStG+ z2prbF&CRs}l`#6VXIE+8%5(uckl5PDRisMJVK7Q&o=1Wtf z3AlK^eL(qd-sa-cv1G0KsXyLk+YBE>*S~n1zorx5>i^7E9m0JhXSa8ibX1m1MIlg^BoLJkVAMv5K*IM)Yqk$u5 zzt{bHZ*#;UshNLzn-9UyJz1Nm`0@#!s`pI^5O%CbWZ=n6F((d57y%m2sK!3gS2>t%+Jvl*pWymZ0+{y>vlB$*A zfd8v7r@cE*+c1lU30xaZ#5{TAaLs4$1*^E2Phn%0S=@B2S`!2I-sJFn_RGXqDH+Hc zd=Qtc1HiqB#JlqwF$4FPW6(Snjx??GVQXW)#Pdo&<|=pF^InlMhV$IV>fX()I~SB= zzro7LCd=6Uhpd;CEXO07_Zxb4Z0lA%T40ZtI?uKCp1ML>X*_xRiN%kE2X_Q!PS@?X zJ~ME#Z(NB^2;bBijpo8_MSi1-E?x)%0XxTH-?eg3_%M$HV>T>-1D4UjMkfdK^&V!5 zSH)O8xBIDOYo6fcq;dUr;*UeVBDuuZKIv?`8GBoctiB$-T_K8sXFH$Yh6W}ig2wuI z;kNB}gcdJlwBm^LBkd~rUT03aJ(sk1t>f&4CF+YPN$6(O%^F>gSI8R^lbjNR4X31# zK^8yRYgV68M4uCjO2;iZj}f0Aq(Ws`00B!xQ*|`)QqjjvCwx~As{bNkV3XYs~x-n;Zotx^j_TO z0!d0DAhd5uw3b&e&Ld0#RSE&SiQbQKA8?iSU_^r`gp`v>iiZx|>PliB!W|_cB|Vsc zb}IpSWY5GG?pivOPR=?eJxVJ5X`kVENb&o!YuAC&z2V7+6>+wNy+4e2QeLJ9awT0v zZf7*9$r+BKHpf*x155XK6ebqr2o#uy9)1|>o#+JAi4j%(bEO)AG%a&Ao7G}?TIzC9 z$+QBI{fa(X#>rGmojyY#!9}2Nh3fJWkymihJ6#SH6H*;xww&#g=9Wu{|8;M3!(aV{ z=Ta-2W!2s{dt04)!mKz^0k(n6|F2=r?xDYjIV-(X9sU;P%z0h;e}*}Qt9)%7hWm3@ z9+f&(`MY)x4>qsVF;lAod>lRw^M+UI8(&uihIW7ays^^260W8sIE;+RtTuK!RR?Ex zk4zY^HnCHyLrNSz%^X{89(rAUsiFJReE8~Pj_`x9mkytoa#vfXoF0U~@BX~fy!vDz z^+DvM!^S?%ve>&|F3$R zI}g;?X1|{E-naRIomT&-#Ob@g`{wXaZ+(5k>+gXPn;$uRiuT`oo1Yz_T}G5!ul##& z^Fc$u&H{@0Ckw@Ka@g|<<;A4!Wn&U=8aoVn7tD!V>Qx+P z#%)(0TlWBVbzt9|N^`qe$`!0I_qn`}&1Paa9#gvw3KB_wJYu0N|5&j7JCD8jxnlQn z2I2Q?j1R_W&NCzNE)A1(GW`qj6efPR>C&{iiCst9dT+$mPX=axy6Uct{@Yg?L=OI* zw#W>BhlyXVNVlKe`$Ka0<(9_7H&4FL)wpK3Gjrz@(9-1XWD5 z+56$;0K&3(?OBSG#=w7enu8y*ez z1xS2#H2)8hA%`gdf^bFD_6pb#Hp_vVviZ*(v=fj0N=6fE&`LSmJbck#nP>zB^n-aN z>J&zf1H#f{c}(zje!PhVfwKWOHZ*}9?L-IJlcR0CBcY2iR~KUx)Tmya=t!jM3Iiid zhFo0W@2EH+lp$6qfv-M>C6K}CIn)GOua5WBuL~HQl$1wUf+P!_#Z2<|7l&YCO%2g^OOs9A&@Yjqrkycf zzVXKjQlP{XwY`oPfIJ1;m6I~T zM9*SVzcJBdwfG&xD_)7{(oQkbR1BDwZlZ=gnxpX1=Ngs+H(-P8>DX(M;1FiKCL3_3 zr|rZeA&WHAQMel=61hk_jE%=#&M=eWzw}h4AS4f;3TYBUU{eLkk_C84sTryvl7zHC zCX$W|xgr@9MgoJ@5;@2#Go5LzIdl_Gv^)j17K+7A!8egKSmI5GDfk;H(f&0wcwKy! zgh5Ti52$13a}-wCK(%2!xG&|)OrXW<381f2OOQ69-f;L!4EjNHV?R94; z&Diep_M;+E>Ni!`z&Hi;C^4;wfIzSyaa8C_Bw;Ixpz}u9H>D{)WpbhhA^ArUDx~N_^`vXA$nDHKt4&@NA2O9a zuSoO(d&wv%{Ov3b1X2Ui$AkARV1yY!76Z731#g?qQC_?mza}1y1;^pA5!71-ujpqd z3oeonlB}>tu6zI}4~vf(aE%?g> zo3CVFXhZ_b(Lp>q$jZK$Cw1coCHcf6n8zrDDk3m?X`+pwN=DRq_002rm^eCUO#0q* zV_IdB$cpq0fgs=-0Szamx$}TH5|Gr@bbBfXo9&ll!hqt8!LCEVZc1DwfcV)dpnR;r zf1@xQd{K@H!;;aOB-)4fQR3NAKO|uk{~}v~WP1&fS4=E;4HH5|$gz+vBb>1k0~uw)2l4ZD2+A@d4%HqS?13qNC+m zHxZOPlFg-uK4-q%Dw4W>OCEa-HJSn=AVMgRZzL*$0)=v5DrD+k&3vl?m>+)Qv2#?g zF}IpPE<6fgfa5<-+%a0X`*B|=UrkdixrdaTYmzS9{_2!pq z8tp}PNr@cw&G@xOQ%uZ2wPJ9IH-6=$Q*-Ked~6)Fk8i&mzruh{uST?mHe8k|bxf)j z^Q4P-qMeOvf0608{ca#?(qF4%f3YyMv-CxcdQ+(fei}ET`olkj(mopGe$yzhkzqFG z#=S-+4%s#zlWNiYP_xmP!YI8Fos+_!>EE_Tj|)a$ef$iN zjXt^dY_;Oqmcx^Q*=HawjTO;25b;c)C8Kq-<=ZUF%r^-^2I%DS%dHRI*Dy{GGJH2M zLU}Aft;U3FZCa?-Z6j@3Ep6K>S@^j&lm~0&>~rI}n5~a(u*x>R+gS@0=R`p8D45w< ziS_c}aWZO^gyP}vnoPkDI=na%fObuJakApY(a0AkJYINIzHpZ6IO*8oUHQU$r4ItwHR8)_IgGrE*P|yZ}pA!(a0|b5p0=+`78FW;? z?p{gJQPJ+FtjJp)3o2W4M>tb9Gz^ZH%h>rb+;r}9voxz}?ZuYWJRUNm|A zQ})f!T(2Dm;X}b}+o$$2&+EBX<_`+Whm43~BaX9S0_PCNscejJAG(SySj855!WKH- zCv~S!qN-2QsZZ`VTe_-m$Nv5(DjTicrx7r~s~ z9F-0H^ltwbh~n3GuSanwFhg<}y z4!d40XES=2GOAR=*<&iw^&M@rh2fGgxcpBQv)=^eG4C{=oO=4zqI%@p_pjfcd^LV5 zI{KaC%D~J=NW*;Yr0nMUMT7#l5GP4nkXNab3=lP%{BqpwR3{e2} zM~F;5i4k+g+>np!`#6mfx{s5J?)sgy(v4XU14PLn5(P*Eq9^uGZ@OU)GvXviSyg4& zjqebr-{S{Cw2O?o?4xKeBP>KFKDru1XO3Y-z~}LBtS8us0Aw;n3?d-cIk31_C?QUc z8>jXJ6D7~#U*my<2q;q~sNV*MQ7|l{>y_wAmL|K zR%nUg-gqwG(LGwlU z+x+gsSg}0TynvGIn=-E?B+51LC*Bh(xp4JD3e^pdSiyp?W1(>iSBdyS9v(7~4Ip#5Bjm-9E#zNKv!?v%ZM1Cn)TFsSVnJCN?<37fJRp=BEHupltS`uM| z5tTU-VFv`*ql(WYoU)*|i3@L?$*I{98!aw`*z3}HzB|q^Y;zp@_YAp`#@vRx8D2i@Bh_45b@nf+!i|zgG0kyj!){y7hW}47*RLuw6NN# z_#%Em&zy)9+Cv&IZLPQ#qhklS+4FIAs*wDQ+A&_KUd%`kBC@@y@J9goPnZ({*d3&f z{zvB&b=Q3kpUp82sgdYV*a?S z8Ng;iwomycmNw=^3#5n6)y(t5od3~2P}PP`Zz~Tjk>6HZ`%>OS)~lSRa%`xOf!^Akt-BcU=}^1rQURT&b{a~nCRR2$)2sHHEL@AE2op=HDZMu$Gg)Rh z-)Hjz{k&(UVP+0DDP-2}a=}UeW5`b@!>^eXye)L8x?JLsy|O5#rE~`Vvwo@pr82=Y;n=H181*ui4FODK zFSo`+j^Tw0v>Wi1`Qep%TJpv99t+(^|HVFVQE=aP%0(Yn;*Gy-NtYgohO|pIa9-+$ zt_5{L1$`GpGnBDYM=<9z!@fejU}sA6wTJfRXu}S|-k$uYeSigzuwgVIEjGoxP8{|uZ5BsAz8{tD)Z%*s;3 zgJ=9j4_`tesoTnMfY%9$vUmL5KJZzPyrf2hGx27Ztp0<2K)gqu2X&)@vGy#m8l6?E zW?Lz2kBw8$8>KxtEwXu{Qv^b1GAxvnOVK;5&E>32 z#zby(TJAJ=PCi&PCRWvGsc}l=+7ZV>iTjQ1ME*Y_Mo4pMIc)4cHc{@j+dbo~DeJu* zB58qnUuD0ky)<~Ln-+qMBN_L_nI~4C`7!0GD16!0QYBcYN)x0Y)EBSM_lu^|m3L~Y zzj8RBcjMM0uN_KdcBD%gH*SmVRJSR!voF@WdCu2T^SIF~=deQpq zQ(5QSx}B}J66%T}WPj08dY}5CTissXyYD3JnwyG|_XS&uR`O8E%E*Tbc6dwC`VX&_ z$%k)$p7S;eS>34`8k&D(;`B$w}XFsYH7A6LUh2NZ%B%I(_D>`={iazWt|jCmCmt ze-C$U>Hj69JFa>BTkHEL^Y0!|_rE+TxZSNyK))tRd+yYajrY7KT^6;W`(sQrBGN?F zE-^2E3-A&CIMlKA>p`%%vfdZ_{#yB6m45rro;|v~|82*S`cri;_i=(SO%q2Nno?st zA|AVQ`eVe}gmu()bVo+el1;5nIu}wOk9-;%tZ0YL2c=hhoIMdO|Ndsh#fE*yzsF0q zbij56)$Q{bK{sHFw7&<~@N2wrRD`5kEKX`PT`*Bqz=u{9@q6=&xAjlC4Jo`lPL~YD ztZC**+gz@Cj zH(~X=@BDJE&{w#8YdjH*;ZK{9vK6?CIc@9wIiQdw5oIS4a$h^j&(SB>*h>k4N#mD8 z0$ODQ*AVHS$Pj})%{YqftpDEM{%$Xi4L&^5eKZpryUwU}jDGe)Y{7!#?WyLw0uEz3&1{zYgmpeV*GIk&NsuJ1+@t_Nl6#HWJ zz7rQ1P@zm80jw`U%sU`3a?<_FBkTN|+lGc^b=%-Po>ZgjMn$X;p88RU1zca{_seX! zom_3(#%!DMhnXyEUL%OPxfy6ox&2u^BkYyam8JS}ahjvC`wi^p*sIEC`m3!IWAGHJ zao9eAFv8_GQCmMPlvp_5jF->W9nd?~7^pyBb9hVtOf0?(LJfvU*e`@Ie2&k$f7v(+ z$LBrJgmUao(zXj=cMR%4KPJ?-3fr?TRKGkve<2}k2oeK~YsGeEk)lZ>ROs1#CW?Fj z>;niB+N^qF@!HiDvjMEE`Oxt>pPl>4c)HVd*88FI_|`8Edc)WWCzb(IhtDyGrJNZ@muLOm6R z!g)lTkh!AE4TFb`ERtFFW8?RF*AxTHRU_MwO^UOftzVCttF@SG^|aN440ZM(cMO>0 zg)DSqx9f1*bWJSwI9eDIHF>*TEDRzo3@hpSDHg_+7W-n;gq17yjaZn@Sxn|wnDO7e zvX+g<2ntY3b4N=n$972%OPfeb+Z0Q?JWKmZONSOq#~w?k5z7N}mIt|(Bq1wjS*t@@ zR)tqy2pk`{Drml1Tf~ z6#KF~`|?WriWd9I9{Z{h`|3IS2V8rmkVB2EL#>v>LlcKbjt+Gm4)p;J4UrCwDGp6} z4$YMgk6RpCdK{jNI6R$mc*b>L2|2dPI<{#!J~we}cXWK=;n)%2_%hP5GsW>$o?};~ zV|R;VPmkm45y##+$2VL@wvbbwtW&?1(_0g#mT|~{$7>V{`M;-vAOH{0QUE|eCsYBP z@U=yJ{tZbqZ5c}Y6&M}~HjV9Tvb#UYH6$lAE^^Hxns@It7$`^jHvT-AKaw503Tf6dq<44smxar3KoUp?uu(SEhbjeNA!_td-N zo@gO994T|37a4EZD zgL@z_Ww2gsN6M$4-QxCY(E7XhEDkq2+6bAnu3;T=rFvoM=Nuw?laHP}f6;c}DYr09 z+5V81yuQoK;zoS!h`Bx#oVeCIIB@3f9pL)ix zC1}DlKe!RvGRu7{+4i($_|wO+iSdcgBmKkU;T_!I<~d0ETvzYF*2WqiGvWu@H@cuR z^HWPJo1ce=_;r!+=9Q_bkX{= zT$-BdjQ4F%Y?m2ljrFqUrq=jnlI4y8KIPNf-YJV_4X?1xJ(OLPS%u{(5*{9`uFO3W z0*S$==0pt6bFfd2=mApbK$NU!Imd@6|VCRk?h zsUS43!~b8Xpg1r9@TnldtOsp>qk>c_=4yL_OOYzC|49Ye7h9k|T$=sf@GmuY{a4ZO z_Tt&V1}!gKEB41=L={4d$%%c!Jupk###_2Fet&ND z)8UU=IReKTdE>Egf@6`vv$FwOY!#$%nn5fGnvVr2rys?`#h-97NS@&V`~*6+W$mc? z4{iF`b`f0?93kRtX|XO)^mUT?wZ29GB~7PTq0TbeW}!yreKR!(v+XminDGTOQ!dH! zi0q>0<;*LfTRIU}fLL8hn#hiEStpm5tulJCB1P_?xfm2hXAo2;#X@HXpcypp%| z$1%zGIoq1$bn%D8?#Xs{b{LO&r6hmwe8Z5k*|#C0vUo#4?y~4Z)2#96t1j*$U!)}E z_4KqT+da_{`pq^f8Gh$Tt%!vZN$kLs_A_vsOsNfhuZzg#ycVx_OE01kqi2NR!BFSeoo=dj5j7g+QXOdw&~(zlUVsQD8UxIk5-J1p9 zzA6se*QydpXJC7Qi!~10eb@zFvGVAsv^l}K`&h|TMIAG$3n9gLJM{lkL6o$Id6WNd)ZG6YRM3B3b3fSF zCfU0XzmGeLO>b;hJ+PSU&K;BbuTnvnKe@0extIl`l%?zG*RjW^aK_E%nQ6<#`+iT8 z(whfL4*V*2|2^aOrg^ZT_g8hq?^!bD@zBcyE48;^D9|sgLL$n{-P+9fsDT!eh-Iw3 z1Q|19-@iGrToIazCF7|R`@Ue%OqQtc-N>Qw)7ThJ8|u;m2E-awpdih7(i}$Y4ny)< z__L=kelyS)xz8~aB#jOa+KgMH33<82D&VNU-=A)V1OrktRLuPQD2t3Jl?CvZRm?sz zxJ?!7MuF^Fz@XF@zrtms0*gg+Uf*h#DvshXpTy(M)i$jo)@#DKFer zVlCJj4}fu4Icx-U5pC2N1!h3qNRd2M1fC@dUBkc(v0zdxn2FRKy>f*>b)LdfD1fOR zQjP+)0T8=zP&syVjcbU(8b+K9`sL#XxW(>jMPFIK#Bvb(a0oXJUlWA1^Nn32P%kH9 z&iP(le7VD>0lbd^y+Q(M(yt(hA#ymR01~3eV?@Z<#%el)gbA=Ya>5J;agCpdXF^dd z&~4z^ZPjzmoG?D0OBMg$`C^ zgCZzkaR5TbA+2c1<{7EtZ0!36gbFTwBr!fCNA$!(+&UXIuLeMH&>wV+Ng|A&HMa&` zEt67KXJIW3kSl8GDC#v0XAlNRqcY&m$OKh3NQVI0$ALMMK~^d97;68Gv+8L-BB94he5SjfWBP~dmkF5$pK;;A^jycWfuVfUAk*cin`Gb{xz5l z9@ud!C&K`F2M66Dl^H>&g}o9{Wn&@u^dpKnCgxY=2q0A!%z=}Yz8da9LI^a*Dw60K zNg}grn5r-=g`V;tDT|tj60wVdEQX_4(C(qQlR18Vi6Z>^%#JV#HEHFCK9Pr$;!yn1 zi!y-ppx$mZ68SKVIP50jFn#AGBEF^ptjdZOxs@-fn|wJe;Z)xpbJ4qnuBmdA2)(3u za{^7;GugWadBiPhzh~&>SCUa`fN-*8GBwgLJAy}nd`id*r={R=(1gT-z=A6WR?$DP z0vHkq%*ww4LfG934FlyJEJ4mQ!6zu-RFX(E2@%aknh8Wkv+r356q(8tF@PclzUU&k zh_F#)XJH*HvDuQC_7{QEy!FIJcrvqoQrNqQbsBexdwXb9q^A<&)v^3#8&(UE5aam{lq& z8IS0|BR&jQjcinHV5`35R*lY7ebcBOH?E!uub!N#nh>a77_MH(t-6z2os5Oe43{l+ zRZnSDe@lL_T#nozN4}lec9YMEumME4DB>gYCJu_;UW4r3X3k(D&w_s)Wh!}w8o6!z zZbOBv)hJdZ9BECEIUB-0wJnx|(fnAewOJd>tUWS{`Ea>bkw-)QWJqsuFtEn59RG*t z>$D?X(#{MF;kF1|S|$!xWpi639*4Oj0=|HSc@IAlFF^hVWJZqF9oZ+Mwt?bNF*=3mq_95B97F)9ST#5kFaV$G3~9b%o848xWud1CfW`74=jH ztgZtx1p83yb|a+%wQIAUUV%EViA~l7vMBYcL;<764PrqLGO+ate4dOIrCCr9DQNU! z*5(qBd(UFE9pE8AL$(7Vi&dZGfINS@F;ETgqJvY}fEPYqnbwf+AQE*g_Fe>bAN`hc z&BLmX32Qju>Fos1Swt)ad#N+wP$K5q0{A$O1ywkkknDhnP{UTtBKQd?6f;}Jv*o3x z$ZA*E8UrQl43ZPv=8pqh=uEIP0@(-b0YF#+giJtTDUiKP*e)hSn84b@eC9|&*iFM# z0La7|dN@?{0volcDe_9Q9$i3JAzr;eLd5w-Fp(n8>^2?~G5HF!lY_!AK^Rh1lO!0= zf}$u9?0%FO87xP*8hW(l&SooyR(Iub%f;^Y9sdV=?;X`tgRgDxoxPLnP_hFeO-fKi zRK(a26(OJkDrz1ZMTAg9L`npum(V)|sUl(kMQj)q1ra460wQX#0AdSPP=wH1Am8?x z=giDIGv|CW=X~$^)_ULb4+#7rtOeq}f7gB8rjTY3uowUruA{g-B2KcBCBizy2~=R7 zR2KnjSzrkhG!%e0k0d|Dcz+V2C?XT7fDN}!feTQyh?B~4qT~kh;4P=4waDP@omTRz zIXH`;baPe$D#8AdTn9+e>j}T5NEoL{Two;wO5h?3>EH?;bdU~41E3X)U@ru6f`A+j zK3Z_!LPR-ZTOhxJ7)zx_to8hji!hhgM;bM2X#tj)S%cXu0T74@>jdHU1Ixkzf<7Nl zwmhZ90&z|_ZBd3IK&TZXlWZJ92i>@U8xyYp5HjhQ%UN(NPMt-7 zGMdQjheTfMLlLUO1+o@X^aY?S^QFBAaOVQYXm~!A6wg57nIZm6P>z9Hu#vN!(zKcf zs{@Y}sZX@zUSJb`159FE)6wuNkCBXfuaC+vm_mOO0I^lL(SQ(pmE(_Vh)8#!z=NLH zuS>bLO#aNW7l>Rv_>+P+?2!BI&g;oYcgfxO@*j6yx#Z(?;wg-5q`jZ`Ruw}94p4Fa z!0|~Mx{v~n9mK^`@cVgSId(F%eSbL_ov^;SVyTdLP_AJ6JK650mC15l*uAT}nt1&t zu#UA3c_K=iI%qv-O3-ig!{D zl;Ne-DyBr}*gI02(0f9dBVBoDTB>40x6kx#D-muh3-ngOkE(+UL~nLch}z8V7~oFL zsI5|#e^$}7(o93{;OwUr+bKKsnrFGB{$;p%Kgs^s|K0 z^q}_UipU`p=#U6@?%;uh$$gF&Qy;9I-@4EItfdMT~5|He#GU zyv}5JZN#uY{o`2JsIAF}KY!H0@!LUk%+X}nMRUw``Iv+~jLRU!@rXf}0}{L`x^_q$ zhqNR@c8oI~e0Dt02kl@;bJ*nCT5>H)s=qeq?6t_H^uKOTvHW9ZBh#%LIA34sn)=uNDlO+JDK~hUD z6C`Evk$M$_MR2@4a|yar%wr|&T)|eX2lIhol6&vC)-jk5&v$@ zeN%$m!ky=A+CFYcQCZ{t`LEX8KXL$~oYa%# z;^iM|D|P;$g3=~O`eQffe&9w1cT1%tcZi%C{%Xw~4ZTq2ShO+r?axy;@2ol;aC%cZ zVPpQ@BhLy=ug$()zxw;jE9-J|BpWZ>c7J}`E8h6swNOq3B z@L47q`t+<8_hSL={_NK~1GU5jVzhP=m-VbZNKZzjPJS~i+C*90wNy$;mFfa05O>!{ zQi_2TUcFh?F>}?U71$=pi{a!=8X+Tt7Sw13U(5L`7N4}#Ox^6eRp&!neAA+JDJLzm zd@F`pz7cwO+;>c#Fo zTB&~f_HSxg1nLk(E?f{9+5{L9*jh0Qh4NSS{q-ivK`Wl_dae_j=14)JAh^CbY5`1f zxBk(%=dU(N-X7Xu2og+u*VM)8hCew>TJB$U%PR2RmcQC0X@vc$bK)Y6yu1_PC6pdS zFI4^CHc1{VYkitBZ))_cX)$mJ0158QB3-@C?z7+$OW~)qf7>KkvBpQgj3#e8+jJ;Q zI>|XPqsge~z?nZbN!GiUj@QRQ-<<(~lNjM1l#{ArUUeVN{zow!6ho`c-` zx@102(LGiwOB78|a?ty?O_K8^j`eTzMy{E%8$Iz5Y+)uTt zi6;E^)|;qNDgM(Y$r%%ekD$NgI=91Eu3j5a%~IwbZ~xOK$*!?$Q5wq46BeeqhG*w; zbX9!r#Qw2KVpO-E_VKKemCY>cyP0kfdwqY+?4LGCP8#l*IJ>cMpL2()R@jfLt#?># zSM3@`VHoghlSGEQ;d3@>6+;iexyzk^_mq+Igm~9LkZNQ>|9z80=6&FX**g5X0xF^& zC~P9MC7$U1?q!{>HYcx0N`*|fBN9>m&z>cJyx(TE`FK59?l>J^=ogh z-QzHKhtv=PT5Ai5tr4S#9E!C*t`!dao`MlS&&(SHh!>@Mp33$*}l%)lmJV zy(6QeGN;GvtHrW0x8xaVu@%dZ0a{roHq_r9r~B?y&HW5S%C9_;eCpZ;=8&~?tp zw?_C>M3>Lu=D(!d2Y-If@zhaddR8^RP1AkaB1#zIKmE?_=Qh~Q=kwaR)edwwwpu<< zC=&2%G~BlpG@Qiz_dUXsEG8mD%aYP=Ofy0X1aMx@h`48BLO`ES?fE+KnaaQ*R!-aC9CI3%IX_Kf~l8CS4+dCA#Q1w zdwbW22s@ZwYW7}DbzaTnI`GZebY7=GEr;I9X~2$>zYdgfVqDw^cEQB#2G~Ip7xhbm z@arfXg}waG`wO-wptJV^|M8`=#4__gxKwJuqVy}B|4o-l&7Cz>FXlC7E_HkwIu!L) zP_q4OxwX_Uf5FiK5C6O41HuQ%63t!MrSf-w!L$4KrpHB}9-rM+dw*tnV))mkvQ{Di z2){0sitfTl?ek5~JL{sP@kDXZK61%JUmb*Z$qq2Ts8 zVg7<@h0Th-{sM}H-k<#iR|Xr^0{RA>WNYPudUVh0FpM_RMQr6A&iq)c6T1t`3Vao@qU7|R{)*^C1^8;*v zE1oV>Op(M}Hq2KYOt7>nmd|Z&&{;p2$Ve$xxM2BkiQQn5O>41YW%EP*;K5|3Oo?)n zW#h{H!4!9^64j38MuY0XR8~rf+BeIl^<9H$fvqJP;Yq7Oucm7aTnbr9v){k2D zR}W?LQqJog-ul?CYbd9x^}K$-qsI&zy0E_E(Nq8G;WMI?3r63zJ`3&| zE}Uq+U_Aav@+^F6_$(k>Mkj6)M5&H&5sbrCY7xY(A1R`wmTg|Ntu4uJq*(b$nfcn5 zwzS}p5~}P)ON(vKPv(!D)7^1#n{~_coa&MDwA71Mhqt}R?;0sJd~$JTK+B85sgVnG z*-MQ0Z7+*eN6Re#b$`L_>d~vL)XVnYwsll@jg|*Kx$H3B(s6(4U-TDvEmooJj*ET! zNuwyW)p%u8*Gmt#Tgs6?O~h-Vs3%2d8e7{4+>%rr^d7fa+=QT2O zW+UH^{JZ`Fa*1d1b0Bqw*EF9xh|=}uOKs7iS$m4p&5-y}Ldp$ZbONfnk#^CgMPRjxo zN~A0)4fAKaos^_wG!G=;GypBwkjKRJ;rkcp4aY~MILQ!fmzlsTBV__j5z7QnOS$iW zZfnWvX~UICazgk+mkWwb!l%ruaW~+bK2c)Rd_b*F!#hi{2p%yRb3%x&d<~X}jszb? zRi3%DoqQCjw8peZojQRvmrq3E`hLSn_2pNdosGY&b<5Q$Tgh#oAEY3&{y z+5{nnw{Z3XVyxs-N9MYpd|7)JRWwF3Mg+)<*f4q}^25cSw<@;Y?+R%R{#TVI>>Xqi#!h8EI@_m!4JqOg*tCw4tV2YSOu?-Pwz4SD(%Bh=0jiOBf7XN{U z?@YR}a>zLa!Q=T-bsYDAcR!RCS*Df<@un|JU>YCyP@?~w|0%XbLai|~dn#&G3v5?y z#=66-NXo zoyPQK+aFLV1`4{9a*0!e-{#L4?9yC@5rT0=Cbs7Gs%yF`!zFufa$*^K7b-Z~=zE&H z&oq;HKNEe{Z=d3C>5;Y3{rNQvd+4jIlpCZepYird{5x4@9nON`&470pG~1`^D!Ne**wg1^Pbfh)yRVL-C#bN4 zDMVxdLvA>U5NF>h@5%BB%Sc>s3ypRokO4(D9oohRucH(xLU&c7(_ku82i|0opl)EISze^9Uh&XpdEBwd%01h8@Ut@c`R;^Dsyajr zebeMiK62PUPvMmXMdaorq2M+fq|6DLBe9_@%5k3IdnxgJ)O!`CS@;cnf*&S0*Fr*t zco)nPK?B#U7N z#JjMGEmUT0$>$xpA`E&0R*bIO)> zV$oW{UPb5C_JMsq@ z$M8jfB|k^?Hbuu>j{ya^9>xs>CBk zaj~h(W8&BH#b5o#Ii5^9QC~=`untWs%|$4r1Vw^YJ6GK4E9PZa>^r8sgt_BX05%mG z&d#K+m+$!Myg&-u3t`4_PadQZ0(it#)&a|_3rhi&p@E^xwx+TV)-NXAF%@TAH@prF97;i=uiVM#>EFZqI(NI`1v0z zJ;(LG{0<8gRz$aDzZ5Uc9wZ?68`U*euH7syDA3<#pIKUAyNUFuVzXOtXkV)(_MDGB z#=Gy8S-M#5Q5m{C;QDPn1>?Y57_Tf{Fe$7c`fh_=%0Bbjrq6bZ@9V4K_h!}Hz0*~{ z+AO89r-6EXK-~TIjbBE2u&M&TPkcF86^jPK4dSm*l zo@tF^*W+5nO7TAhZBG^@yf;qi45=AQ!A4x{>`MgWtz+U>9qlzsWL2Ud($h{dxV2qi|Ou{%b}qsI2mhCV7z(hh5wN-J-DH7Nc$BX+$s zH9xAaxPHX<##=b1&$-}bbc5I ztIASsSS_QgW+!y078sP$<#njKIovV9=jLiR>5!Kv|^dXl}ml^mo&WhV3P|4{el`BdHQ>q&B}rF{0X6r z0kdDk6{P86w#CiW!gKxHuM+};k8CV8Amohv@*w`o4u01tVm>u2P&he)WeQ_|V9*#0 zjlGGz^S=Z@uQmU70O(AMzXPDRFJr!I`D-m=w%xP;4gmUBtT6bg`B$t^g8|ULVuhXe ze%B%%#Q^C4LaY!yyAkNd0O-zBu;MQ*V(P~FUs}ZGeMJ2#_Cxc6guiGJ|F^^nf2&2* z4V))~X%PbsvHwPk_zj=qc4_ghQwpEWh^POeMJz0REOqg(w1~6XQN_3ZkrwfH0NUV3 z-%WQN5n3krvlg*+t2BTC(9&)5KIRa&zg#MsmBS-^=l?P#uDN+ zgPMKr14O-F0JNuQ+v4hwKeUMdT&ytknAX(SS-Z01?P*2a4i06}ncWQoq;b0ubAf@< zj4g@-O`p$Oq>*y5?IUPfVH#jHbBrRfL{0>5tPst4ZY%wH%}pC0bqBl6uOefKy-fG9 zH<@Q>CtoSwyN-VwxPAXMi?|fY%&uq3PHiJ}z{ty!LgD>p_P#6Zz|HQI7eP_P4C~pq z_$xN$LB2MEn#pgqw}5p$=W@NLddn`9Pkp~q8Sbc4P*cSFQE|HQ5sAV$Fx_8r4>ZN? z6X}P#`&2L@YaT4RCLY2r?Hiswu~9w%O^1~T|IOCTk8j`Z6 z4YPyfrEI2r{}vyc#d1-&)XExTN(>k-O1Io>Ca;?lvoMDP&yQhCmz)`J`#hMABHA(; zd9>IcZ3*U#kJ1uB1Gr?Ki^>5V4daO>E$zW{O=UiUQ9V*-TzC#QQcgnOJcrJUpFi)^ z%G^Ml%>1JC2vHggV@{JFt(joAq+K+~m+?$)z;^l=v{6aN;%?O7` zHWrarH{9t=jKq=CX3_%{%!n!MNF^JlV+?hkj5#uX>w1_nD5Sm~tcsBX+VIO?Qrk|e z`)Cz%z5VCSd;RWyjQo9G%(2|uj(fB5aug@8)zfciO~zwqAJGT5su{HjG5yk{_ zwJ1nVHUDRAR#U5p+qtX!UPfr(#jSr1TY6|Hzb zcnR0~{#xR)pyh1@S z|9pSJu^r5h6q=^bzIj@d9fpVye<#?;MnJ%Y@?l$d+`=4o9NJU&((h|2dBm9%PETmA z==ZzYElM+YkCM-tAgZPaqcfBJ1_K|7P1GXBTfB3cwQO+nSA+4Iosr0HVf|~l`#S`m zVm19Gg7^);L56(#9E65L_za{uU45lIu_EgcKNg%mH71nVbjsq@dkol~IB9BdSsg4K28AT~b1CgpR{99pzq87gMS zaqcMK+d8WJ@+kIE`zAbQ_!J7TiFDHfIwscegfEuN?FNtSxd1kggk#wd#3H!SaJvPhPjmhJDe;3sBuzraBs7OcSR@Z7A;eJW zMgZQ34Xxwig8BIHwRn3fq$VUt09+&wI!(nJaG@_-fLug=BA#UR8$`gAcNl!d2go!; zS%i-ekhU?Bf++w^K$sSx-+6>DuZY(X`7xFP%my(?d<_$~g9~cYQ5hOc=Kk_GV$(7@ zG`uAR7!VLni_lpSn9Ii@tmJ29iuOzx8&5Z8K&x1YH4X5fN<$PBquhq*Ac+F5V-Xs4 zA>1HdlV*!>@WW+_#?17IGQgQeSRwQ_n-y0_*5r<}8wgLWmTh#$3qJ zFvG1ITFC`>a}Y>E#}5K{5(hUTAU*2z$}9tfH^GA2ZwXgE9z8fG|n@BnRI zt~4LUNaF=8R3yTiH>0daX$LxUoZHYbTCyVzw}k^0oF_=JAZ->TCCpty!(roSB6egH z_VC|{R+Qx>t3=CnqV5cM3CA|*PVVNd_~R64D>HJIpQdccmUqu5W#sL4iiVp(M=BA| z!=7*n7Z?O94sI`vf>0t=nom=Xo!%cA(S8I?qMlJNBH&CR1Lj;6!~7IUZ#=RBM>jvy z^_pVHB3R2s_xBc_529=p7WPgmG6;td5HA6e#}m(v9#IMjf*!5oN)joj`DZ*$@m4&p zbXP&REf+6`{^(I`4I;E&Tr~8BaWD}Ibv{wJ-uk?Z zP)j~%PCGIHI7ygz3BzyTVX>#UGfD8 zN^lxwBTf`Tf(UZ9_O+^>o3jrw7J&yTq%1bUgT&mUgKWlnL3Eb=)OiOd+e{J8mP^WD zprLFS&N=aAA?7G80ogEd(S_Z|PP}ykSX7d>#4TKB91Q_H+_}i|MIq0>grABm8`N>z zm0OZm4K2f%JcFVau^01x^R}eJbKHCm1zkw=J<4`x*yi6NE*C+gba)-z<^DFx zX&}i&fJAS*+}WkTWcj|$$J01RV1x33(Zhjk!iSa%Kc*CPFfv96kJHMA^C{t9p->(? zKmq#hT-#aaRj?2Z5klTV=%Gc(r-wKP09xZu_};>^IOe<9`b214*^d*zc7T{Ff`5Fu zZgt%u!Q({VKL7XoQxbS^SO*o~({#hQ=;~IbtG)pa*$>@KC?t12F_?36{o^_Mm;K}e zd|!>D_Cmr+5mYaA{9b;Art}S|(&P8c(O7_>#Ru7Z*HIB{lzhv)=;HddH-ln$Nw>|~ZiasK(j!8nte70Wt2sbWI(#Yc$DG2oH)45E2OCLYBL<>iq7eEP zUlD&m!7dk41)vl*uoA!}vhEyQ;SfT@KVHNv-cT*!kqX-#F20%j$lw3kUxe((u~c{&uPAt zPqX6df+>vuP-Az8HBFi4jXn7^RrY*RI(>3?wRrXgA^f?xaa`<{Rx>|KWN~5A!$0NC zh*&A*^W5k!%h^w5^2C|<$2MfYO?f2txb*Vaje$$U;*pWjA0y%~!{V-LJ?Y3{*Gr#` zLTj)nW}*R>N|@3MuE84kg!HMo;h*|v#aO%}A2)$ZnjC9^acL8Tq-h-XX4Gfg$?2)7 z2}0x)Ibn(rH-X_Jzrd032`tGW$Ms?O2nLa~j|lQ!(s`=xed3<7Aue)Uh~+RC;qmqy zHBNOiZ%BYK7UEXrdVx_&J2x-OJ;#Ac)}THWP*S=?X7)Bc69O#Q!E%+f%}k8yz}Sv4 z4&5%ahnA3sK_?jhaivh({G)Ka9UntR)IRdbQZ&~gq5VtY`j7PX*0&g{;=%31xD$*K zdC%oXWr^08(R+GY8>*<{5s{&9v*&7UZ9^H1FIlh6$EcL2ec0#ll2*YL3G!&iMGYf@ z{071PaH@lE!Bc@JokD+^MvocdGbv2Qm1eh^R@cx5T0VbUCh=yqiV zn2-Zb=&@O%U8vd+m8Gq!z})|lo0FxT(M#2k9;^Xzbp55j+Q)D_CE8U|^*8$%e-45Kznbum zk}Q7SN^WQWydC55_-AF9opgVdfiYG8PEYCO{%ZNc$NhIb^nrnzBWcPf?~VMvkMZ2? z;k>0|OIbNSYGxlTmyrK8zT{UBq&M7pa9LfXnPmTQ+7qJ%O>DY>_TC3iH!8^%%5IKW zo!Djt9qu+UiT~{NVsA-DulaU0UL$?y=6jyc7sxPfMQ@c>t1xv=597+N4Sw^w07o{}TlLAIF!>buxM0qPg0&;VP-O$?o-3ftjmo`SDS*!=fA3F(WP-L9$o= zwh6y}>^dj)zqXHY^4zs!*_VAx7QBtPazZ2I%w_xByY}2|b*2xO=_}5H(MmRJq0JNV z>LYFGW(rDW8{HXx;L=znE1~8%uW4idV7jq(5y?-a|64lseeKf{X&SHzFH=v9qyoTZ zW$DbqRN0%a|T zVG~K1;6)pieEYM6o&Z_re4;%L+`?7JhAV&6hB!#^Xp(2AggO^%TTlH@_hq66PJ37gJyy1*F zxM=!bDo|Zs!Ii9c|EzDGPr90R6 zudXJB#p_g9LwXZ_ciwoqIYz9NlJxk@;Ta7yUpesR=qsX3C)+`dLD!s#v$}coO8SW( z(BtKS^;8ipaskz-JEeQf=%oNye9rWh$3#3NlR;dvm-;?J5_Uubz7a2fUVJSe!4&)~ z1Xk5>WwkjElx8D|vYj|2uyMk$CLn&HE!<1(7seF!i`~AEIYzIpNFw8u zDvUH+uB99#o=oV$hFkI{r=@4Xu)aNUIH>o&WPI^W^j=_{w6S7>$_dd{@koV0ITrzbXO1G7<)_Vnm(wCt0Gx{udzc5b{iBq$a6|rz zQ~{(e0$0$8vK@!^U=Q#dF!e%o_;0`)r5IU0yorL_(GD$Tz#9d4J$?+^6w(7?%$i|6 zHn2f}!&;j2sIX;IEc<$_sWN0nCFrw3b1p%P?l=!1c=jkcAaN{R!fG~nm_xvcVpnkE zLza&5FZcTE`0z3jj>(oaZX_}+GI76wMiM$)cl)Gg z8}6%+D1Y1c$3q9mlo{6OBKIhB-wNvh0e-8H=x9yU7NHB>;E{!tT@>fV%wyZjvK&@e z`?HUS@`>YYh#o*$%tH6FP%;4ff6aCrJg81RtVO_EPNKc$FquI-&Udw9hn&af-M`?C z`|YSZ0p~8rhK>={0YVtXbp zFdgv_fZOPxjO~e7YMeelXFls#OVC_*o~NdYr)-lw5nHEs*bjQ1DtL2bZd9rFnYAfK z1RF!1-&TOr8#MRFq}#YH#oGYhGlmkZ&pJg0S$y@}n~2He(L@4w&Ye^5ZSBbv#8CuW zU*y^sdCAxXIhTPtYflVqDSEuPFo5F89<@d~a8x1Akxyg-j^}%eEKP$C((t>P#Hhok zm4&hk42Jig{3&|j_ghsJ_{(BP3(~bwu^Id3rpl>s zHhYndn$t6J$g}Ckz0*g^e|GhbCq5jv<_)YU_*v6EeWv_QN7pNPhx8a%Sl7%BbEA23 zt|gx?ftT#nOX_&`ZqQ<*nu%Zfk0)F0naun3HScdp-=7e7RGGj;7;z^~G zKQYgq+11H?navs*Zw}uZ;h%)>m+qB~8^+=a`Qx91b9o{6M)#f(Dj&c9ZdUwKEN+<* z?<;KfW^-tfcb0fn6z69VA&F{~B~0ezpWN>?H}rN^$-9 z_r(}`h|}2&WlRQL|ANIcgCirD;SDq0U4GcP?Bw9wD`Gfd()Qxp(56Y3(@nzRX_<3V zCxg|b3MS*LrdD1SkIhW`)_k7og2|_+OK;ccT*Mj{6UX^utxsFM`GY#;VkmUN-jxIGm||{f+@Ig4 zdP)4WxnW7^cuNZ(Tjgx6=VL>g`US1QDMnw1=q=oaq%Oh7=7#;;Ed472!&2^*G47HZ z6TvxsLp`la%6i%bd>(^dJ|<8t7qD^?yuZ?y@OpI0=`B>go^Er3yA6-UY+>?03bMHE z-1f%Sn)d=h3y;Nb{z|1I`GS_lmsoe^JGV@uyvMg$7+jU-uglky(Pesm{>r2eO$c~G zI$Y4>zn*FLm1{|{?3xg;zj9eOj6RCE>=EIJ;H8?G8q=OD?@*)tmCci)7q$z!dIT~B zJ=m-%w!yjN(g-1c1XB)TdCae7N13IDjplC|XTcoU1If5V%c{QrYD$zC=a7WjM2(5@~nVgJsX z_&t-j&iTE@V)}R@*WjP6vHYEIZ#}{E*9@n#(~2zRSaZFUU%biAIQs9xJ?8SK|6kWw z{+2iSn;A~svquq_Uy`*yxI^`*h>6W`*2ftx8BXu)A6M7+--*ge?yok!-PC_Kp!{3E*VekDJ|4qerM>sW&uv|5 zf!awQK0H45k&pj>0Em?)vv@EPuodt2;b@7w!!|H5%_5enuxQ z!;V9PMQi~QYRG8Ve77k|Md}`ZWHXY$_)P|Prsrz=jt>EB`kte%{U$y(+7E&cUf5`N z&vAhQG*{`=QnNQ69bxY~S&rKE^K7Ig4Y+r&=BsVG=f7Rqf6G1}>073U72cOnB{n}N zK7Y{SulbVqt&IQiRKR<+xhF&Pr+nv&R!sFiKA7^0H^E{CUX%WGU&TL+89od@xHRt< zZ}QK_4B^*OC9B4!M?SpVBp&^rnBjkFEdNoB<;?>*O1se^PLmU)jXq2|cRl$G>Nt?&LzZ35LS9uffWAlD=MljZDb!7J+zVU03)0&#}#M^oefRK(^Q!QwGg7OL}bFL|1 z4qOYk^;o6pc8R(Mc0QeTLT1N0D6+uvFjL5O0a7F-v4l)RMd$`?p{5#zE_Z(l4_TGX z`SPT0KEXMG{HBhonPai&>jviIiU-K1KprX&#L4JUaS|Sn-Y3Fq_F3~6Hp-~Q2&2(O zR0uJRMs=}E>uNsq;mP$wpEDAT01!{2M48P8;%29)kTv6mYyHu8{>={%ZyPg068&Rj z^8>)Zod(jlhnkunNFH~e_uf#>h_PhyNryBn6?bw*J)I0J3}s0P4^4Eiut*YH&89z4(s&<-N^5`e>X}UUdaB&)T#U#y zv*qOlp9(9T9`56?!4yvawU5)Lo!;>T0|BTRm`C=e(76w{MXww=Kd0t-<*jex^aXsO zrd$GFE{PR;Ibs#)IAJkQ21Aj*$e^%K{7^BF0cR6l^96TVjFcEpoI ztd<9Ti}M~3VuYk5H8bR_l5~%$4|b%n*H1j*cd;ZWxG%?4S{neZ4Yeq*GtbF@XF0c| z&Azv9-_vl26QfApy>%y1;-i2+SWgs5j{9Lqg^ zmWBo;#P^9@lqo?`{z35^)IBhMkc$@EB%RYux?q@eUODlkO;Y(p(v{|Ix0x!cP7^=r#$FP&S9oBSD{U1DUB1!wN)uD0^+$cG^07GSULF`lFaEu zqv?=O&d~)rq_YWex0U11xhKC2OlIY!RahpM^rXF1PXDQ!J~EN^!ae?K8K&=w&lDyn ziIOuJ*x!;qicJ!3m*OZRBBM#QAruug^S#;Lg7a#a<(ZZi!+)K z4&9bxp^`;7!db(L&u~w^Y?--=bduA9zI6v!!a#0&;386zZ*zuzZ&H6%oT_ckaA3{| zlJ1h2ex-*TMj@E1WR0@WnLM&_5L%l@CLGBfW#(qG(EE90{NlW@b$Nuu+-YuZj)
    SoLsW=XxyoYBp&ym)$>Ehj=m8s?oWS{J`_apsq*xHpD~&1C4MQv7LQcBOmf zrJ#7HGIBJRJV-;sxMbIfys^$Ss%@N$B;m|W!^GV|8B+}CX=mn-JB20~e3N*(Zyl#* z-RW^I;>1OgL_}EuxE_dOkkY>#$r%ldH|!Coi5*%*IY*cz#&U}yD4a}T$+{)yrUeP1o!|x@U?u?jM5kz7DDs^wmsH@nHTz-E zsqZ?(AHbQlq{6xDQ3EzkiAteSz(mnmLn=InhJ?}393)ZQHrpi+H4p$Ye9%BZbnYyU zZMopOwPci%fc2gTXGLY{E%6hRNP1UUPFLBEt}+)OVN?Fu+@!NkY$%Wq6bV2jQK>pV zZdibFddU4;a_Cf?pL-@jD&2dri_T<$>tvGQDO8sUSaS}^2jEXL5i=?(C&Eup;QJ}Z zR~w?=nX!u&!RA6xSA>tIq0gqG_m^FGa;Z3*0mU+iD5HEgkNCNo7{ZVL99$kk#cS9> zCm2vJ1Il4Q->b`~R0t<%h(#w68!QcBqC)@_!N#evz<2@Z#Vy`%SQ5s+>LrTiBAK3+ zr@ZpG(zMb~?rH8x1zrF?m;q~IMKh7Jk^t18qRMQ7p$M-|g{66b8W&QRaCj;#P>Bj_ zFko{YrWb=0zoX{k1jx~*=!Z>`#zpS;uLUkW z*PD(M-%lb~2>e%5F@XzCoeBJ8gZtSyMT*Np8gZu(glNzfUiBspbFGz`7~)fdtmEJ=PlG=(V=91GWy0}Pa24>7W)GjO0aqHq912dGK{&|7 zOnP{AA^r>#$N`{WKIlb-M<}2R1z}S#aVsFB_Hg4}a5EFaYQDQ@5H_)=D}0Llbh&A)%1!m;-Xlc@0AU-Z#^Hh8cL4)Trpjsx(F>4>{3FzwpNjD$W{ZXZSgML< zGY~n}V=p?9$-#c}JysJ!Fom@C3IS_VuAzFFbCCMJdQ-upcp4!23I@;!ONGD)AGTrQ zAZ!zx5AR~b7OcnLsf3@@Cy@*SjSVr`gq8NV93yC-gaJJg!+XB98t{=JA*fDiyx5#Z zxO9E+E-4!+O#YEID{@ zh>&c5Ga$anq&85pfe+ycRelnB=^yi zr9rV490wIXvf1-#3JcFa4apl2O{q=?mqmqFL*~3{M@+TLgp~V06_JnsOkL|n$QpoT zc;FDLDbNevKyT|%Y73DxzVqYZw(T&c1sq z55k3BFY3*SG$Cw30k<$3OrAW^42j?Tv&wu~ahYY}2KBpa7G9bC__<>DJU(bHu&KKQ zvO^!}a?m6_^l~z;OXY^TE-F`uSf_#)m!j69M0fU;HEj40x8s2t%%ZnIR3KP@FQB42 zR0v~IN9YGd1cWRCIUCXTch4>PAAiyyGvU30um>b|yEPy27arNk1s7vqxhIr7@8y_H zW7F3Hx#09N_u^S5HJO{M`+4$vGPD8oQyX|OX3RAWPmd~jLmZ37Wrh6f$E3&wC@h>l2DP1&@ftvee3 zANJln8tVV?`+mP?pCL2$ogv9uQ>koe>}yQ+LPnNs)$~batub~flaLk~k}Wi33u#ai zVw6fz4GC>bg)Eb~-=EL-`u%>_b*}q&U*B`z|K8^~&ipfuIn2CgUeD+A@kpRQyMMZe ztKIWNJ|lsI$)l#QM$vKfa?dy4|L~KYN7*g~slP~=Z)8TqXZ#1Vx)mrMkc(R9qIdCY zchYbE!d3lrsHKlqd?q6zd9Zoznbhxq=se&HU{ndPQv}pG0&2GEW+1=z*Fh|{syt{p zDelHY1>%VUW?Oz}cEtM}{vDooRc5{SjXbS8aY91!o3M-kxf{FA{W_tQ8ljb%oLS!N zooCQn{;6O-iG=wXTiG66diiaIX(gtZgi<5H6o42S57+|Do7rEys4z9=%|-f6+t|_z ztI!HI{Rih)q*kgw`w2}J45DF-Iby|zJvkNlkfMm6{XE043+k2lRU-0e^v}%)uhuN5 z#ugMhJS)$7SRVEP&Gd%{vTtpOVYYd%z@A>#A|W?XV`*f}hI!xw2f2|5=F@NHQ*T-7 zlwKxWxTjU(Q7Pt6{VR`@^1Ps@tl%wn?&uO}LH7;sc~MKIW8wY1=k>qbW_lO(#$1?= zPJ_zgT!&k$@}(jN@FV_z*mO9S274g{(OdZV69DW4>8lzS=ol@1>5mDdz&k(Zj$m$O z6tNOWC8}6K?rgpY5j(OJYr$N;jV1g*;6`?HKai6#i^`@2+==e!4IlNT47W~nDy%_- zsOIdCX4%Be33@@5+#F4x^%}j)pFiYl?|i-wcHl1IiG9A*ON#7J;lmX3KYx6eB`3QX zb+e%34u?3gACFXA#GZ;58lAFwVrTZ<{?U-qo;PH=R0DmZkx=ey7vi#& z;;DuGb{q4eTpe^94Q%W^ClTUjttOs`pS6&dRyoVds2Xv7W+DAD&vetG$NrVXK6i@q zDd_!!viK%1+t`;oM-B>4aKJ4}@=LE=5X-?$c@@{|fY(YWLpX@8;dg&|qX zUBYUs^cmm3`gi{Jje6m6#;>w#BZzQrKM$`m{L=XQQ2gGhWXU)os3vx{?E+jpR;ado zGxqc2-|y*g)aao!*&?K!e_yGvU#)W{&pq`jBLAhu%1z51GBKZRKb?5{`CL&*Y`C!MPSa|5 z^{wX?7xSh@jqlv`dV4M6ZrdwHPo40`+aQIB!#?Mof(1Get>*Cx;gw!}WA`h*F0CEs zz-8lUT_V5d=FZh>slybK36rX7sGaeD_31VX{uVs8$Eg6U-`@FsSFm%;ah08n2Bh{+1LsS zi4*&4@bPl_!Uq0*h85sQ3uCia$u8J^xrFbk!lAI#{&M4ZcNIqD$CZ+E8bC!B9Ixk}_R!`9>Os8*vPQFxN7Fj1t z1C_tGsBagW&vH&u|8P-GI)=&uv7|?YxoAkk>3Zq>4F~z9&~BY$q-NZkUhnp28R?e3LHcnA1{jeAk0T>P_N*P? z?s5qC5Iq{UFYX}iTI0Qn;G+?jCycOv39?kAK0c7r*Via0s|hQ(uOHugqJDahKGvh^(-?>H z;g8^MCi0{+Vt#e?gzpCQg_Vw*vNo>-AHVUBCFhnd3N{t+x~iSnBg)^ZB?Ojz3AIIR#v$ArR~#GHE@oyOX3rk&_%5CCqxc-6pZh|B z(Z0}+lM%(35Jmg$>RXo2+MD2YS_Pl_{ZBpM|6W{38dy%P8*5n*oR2_Uez9zGaqwNo zwxq7rYXt>Iil3d$xsjBZ2)W-38rOE5zEb;9fG%8y`txV{mt|Al^c11jU$sL8d(Ol5 zUtNf@+Uma6pr-!OmjZ!QJb!PS0Cp%h(^yHgWObJeg4H!*-1s-2G5XO@NZv+nTopV; zEd3D(UdSA)?M0QWExjLEU0*xcBS6;*Y@qvIU3P{#`A`AA{BNKEtW4n4A$b3G1by|( z`sxxCKXY8$ezCVIUi{DUH0$i2gVC#x#*{n@6Ir&kqXUA;Ld#>0uuCE07 z;w(#Zmi#=K_)W*^>;kXj8+m+ofFovwD4V6Ua*bQKzNS=;VQ5GG>@FRSL&t10*6zfYqhdRrF z>~1zKtd7)*@l|eUmZ?}Z*D0K5+{=ri@wU{HGj%w9r4^ZGRGT0RDc)_#v|5J%Q&{gT@JY(Rx;mI%KPw$lv-6SXBlpPu>hX0=-iJ8idO_0t_(p=zn zzNu!cnfA9crn&ZATlB9l@A{kXet1ZSi>NrYuqV3HC3O!CwA6ik!rbUsx4uq8W6w^`{`zwurKyw*Nyj=>N8zvyVZPolF*To&QOfb$jgpfh4}t z=lland>c9c-$N4rw{-b5RAQ$l64lc+@uQ8T-bbwQ-#RxdnJ`G_mj4JLd3O2I)Mbi|_NQET&#+H<{}v?i|Bx=v-eTJ5d@jxP z4F7z);6EXWtpB1Jl&z|uU_Xi>o!fR{YNCqvqwudaDFGav+V=lUm(R^Pe5>pAT(mQH z)P!gTP>KC$M5RFTQNw76;)u$;6oq3VjAngrnd)h??KHYo?k6w(#N@y!sLmcgHIk;Q)IXKaIGD5gdb13%M7$LpNUSGfAsXXAWfR#Vz{;D_->8d{I>@#yUv|kLfxunHN3ndvr1;r07EpVM5Li z>fDx`6w95g3Viu=M%Ck(>{MlTF1rhJ`Tgqu1WEk2O6>j*=92bpSzoc=M_qS3vR3$F zRkmi?MP_3H@X&JZ^}0BsszflPEIQEz!*m%he4l|k-M?woL6W$z;($hI9~{Rq$ndVs zIQ=j>%xgROk{&CxJI4hr9B#xNWb1wD7U?&IC87{1=Y-yXut-J%!=6A@F&& zg)kllB&iDBd9Y1_TUeEeE>uDacmo>*(_Bys&|->PvHOmuWFYLQ%i^0-Ghshp*vZ|l zkRu+N%1j&n;KIh}kaD)|G#tPv?EAPElhc3h_%|;p;X-4gHx;xQ2z=0hsi0ro&zyJN zs4i7P9it~A?Le4AZjzW52ZeK@qh3u}=(+G5E08HLh3J0~= z9Hei$m42f=WkAckXbTfSsjH=J%_WL@nE-~zxqwJ6E94N@QbR>8QI9r(ol8nrDW&eu z4&Xr%M;9nVa}}*%u}IHE6=g`^mI@Z=P)e4SAt!EgBI6`mzzqo+py)C64cnsvaHvee zv9l*d$*Z<|Hj%R=ttL_0p}|hg3RkgK6L7=JfcLxEX6L9VQEiI3#D||RIOy(NkiE+Q2OCV1kIDFN!R$-S$*sO)rb6$#s!4DBt#OM9O;^gYLE@D!w z&ze&Z46^=`nkt8G(TGVjnB`$d8m2cmoR`tI0>$M_t0PU+6S2Zl7N~2ih@q`!+g1=o zLZ5xzOX7__v*4kK8^SD)F}a$3#SKf2HA-w9?|bp|`&$cZPVaObQpQbX`^#Bc`w`u> zOA{+}FrW5n0O^v@3GC^pbd}V83WoJ9Qe?Ty!;k5AkGvDNaeQv1;ToY0x6H}8e?74n zE3RNX753wT4rB9x?3?{!>aG<&2TUq`adD&DrX20k6=6ocXO|yoIoD-+4NS_kEk7n* ztjjv$^ig4KxyNv@?&6t&k1A`+Psn2R%rw1Cd$n?U?JoAKBkFk?CU5i%t2ICOvT%;2x0HNgxS-^xvMUMNxgGi&G4`uxh^|2v(V^Y7NNKXcJTZSQ{% z{_a@&Gf&62^UyBKU5e}cbeHx?*`ehgh-|^kZlBuhveNfI>)h6VvG9LR-OwToUGQE= z`Z>4vSjMX5g#gi-><8bDxU9XM5h(K{Fmor5$B`$_67wn$^KmYMNk!puuS>_zD?@^5 z6X6OsyJMl;<g%EPr8eOoe)dDb zjEit}Ot`*0^gn0@5UN%VI+&ynygKcdw&MsU?bPDa=!_p5}=X z#fd_GoU}JlX_=t5oT%Z=(2Qni6)<#K7DENVPFCF5YnUG+uB#bFCc$i|8A9k3JROPHmNtY2e7aJZ5I}%} z$O?tR5Q088J)E1ET#wK69#75P=Tgp#TIWY6Tp`6Q+4?nHgsf( zcUF7i`Ox(9@cn2bB0-4^d)}fr0^ulrh?R||M{qB+nqSyBibC3tszt|+6jRm(Lsp&!%ln`aF6r`@TWC^(_h{X)cP(<9%7IL#}NEizOv*}3sJOypR zOOJfc#O%jDD_~j>z^2_WYZ?@Cf?sDd!WgMt<&XnCoy1Q^@v<9tLsJr1o{)}`zkf+Z zKAvZhuF?YANd@#d;1S-%rrj7APg6D>2Cz}#bl8vd451-mCpYUsT5fiQrb-y9HXR9Y zbHXrNZjoUZLlG1JUYZ_T*pfqH0oHV6cLh`}i0|B-u1mydurCTZV8DU2C+N&jMjSxA z;!QZO!9$RkS-JrH@@Tqs4630Zo{^!MM~8(obM%?$jZC;F83y4Ll=vAX1^G-$yfT@< zs>nGa5g$%Ce@FiOh2;!ZFX%~t5`Z{`m5k07&0A3TMTTwUfK2VI7!GJe1hnXRV_qog zBmxS5N=DOBRHPR+E#gf)q?fzJlYR440YOIzg}n0!_6@pyRGzk64Cg{HzwqcpQ8l>b z1m@+_J)zmXT3jv{L)b(lY+7eL8p-9lV{+?VmKHT`bZw^R`zX zCWHw1wZdV%+W~KHA3j(X6k8T}tt_OfEHu0FP?>F9nR~D@TcI*Nvofc(^3oTvDkAD6 z3sa&~brI6JRbg&tR+V3?s&1{St*T;w!4y|v@I36b@X8j4%I0fWLmonxb}O-u(6Si^ z(BXC*Y#I#@RW$lz@ldZ|;2M6gs(OWly-cZjeXZtYYt7s6npc@MW7qH#u{Atn>?#v+ z5~?JVkqa#B0>758aQCP2-Gzg9mvrtz{xUohvC6M`+gAfg;3kc0FViqPXxDji)x^5E zU=C&tsCns7(|@g6Qn&8;!8*DAYKc45zqxf%x^;4Qs=@1c0U!87z;8A|{vjcMaO$^= z)sxohw=3Q=FuAu&sCaMd7~Y+Um~^O9P^?#VtQ)#kJr#?e<6zHKvPIU!N+^JsNR5n1 z-LOuhyGf&`Ph%Rt`k+aTrwM!bOAVf0uk*EDyRAONr0K}@rqH&g@Uf=QvHB24Jf4I1 z@@e*otFii8{XDZKjRhK1H4y7cobTW#TN}M28V9d6zKCt{ZmY{|s~$IQ9IC=->o(E) z>vbdUUv0ZzFn0gi*ZVit?$gfKZ(ak&`dap0ZL2GdUJ)y z{X=bS?PF~Z`dj1T+U&`g!-}mvBCWl;txxW>2a4SLK|&w6-ge5T5gyl|z`IfRRs0qO zg`^>yL~5Q3bsMKzs}HU<#yWPyo^LMKt>yW2M6UtKoce7(O+j(@p7}idrF-w{`G*+n5Ypt&)AvLK;HyRGO(K(Qb7gy?h z?$d(218TH#M8_XA-Kn$G?HXvUUS;Fc_yC@OE2g6DspzXzw0vaED!FA4hyM-W-^b!t zxsPQ9HEK5+AswNB4*f$R-6&70>Ge_L_3q5B(6)!C+H0>-o-l57Mfvu|Ikmd8pD=_@ z$V>obJb(dMknIebAOeT7An73fG6(<8xaL)Bi<@KJp=!|Ko479b0l~C!nbo;MM;J0e zWjYE0mG?;SGyqjWM)qFoBn$4o3P;-kC|d#^&+JTId#VywOXXwT`Pji~>@_a_`v1AH7hlS%bzyY?v;q0GEK&=b|Pt1NQ94SDDx~a!Z)+@Kq{s zln$$!Z7rg4ZZLa%Z(!}%h}TYcJ}dOP6RJ+K5ud+c9QnXSAy;gHUR95KsIOdQ2%vt@ zUhMdeN%pN;HAWj9MdgtJcRJjQ35Jl67x};q%J3YmZjCjZz1o?zR((s93ts4pi)-Ot z!%~62BXlc%Unmo_prGf;fC3p=n}t?jfo@b_2L&fjManZl6AE05ew9i`$bRjUXMu5h z;3uiDb_@Wp;cg_fEejQZgYF130RU5Dq$dj%&U}--56bfZbt*gxKzR~@i$_tORG2N) zDP+TMJ%DRcaLTl+05>gnA1s80f>KunI@*v@v4i|N?kEZ(fhGHKN8Y|XR3l#g?Ll)~ z;{g-w8Vd-iK^Zc!Pg@a=!mAlsOhhQ{N`@VRej!Vj4m`zRwWuf*t+V|gc=|ppgoL#P z;1By6$t^{n-N%N61D|C;ELFLVcfRE}32wxMN3ejSWPr&6_1W-w zA{58i0my*hET--3Pbw9Sj6ma|zlIhSd76lbpaM@jU==j1CTkvGi9&m_ zOfoFwD9U*Y)a*c!h#0%<@8V<_o{T6Z;h&HIh#!4$9%V+vLXuruI$oZ6d7)_J2Yo)h zcACtD8X`p^go|V9SH+gM2CRcZdfs*GNcl7HCf|VA4@|Haw37o@T-aYk}`% zz?ldG=wDGJtiCE}$ZJg_{tAV3Yi97HROHh`sAvvellqDbd=CXs8WbR78AbO)znxo1 zog41fhixbVuzWE!F1&<*Mw1X7v4|=rm~?aQP{#;G2-%GQdoHL&Lmg!;Xx5^J=O*v? za);aa(R;;g=SC|1LP@Jpa2j`G~q#xcbK zBrMniANw|$mT)O=>R?FbZh&Hi5eHM~O7=n3L^Z^-y)b2p`xiFi=>yA^66d^wF9+2& z2pf)ldi(P0|2bWLJ@3y+MB+7lNBN`Mk+rk^yDN1(s#Zft5({F_Go?vRLEFJw&-a3E z>(AoS-eh13$swcIywYwHsqhe5tMJJi``Zo$`@ip)Ks;|Bf3+nzbawW_z8yH7pT0lt zUieE2OAwfxCcie>Ki_a(;oV1k*2X*Ol2q%-r8WgJg@BouDo;c!d$Pg<)Gekl!PnG{ z5cr>gmCK!9NH7rtK16_WrwTBwnFXNe4uf7E zPASCDN=8X803mvytQWxR)*8alIu}`tz0u#iVR+Mu01rJV z0ge!pl11OLVR=MV^5kWqZa&RwgX-b*;xq?^7V{1+e0ecpsV+&?M9D-0s}a-)e;vo` zEU%;9oty$~rLJ0v>lg&2FpZQl(o}3Yz4^Ek+fFZa=f5e?> zDH9Wv%`^3Vx z?QgxQy*iALj4k6Ps|aIpr&lFoE4ZuvI(>DC=*)8dqB-$I zGGSpj+9Sbm=0;udQI&U+US3aUW^O8fe6%e(Cz^`YnGCxYHolgD=4ns9NyscaF8nQ} z6iq13ik2+cov1><1OdqCy(ze|moF1=o*mLH)Apuyiv*3F#bnQ`{wjixy)V4ZB`l4d z5hg5uw7qj*cUP(W^wo%IZr$MK;k22Trv^{nj>wu_-EFYGvrI?O>n)MPOXsZ&h5>;G zzZZmD~#a)na$=yjRc-eN71qUwa)T#Pf_txB7yA*Uq_<8DxoE$Q3 zZ}tgTx=nnVgz}1=osDbGWnbUJ;Z#Q3qNvq%J=SN>C-yzn&bja5m$ddB=-YRCDEA_` zUu(~mWFxA&pYz)5ho!q5TZXs$eJ<(JHVA+z8j?kXbWjP}8t)#ZOSc7u>=348pfwUz z?*!h~#0u>ku7|nimR?UZg)oSAQgxSdHI5iPi*b%BdqGYlb($fTouhl)ihh+I*)#Jr z+i}1=Vr}H$tL4u_)!G+u5hoEZ^QmxxC>0PR^nhY4AgN{_i=r56z4Hg)!S60oyf9;? zc>;;xuz)Cy$s;2%uDNCIw{<!i zi5q&s5kBu$JzFelMRm34o&-7_nDV$Aa~tKg@b+~LCGc*%a%8~b7wOK};Je-94nPBG zRQN=pi7h1h;A2^N0M)bp`lpD%-`7SPNKJrwR>a@w@<^FyV~l-7@?2kDoAc(Td$*59 zeqYTF=vY#%msUF-5#b}g{j~1GO>>cP5o5S&&-?ws$4(YTyuIJ5eP8t2++MqM`jjV7 zcA)~$qJGJnW2m>i`hF}%xF1~bB+E`du8lUIc+b!GYX6ZiAJ-l6VYRin<9C8~Z1eNC zGbnHUw+HT==KQ?qU?9;MAx%qC7ErMlU>s3~xfhNyArkSa>(pZAb;D}uOQ)?%rD>P# zbe$%DU0m)yt#%?^O)yzc80BnVM<+=Nt}1qWKQWm;k)0q2Y#xy7)S3l=w|u+=T^ORf z!f-e_m5&Vh=~fT zWr@40Cse(;nc#XI%#OJ-d`t6G<-UaQ8ZE=;k*UcA;?>f`DGnxO9sQV=1nqAQzHTe~ zS@kB;wI)6Ud5Rk)B34K}wAtrPf5_>R3Ho1ZM|i3>90oxh_#Se^XKZYGm(k6_*?v+< zzjr8{-Ij1Hs@&(@+(uG~q~AxeXoaVxerFzhPdFZ*_H7KUNynDe&~Y<9JRy8@bf@an zSA{FqV8^!TZsm1a`d8${krNh=^v|BiIufrpD%Nj;2uL}%!}sIH%`s0!I(S1E`C(mI z##6ubzY59~J6VTF7v2cOcD5hT?L8kel(7EGb|@aX(;IH#$vviU#0DIh1_%;jQ5Cj+ zUxJdohSW$c_mD4vo8#UDWKrcF(c#`43$ZBICpMli2`w^QUX(vw z-Tm%c+)UgDk2VITw-wo=34)P>`3|hOSdZ%p*M81og%S({eoS+H)~_ZXAb@Te(#v5s~w5aICPdD z!y}6!=!|!p{a52s0%kM6c3;e-kn& z0rfLp{oT*lqkz17X~Xp5QhFA1>D9hh9ga6s2$s1cjW-SC&wbb#+wknph8Hh~?HnAH zYXwKb!YfACez;gs?NDu3(ACv7PuY7O-jdP5BCNI{$Li6%5AU{Y*>=nmncMeE@7~&* zHZ|1wmC7_^-;++at%%eL&i*r(O0u0Vy%i)!qTKc%6AmMFWf1J2f)^_SBpm5kH$TDA z<8|68AIYUXn0xp`aMS@Ik3;k~xRhv0DaqqMKg2Tn`B}%2XCKUMRYzjY0)i?gKRA#&pY{E&3ZH1S2|v7qWTLn1x={;@aw;apbQq zVtl(1?3#u7R|=zKE?A9B$=5tlZynRY#}t_gWv~az!IEMh|jzWCtUf zSh&J#x#gVa=Z=vcyjhLxU;Fj*XU8DVcCV80?(ObY+J{{?c=QOY>(@50))t23FOp4j zrUjceZJy{ch&;3zI`Dw0ST$Xu$*Cs;Fz%is%XuoRbbQf&A5vk z6ip-)vHE6NGKa=J3DgRXR=N|_Sc_9&z?o*yxl7!>IY>U)8$=+sGB``)yyXRMYJ+LG z4l%U7H+`U>q++)0=M9}f-g_C!^AW3R8u9E!Voomcy#d!Or@$s0I!T?)pEku5aYNg0 zShR2}8iLH)S)4vA!Rjn0im0bReeaNN+%ik(<><6Y?^-nv^)vWb?NO7``oP#@Q=%J*sgZ3r?LC=pM*_kRl+ z)K^vW>udO5AcHj_egBJX;-2wtmS6w>v7hnqS@D1NGvsf*J$L1#Rn>p=GsM~^>N$$H z-0mED*4p^>wW4Ep(Z05(?_({Juf;<*HqU?HB#EfLH|Tn3ryCTgIoKZKjf0^nxgF#8 z7r(k+K*K4mgPz}b-M56d0Y6A$X@0?f^1U*&{`b%(G9Zbi`JvQ{m`c zBo0ICABp9wQ4V}VP<gp7K3Y8V?I+gQJKchBp z`qPy|W+eJ0-~6!YtDy?0>1!0@tJBwMJ=!xqk*|zq3Zthh%iT}a-=DcjN9oM&OQ<#a zM`EdEo5HyNuYLyk!davL>St(YN|X}5RFvc!e<`o%$g`-bJ}aFhvkf8q@uj-H3m0*x zC12XAw%v2_;@)|If*!jIH}S>`3n9$TJB-&|BI zA`Gfo{>Zfb2QpZ@<)e-_1R2!7(77^WHV8IJk^&|+ZrPc@kcfd-tJia_Uh@z zRokC}jV9m!Lt<%qcwO-EJO96f4BnhyxVLt2J^7sL^5g4L>%Yg!{bg1#b;sRTq^xx% z1U-Al&YCam)p$5J*m`$e=>NHB@6@He4a?aYXeE0X*h{{XJ0HIxi*+B-!kjCf*LZJI zWZrvZ??pis-5Qj^Y_hW`U%egxMQzX{z4L6WQr=*JyV@1g+JICn`YXMv{tR>t3B?&xh(Os z)BjHrz4g~kWO<8)*n3)%l7MPAuGJ+XmdsEdr%FHmZEmdKqB763MP0Y+%}4adF$e+T zVFlgmpSF4ja1+Ir0&F&JIgxsyeL~U4PA_Ma3c2q%UFi}dtdd;m!C=Ex4N z2&?t4-HRJjvfI_HZGCE*pXHsLzuU;ZLw}manix~xG4?w}kDw;vPtmmaqiqrza4AzF zAx*4;0E^~#-|%0!{qtCwq%@-wX-f2j_T# z^wm(5S?;%Q>p8p{s-PQGdBGc&YO-bYgImO)6w;2R8&YUtcX3-JX!T;V`O0W zW=th)K}3?pFe`85=G=C_&56keBdJMPjR4h1CK)r$M>;|p5*b35Y!`IOF7)nF4W=e- zdM}=W#Hhh#iB^OTGF{OZ!0|`Z2s)IM-55}1CEWsrqksqw5qnqPLN3JQ-4|yyY$TZ@ zHBQCGXsDrND!R~m+s5!xJd_OoyDWrH6O|+4yf-A`%-GpR?Hl1c6zQziMXFM zOC*(ucVw%<=j~u8Kd`WIy>JzaXgExVm^}9bj>1&H(tZbIjCXNh$1x0o9@Q_}^u+yV z-}!nolvH&N{l4ll%yddES&_)w@Oq&rS)BTAYqXlk`9%wf?M%?o8-|i(b55;Y!oSXJ z0j$#*dsr(d@iX44#zYIuF_YeG=sejUIC@C#h{ZWAb0JcP$$|AS-x3OT1G{L6E&;@J z1uZq~dPO2)l$}kWu`uAQ1*(H)rkR$5jy(-RI5i}1l?u1`1fqNiX#|a8QEfh`;me1f zcJvpfG`P+vJ508k3OkezL;JEp)loY7pdaykUG z3QHX$L17T}m`Cj0j77CrjV{f1;Hp+{fs=MH{1$qm=^YDXYd)uBtux7xB!+x{>#&3c z8zwrd0GC@#11ITWr*;?vM%119lCl|c!K)KaRiPD%4*vKIOtl%UnQYRD! z(2s>C?@b2=k5%tgM-Q!xXE8p+7JdaWNtLoJxE#kwRAe+>re!avY!|Sg1t5dCwtS6f zQ@Y1b0!*6%0%b0LSg>=uP#_VsCZnQfkbx`&bX*-sjB#VZH?p8*8(fA5@6|vGsn{o) zU{4c3ZNygqR7tkaZ+G|sT96eRdU!AgGOB+!^#C(ojROBu4mYKRT0*PES5Sl;DMyWD z+ajpklM4+N>m_#j$5OGBHk#Y zWh8@@a*UXmW`nXKCCvj!Qx;ZvnP$v}0i;YnPCP^yM3J)mcY@))9s*)g=wsSWGIA#k zR3ihD0CL6E`&k}jH(Q^>FJ0& zR=^_ZxZkA*(p%7eT+tF?G%kRgb!quP?(${P;w%yye~ks(#e;*Sv#tPqornn_qyF$v zVdXG4di<~rs1X#B>La!qAq$b{&e&#M3F2Mo)j1qMKcrQ9VfB@+5&mpL(=cjWipYfg^&=?kw zB)NfX=r-I9gM?vmUM+bhvIrd_eV;vw!L;MLrXE>Fjun7@q>xTb+7S%yRD~l#9u~a& zNE+4u4-rAo!b`HV1KCKB0vDmDKYxXHmPd8MGT2WXCGNqFlaG+)O@ypO%P_16D*_Y} z@e^SHy9A-e^p=6PivS!iheiQ8`$-q1iMn@qr>vV{{%7E39Jpi84NiJKNDB>+0S*!I zeZ5)IVc<{7>Gwy#R3_LNeL=V4f(X^$f{G0wA{}_BwscU2jm+mE+e1MC_ZXFqvu4Az zncyK(j&dbZjQ|T`A}JK`3?E%`1rfaa6v#$PLe4J$wV#?^W|Shy$uOq?rsOL!L0Cx| z=+2B%;ueW;k(vaAH4W6Eozx}WMpEJ%8okX~$+zi%1O;i%M?(OBc^=A-2}7|Ex+K`! za@ciQgfs_!fS?C;2ZN~|76#-P4JnHwg~9c}Sd217$Sf#H!g&zTume#qm!QkF@A_x_ zRu81#qL?)&=aXjT3JHCZ>lRxE%eA?_+Yqe;pt@V)!w+0P#1}JV7C2W#R+k;w#X^*D zkHCyj*8F5EZ7^gLB9H^GOvPmz<@%H&b$K~=crcKQLsH>Ntl)J3(<*~r-sOKiHB5_h zG>#DFKs{6`kMdyyyD&I>FZ=-tHK*w=an%!QfZ_^ZbDF39=~rs=Va=L|HaXfBZizjs zR)$~lQVQ-)g&R@OTL`s*WE7PNGv!_1T>-yWcElBkVi1wF2kjARHqca;Q*Uloyf5pK zbov*<)`p7d61X)dwDm<`Fc0&XVf)Gd&t-S< zm!7Z%u~i`lKf2&apYr-iHF2|c8n+_jvLyyBi-710)?sb;CTh}(UOAcHAKn*$vS-+^Z_>9b^T~SsY=Qa&7$PJ0@PFA}5_Y53!$89G!?v-~BX>8}dQ16Y8 zCba48&unNvJF-`7=d-B>+prNA8z-|R7QP4OZIMRtit6xO6p)x-M-RvDT-X(J^|UB@4F=c(Y@QF0UtIDDP=NB;Wd#D zpXFK&`95G|^)%n0aQ$)6g+}=-$QSUba*S;W#Eajc6{WvfPdR{pj=chh?W*GVuw88_61Q-=(MH# zy^a_k+%)0of1@dgY`yE0^gO{nh#7jv&-j!*zH;7OP4@l)( za$t6fFI~WHH!pzq2$c4C(LUg$6`;eqq{MRJ6Z!+6 zIjNlDY;t_`*8SPlhJC{p!(&RQoa^S5GbxAj@WB8Qq++da41SL1Tr_y5bn3Y`Vgw=W zs^k7l+x?m9B4sSd=FLb4F(yTg6AJF62p$Z7YS{0ci>HuX)=J;rtb>uF#ZJ7D zHYb;xrXmwTAqA=XEO|!P_|>0%uAeO5?jbl(0r3ELA@6GIJ^aJzzx#>)a>e1x-P1v( z1o3<$@5g43VB?ra$C1X2dB}U4LFH){EVe!omquS@?d^p#U~o0>XR{5ONgw zWsLw2N)U9Ct4a&R&~herBI{q`gW0Dh^AJSMV68BydwbAHh%{(AB|~03Nd>b>lidYK zC4%S7R}_VO>{9eE%rpwg2M<>l1aOJH?5P&2A zuO8z~$}FBs!v_}q)<&B3mW)T8eq%T&dwz-V$QgMyFm~!Nh630F`u-4wTL_-J<14v~ zKM&yjW{Vf*=32T!41eTF5|Q_o@n(FC904t)(SI%BmwF84Ue+PN2bfF94ZFkTm|zJD zv5SD#X49-LA=j4hYoQ*4jJgKl(upe_=YxM^dS3k;%LCuK71 zkGT~3_kgSjxFgM&5I%4`d=5p>N$#}_2((mEH8q@~sZDgtsp&+vq~B7{FjbLrT~6Pa zctK3;ghIVM+{QXJ;Uwh%WxsWbL`9X~{-D?iCm}PMV0UTz&ix*)G-vDfteJ zD>#BoBOTJL=KpYm72Gt_jK6ebqWpZR)!Lu6oPg}?4O=3$?CXaj#1s!cWL;x`vzdfL z+wHEBsW23TiT_q7zMIprRpeVO2ja3_IiqD|_NV#yO$jl1%7s6#-~2klEw;|q^n1Gy zHd5(vH{{*h#fZ_m;Gr_1-`LX8@%yLdr{9hJKF;fmuoYi7e!O>5sP{*g`tgI5zHp0^ zodi!c8-`qe*~=G;N`GlDkB3h4KVV+{7$D@Mo8tL8iZK6E2R6@EpRr}o3r5TY2 zo@Dd$Fb!f!7HNse0`y7VAgC|O;jLjg05M!nUL%Ie#RqFBQU3Q{|YTPz|urv+r`HPJ0# zD!TkcoUl{#(PZ}Z!(0oPc8-=M^!rwuXKGDdy>+ub^3f$UR))D50dL^IT-2sHJR5xq zZwp)psAHivwcDvD6P#|RY~F495(Yu(iA02jY#tfw*uy2*#k@bcbRhIr-sywkcN&)t zM&5gQ+UHo^Cti|gE^|`NvSuyq-VWhYYSy;ZdmL4%cpi`vvxB0as+UgrvR%4QE(xtN zKDrsZsa5%?sv2c^vuMJ?i|oCd#zTMal8#zFA|^0)6wkBV6_2Jn?5C96#JXb0XgN`? zEJ|BX%d(e%*k+ZnV{ubo+u2onn5g!4AUF$oRwF5$ki(Qf?xRlwb~+qp%SU8BHyJM6 zgt*VfC})oTrK;j?cMzk^VcMoEJbFK)sslTlrm7seSdygxlas+IYx2mM$TEuBdC_nZ zc?dWwWpzutEBc7&K3DPte_I7bEfpL4zC=_#ceF%9x}ku0Y)>9D*%BtX@i1&_4>bvD z+sSVf-BZjgq3bQT-dH3Z$|p10rkYMrVHge$!b@tYk zv$0?9G_S`(>;FT>L(ABrv7Z`RL-%m%=G2>K1m<`$*R_DRa<0VDWtS9nR*#q1S#gNE z$iY|^WyQ>>qG<5rD0kM`Z{5d4D4w#SEX=0l03Be~LUxIDSA)+1TCUNB5}IV>^P^it zm`~p*MW(=7Ki!fxzfKn`Wy)&*;P}rGRB*6esEP{{a3u^VAI@foM+G1@VmeJ&wC?ou zeUeYECDEU2vL69d3#%474#Nht5JbemadoLOstmM}L;YVAop)4{?;FNnmLMWaK-@S= z+_SWDfLn9m49ybD%*xEsvaDVZx8_JqtFK~NSy|b(QUh0N?v*RUGPAOrm6gSh-@lym za1MtTp8LM;>;7DF$6xL=j)l-snl8H>5ij&jA&!Qect2CHPsn;93xK>0wKR|TA1Q`& zM!^nZ05^RPB!trPiJ&T3I`lM23isJK;z%wqMOv|G`B{a61y)5eavu}HAiYBs;t?~! z02!FrX|Us$$J~_e?wZOyMh6pLjY`!IdMt#$rin^M2scw_vwfhwF3bSq9Ue-KJFbaw zBW=Rtc^81U$lLCkDv?XHdulH*2=P>s#+_(sl?PVy32<;3BJaRJxQ-!*O znAAiu^C~p_L<8^+P)R?6Bj-5Mw0lw$he)N#ybC#hUnd-*ID;U&uDrhA%4xcO5EW;$ z;woQ7gC`X*@$+H`NvGH;(U7nn={3GIs11R^g)u}rk5)+Ig2o{F<+EM#kG0ZG(^u4H zvm7WvtQ$t{yD?P^F3D1{_lbK&&>vHG{CWml&Tw6owp!lo`q-yx|8C25JjWn8HDKSt zaE*uKS?PYUr~#?g@Q=nW%LE3b!JzqcA&*oE`UpN-6zOp_jQ_v=zdq<*)}HDg!dRH( zO^Lw5QBWwV6RUSN_gI8fIqaPnD5XZFF?$2}3itg1&Fa<*|CO#UEnCLjz>7|}({mu3 zEmFoyNMzp<9u~#dKy2(G#^ix=Qc|hf+?2DeUn5>e7QlE)EhVKe`=#)70-S~lIo^b> z5~tu)$u38DOs9HNUv(i6g_AEBXsuxk#0i1<+D|Ig&B?N{Mw}|Qcd7-w2r@~ymA)`W zeHgikqQ=(HOot(tG~sIb#%MjM&vE4Jq}Y&GwROr<{^Y?1ubB69w=J_B)1BML}qh7y4GI?Pn6dGdYmTZE!6}y9WEM_ zWoXHp8p_75%CM|kR9o?&{8t#5a&Yd!%KOsDqTsFrkqH;y7#d+~#a#)f_n;{YqnE!n zxl$M!rzchP&E~H_Hwsz74F$=+8m?$;^t+3ACrmc0YLh1}iqN6LbIBpXeoi~6n9547 zn`?^8IsJuNNy{@a@!GHF_8-2=H2-YX&p`(UTmHECEf7k378V47{k&9g3@`BJQ6HjP zd$E`~rrvxlku_WZzg8=z5ve@8MggxqR>)sh@V-(Y2s)A9tQNK?(le}x^4`OMQdis2 z`#<1JM`&2RTA{X^pQ2!u2JB=5RZs9Kwv_@`N%3j8Un-Efi7#!0_Jt7LHs_~CFf>B_ zA(-ABw9U)wPrZlFus4>)<)wvAYag?Kx}A=XDdJlHQbxc2d_8KdO&cAZ?$AA%&xaO< zV}GqeG57@;NO>?ax`uBv!2-Ngdx;JuJW~k`e)#>`M^mYEz5jZ$$%-RV|E-bA1TELR zP(=Kb?m#gAAhWTM>+k8xK=3&kr}_1>#UOWVnUIR})Z8c95~);oHs;x027bR`vP}Vy zjNw;kSebwbyimqhD&afSGRMQgu4AYQ=s}Hi9VrCr)_Eq<*)^EN%I8z-rsPfCc(zLq zE*r8Sv#1gWVng09G+O{QU64GRQjy4PJT4+uH$AgGY?@;11)1H1OIEqY0?}kJEws<( zkuY*YV;_dv07~ZvN#LZ}t^e{6;d}1ZxZSmy{ULMeC1B!ZSif zqP4BMDO`Q0v+d^CkF?=dAURrq zqlJy5rDxMN4-3f}%zi^ab&GbgEGzR;U&-q)*_UoO+H@)fbu_IBb0H#oJ01MS=_cSX zb@krU-zsuYQK`L+;w4{8;MofX>AJ-ik(OZ=eimyxCu|wW{qu!+5hf&UvT#gNk6UW8 z?<@@naAMdfGT_290L`ltGzhivDO~3e>Qs_IRqt#fg*!WMsl(?%vC^-!EzPD=*m6!F zTa#vRxXH>%Uao{kUCq{Fq--j2iJ5abwAT98+M);V8e6$84k{n4`f?Z$+^ccwXTRv- zwDd7r5~oGStA*-=B~-p^j(ffWiP1;1IGN-czmm;Oa_wEUwt48Z0Bh@^J?QPlSw*x} zY_5_duVugCw#D1X@A{09QG%KLL6QW#97FeWHtpxu910JwizmJGo)ZqNI`vU4`t#hg zG0h;~y^kgAjcRsPeaQ=TL)g3=%3H?_a6bi?SBQ|mGMD`p-7yY02Re0}tn4US!9cC$ z|33A&Gv{%4&7%f`UH!yN8+1Ps(1Esjbtzju_?goHb?Y%tj|bTvahIIZ2i=B*TZd}e z69YUR1$3-rxW1U%dQNBk$xWAfStT{0o~_ZIFOxbGJ-5DgE5{@imnXTl8+JV5dmK)3 z=RNeehIx@b_hKx{qiqE<_O7g_HeV;IYnIhHknJ^k$!iSrYRh4Y^SRd7y|4NK+M6VK z$=k}}`_)~8QHUPeH9RC|P|JHJ+WTWtclP^+{=Dx0RyzBqJ@4swjkdY&pK_nIl>aLW z)y)IXpa@HcJ-pJd&4>E@i1zteS9X}6;to9!M%FljC;IFTb(O*APd4IDHt%KE&{SX9{#g{Cr`fohw zZ*|Il)J6rH2QaNKYNzKs2ezraMeN`9YXA3EZ6 zG}J~p+Wm%V$LY4Tok{HZ*%32GwqvJbNpd@T%_y+a>6};jIYh_z-RzP#FP{(MqT@$= zEuE88w;tKx_IlihS=h`OB+04fdG(dJtB%NryVC+z8vx zSP@aHces>Hi)0Tw+1b#~ToP)-UBWJnV<-OeGE+_4sPR$t1j?^5c?bOY_ zhr&(0x?aA76@uQeN1G<~CLxz#P2A9miT?zj86{ijBd0uSJG*E$LdmVsJ4RyL?=Q{8 zO8Nq*mMLFzmN^$VaoMP1M1Jy825;%+9nDxZn<*|jHaTm{#M<%>_e;{1r{tV0X!uwf zp30S_CMN|l-W_<&JvC|Z$}7OqDZq_`WkK}wpz4f_nHH)-GpC^_O*V8Ahk>bv3UA6m z^lSK-1%Xa4Tj4AZ++lN*yxr;W?i{K7I&*1-|pm8o&y_S(-u8?gDmD+vf4mnH?BSka`a@f;lo!W z-_wMF1XDMz7F#V5} zQZk0c#p6HnlaR1j2yFI=wbYUA)0! zTr}G}LjkV7nkT!Eho((SE_Wf1Byh=Yt@&eV&uSpXH`wvs-^{!SGqRvjRF_Fx+WQ39 z88OnT4W#dWre6ZJTIG%Dfz%p6j#GcS2He~Z9`eRRr9q$hyr6U*Zo$Z%Sa0IS!&J3W zV_^Zp?C1blDhomyL0ZwFRttAqRpx(VRrTpSQ}#2xDyUpK#H5cqR|O*40MQ?))E=hU z`(8Th8-7?n-@x5ZN-<4`!rUORbm`gW(AotI-n`V&hI#y}O@T&Xkq{mJ}cE;GAmouqC?-vL8-BIxL92(2r)jk zMdDimWq^>VOR%n6&?j<}6$W6}^Ey+Mx@;9lcf&L+@aVm1bYUi`2GmLCQ9ovy(?MvD zvXvOAc^uY#?x`urwd$?UqTWHiwQWmZ)}zkTN_eu=-OdA%T8gGYp*E}Q6W%C5Pl=zp zxPmII@1|lC*PeK4p8b`Rah{tOaJ4#;e)wWHR{0)Z=XmV&0Xa=^se~Xuz4;LhNEwwO z$O!?t1t`=Mv|Y8K&q94^z*}F)X%#LGnG*Fe&&^w4PS@FA&eK`6wA=RsnhrB_0!k)-@0Z6wt7$v`Y`l{-vK6@E^tvqIjH7W@pjbcr7R{jb1<=NtR{j-OcA2 zk05!@@mF`k4PSnY0ZF0{G?8nHEYphRW~kqmojH7h+Nx@Hu3JS1_LLA9W?sDZ0 zSODx>5Gn()bwu@QZ(G>dj;pfVS5)aM*{5OYvhIgx7p|LNNMr}NJYo7!IRfK9{eAiM z-M6ZV{(hc}tGO5)**z6Ml^@~R3{)Bad$8*5DzjB?zhT?Y?yV?UC5QBgPxBhR0*5rB z(f$>Bf2GHH^MjvP^aiW^uKV5I|6PB$I^;?G*U#S#MrwAwEa>{|qkdD5sKYk})-$MH zs>ie4FFUj-ni69;H?%Z`RIX7iloDRmaE_J0=6^+AcfejtTc#1*5-a4wG*LR(OT=y((0 znu;KySz`lzDrMgx4i`WQxZ#cfdrbr(!%Ew3-vLj~mimkk0vgkPk6Q(g!lw79 zV5?RwUT%@&$U5R>=E9jo$^vjrc1Piq43bLf{eV^yGMoX5n}DyfgLIbFVeSOmifwH3PcJwlGXbl`qW6)Raq zw6VBZ5r5UR&o0D6vsqEeL(r(sN9FgZx?BE0*ep!HNAQ)B7QJQ8>}#iP-Sg{@i4Y=Z zV=6+ZB$+nK8q}FKZ3}*gQ=zWn3vO?YhRBe4qzVVArAiZm*<5wCk=pIMo*(~5DAhkm zOY|*JnanDX3-=c|$wh|og~1RiCyz<}lRf2wvb+*|UWfXyRRq25_O3}Kf>UWo);w6@V_`8^;}hN`M#=IY=+_gn$(?gstWnFuhB7SJA9!Mp$C^RSila$g%sM~s%?&_ zRjwTg6^>01YP_BtG(&%q{zb68&<=U|VX{1$<}6etau?U+AykGAHf~Ashp0to!@>b) znVOgOSLV9pWNL+XF6ULI(6dk;ZcrE2eI$MLO4>Xl1%Eu2YrbG2r)hne{~2j~hF&4# zF#EDvCr^(g1j1Y&cHyI!5DTMQx2n!V-lbj1`5T|6Y}WX1hYEB~8$P*z{)$ zI#MqgL*5twObeOzQtsmO%_Q5`Yynw=0Rbe&4ERQ!3Pw;ClNAj{rf> zGaPy;E}L|d0s7Uxl2fW0bDuq$zK-1*Gyh&R`J1aF#av;ultNF=?53SiYrV*13sJ_s zDUsRW`UDh&1XS>419ZLU`9gRrNI1>r?bx-ei8{lQ(Wh7V>N8T-g(A^vZN{kWC(@=c zD=9Jk8R*YC5sFe*L)k1qG7n(l)6?8$e8Ug@p?4#W3n4(P1&oej0G~HO=$HzrV{os< zGgdNC3z1>ruWB$IbQ5(TNiRsDN&=wKh{%kf0t|VV-fo0-rNfs`Zgvmh{WyNS)bcM( z))8X^+L|<^p)8mHjwG3knwI-p(vG-r59!qv0f~u9!3%|s>qZ#RIaLU0^Myt!IYH|$ zs>6Bdo--mCO7=Ac;Uf!YL%leM-AB^V6JlK2G|XMG4YZxqOqU~8$gxn4afUUyr%+n% zADbB{9*u9s#XC4vLEee`a*c**u$4wo_LAVb7fGyDe?mL{+^vZZ=1-n>pE5qIIP>B= zAanRnTROH7ZEuoSArrRZN_DY9s^eoZj+v9lN@4OQ&_Qb9Y*Bq|3TgIYB5r#+pzz4d zpiWH;M95f?27Fu$oUMzKi#%fiJfN)_!Jq!g#eeQ^zH=4nyO{;Wi50_sd(w_6RfM1} z-*DeAL1PcCJLP(R_DVow8P;y8z0vwD0aP6kJKre<74L7}T!`nQARyEGvx};G6-R@l zcb<5eqkOR<52Zi@a8(P~UmhaTc1{#?(>7y0v3F`H6h>&IZ8qmKNdfwWZgR6;CWg5Q zYpac?Fs58Uz&PVBElRH~l=<$%fO}<=X)dlo%!n$PorccO3wsd`TlMl6GRZs%ZkKQ zdY&fx)!5M8N#A_+4sCWYm5DMWumaYOp%dua6wOVM@7w@14^XSId2Y`+cvSMBxGXsY zQ-ce@Xb!cQGhW~-OoYXS z=0ebdSZa26fZa$Fv`&aqcN4mh#UeOXDZFqIAjhz?CieP%nZdM^9~)9-MZ*5AxU6UjQK z!%2lSb8)J>yadu#n}N0|Lyue}`?XenI%mJoRKx)(Z7-GIsmKI?<(+M|UJ5F1JoyD- zdaMwexec`nkOa`n={zf0UJ`+em_B>|k{2HDiXIt9=Xva?4j@G{ov1wz|0|PI-K7e8 z)-c5Nzrg*7d{Xo4HTLKT9Rgu+l{yr?l9<#g5`_A`KAfSX!`(RxSltXDnr>H};~wgI z&0X6@VM8ysNnq$|fKnolOwvY=Fc7onu(3eH4F>f%ml!HU&oR^MV4KE3IUQ|GHnVV~ z>$HFRhCBe$;0)F2 z3LM|ffRUjS%OFRLMC6O>KQIuU!)qnlN+lV1Re?S%Udvp+77iw5PW4AN|qr+Fo=nJc|HkADzj{n{uw;6qz}ZztDk9k=GM z$JRM{lFT&@c6~VIS~z85vX+T3jKouz%(i5e8ZMSvtcVhkXbi-Jul=kL=_J`fvR>~} z%arlt;`vO1;mj@>E{-RN$5z85L!20AJvN@%?|UfUByp;2lhMIv3b}+ z5#@(0rfoOTRF``>B;8r0vDkFCWN)NCU8QiZ(%N3EbpEeG6P~#YwQ2+r0Srt!Fa8nP=)JDx)-y9hv0-&|m@TTs#L>*)u6T+D(X>?546^X&aZ5Cjd0N?^zw8cq; zyc9)5F=g^ZId=OnYadl>VPS9xr3y-#8;(xhhoR#p1%OliPQYz%*pDV8d`kZKN90KI ziPL~5nV~24Q1WC#lJ*j6A!WO69%}@{AMs(C>q?Xvk$3nG6cE8?5Yiiue#;5{CZ7(? ziBVF_N#**@&|avmzrX(0ePe?M8x4Z%nrbVc!Ab|v*o)2)W2%+n;OOw+t28OM3G4l( zChovJr7zMt^O^of=LL=n{W|1tReX@-)^gN=d%svUQylvmCVGyGLk^BTbLWoa=det|`3^^*eC4 z_LiUWurtf;Uh37FB690agD1)dyoI1?1+}3AX3rPpMji;eCVsla>HK$qO}Xgkncj0B z{^VQN<6;A6Aj{Q5_Hb?o4qrdDKs4bDS|Cs#37LY{}w!F)WC?&`Il)soos6eOpko5J3TiAjs6hw zW#Zp~CNc-|db7E(s4I1pwH3SYtzV z%^og<4Xud~>XDr8@~=YoD(?!8e$p}b=(0ikwOB}&$>h#ksX}p6Q!5b{Ie(%y*zAU;lJ`nU1^zO*WnF|CZfS+Zr?7 zM}8(7{7sJ3a21tMhokCYO0&YZcKo=n$#$yEv05F>2L=arnD?eCVozwKP=j3-3~7Iw z1hNioe#Rl^4G`y)9)6S8uaPrwG^nc>aW7YX@uCZ~K?&Do2Tbz@) zDxQqZ6~fdq1coZyrpI0HCb`azbc%2gZ9_1W=8`?BJQ52+h)s1INzQF(+I?Mtd`Vxw zkXexTm^4=wdYXvK2DaCV?4pPHhSCi&5F5c?SHpFNfJFWei#XwqDo`^*RL1K;4Zc*B z=7Zc(j&Bkk)#qwnTHJNU>Ui3dZGvrGYNYR6KbIU*Dy+69SbtJroquw6-a7YZZLY*R z-aWjbL;{C&s;G6rqoPIAhFr~1hF$*GlLSyJR(_hvRm3yqWE&MR%q>rME+1r`{M$lY z@kK;)=i=T!l}Wt@I^Z#xSR1*BK8I6DT)UN>r3wrLom;QNT^9|>qFzwJ4;F0$UX6I4 z#e)S~Z(s2hsZKX}!Zua9KCATEe0AGzf9c1#_VSd46{M!@n4l5r2Bki9Q1TSwRar_- zB4Z|muzJI94@0JeSDY{npF=xhj!gimCtFUC_*^^SHqpjmWpwJYExa)pAQ=iNhcBRo z3>i-V`(q=vH3uSSyt-qYqT0=y<{zsFJFZPl*B)0*QlwOfAIe8<)O=fsO#} z@N>yTDCiDoG{DmLb9|NBif#yLJA?>EXzH^g32wrR^Euds<|-XX;gAp+;iP^0yr~E2 z=glqMAM3j3ZF*GJKbI@{{o|-{IHaWXN=MasQ*KPgQOLK_^Q73W-4}z-?umNR^4jBT z59+80z5sih13s4>=$M1F?Pjzt7T-4@(ME;(q2+L?AA~RqHO*42gY|Sg?yUf^$0036 zkl?H27b<7ba~)kjZKf0(rZnu{-R-LY&R$CsmE#!-EyoWZ4)sy-vZh`$f-^ zxQZ;ULKjzMBA>PZE8sAI+M-#c=x7Xth8Nvo80fn}fM#LQmC3|-5bh}e10lEAet1tM z=-i-Uw&?x~#0ptKDDBL1$|KhAl%=j5B?BC&46k3;r9kG=T0H$_q_!QHhljlaAiu9z=<$kQ2s%dO~292H( ztNBU+cgC!`Sr*Zuut8QYz&g$kkSZP8PnCS4&Yb@H=hx4llDGAzr>FL&lcEp{gn1#V~ zHY2bz3u(>AR`eX9Ipzcqz)zI}QO*dD`gK66MP3gPNCMnzWBK?QAI>>4@j=U^C(+|(<+W00(q1*by zrE}ezzt$=A*xb_Z&^R3-CxB{B5}e9(&?p+H)v(~oNE{icNJr}!ak!=pAW{a7Iqt~% zv8H5}jfu$%@T2}-bV%338__b3NdYP6HZ{1B@nU{WR>$eJ3~3I|hhJJ5xS)e%bv1Lh z#sY->Bd2p#H&LY5QsGV-n)6dH8BM1fdi2E9|D{aCwy2$-i0`s}?M+m>x}bJuvOSP- zY-{25W};%9Vi_Xg>J$2v!ImNq2@#=QTfS*^sHo2+Vb7p(%B_o6!XPg}w(vB3>Uzg1 zR(Rp=Ge4$YYB1eYwE-;ki{hKYz@4QZig%n=nkm^6bn8v#uWajgM7eJzPJD&o?;MEh zT&YJU@`o;`^5Bn$dw0CwbGIt=z_k*O#G3{;BP&#bF6?zdlyZ0xx5`TA?swU#e0?~y z^WworaO2J53%AradzF99x0*WTzJ~mG^G!|&C;gn=iTV0mBFn4cqD*ZV_u$drG2CA< zuNQxu4SDdjbHm$9%iXpT)x&FAr(G8>eY(9RZt&2|vzQ;^4<-9v|BA?sKbv!ts2B6) z=(E1l`&>64nq0TdCj7Odz51`|qOh`Gl9~U`sQ;e5T3+`1^X(Vvf94*&E&KDWUZTFX z(4tYkw$x>>@pok?to-kfH)k~dt$rvk|M&ar3k}KI_qXMee}5$!AcQ0aWZ4XuI-V;l z4LeX8VIb}BJVK!uuE%D|?ZhW54T@zpjWBVi@qA6v6w00LpiqWS(F>SD2ah-?HsDju z3a2pp*p4cb__R%fQ`p22M~#2@bSCK?K7;L~txm{r4|qo`9dXjNBV_s(z9ZdWI~(jI zWCahtqdXmPHaShm4kx{*wzFL<$_P380^Tc+j<{Gg5YEOGzE}OkcHJ^b$W0u4ul{Sq z)&3tLk4u`S$p*VQsuS}w0;VNeN~3PBcEp1G!f747VE3&%iRVfOr`K;9b@w?#}LgH}^EDQj`42%{|2LTp8)AUf?H>;4#1R4Ww&kMV~zPh4^2b zBwgP$^vOGM%)k5}sftPd%*v321YA)k-*6B7>{mJ#aNUl4)3@kzz>Sc=TRX|Of`>i_ zJsk_YdzxGwPX5Af4+(luM!vl-@Jq<(SkRLO@}0P%FQK18wmqLD-%T9)vh&y2wio}% zHC*x>M|L~ANu6>pBXDk)(m4C29p!$0(OiVy_TX1LDGy4A<{~$Z2lt$&JggvpjdI@} zGEhc&bR+QV{^0SD*A0}%_lmwo@7un8e3J6y>5vrXHNO4rKT55L{4F+Pd+2+0#i#9o z-{MQhLqFOnKI<#`cKF8j9ba}TJ|7+WcJ%4^j``DybyMW|R9w8DtXNYGCuTdX6SMBeiXw0U1RJkq*p zc=2rF#BL1Txvcai%GF-EKfidTQt#A^Jk($l!Jx2kseNZt=zSpV@V^AySF_3EHt z=3!M+;{I*dFATN89OPO{X12YRD7U1YJu=P!xFHvnU*CyLp-S_AclcYpzKMOD+0qM@ z!HV(`{N0&#&yiG4oaRrlz=t&xmQwu-#$ESK8< zUl+?hMIFz8q0YvFdtaX%YuS0kf3}aOt^>ejXF&k)?%HKPF~~~%X-_o$lIn9#9jCj& zKWGgezYLL8Oq6$z$kS&XYbc)|w z);=}&?LtFp02Epby;rm&IxuczOeRLmw`j}Zmie!g3jIg`s)b%r~PIj(o&WCJ?c33aZ%$b z<1;7UoB+QMy8|Jh3>$##6CkMGVy&+&Wt{Kt<}Z2T7U}XWg;Vq&@@uW12K>4tX!#a6 z2&oky;WY*lY53ny7-CxSs9{RTFf?v3*a=2>8WkRzvrd5*+1&W1p<1@bXW`IvC^8LpC~!dG6f zsC02r>293*pg`V62wR|0>IkYYd{vwBRbTe0z9Ojg_^J)$tG(`18#hxs0Kx6&su+lr z?ky@Eg2=Cd!~D3jmfasLyEP7Gt1FAJ)dUR%Kh2L*>Sbp51x?%nQ%ko%%b;J&gs5%d zr)^cBy`^7!ow=5trj~n!JjGmP9Kde$$<6j1ow+lX?nS#;O*kQ)T#0lJ^{<}~C)qHx zocnc`#kzVT-Nh*kolDPI!Ypu!1@U@CMEa?Cde#y>!%wfYK(Cx=knd-3Lkf#GH@FgS zaQnXgf9CWXep)by#*zD)Ljt0=5Ve@T4q^O0wQIB_#<Y8Ga%`pvBdqzBE9J+RXAx87i3oiSjov8=DK zY*B7zsT5E0c#zi|L#XVYP_AjW_1ktWV+Q^0rj~8b``NyJKwmy*yS!|h;b(u#&#q^g-gnMQyB`))vE`zIjgK^9 zsNiFE+{olt)VqU|vj=H=Jux-sOjP_Vl?pZQ<{Mq~RgpZ;C!sBLH2s{r3P=kAXZLWe zaFU%tzYX)g?tk&latY3x66`)cFuY-|w+M0hkEoilgeVasFqT?H1@7)sPQC&39CMtF zfEbyuu_7VY{Op^;%OfiXzpQl;&v*9RUsgW2WKx=7`M}HuRw2(25FhtJpqhF{+)fX9V+Xq!_LE@T_Akh;!t?PFe^*Ns}49O?s?gy&BFx&ouK!5Pa z`9)mFB28ZGqHQ(QubuqLz5vPs#dHq@%4K%M}{GQ%}U1_plr7g_8W{yH23-W zkPHi-3ISye1NCzJur>nnb2Gi=!;yV~kx%0yzYqE?(|k-e>|Lbc4Tn%r(cV47etHna z1+GedvC1EiFw2#h76WTy_)(6>kz#TmSut;zY%6tQ_+j-c);k6SD*VVx^#W|}%sAX> z*P>`X^4A;^17|P8q~HNbun=1U%Am2(NWk3(zJu6XxwqOY47l@bo7-5U!bj|_S)^13lan3(y+^?JobTc4vi zAmg#e(+GbH2%(&p0|m0NHM0M>3R^gkdnGcB2W5U2Bf15<<*}$$Yd-l2;zulG zFG!%&z~;c=5H=n8nAot*^19+#2cwTJ*6)Ph0&}pl`@Lr;e`rMAKl$SPmU4gj(A*LF zJc7YN+7!#C7R%0YnurL8{N<45gu6cokbcr< zj||1I_}c{vY5*2aBm4-S&<`)(Cn!NCc$g%{Y}+6M>*BSrKXJMTV~;Oi@cL}nUHEfJ zJ;5*L;sau~7;yOw41+S%C-RY{2)8L95=68nLL5s3r9xNYCZu1Wj<0~Y3E(6F9A5#8zKfXNM5@jq z4uj+<24(Or!l5>23wSM+Vws|By}%#6TaO{Q{@8{`)N} z%9$hHK^C(-CCpuYhqpXfL{O&SV=JggaB@|!`|d9UMGE; zd%jI#;VX9ri|5kf%vDM`mwW&ev~+TeBY(l@h+-^3W~y?}v-4pt;Mg3P-BnvwbV9!5g1iI?sb$&_9zVmX3ka4BcrycT36h;aNWU1}c;eZui$uzJ zIc^j{R@}x3AGL7gyTz5;#aC^In8JsjQ&Xi2|+2D2Yf%4FwoC~ID!Qy|Gy+wQOAR=;q6NNvtuqJBHqx&q2RF)`n zX5>c}_+28%Z-C=ktdjO)CjWclo{jk4BKJqudlSv|b{~y&-LQ9=76}Ooc>QQc>363O z(&QwXJjWYDXSA+6)q-Toq(AjT`0FKXj9e^I`LA%_9~wSVJQ1t>;iy2R^r4R9gDvwF z?G-qA$^6B*N7&U+MQjf4SL_a4@!b>W3}0xgSPrbHUpCWJqkY=V+%bCOQF(ygdrhDG zAs^U~is+PIS74}S0cqOT?ZNjrxef111N18XA@jgdIs@L%X#IE`h@frXpb`8ZDU2y` z)+KAKe=+L61RMipsV_{&#g0Qu?+%Q#A3SL6BmQ@@=XXiiy&J|0`Pq}Kr=9}=MVcp- z-5+c53xm_`TB5_{Zdk&bVpDyBmz!%&!2m0@>NypM%SxcccVz zE*2~HhVcBf5w%$Z7A|y+mc~^ zRnk#pxcym@ti`p?Qp*Elbr}}dyZ^I^>;IFnq-$^j$_9J|NPhoS*%eig#^`J>XPgYF z&)jfp_;%>?6MxYgt4Hodyt-hUwejmnfF!a?X`T6<(EQk`ZuwD{Zih6aUjFBcy0I?F zdzYH89G21Cm6V~RXrpbK%WPkzp{tXE&6{~9*=yE%w4C&F77h4n&=y~|Hk z|Ev|r{I9u#m8pf^S6SfgvF~cJhrWw8^wJ9S-5T?BrYy^NYjnO0SIxE)I8?XPz15`d+a2y9+<_H=NyEQ? za$aCZT&e$ingjhnflVTNj&&^9L41z_{<-`Yj9rS0?4!*7)|RYfeM$ z>+W{OzcPM-vGBQJ>2OH~lkIX2wYj`9p~vp$#6XV&&TFMdlAh4(gJavJ_x3*QbAs$GtdJgo-{Fd2G^Z z{`SwYM2)Va;`qC#o=kqJJ!l0>o9|kEmt}C)`fYa4ss1TR6nJ!oQReBB8}Oa_gMT4c z;(g-NwcN5#*R0;C-51{(s8^WL4Och!x;>u#d`>SVbj$pc-~Y6(;i>X z<0QcgFXvDFYtN`xt<8-8Xg_zu^9Vk(uO8Ys~`Dwd}=j+JPoi!l48 zY*A^)EOHd#p;vhth840t>5ZhDHGD0SfVvZPhujgHYFS+&f2i#~;V}!y!h@1nR5J}7 zm+oY!g*w*8)18HEQMA0QP>yP$d&Fe|l{5nyn5wNhg>b_={>MLqKx-YS1aa;7;cPCKd0K5)}Gn}1J!)3HN=@TPQH;dIb zy>46j4sMoZJ07KEw0rK4KbN05E$cc`P*KC!>9?0R|wGqRN;BdRYX$M zdj)pJtI*H!=kb+Dtxz%ak!SCLG8=asaUmB*gGARwU$ZEe?YiwtL+*>p4}Ox@d6(6jjNgwF}(Yjb-~sDmhz z`~GQ`mmzo$VT$z$@3ip>k^Q%Q9%nobUnbp-Vh@l0cg%qSadiXmk`Qq>`Yb*xWRA-) z%Iq(^dHAZ)zH{-Qxi&;qjEZt&An!M^D$>Jqc$QFjLtDQ zaGN<$ahs#m%pAB;QPG^`AXk=Fn%f+pxJPJKR%$qM#ue4$PTpnG^Tn z^ZR_yxvt;2&iVgu9N-ogTo>E|-n^cVSD=Y{C-0}?P+At6P%dQnwm?(t4As^jXqJ{f zTyyExt)C~dPahjikZV>4+8&vtK(OHJmU2Kg=%Ujk`{42d|)Bo!R~vDQ*0*|+U>qEk%n;&idP(KE*NlpbExKY z1C7du-7b0aP}vs-3Mx8p%<+Bn-R*3HoOHtt8vG{--INfTZXr6{^_4xMr3>mkU-?6H zL4LMb73UxPfMa~Y@^L_KEl+mct~D~iGUCP9avf(_?`yL+gD+-|)kle)`X-$G>&g7( z`s%Har`1c#~IpLeHS?nx13GB9)Eg38jqe9lPG{+O(X01!^0UBO!`d(x)U`QAN^0r3VtZ~y$6;}9iltI@Nk9@f?$R7A=Wo~iCeq!%z z$+xRbzheWAco03IH@2VNS1yi)QfKy_ZS4ux?eUoCt2OM(JzU)yaU5&6y^~;0wB@vx zVB2q&x3VUz{Q2{&f6VqY9Gc3!P%*E{fe1SXYiexT8r6tztL?(ND`8Se@p<1a+l+d0EJXEl{z`=5olkcg<4t0!*m2v%-68Ys-p{n_2w zHtN{h+}VCVzWV3gu}=g2P=0lV+TF=!)w+8QoR7A5-$B#DkI6RfokT*kTlV_jzem^Z zR@cxwstgsI_F`Jcq#F0`r6?SXz+Sz49_=N6wt5J5d+f@mz0;4Dz~#)aF6Pb%1kt#s z)wm0*-j#Z~r`WnD_;gRaX-}(~xpT0dnvRxlUg!=-Yc&r>chfXlXe%wf{5~_kDOm1? zL8(#YA7g4-)coI0{Fcge?mTRH9Iar5#?s|Mb<9x;y=yeIYe;!>Y=&005Lt)irqPaH zS=n44b!jQM_i2!-L6_=4EiKd(waPEm1k&EoSV}#62R3~M8@@tEH!nb{7iK2hxO?d= zgg!5hA+>`2t*za)zvJOotD0_izf>O9M* zXKC~-ZvTLF`+wx;1vUOJ{QPm?-kJ3O&d)bpdeh4A{8CHoOc%3yTJyEZ|8uo_##%r> zG-$lB(CS&;_>0K3#qqvp^^>njU=DG7OT$!WDxZ=^|G)fv{gRR473b&tFS3~_aO6Bs zuuO)yb!+p_&y^B=!hl4^Y~Nj>JRspbxPVJQtJC`Zi+}lfDQ7s$4MwiY+Xr=Qe20Lf%^lm1 zCZ>P}YEd*K$$65Dkga4Sa886y8XQ3jIXl-{Hv`4Mel6{xT;U5-wh$D-4!j)8;^)1_ zokh{NmXqO7P*jdxbdUp9EM0r9G8cG3gGe)xT$G=oT36+_1CE9JvSoS*gK`9fSZjT= zv|7z)Zn-!?a5oIh_vYR<3ND zFIH8S~tcO>A?%c5_k$X9!tzpg%5 zXRiIBLxciX{$Kg|wE^8N7C(=LAN$|=`OgG%7C-Oce0gKo<--5s=Y?dAM}6+-O>+4C z%g--weh=#Tho6`8$8m+t*G70o{P~xk=f0&60jg_Qqg%_kIuKh*^&LF;#<8v`a6GbkoK&mK^DDf zj*qFSoE&UMj7OT7Pd9c~X*S7B9zhjMu31i*nZ|QeynnFF{O5ZHi(9=)!K8>oG{fK< z^rn!`sw|EHTy(gLvP57c%xJwl$m7U_Q92@x-UE>MM2@GCZ#PqVRi57l@#ZzEsg?NH zQqU-sE(+Km2UH691a>kzFDd3?EM?F7;>6;MIR65nPAJQi8Z-iAM>Y(aMM2-K-DQrk z3H_cw%(=f@DG z#OU&duzNZDH8ixJ_Ro*FQz-GE%909R1w&Gb2!D`68B;#ZGAkLD&)s+T^%R{W82xDt zs)2dq_6I4#^2%U59UMm*ttkz8To6e^Wmw0j z9u$KDnU|A5>_atrgVdq4!Ok3Y{|7o>FQ%fGRAKT6@}><*Nh0+; z)L&bHZIF=o(hC4@J9@>ii{PBkoPKE%RUb2}8Khohk$6%r?lH6$S92< z5OKiUQ-n3rVY$~K-oWG%!kI`FUlJ1VNAs_R$v z36c%5k~eNj{w3a&;KdGUZi7ZlK>LU<+Wl_E8 z>kp+GUT0}u8u?SC)~2|7xcRJa?)rku^!KSG z4$X%`wLvO2x*>%Vp%oi1>vJW#ZoU>gRrYczBzf>oka9sG_?*k-P&i%!hcjd!X}Dy0 zI&I?Qhqv#~)Lk1hEfB}FDBTIB+ughFLkAkWNyOEiYC=Myirj+upvTXr4VM0fDMWXw zZ=Jf8;JnCpurn|E=!OcUeWbAav}MeM6MxK*G}|-8x=AEoUFS@Q+#j8eZ|`_w8Cdo_ z?V?$pAJ-Clx6yut%O)rx>?sa+bXndd>*M;vEnhSR^(w`AD@8+2eO8@6s5InS$%)F< zc!3!V*k3^Ma>UNqvtw2Le>!^oEh_L>MK$-{Ye~tRJc&k#X%=9YvZq711K*@TY(6{(c)E$ zV_zi0_9<&6v&C9>TUoU$k!3&{s!e0l>CUFkAmXyXh|^Wgxd`Ql~8as06=(#N0-EI zV#=mO$F>Ua1Q3nb|2nf)SV*G4%W^y%4--I#JeKbT_-<2x!VO6px4eaE?B5>7Cc@pX zqV?4qK#VU*zI0x4B@de^P@M!2ULnAPjSsQ5R~e`ZCQ`DJ_;}DGx5b)`2$S~bRVQQw z^{OfPAS;=^DmZYWpbV24ia;}7Lg zj~hT<^E{7NqJ&W(dm@!5hkP0V5xxaFC4(9m0v4b%d3ivln|!_~@WV(TavS;M3)qGR zYT3NZDvs%E*)hU#YY6Je!>M!-PeOn^YP}%|{P+wTl#ica)z?oJ^-#kSJ|6x+K()b$JZU~TX zbV;K&N#Jj{EH7&2sTzXJd=dOnRJ8YvQ^99x&p^HnsYp9LG6Iafg|c$tk#caBBwFhS zpZ#V`VE=n#2y!Djil1k_~#09DuX}N{IaY3l(vs0UvBaV8N+b3ABqM+O2s&)AlH%J&#*w@zi-m&1~ z(~?PtD2vZR+S<2~8wo_n<6G!pV4n#xZ4i9A7uB(i)J4JVDyZ6usCs_NAr+JaD1-jZ zr-wuw(o1->0tA4iP|2_WS_#Gwd!!eoOL)i=T$&l_IbyJ^mDmwMAv#ju)cWr50QrMt7E#^c2!#5T zD~Bg(QO>5HU3qpIoaCnrBhKn4F5XNsv}|p$Rto~*(?d>gX=fzUG^efsU9-SE*mV?# zmtau$0y3=ucxrX4VgDlqo;&tN>QOWlq3U?A^=gMSyr2) z*0zy#u6&}XoI56L+9dE|qS)|wZ%6W?5YP0;#Y=~+A@sAg zZ@0sB?g$~QgqF9FvlS>X3cTk7Yf5`~I0)wrJL|fFT=g;X8U%{cK%r;(w20Pv)ayp~ zQKzUNF}hvT4xbrXU*|1vKBK5a0OE=TH3~I709`Vezx3D3h>d>pR}!LtfLEtGRBt0O zXuGZSlX^YCYGKg(utt?&(C{=sh>l}RMxCNlMX{C*EqnpDKxzTJ=PUF?2Z62x@Kugy z8s2^z#gUTOsxR6Z?6&|WBuM=3bAbTVNH6SM2G9?6SA`5K-?7VnQ4LX#f1~l-uOa-@ zV6r|B$I)%xSRyQsiV&r-3p1XU?c!3c&PYqnl z_$l@>m35^5u!{J41m&WTWCJLlUU$r-%ma_hK5SBL(h5+a6rh5&BPyC?f+H~1RoSho z13obSpn%hMchf}QjXb^L`Yak6TqQW`no z=XXZMd3ulhdKYizhiW(Cc{>CvTVnb+PF_{JP;>gb(Y-U5YVdE*&ilgD--DAOz^!QM z`O-eoft0f)f;~oIZh_;n1B<$HW`p3An@ILK`Y+uNTt9HK%|{0K!FqshP12i4s}F!I zw2APOM_onQ1ei?d6X46iH9P!P6X+C)U5O4=BpP7|;MD#>kz*1Qmyl*FcB<<}m2Dp} zv0`s9whC0_fb%Ei_h?Njq7rQ+M1D01z!9QiY1s2^ya?^ocG$%9el`$Ap~1QWIUQ2@xvw>){N`U*in|l@L+($#spU#Kz>M3~^ zdyi(j3;r&DH!_Agq2wvOKbr3@AP`{@^(DBMT`zN3`_BG*xM7H6bHRh~ezxFC_gcRl zGeMQU=iz{byivRwa@un+vr?v_Z(Xyg)AHHc@Re$@_upU_2kr(5%-2_)_wCucn_`TWM84l*kjTen!Vj7@{g^uJsDeyY(auJY546LcHK>xSkGEA*rmGh?{hQLk(@#Jb z`cRzW0b#n2OxbwcVg8jtu}}9y~f0S#Ly-qwb&rQViG zVkH6b;ESPyqi;{*sg8+71)zgug8^nx-;7oXYX_F1+$UPuKGcDLKfxl@QIA(hO%zz4 z0P8eI31uw&yjF`St{qbhn-rxK_Uwu0H1aX4%ksw^%t4z&6E?Efk0^ejFVsiZ% zj0_7zL(Hr^)El6}RD=jtpKv=wz4md4rX$o2kE;Lu?NbBW--gg9U0|M-rVM=#s|UIt zAKyRih|T~%rXr%SMfRtS$N0)z={UxQjS?E-M|gh38YPd0wKYN61`Vp=;Pi$}NDdN5 z$DIys2jvWlH5ho&zaZ6}05Yi4p$5%(;CdO4F(wca{Jie5!4C&88`bST^rI=aI0_ezHIjPX@II8 z%J&erImz36E(>LPz1hMFg+GU|;doN5^ThGdpnA@es;(zfo~Um}?JKDW3bttN0xUTU zC_(8rjcs93x?ZX58*uzTMmHgB)_7jJzwK!BMIH|sp zx{ghd<MB+}Qt_pDzvBvpO97Tq$f)klT&QEmbk(6=T16#AVvk zBVJU#3y~Ab_%eFU77|WcofNr_iJEaapA4=Rr4$(O_ew(h*TCczu~9<_-+nPKYwpGb z>vR;?@?#$6jrZ7l2S;cvclwF=B<|?m_NV=s(m=jVds=3#rhW!F@y^b5i;j4Elo2N{ z!7!P;+lGPL!;bx1(b+_+6=y-x*RVF{LYdTnJDnuSAy(DSK zslrP`D>yiza})J1^_o90!3oonzly$7)luu@55XVr(^$i6e0B)2*7~k{Mpo53sxt9p zj3o(yi94E_$nB&iPd<)V{PbEpnoj3DlzV65JxFF&XVcmc>C?3MmJ_8n;&~-8o$>F4 zgJ=SbJ@a(Ct@X<)cI0%KKK&57EtC`YUP(LUlA?67aH@Pmisq|Dpui_1DS3#khm>Th zh(=}r!2QIp1Q5G!<`m^?bm$W>KaphX${ub>x5cQCuF!0uVaIaB9pt^C#0bpEI)PLM zBSAcp#dgIyA*51))Q2fW%J86fl5(RVYeWj4Q{?&Nqv6c+snX%Kr(njt#Z)?#m{=^p z`xcm`PYp}8Rms76am}tyqk-Zx>*^oXgXwB1d?G&rp6*e<|9nu7TggB>$R4#-!4OVq zrRry@^=0Z_V*sTc8mHGE94f;;FHL_6%Mzm#++*x?@KCNWdMQkSqYw?pAAZIYiaj5o@pUEkV|U?d8~ zMgGX}j2uf=kJ6N$_X7e)1+hB>r3;77=p8b_Fbz_1Jbq5H zfq6deQ(IeMMEO7!JJ9{Be6*kzt@HX z!8rqD4G|CUjo`%iOhm*{Zy(zgG@zbKz0DR7=<5*Rw2*{{~F|EtL-l> z))}E#ntFpF8D)7V0W$O$d>;!oCy-M67y$V7bVGLiPj{hoMq+Z`LnMDYFqXe0@RVA@ zO|8Sfa0wa!z%6Nb^MGJ@od!(#s?1(6;Ei~{XU7vJl_pHG@6tJF7srj}{EW^6sW6E^ zeWq~|bp_6!+9;g_;P_nzQ;gAuL|ydpHx}C=q?$RDz?;n35!Fb(LOC7*MRpy{6+5oM z4DmI8L@>J%Tf(4{phA%4(A+7t6K}}yU`BDA&*}rJ5067~-$%C*KZ;1dcd4d}q=(Bj zrhMU}xW=|pwbiWMx~p9&HNYj zdCx<*3eZWFF5q*^AHlRbAXl&e$RW_%fUO#Y0F+WtHY+er`Cc8*=}a#B1>Qq(LWz;W zUZvH-V`*uVDT%XUK1dDXXm1=PgHPu2MeFNlhsvFv(27%d*SwD3eE(Sj9-H>FC6y9C zrDeSybf1@F@hQ1~QNj-kHq-OAjh^x4YYO|W|1?#sZ+)aF{43<@_(;k0V0c>n$FJ@t zj-S=XeIHG0-Yralsihus_J>l*0y-WLA6{iti? zTS!+hu;FUd=?@S0GVtdd{pz|SH`I2oUa*$gQ>!=XejHDg72;Qp ziaK`R!26s~VN18OtVR5=pU@c4wNszFK4fc;ag0}|E%McB)LNj>gxS4!YT2e4CCLzx z?;&kF*rYs*CjQuL!$!9Ir~hhEgQG77R@T zf-EXC%aso4dB3#BJS5R2=e*N%H}MA{G`RbMv7F8ku1#d2!ygDY-SCJXrE?IoDsdqe zq1aDC93?BnS-ds>`0^mEA;o>k+u7P)ZRoLlupzWb(vVA;^PctFqb}eNnJ-pGP(~0k z*fGP3OFJc?5$>^)C>JwDE=q9eD!Di1-Bw`@uJI4)b{COLb!L~jll>;LH+ep0Uhgn! zP*q#O)1v*B*MJBw>rmYby@gfWMyXTi`N2QwnQAeA2IoDtUd$iH{z;jSa3I;K8V%L? z?n&K^Cy*d(`6)wZOTID|PipKu@i300lDJp&RQyMSGNk@oUrG6gpEtN@L{0MM>N=VI z1CUzgd3TMI;VfYRfR8e?qH9PHi9@*LD4>DgztsCumM$XUh=KuxMaH>dVN0A5A_ytc z1Kl8WKl28eDUhs|D9x^L9RQLdy&_jC)nP#=7_={`V7KQFU~Yzjfrdi;dNyk*1&J8; z-nJJFDK2Wf&x7vN?WX8_lFs-kokF|Ig91BSkg|ig9D1MgL>kJ)7|CZEJ)R~RQQ1y% zJgB~RU$YWO-KkVGNvt`C;-XcVv;eBTxuRE;D{mSdY6Tjfj4_V5uhur2`Ru$_15Uj) z(O7THSbwRrKIHMA04?p$$bdd$16>wdZDQ(na;7ok{UgpJ=T7|jE`>N}V%27X?>AA) zIAPp;{B&uT&5((msHwfO=^0&92fV4Ho2gTvsdJ2}OQxx7f$7;A({pX6ZvCe2W2PQU zrk;DIL{78wqGn#oX5PAHK6o=4|6jQ4>XU6F^|kNk18;at}(yfW**aT9y?|pw`3l_XHH@b!HVJ% zlyQl=I0_z@RWkrl-Wu|3Sfn{}#<)b#sntsdLvH!)-TRj%FYE-sr(zR;FTRm~JdKzf;EXJxO z)9QJFRcnpai#Dsaeyf*bRKI9?Js{}24U9iN^ZzxDs*=VR@Jv+Rx({!f1X zy`9*&o%phy#QuNyd8uRe(t7q7YkQgh@bmWaS@sHr_KLOt^7Hn`#_d&>?N$Hf=f%z( zKX&GX-Wd(+Gl!b)|KaDgv(B6#sw(Q|aLc69uQpLcYQb#%#cbp3~) zcl26aATH-%G3RT?oI~`SL#>^|+?~TOJ4eJiM`k%k6*@=PI$wY39P=LM zw+xS?J0j40ewS~0a=C<^8HqV&fM{Tih(Rq#5H&R51Q3cN@*Ro@r>40-i_;s0j#Wrq zBE`|jQi?a_0AMZhXnf0PXaI?<=8^?{4Fx2naJdrDH{t#rT4aC(8ju&Jd21hj`|{Th zO5{SZR9+hS1ZyG`@a;Zpvf?aB;|LIpc76EJqWp4dkXxWoO~1L#=$FL>KVBl$AIEs0Vb_T+V#+lQkr3D#DG|_wLJX@40k8$<%s5 zM?N1LZ*X%TiFF^%a{pTB{;k&i`%Cw+_wM84?i0)7htr|%ld+W+sXgbR6AWK@4x0J2 zo`=RgVC2l$tnb8e5%7Nz-{V^nXwh_%wc;mr z2L2${b1e)p;QneUV?7D9DU-TC?70!vo9XU4nD4f*@pW0o^B32Ip39`VKXHE_ zzGyuOOYTjpog4s+Z@(e#4o@)lNgJk~P=6v!JQ3vtfJWkSmxpf(xOpW_#LdDDQ4}~~ zs(Y5f@FgKrNv6yc*2w6o(L_lX2x=EMxycArL1!!#i<4E05Crp0llx40Qsas9sE&Q6cWxi9+znB7i(PF)nfjM3`cI z?6L`S$p?WA(coBz^XEr6;~D_6h^bSlKZLZ13B(`5f)IlK1VZ~O$RBtT=9i~8^-&m% zL{R{PJ=B+OeRM}dCJ-qOHp?e_CQWY%P^415IDU__X#;G2!!4M;IGZf>RFcK0V=M%0 zI>AYdCHYT)p{b-p5EE`lns#@mAoJ&rJe{A|2gt4@$`TV~0YE+RRHQ5y?`^PUU2j}I znN2(u(*nEZ$q@UCG{ej=F!g7%)blucw& zf>2U|UOxDE3z_8MzclW7urYbxWEw=g#Fov7CrqC5Pf(uwIkr5B+`M!cOT51~tb8RQ zlY6Q$nNj|G4qoa1B<@SUDc2^~65Wqj7cShAZ7%zY%tjr zeP<7+3Q48}UsgpuxqbPE?3L&8zmr|u)Xpq_pL5Ih`0{SkLoE^@Smy$3y7EgL(UAmD zYgi7hnU9XU5}NgU)%S{eBIV=36>#_Eh+$}75@hS?7&H0LR?(ld7RMcs|fTo1(Rn2sMDP{x^c91i=g-E`$}Wh9J(Xi5y>6I46UUe}Yhx zK~RZc9@Svp!ys$SH61}jlRGDIn+^~U%*$ai)*Qe+#tUE|- zI680G)u*_wgt{7R*j8+~)`z*h4s(AN=J8>}V=~MW8BTm1rrbg~qV^|TbaKPv>Ys{5Mrfcb{ajWFjgn-24=&3+pJ$cSKxh-<15AqHE)Jqd(-a`H=aUwDXb zieq0=_{FXD$jX%KAGVZQwqkp>;%=mzP1$gq4|j>!xb!E2G9Qry4~zQ%B}6a}l}M3k z@sa7ak;$(kGd?hrzC>nDM&9@nX|EbS|E4Em^2@uYjuw#=*-@ZP{08d@K{p~}DmERi zZa5u=lOJr`q-@*VfEV>dv-6JK$({0w@Cvz|a@*+YicMSR zts}jEV%z@u)jRgZQv9!O$InOIy%9+|j3U%;2Y!fp`fM}v*_NkV80pT&^EvK{{+Vl+OwI3>2UXaCS`VXLq{ z_5m{HO9XTLWRh(?7)B%^gh5RYqAHM)DG|}-<~z*>dtGup=YG#{cK==W^*NUWX}GX$ zH^2V{&Z6Fd)~OUp1k`$gqN4_l@~7wkwwO0IVjd**A(PAoA@=gD*8#r|PmOlIHk=Xh zFuPp`@@pu-U+qh$5_o#J>clUv&O{W4Q=7f&ovuWdA+P?h%1#Alp^F!`zv@(|^!J(q z|7Ziv{JxIww}L2W-$T%0^8byWuij@~9^a|=d|kiyDh_(|Y30{uVpHSgUz^9qTCUB1 zstwpunP`jNT3!CNrRu5nDR*gM=1_gYnhY^MPGq!aK{>8`Q$uK$W!+0u4;Vf^YxkqV zrl6jL%Pq5!PveK?9yhi8(Wi6=9~OP=ez@G2^EJ=AGWUlbj+H@1qPapM9juF%{Y;&s(o`|z%}z_Yeo69b2#b_7D4Y1fl}&;Q7*;T_@a=`^n4=CSif zh7-jTVt2MLxVwMsK^o*DR_Wk`%v%!nJGD^xvK&htg@?D!Mk|yDv2`=7r+>PBkh!Nu z_UAdK?MH?i_XEkJt60p2zyc)T-N%4E~ z^Wv7{OO_RvH6|ic$doq%KYgRsI)J=b|F}KT=uV`nezZiX@6S7G-A4l2)O*CP7bswE zs4>5KrM`Fgq*SVZxB>>taRZHjNbIK@7`}cZ)8ai{HA4;oksUfFeNopCA~O!|;L0Vv zxdE>ytssi`us_vlibp{03U%5_Z!88AsQp0mj0jhWI&Z!IFY}$qV!XM)JY) zV_ux>qsA`=as`{U*%M`TCE3qZb_le}_(;Df0H zD?AarM{_(Dk^@LtVeceP@j0L%=eq^!pRyK@*D8WAeyDVWE<++Cm7WoP!PJ1nV}>Rs z0njT*(B3p)?j8Wc&gg=Zi0}qR4`hpj6e$*1L;5$G=K+11V#J1i|x~qif+aH)E1i~e+6+SBPCQ*)>*U^ zjSYDUm7uGhx+s{~;&6N&OPYSi37axR>5}xNn@8o3R)5U8)?6x{mBC?sM=p^HcesbW z2QPy_T{MCa&|WY3d{nQ*XmwbJG8R$?=*E01;k(}2!FT>~qK-015KRMNDDOzI9w*9E zzsatIe=$9td;)aZ9|)ue!9eSY08>T^@ZdZNF!Goy7lGAd_#c+XfEpcn&~NxM&?c}Y znmbhBhOwn(QBquU{o+)*OJffNnt7gEeHTs?^DRF5`$9-utg?@^lB-~H4clp#@+lug zwOK>0W5$Xx00We=JxfP+u8l(?HBA^(>+IM3jep59($k5>>}QDL%3d(NMJPbffKk-8 z5}6jLl5jubG+p{&3V!9F6mf_G0yu-X5F{gB8i^Ekk-*wD69V^}J zQ(z38dYjN5cH_mb*FlZKWK>}8&6o9V%HNQtZ5BZP4 z#NsNQh>-w?Lj>%y86XluYd2s`J)u2qcn_%*F$A`U`+XBP9w9P*0PkHJNo3DODSko; zXqXM0R4@9Wl-Q|!Ya90ih!;)=g;%#X`uB#jtj+$s^$5dV7<~wJ3>poECUq$3o=x~VsqWfE)F)0b2aWY)PBEP;&gAs(Knfq(x3T= z3yJ4LLjv_l*HWVegHW1IbEtG}syQ z9}?mIB<>}Wxjk_z2lbW>b1ZfKvUJj+L@S`Lzp?kN9`-z^MZ?sm7$G1uZx>8|B>Zgp z*q^A+rxk8A)Yt~+4z^|cB+KZ0ycOLnMbXN)1>biR5Mhj?tput;fh! z?)KU?U*1#;P*H}Cf?pI9e#Zy7FU}Sj^SzVW{L1&5*=;`i(pqlni4`?L+!beSW6t~2 z86qv4kygl_Ae`?2N#?(M-K<4A#}zXptC7}&_dgCf)q;he00E8m5uV#a!MPwj_e#)*S?v)} zI1L_0?7?LvV1WE>;}vCMQN0w~nS>}86LZFcgJIUPjxN)fWUMa4kVIMRqI?tR+I|DW zp(&fzUFI_#sC-d7w?lC*Wl3P=XA~M{y-;`+QM^4)F``OXyBS?*F1#>9S&T8UsLBQ< zpqIIl(3~hRLtKu_hz|nr%8?Z9E*6!=7h@B6l{>gsQXx4*#w&OIetL3tqo%4KfRLYET+x$~s}RW!>J;(2*Pe;k9;x;rFQ#A8 zkw5*Hi}~V{>@nqZ#Q~{fBPC=K(3;E0A7g&aKP7xcN)0w0!a2Rb<9%5hejGHd3X?t| zF0HEKePYBcNE@!8M(1$>$#W)gyBGMfVWZ$u-q6!!7@W}jFD`ak&2I@Rs!}n36Mz_ zf^>+vkY$*3c&4cF6^wcMSULvCrOWy=fme62R9;iC?QWT69meV@6hk7Pw&_4J$r7Ro z))O;QV`VnKF}9m!wg(u(4<7=zjP>mVabeasZ7f)n#JxZViW*t3`q*&GIR2h-5buz} z038khkjflbk-bIrjOmd#E>Fu`i)7AuR=8MlMZ*|!hfCuBV4X3x#Z zcrMNox_s?M+wF#YJz4y`h%B{=$FA4wY$Fxy#m^Y^_O_Ar9g&hzY$wRi*(pn2a60VZ zjh?%pGDQF!$>D)sD3ZMtE^9vs@K2Dv^wjS{w`@Ss9KiuJcURVK)bG-7*{hp={sVqj z4-);jO%ABw%S> zc?i+ZZBMR*e&OY~xx9sJqFE)S9EEqPO!AP&+f*i7zMI1?B*)38CRe5o6vr}pQj6r% z%PZ5h-%=2qTWC9>5eJ8zEERFSb* zHXrG;*p8qCa(EbzeWuUF)s&d7lqCNwQ}sCukN%R|)m24`35FmblZ0fx;c^}7+ykrx z66{44t0xre<}Mi*wj)N#rH%8Sumf;WLk`-xXc5J##p-|fc`vH{K))yH{Rlrf{w=T` zE!QX;&~!!VS@^H(GZ!6&0l=|APYtJdff0!CXmk-q_F>htS4wT&hXHQQi*_0$Odg$& zKM9Dva7OrR{b~}z{XM3a43Y;NaRFpqVbEG0wQ1FK>erkBV8K`=JG}BMEz2_+qzAVj zxh_@RjisIs{!noDO|d+Cr;+lza^)_N(KWmNu5u7S6iO3JI-T&yoy66$VGJY?ArvuJ zLjQ}s+i_LO9|bRWc1RDtnh7$ZzZOrr4eBQO+H#;q4A%2U^5q3E?V>T*)~8h;hS4GGi{)bN(+D$65v%Qi{iRj|nI@2r!oqZ2ACEN(^rO^j$di)cRD zPYT1lThXdt)42-1E&oDab;C(@*~_ND>(}^M)va*VHXZ*?^!#SD>h|qFPgSgmKff^V zsqQ|#TBUeFPrq(=Ky|-pQRc~f|49A8@A~Ty$bUlR|Bs3p0$^3l{{+tSkYk_}#uHdX z_e#X|7^$ON`Y8j7A>EC~cd-s;^iyL-5kuuE2uH(hVWdpy2= z``&RMZf0eseiV-BI9aE~IZ(;*kOI9I0lRZIKc(?IzHq|Rl1+~ES*~%)pKqhQf!dLUS*w* zy~4@8{qHL9?Cle|J365zA+^7A{UPNWduwzK4JBB#Kg7w&!6dG%ow*mROyL1XHzj(E)b*>5M_$s&vT`JZAlhhuY@my1fddwM4Y2q(HIT z#Hf7iX-B_K>t39nvQGUjh*!Dw-I$jXL70T33^~ zkW3n=ZqZ*P?H#OS6NoF?+M*sdX+ZNL0hN^WUi0iPM)DB(@oyF z=u6SL>jwK-I($oSWpbHpwelcdTU<+np*1MdrQ4NE6m1RU%*6JOU?x^^1q)b)Afcv9 znY)r^(ki?-HrO4B_G`lyY0+~BXq;N|11&3=B3Ml0pnq!td#keFabkC_8mm@jHOs7u znN=&Za%NV-{7=`+3Yic7>6%%kGpl80rTmCPz#*F`u7TE`h~QIn>uo6ROhHLo7T_M2 zyvYzgacQjgacR#Dv~jwqMPu39oAPI>-QG4n?7O4peO6hrsr>zY?U2Q>w@nov9$*vM z#VngEKb9J)qut;A?-ld-yC;vn)c?1Nx$kN1_h&)V@BaTQX08gOPjizn@*U}biT>wJ z^B-t0xTikNK`QtvjURcuZ+-IXOT)=Ig~wAGi+qnmeog#SF*gc8ijI>Ff0}X}y`p4Z zxczKx9?yrV>@}hVFN`+zaUI+czVSmiXY%kMWw+}o-}@(zJS8*@!!}o@GiI}AcQ>-1 zeeRq5@StM%000vfh&am$6gSet;Oyc+TEY^%zAer$RbPi@5*AEgCB?nk3sWg}3YA1d zc!K|rI9zJG5r`u%=goDwZu#kRQrWm4nc5vE3#CqNE|j|H@t5I~4FvCwCz*&;&Eyj7 z7;wWooJ7z~hu^n*47MDrW^e1wlG~F&k~uPWd~RQyyK5jQ_r|~^J8kZMP`85I^*6Uz zhaHh~RTl!_tYIQR>dq^y-<>=wYX49HB+p@huK{E`S5>`cAim9Jp6)A zC)5;r5rXuh(gi6d^iBXpni`6Tpfmxg5}FhdLa%D5BA}umT@46IHz3jkjEH~~4M=ZU z{_oj)_TJsS=iPJmoSgZR%zVjYW-{|UzbDV5Af4HkLou#`d{4HjQY3=@6stw253`mw zEG<>5yE1@7ye!g$IK#${s^#ZxMOcQj%zxeinB?jI?-p|`JOwMARkPkZUQPlr%YT$t_Khsk`a7V$ zQ1d@6X3Z`jfU3`Xm`gR3dbTlaUKfNoZ^7!(eV$97eO=q0*E{HH#R|Ax%+~ke%TZ9M zXz*1cA9`zo_iOAX_6liWYbsFl8e)XeefjKVr+P-+ov$H`Q#&-B2|w8P+h5G_y@_&K z6o9e1Xgmz^of_g4iHu|akt-mxB1h+w7v%<9U`bOxp*J@yeCAoAF+E;}94mL(aHd?vT78Hr>pT6D>-=y)1 zv~a#d1ioR}8rMsk`QG?q^-uoaP0D#hQG43n?}bmRfAszs=(4DgfqZQg#2GH#D0q== zh8no;p1I6PuwM*wHDH3^m2I9*@NkEM3AU1iBv`{?}YJH z^==6SNF)j&&%_Z0U_TJjN+3(as9XmM4&M(*gi*nk(5;15equGPTa-C zMdBf>T#xd)DAdwGu!F1a%37KY#4zP@3M&_xWJuv+eGuayqE~B-(x^BSc`K_|;O`=j z)@+*c9rxn_`2lH~E$nF#aV&zI%{jV9Kki~=Mls)QjL+Q_kIc{)7dzY2V;Q!dNoFgT zHZtk8DOk^{G%uIE)YEI%vYuU=QZ9epq|b43J*TO^{Pdk>d9(HP+?90+g#?r5S5bfS za%0@|C^Xb*PyKus2a)q}N&Q~W=RgGK?!Wl;YCAsVlLEvJwOdM-X?&S5z2bzgy}KE{ zFmn)S2&hM?Y zW-zW3DDq({8YdB~9;?9V!>FCo;r>N0}kkjR7gKnsbv^8|Q?I7T0W zF&4&2(1~(f{S^>Z*@%iJ9+QY-X%n^{?L6Y=cw+*T6ZI6Q1V1i|)nm|p(;fCzMD{Hg z7Q1Op zmbnYe2J&xN%+iM#0+5E3iv!nX&=W~QIBw`=^ zAsT@3;lyFW1RuzC&93ZjtV#^{G@WS3g=8bpjPm4W?e7I1j|2(%gH54AnJ!oZ57fbS znb?bOriRizJ6>VOy{?^lX4SXEDz0tn^5LpQT?+jB$AmE{3!js5!k^;`gal{RQb>-O z2cFQxRU8FsG}ne43d&hkOpBe;8#}QR)J7ZOd&IiJuv>1 z_N`NwoT6Z7#oukdAqDHTr%4RW=~hOf8!b3LfUKLo&JUpO@s>^RUXUVa-K8%tFOQ3_t{oc_G6?*3Hm+`Y~OLqm8d*4Y)X4EU! zTISLAhcjq*Qe$ z28Nf7bA1O3XAo>3O#KEiO~daz^y(1d+7p|XGS*>ng+$cH)osQ{EZFF<;8{+(+uZNG zp@X{wwGJ^G4PgQ*gE26DL#|_~Ic(eBm8h*ofm|kB6lpiS&x=}mkNBI7%D`xzArpCk z+H$B%uyzFOqRwTqCrDlK5+3eC0-Yy-1eK6hBavF|@T^7`S+XOSD2Sa5^oMbw=`e<$ zraLB-!v%!KfCxd5>r`mK7|NqAj_ajmYy&b0e=6mJ2B+U)D9<* zv>5cOBz&-xzpO_{>`z^=IzUyOkYECbk&5)`X$$Py^9H%$mxtt1OadHq=U?OplC9naGa;p7+H>& zH-OK_>l9=dsxC(=i<_h4Ojok9k1aALxu)GJ0 zo@g{aP7N5(+}dyYH`W&Mu0y*1Ng_eBBhZcN!%uMsEK|m zpLM!KJJZQ8&C#->ZP$6 zKT2IHz(MV%ld|zH6Us6l$w6kZ49#U;!~64Ow65ndMFXAY*_Sp@ zKx1UXSb?G6ec7OhBrNg)@@@nUp{3!EyAy5$^v>+zEHx_NNcVa5ArG4wEWYTP#-(oc z6WO~J5IZ$QOO~8{?N)F+9ndXln~{J)n6{=3DMJan9MX^yVWW;(=gA zuQV0yk-#j@Xyd;(P75d8U~`E*Axa)LK*G)$f>2@aZ}4`lgD&$Czr^F9Lr`&rLUVt) zmt&lS+QJk5>WvwZ(WTcps1JBTCD-qTqZJ>CSDHBJ@$Bi}wtIqP$ngAeaK8!5c8t!^ z`|gfj!^P8}5|Yqp1&QjA5`PA=Pg78 z4zXmpmB4T?7kq_1&WpiNV6spICtk~720~-H3{;3rMr2?)g-ML>NkB*0P(?{l0U3^} zWdB%l+a(z`lmm1>)F-C;ID^5+x)hA|TUf&x*Hna-11tWaI0~^1# zR{2|5#omA{w|3s=E0b+Yb!zK%;#Kbp+^&Cg^7?C4QIjl9TYjTAg{>$;byk$)8-${X zIK#+aOY!k=Yg>QJV|(|!$4qZUrMSm~t@`!D+_H4eoV{rq=Cz^F#EbLsFRgPD^>;HX z{8s-4tcU=%p>K}7c@pMReC_Rzlh4>+>V$#YC%$riFbU9kYO(Y_)FIYmj}osi?(dnN zb)M;_#6Ci~no}((YDN=znXa|t2eU@nZ7fl~qLX3%k8C8bx7y{|evgTiL0R4Q!N9zs z?$1ON0Gpl>qz&#K9@Ni3$SW`89ou%8OBdW)_0qvZ0)+`rabd!Ou6VuwHd~H9hh%pu z=9T4c1hqq>!KFW6Z7_RYp)e8ef%g=`)v53jxdQ(0EGo6&TSaZM#l?qT3OIm84Gc6& zzyN7`;BQWVl*@4f`a*t?B@KfY@fR$HXb96b_g#eSq#)TS#F=Xb( zHk1hgA9B&zte+D@t`R5$-et@1=n8yBymlcGX)uAjP6xYC0f*<1BDG-XDtbH_i6%1b zP(1Xoxa!S;&$H0@No3+ui(PwVYD=nJ`K9AaM>zucsviX72QXxiL1!dBs9<~fa3C*A ze^s8=o)c%_7l1kmbcO^vcfuy@XICdPiX{j#VvdvnfVyRo97OO!1X`*Ri6%fc@Nf}8 zu^!;&LzdxBB~{S&D%u>^i*u;Y2Z-VBVD%t?njb)x&>N4<1}hreY#ik9KL^5TP(}gy z$SAgAHR|0$|P~)Od z(n9|%H|KC2Lu;pv|t?Qnn~>TV=gQx%GxpD8)`e1oS(J3Fce z3{5LaW%&**J`6_qJKlMgAuMWJqAlyOQC&`d_MLI=`A-(ql}*rX1@H@PE<6z-RfF0u zaBXyhS<^l`aF4K|VCN`}X6@c;7@$A)8{8jqY3J+bZYY3meVx?KY@K!SGIIF=(gXuS zV+YQJ7BCO7oY(}Mq<-bcu}nOZYdS>i$|Cm#hS;N-@M;o_7A}y}WAW$#29@QC-_Vl- z#HRFD*68C2``>}Ajla|(Xm@QJKY-RgLXI>7OMiMru#RI*-G=b8=QC9Dq5lrW+>$26 zC;H<=stnrfrQIpi70iuI<8%D`okFcBFvPpz2jJQuYKD!|hi8J|XZ>po%1bQfCBd)P z7N4gew5}j;lYu`A--Dt@>rK4z3J60+E!dg{i1R@mJ^Yyy^U7YYo|CE5O7z(&C-knQ zvANN&IMizweXbDG(mQcy-?RQ2a`pFJcxURq#3CBeJyDk_h=z>`K;mxQy33h+Z|Ntx z%}f*JAZGsLE!xryO>3WhPaB1%0Cjm-8}S`@aw58VYfI9~AS^m-~s& zyY1DiW&xw5ES4$GB<6|tmaA`E8*Gw8@O7bhG4F#>nu~YU%A;woLgXz?3Ky@iS*`B8L95fX z8YF<4-ApDw0og((qKtJYuqlSIk7oC?KEBmbhJ=dKVKQXcc|V8?0RkYWZV=|aX|5_n zwI+C5+1H>7S)gb-=*E}7>U1hQGNp0h*J1v~nQu*Jtl>S^z!>UZ&=9nJ6J&#g`YTv- z$aOd~wtViwtkWvE>cJ^=FfQl##}a8y_%X!1P5guwrvoIq`q1uRWhCr}Ba5NPPU<@} z3*I&4^;PyEC}6=8frXu^1yda1?0x|Iot=_1oO8+=%7j_#d-pwaZkAIZY5?ZvKcEl% z03I~m(y0AY-vKRF>_ImxnO}N$DIwGWFg&>c&Ny!4tT(+o5C{IyW?E%IwFQ7(J#L@P z>pK{K@hi0M))j`J?}x1A36Udd7s_9fiMi>!AE%F&-f_Cm-A;}Bvn;|`KhM~>%Giox z>^x@dy<;34-!ViW84wO}dnyeV$IN}&{U3`t5hY<+W5{>0*t;YoDK!UzRV`x^$&VIE}72)Zh5>{My&iRi`HZpM&L2W4|xAg>L@-`E~5i zRmw5xB3ueo)nOITGn{~L?><+V>0jLToQZcQ}@{h6Qsy6sDAk4H#d zncDH6>&ZTIeP(L+_To^v)srjJdqFD`uYDJ0ruXmAzjvicU7a}y-T3w8#r1D9hv7SG zKR-RW`t2z4V0ZJ+!nbdXC;*tt4+~;dp<^MO7yNKA!9Y3=E|%q|%OY1#*JV>4@zdkb z+@R|r^|<`?(Pk=Z`dqdb{0(@V0@n=q+_L-)1-$Fm425ow_!|j_Z>$+%Vz~m0Pu^Eq zHx|#l5MUx%7`SdCU78hODqCH@ZYp0l5@2?^bz|M^|FD0; z@F)yAMr}*8gB`u9UvD|ytost|dFC`;K!!pX#=A;OC2XE(d=N+P)m}Bm2&k zu;tg=S0es?xpVdI{^s^oBA6$H5W}jr^It6HoDkP!xrQCr6y?znw^Yro9XFC5PpEr_ zncA*z6S5#YWk5A?$cuZ z_2c8{t)W(*w~8q))~E|?f3BUtkrl}ukU#WH_JgOJIIr`E@eI4g$eraz z#@&OzV^L8@``gERAPi3gixYtCAy|kcKAP2?06wvUg&X2yILipoQz1Au4}7fP9D%{4 zy@NyE!^esBkLVn^=%OF7a*7%kw_r#KJkPy>d5PbfNkkNvA>f`TKTh}+AyFWh83eW` z8kjdBFh`|{*O_s`_QVbhiwr1Gx_w7FBZ1#0?w%1>H+o=L&p=!;8D~o5?8U!LhGWH$ z6s)7LB2i16kh0hdVqfS!6}2J;5`{-|{~3QKmb{ksz2qB)J=9oV(kA`BySvzlU1MWI zn~cmdcZpM>CgvXK=y2>~N$p(|JjX5e8}Mr~7NMpW=JkDz`rTyjyt)@n8OHr_`ial5 zKi1Q1d_!+a@Lty7bYO93Z+Au>3c0|g_aKSR=JN)@zYzNR7*HbR>vREQ*DSy0JM1hC z5PKln9aW2gG+p?K4M}?6w)a{k(8M;lE@4fFX0*%)Ov>oUKZ#;>eP0Mj+5~LY8NE-vHFkgb}dpZ zqrq_XlX?bAXplTm+DF}mUEMF1PlB^RrwM1|P43HWfBuPhG7)uZ!|jAPY& z6{6u}M6&dX*G!u!k3?Ly1}Frg#M~QGaTD|sJ+ypYOCg#eGX;RTOnWIaO^&|v=_+CH zE&KBjha7$EWWWSbeNe$!J$(YR!uY(YoKs)lmTKL#rwjfV0zC9wc|Es-#K{0mte}1l z_y!$ovgt8C?i$?S#9xs>+apDm0iUFI{Ssa;n2J6d%NCVX|>7w&pwf_6N0h#V3EA zkDx@$2*s4QLY892V$G-Yk3(!&A`@EPiS_Y9VbibW8LFV`A3~Fw$d*L%*HY_g@v$!7 zwbGO;h12|LOTM`Siq4c@C080YniI@Dj=wd2v3&;lBWkjciH`!5vyVP$eb+RrJOVAZ zAJo$|;>0eEO5*FpD!IAX8NT2!JK;SM*)Vg|zRvOQv6Pc))R`+ZtDL!0C6G!~m2hW#?q zHa$!W!;8YwDaM6eZHsr2;$JEaH)W+SXKJ5uG-*xoz1SG0YxgKGw)i)I+wd~d=|{7$ z;v$xbicQDkfjm`52?dwd((cyoieyz9Nw+;*b+8rXs(YLCwDh5uy~@*^rLqc@C%em{ z_etZ#QPrx|DG%Po_LDAmq1;OJG&YKEKjQ;O*ZFawdDStoX$E%Z*>&{1ud?&Bbk+;s zue*Z~5%C#5akawbX_VY;GMv$klPW9vZEsWpwzgB2nCV~Fm-70&;sXT6VIUZQ)A;+G z`hv7uq`bbYlZKv7ZPdc}+GB(} zH&hA^F3~}TY~2zkaj`Pyz}UpX=O|2Bl!jhLG#tnf1NrUf3*e&? zYM zT4o+^8ZoOcl=En4> zJSgZs(aF)V5>;?^@HX7;82+GXFLB02EjF5B5;@>d5QfM`C&G6c*KOe-JRFioG_H(| zJ2teiZP8e5S-et$eax|8$bml_q6b*&kmFWXZ zX%kywo78ZAono92j-5ufkje+O`bqS-Xu|80iZ6S0D^wEYms-FnnrGh5Hk;HXdS)gz z)x~fm#+{W@&(2g*)r9-&L2snA9_%w^-v?gs#HG~6Tq=#p7Ws8T$;414t@+tj#yZajV7MbFdn-Ue&F5Zv!bW&E+Y*Gl)}`_SM~%8!jk!UtDa+bB6l7PxPs- z3rjS~Fi(6aj*f!YM#nGCrz1WW3?-OxC=t@q-xAN~dFzP((}Nr?`WRMx#XH=MKwizQ;=`%%dCW zC+c(sw0fDt`poy4=xq0wk1b}EOw4C(Q8Q6v?@#qaz#pO5qm99{#W*9u|6(y)PFTXq z5u47;A+N-`G<(HuTJ!OS^AUJ@A~lOTuy*5R+eE%9q2-p9LsC2+K)W7{-Qv&)v7IVKTXlB+KB1_!}lh=L(8s1XfRwuN3f39?hO z9tT&gYP&c7Ig?P`yVt`Ef8L`6FKv5i7N0Jmi|utwGFtrHiioWVo&PpEzNlKzPJpO*kQJ$nJN2T><4 zhFPGl%3j*;8M6x*i6TZvCCY;U+Wdm!nxPdALY_d5S_p{pMK^m~T|?%}UjT%7$x_U}>LhD!g2Qi22FPy^R6WSAk+F1@dD8ty-4obxn5572P_FR0-?pS=nk^PrL z2|Kk&+fhN$u{<(`2>ACX8u%X+4Sh`E3_@f;2^Ydsh+hu6yWRxc4tzDaJv2NZB>+F0 z{RQokLZh7O`MwK-z-MOXN`4;@6H{a&`zkWDI-WYNzvdr%iGDP;uT-+|Jc&iWYIV=f zJfz`gfDI(KWd@$I{h>eZ{o#pIyNOxjX#m}y*!FqeJFB%HW@IK@^Hk6izBDzd2l zl`L1^_CalJo$1WMP>Z>{8FXxPME>-t3mF}>E{kieYb}2dT5{mSmoLS7KzP~VwRsXe zPj?H$VRo93pDTZ~^^M$m4n)h=^Lw@+vKLIxLOL8T*wp=@|NhOP<9wXVIF5jvB+ZZS z9*{yf;=8sk>chKU=+~?tsQMRdjhg>GJTT52tax63;S^-;9X#~i=8ygxSD!Ebc*{!f zWh41Pe;yueZv6Fd6c-HXsBdi(Abyu&f^gRzz>0UZjvrK?kZ*bpYvi zCH{QhxMjbi7+s+R`CP)5(=nBikrmOm?Nhap_PAzmSl}37V|%(!8rk3b4ACQx?Dj%s zUmU3MK-e;-RGSZuD;UAO8{mrlqhY98&5~dLo`3t+sj7Wg&B5N@f$+0~W036Ji@npY z4wS04ecvt~?H#CB?QRW1f16P-iAFuI38P4c#Z( z=)-Z+Y8}|E9jg5E#kZ9!2M3F@Hi^mfqHfBHGbt-D27`7V+2|b)qto6dcJleCAGbD~ zbqKG}Z4K`SI)ctplaw&mSExH-ukp9334m|7mR;BWlOd zjsGtcjYWw5DYpOrf}$B`%KkePjjVW7uKoXxqKTP3GH-tMvoBBiKTtHi{|IW>{s)TY z)+hX+xO?SmQ~OVFrgp~DBcVlA7?nh(!p5#O}l zc_1$o!4R<$mbw#-9uzUReXG4P^ZQ5NcK*@T!`&Sht52WaG0fx{bOJF7lF?vy9Mssc zhM*4IC`8DKN?KgHiShS%KAp}-@%+a@jRcGmj~<%_AO4}EXhr30viz*7tD{(h^p6yk zQO_R_j)NLMQnj`gf23hyGIJz-o*Q%N#*)VTl|~89SiG*|>fy;o!5; zC;f#StT2|r88~F#cV}?e;$K0H#yf*wE?(DO`m#U_wA6A;IJI>g)VQ@Z;rYJ>HO6jj zPlqf#+n$No{#Q`r%ytkh?kYcGJYI_9nn;@T@0|oS8i{Chjdrl}^C6Ty$cj~E?W0)X z)zQuNs5UHh5qu)x^nA@vzge+Nk&1g9oI^8s;o>yGR_qC(ET-X_I*C`^=c9@5%|ts5 zwDjJ**Q9Z_OI1bxLal0{5WgLT539WL6gIYKB0;(cWRr)<&LXSC?s;Y!Nsq1J@hEWP z*Vvg0!n3EN1mFUs;O@_B-474fRaFjAWudk}AUs$qOIYi>KBAbPMe?ue^ULi1;3-}% zmJ%?;vK-;OW5k<08=qiK7s2NV(NF%Zzr6tr;-BJ$v6i${5r0d22N;X&ku~@}&=W*| z39vD)H}MPFV-iqnqR8Al3{Yt;DSB6!>&fC{9b|g4{mnG4+~Mds;D-eJzHV+8r4RB- zRsIZVHz$sEL#e$vWE%FzdB57XZ|nVU$G-0t9a&V>5Ef7Kh#O&s1n9Q((?r(9k_Gs7 z>Pl)z(Xtb?^OlP^MIV%8PSczjn$(Tey#X9)%?C12z5AgxOxgNLy#C00oD$efevO&! z0(ypZn3DB5^+y3%dU!cTEWo#+zuN zOzEJN6p_Z=7|xKt63UAUI(_ zw+(D`R!jTw4PuW}FE|0f1KKl-I zS8vg=CF?JAAjX6Lvex3cGioIZSM^xk?BWV?AscBJY9`MhAiw1)an(73{r=U%u8)z; zBnjm?FJoD=++Edmk?gE|WA>OB<~B~**@CIzkMA^VyL^3xP$wvT6)SU7;omims`=aOL8;j@Xo^qG5Z;L!0 zNY>2`8^j*C!Dv}NHL%>Ty>T?C*8mH`{liFATt={eo-?zBpY>*oX)XEb3p?qs><_5# zA_7gi2o*m^;SFFEWb4dK0dgjlMuGgg#=;Rog9_Gi%SkQ*Hjn5DDD>QW^h_bIY(I+U zOgWnXpUfral`jx z34)quiX-Hd7^rDC&HXc;7MpcX4tY;`VnU@C#a}m`$YnYd58Lx{8C{l^CoYZgfIMEEHmf+X1C<{`zYaKn6FRT zCQpFC3rFPXl-lukJ*s*jos6rDuiqH7r^81tTdI1wzgsW@yme)tPDJ}nNd-T<)5cWd z{s-?|-TEb|X8*qWU7~}tgLXSBJt;s!_4z!*xF(iGcQM_pYtZtn@zd=0>K;bZm<4d} zApSB*D@2)Nqg5%uicBpL`{nG+bPK27_shhRykc(h?6ZSr2eZ(a`Z@9`qsTj0ReM`W znTIV{!dW9O^J1_zU2=fjW>aVOw2^km-x8)Vj%_m>Mvi#9u-AyhZ6ZWz(960gK`t07L{vi({j!lu2j>3myD9V< zXgPtCl?qlSoo}c=<`dvKSj{uGs0FdRr@BQfU}$BMxsBnqA44IRF*bKAI3ER{#$%n> zqd^M<<~1TnnF>5Xy^2KX4(7&X>w5fnsRtgqep8*x;iC^%`bEz~Io}+n4JpBpd+PaF z2{J(AGuyi0O9|D(*MFoNEvY4@*x^D95@i_yo}lju?!}&~xP;5!bqQknsm7vNImp9? zByt|Q@E-CJETA|fSrX?3_xA!9dsXfvi>`UWQQo!o_hnqXLDAj~P4^{+yia!Cr|_ZQ zkJ`7}r<_Q?`5`Z*w<)E6JY{evh06C}SpC6>{e#hv2jh7UCYv5ijX#*#c|hY!omEer zvrnB5NnOlKU1~~Q8BhJalS=1HTUSrpuut0xN!!Uw+iOZY7*9LeNdxecKpG^70|^#N zg6ET1nn`REB#vDYl0O}-km!B@soGvtxF1(wL;mou47w zoFPAvae6mHfj?78BU8m8Q!O;}c%Ve)x#mo*iA*qO zM3&`l7M?%bMkD)zL$+OLwtarKV{^9iMD~^4Yyy9dt45ByLykvij%R+3S98wIi5#EZ z96$ct0FB&0huq-M+>rd-u;$!|iQK!pxkUcF7>&F*hrD~Cd5QUX$<28w6M3n-c_jY) z42}FOhy0w-{Ji}9g6909iTp>q`DFfr5{-f~hk}aGg3A1Ys^)^4iGt_51-1NzuQUql z9SR#l3!Cx_Tbc{oCJNu~7E<_&Iy8zp9g04L7Io(r^)?svPZSOA7E$>h4r@Fdad~Wj^Mn=i6%-4! z6bnrj3-1+U!XAN$sPnbR2ellc$>Q52lw3iH^>7I#M%5Bb-UvMn93oExTD0gfrcb+W2vR6(J zsBmSGgC2veH1HXJ!~+FRH-QrxwE$rXK)xNIumnCoUZJd8D%T6Rll(+J00JH=iClW} zvK=r^a(?2EfYO~48K#wnLvR8fpgR0n|uVx2TWnK$K_yKhRuw`ORuS`wHlAMYo*ar)fz<>k8 zo{gUqdEkfOq5viEAP3}&;({U}>~jgi^JN-Df&w(d0_6%`^yEVs#M(CjH4gx_?lc&L zQ2R%gM*;a_)}QB80dR8(riyvV`Bj*08N$GWz)rP;EJd4>a`}5N_8mbHSSYl*NEcgW z3W7;7`nZd$Dz=f(Q>{=P(o&K7b4Vto&TP^LMbK_wo6p zav2MS&;c8!AUVRbFvr(6n%u&DJWw;J4hHN>0yHDQVlXMY$J?hm+Y;9z7eEzdnGW=`F7)wJ^VdGqSQ?yw#MzlWLrP=R( zvp{ik93BCoP01PZtMYByjx-kL|yhlgeQ+T)G^lr=h-4Ox4Tlj8I^WDMMcSmOL7@8E2 zGX)qy0TfXnDHPTk3T*1#zSBEKA%#n;oizexNCvd^zLgq+bNK;r800=4v9Hh}d9y=2 zr9;BJW0Tq;+uw0U=)Hp0dnM=hDiQD1ir$}1LCQJ5mz95COoN*#9QTjfCH)b3bi@)C zzC}PB(mL@6oi;*U7qq%8BD(C^x-1Slog%uNYq|&rU9Kx#?o(YJLLaWBe7LUl!L6vv z{-BFc)MX_E@udRtYTp_jptk)W!4$Z;Jo6!j`4<5Z>)ai86Om0s95RTAY-~5Nru+U> zcar>ZW}JBo)18yjlUu}*-``U>)k8k$DXHlxTj?nm>V2ZsTcOou)7G6T)U!qD&aLUr z!1uhU>3M1XksSc5u99kY%E_X_BifkasNJzb-Q8^6X)B$5Y<&$veHJMQ>PoMr{D6g4 z_gF;N_%X;cH86EB@KtDVQfqKVe(u&~05&1eQ`?B266i#GVnnz8u9!FfVo{DZMeMLk3;oCrYt@&hvY9Y>VL z?`e;RMo!oWeab%Qe04BraR8HNhY|2ncfKA!@dHioJyXzZ@ymyH3Uwjgj2@E4G;5i{ z{D3`&u>4x^y;^YLo5|`o@Qhk`oc0*b4;D^`-Di--?jvX79!v+Z!^dyUj69gRdxCkM zK23Wt!|`yunjIehW-@VgX4PWC(wRB6mPr!{;l_f2Gzc#p7XJobd^kRTYbIKrIh#6o zN&b`5)R)(hUz-jav0>4^T-j#R+ph6SALH)lN4$?{-< zZMsv=0@x7w-Pa5VbOKotUtrC06&c!}ZQ6z`+29_QfU8(28wJ7uz>@u7!L@ZbB;*$j zz9Bd5OPbmU2k6#<X1;4CGL~PbF zrPMOr^Mh&9Vb`$;O$yNC2v#e+eD={)r_YK90q%fhR>dMJ9VUx9+=W2uHo(C|`n#<32P9uD4nZ&Wb1To;d6ec+&fENo` zra&UFV4NQiNP+;d;0gf z;lY44aV*$`L4v5@fxJ{^&(la1%(@943a2B?XiR6U{_^61BoaJWfqBskd>6n3>4R|9 zLY-(3etI=Sf%$mFBm#t+Fz+C;1_VGzc%W6=Z(;WD8MNO#I#N;vbr)#0NT)U*nW;F1 zF6q^-O#)n;2EK{~9?vq#_XBo?jb0!y&Evt?eW)b{451^AFNmSE#$`H`;RhhmVfP4- zU-xT*iS2BFy6YzZLP&trQsV>4_A>rVG6klCh3>GxvVMbGaZGS*Eof-_B7jMb^jd`l zCP)I}?=$Pt5praJ47uI=+%5zU498c6C9fKMLtOjT_1PEUi>*9U@Zfva_3CKhRv10);)E!kSjKs0&gati7AkCF9rj4E- zQ(+gp+-ZMbw3Fi?lGZzy-X~^;n-@`cx8o@=C}XGAg>D7xKEsG35kFvog{gu{3cDFl zYj#=4ahb`8979UscZWORF!3>2{Gh;oz}(|rdAZ*P&G_PsH+Q$5o4%5gsn!n1&ENsx z`CtDHigqj9cUqgWU8yc(?aCZavHDYP(LeUzplFX@*Cimws~y_|x+XsjJp#xbo!VmH zVq+f$K~`23E<_vhuw1pPFQ&wG0QH!T6s`TDhYAgFC%<3lEY{@_Fto$JjC5%xv1bXa zRL=gmnj@>5@`TU<(H@$QK`Kx-fL4P1yhZp~<;r_$r+f;R9ldgp_ps|B9l0Y@JcG z&||w)_pvApsX+tqH`Kbd!eabpA4~T;#N30~kp{}t;G|VzB!}msh}c%8)H#Nia#@Bf z2bF_OV6X`b{GmpbGDY|I>E4S&DhiTzVb@Q z+PQcRdCT^w)UQvX&!}OD%%U9Q?HpjaZrO*=Tb4e`v1!V)8Xu!*K`%P-H;J(w4fO9X zK7gE7?EVvqrqS0?f2l5+XY}sOcPCvPB z+9LtXjZ5ukOe5W9*hg$Bhc7CXC3@1<&9dfW>3D8O+AKQy$%M6+=SlZh-Y3G6K% z|AC^NyCG_&{L1)6jp}R-gYDczYRriWXHizPmjYj!fVpWjAZS$sgOZH!n+56bF}o%_ z@xsTIBpg|L{^otKqehT~9}nS#?eT2fR}?sOc^1S%!~uBtY6nscOGx5iS(S`-=2+X1 zJKl{@h>99l`%g$sDp-EBVoKocWx?A5fus#8VmMCqkS-#D?ns^D%Z zE8YCDMmZ<>B%D7LdEk4JQAll?q;UwIV8Os_jP!_6lH;2Nj zDCt?YNt64GUdK)DFSJ-aMek|4xqY43fq^1}aLk9$iEJ0nc)rgVV!jokCp3>w(Cjq7 zVfmhWl&~l}ufSB8LP!u7FXnWrq;SaA#_K{T@VCsw6Q1P66)FI3SlM|}+#0ApE{d{U zVZsy`#aJGrD&|^lqDLrzfQn*@ihU=PD?PF5CNMSF93m8<2bL)#-1T+=@NvKa0?rut z?fQ?<26CeI?{t`34MmVhG}6Wsp*Q&Tk#AqUx-_8|r0^GsuyBx@c}6|6j0XTC6yEbc zw8^O}yLReUbA81%X}L=#?5~~O;Dq0}b6c2Bjx9psi99!^>*KMCg`r3zKuqEeZ9sU2 z0f2{xppd@cd5$HQv|H=2eBW-!UT`hk+o3LRK;^w~%`VIcf@8aZBx;Rm%NYc9G2{s+69wY5ufLsi=*p+b9sW+>Xu> zl(=DH5oVJW{2{?g*(m+(x)OH8O(eCF3B%*Ufz9(LXAqx=&CqRi4>q0{W$2sVHr2l^ zfAUFOE7Jpe4L4gkhc=Iw4J z+di2edAjK->-4fE&0wbjXzka1UKVL_^5LMdPyhs)itoshY)~Q&eRS2|8)w+d+P%sw zzj^KKq{@v`B^P^dbH7f_x^UYV^fcY`mj$oCBb$V3;e0m)r5tE`(u?P*F}J9VFAGnR z>ECB{L8}(ZE@~)BXU*}XW&sXL(wB9+*N-pWvf%}$<*eO9jqN0y-zqLJt*us11hq8mr0y1gP$f(7`V??(4`fu(~}7ywG9oH(?&_&0-Xao z7I8Rxh{5>&Y-`?GdxZ-B2e%^Jkl)!jjo`Tvf7B^ zKh2%5s$kc?R56^5biIrPUfJLR(SX2Mnrz9N$%~iHpBt?U)-PSQUe0IP8{Lxq^>8;u z?&8w#vGl9<6VymI~l%MAx z!1QA{#w7CA&1Sg8tXON3 z{@GC{=ahXl`flA_PjA#(IK80JeS3z344&r9GzJ2+=!gNF8-O1W#-p{yoZr|sXT#e( z=|P}{>( zAinpK(>k!`#%blw`1ZKZIuo5F?N6RM_~(D_b7d0c?DJ;Zxs^wydj8vPYr@grXIJe$?GQiqTdmA~2Fd^aS5PBrH=O;=^t1N| z%h#j!rx|xkqeYJXK8ZS9jfyHP7Gdl!L@^E-jMpLR03j?$9t(DU%YR$`hb9*GKlpn0 zaHjvj|NFi3=CnD)oQIVWLTDo9m^n2?&V42-i9$p%Ol0y8qjM`(xK$uU&gTo{xt=2@y#;0ulIeS?yaaiNB2`FhJ_# zOGj;_?MVg~5_JV-OhnX7L_^YYFzkX^S=3IYI)ToQi9JB!h}M`$w{buov>2oTpE-Y# zzRVd15{DYAN&sn5Au!?r84uHa{-(e8w~2ZwG$h{@Ej5uv6&8g9Lby0VrpcGfrkVm~ zTJcZCJklR~3p5gA+d7PRZYD<0k$co50dNVJTGy`CW@b2GcKSP@XIOYx=C)usO{6l` zf7r}yH>ffH2pyhkq$af|_7*9gvs93gY5iYNqo&4UCu!9{3YEvE%oaeHX4VZIw*Lk- zx@4qimUt;qy6|11lWRq-1aJR>QL5(+( zfVXgZ432(!L-Md~_q2oMxqpKi-P}#UNZ`p6nq@$FwrDAEN`-D%)iKd)dFj8P#%WM~ zuuQg-8(o!Fy0q1ilKWp!V& zM{;$K-p>Bf&u10d<#+Ga?dLZ% zG`P{aq?$Q@CZT+gqNRJOu`G-7j}`o8Bz$RQB`7F(x*qO$0CAKE53q)f)S!B2e`Cc3 zpFMy6=PhEgRbJiuV50+^o{$oC8s>DFX%W{MS^b_WA>>=TI?J*8{2cL$ec?mYB^Il0 zmaV3Sf;BZYiWL4Zltyg6v0r|nT^P6j$G3ImnBk*j@~7>cT|X2wWi!kH_PmULV_2*2queM*9O%PgZ;Q)bR*@IQ+-vuNS3o zF(duG%F6W+s7T_MT^m&LVKu0NQiLn?Nlt3q$j;73RFXIJcYYox`dngS!uF_Yw!KYn zm8hSe{|M{mMlXD}4J{`xA%N!3t9tt9t@=(Mbh%GKoIbHMn!PX-lywFMrT^TS8rvDg z{{Fq~d{iy?-HyHxOn?6Yw6ZNC>-T7FjitNO?Ig_cdXFhi>%&s-mi&V-I7~`ib+S>- zCYLkYtw%i}si~<06;Zq3c?famx8KVh^&|Sbq>HMW`rofpll^Yd4U=VsjBov_^fT(a z8mZQy&)+6bt-UssVoYh^m6yl4s@6VmFm!upPj{$rm$bFiz`4IQRTZ&{ zI^c?JNY2s$RZS=oTd2dPb(i$7k;>Of_N^PvSSKeokY;qa$-yOO*}aU|8M&plU1sR8 z99y#!J#hv3S%B_B5iD%ooA^2MAyoTU$T-?(jcWjbG{VgDkt8cQAdIB?@5DLNCs zYo`K(cO6*&3ZZr-P#PL);LIIx*$y~!W7iU;p{)ik+W>?AvqZiA*BL^;5e`WozF3Q_76{F;qw}>h4`A--1co@H{ zi*jzoOa6c8qI`!_G>(qw^f#QhE4M!u+jcytSk@Nm;3=tDVm|s%(kWSXzusNGymOrD zgn}y%hU+i>k1k5OFQ@B8^TYSgFa7#vw;W1p4@JSsj<=94isEZMK=371`=WlP!^zh> z;q{+hDyzrIc}hH57$`q+|EHvWaQ*B1-Y1?3Yz3d2Xd%BpIgSynCbp?Pdm;F0&(jkd zi%$*q7PNf-B%6CX*8XX$!^e%9o|AuTpMi6NG~FQd-ticLlfJXzKZKK}gS+>H z&nAVdFpnqV-X(bWXI%~D?vZ}2TpEZSekBt#xbTY`EO#X=HK}~HcO+=<m^u~Pl~}L_GYH+@0R(zAd~Q%WXFDsQh(>lndvaB{%1_Wf~0e~*%$6FZYI9=M!EHY zvnuy2P7a+{4l#UJ_34&W@d*C*u1xgieoxEpf6P|?c$fH9Nf3JOaM=jxrdLVUM(S`?lEcqGCC%!yK~81MyG%HM$<^beZSLoVT&qdJ7y>> zuLZD_Z5;<8q6Z|Ky=5vXrd`I0G}APND;_tdHNOOIXYJ1?a`-^=BI|JkIgdG9_2Yka zQ3~P(Q^uf?x3hu$CaHIB^ER(e-TnivGR5$U7S3HptRcR%3mmGs=Q2gUio)^CsX@^0 z$&wf6yG@eUjA1*XG)WMY!4=A{)3<%ziv4y>`8)|QkvhNgy+a|Nd99+u@Yl*CyRFc~ zz$?W+evM}$d$MiKa`sd<>^Bggf%$j?ZUrMde`|ic_7FYCN-G76m~=_Fufz)W-_jO{ zDJwCx=nK4Q8z68cx&DKuL81+90JFpEI0S{VXHA}8y%MlFYjiujzX>BMXOPs4)-J{kugb`O}@9Qi!!~w-V$?O&nKwMC(BOj>7Z$`H7Mwp z5Tu`|5!Q>2;0=bE#@!kE{cYe&Rjj<@A?_InL14xjL*UNz1If12Y=cDTFin1RI~&7S zcE~4s5h4@ZHF_^zo2G^mZtDnf(R;}IyA$EV^vO;!6BE&H0^b;fYDt1r8|lepEdP_2#$JzoUTllI=m&v*$z)fn(wQBcRd}1TFk#!-(sP0ZCI#} zBB$isXML{|6msH@lxS=q@^Cj-ZWnvt3vi7+kDpI}G{xCtkIXg;so0N_Bw?7E9irC~ z0w1JT==_@RjqfxOa{$aHno_i6Jhb&|NfKgrHg{#ziXdHUaronL3!ydt!u53JV?#t! zebxCOQ4;8&Qy>p%QWOa2kly3oY@!o4O|nLoy~pObG~H(pL3>@!VrnViT4Lg%i5x{GUsG7CmXK5zEKt`7Fl~*Fz5z|Wg6cu zJAJYFg(nNM>YxWeu^yyTq)`RFe4=Nt547?J6hf?)~Ju{CVVX#8WCk)Rz?(x+v^tU zDws{Mud{0n9i(0_5mK$Zxqm&8Dxq*(JBebV>T9wKuYa?>+iITRv>qq#!GXwyXT;gp z%Fr#i?HuU4K zYKwv%$o36;O)9oK{&ON$ir}9&ka>l9!e}|4%TnJmbN`R2w&9i;%u`Eh$zuoc-C# zvi?4%;1gu0)k#SYZpATVU}ul&u2 zeIG@?BEnkCl(saZzh!*MT-bkmt0F7<d zz$7Y2gA~o9f>d_Jh6?mW1XOVyzA6EbsqnM77|1wAp;CC;nYJ%HmQWcslaEQI!pXQp z66ta=i@#Ze^szmhnPjoa0s!NFbc!(~}1Z$K; z^SIH5<8)&t&9WuIV?1H=3Jp<-G{r_AB*fXfL@y}Qm%>1oSaC9y@$Ww+1QU}&u)b76 zB8iF7Wnct|aUUfTVhD5@8eJ+pVZA3dl$o5`lH3YQ^x`dI$dm;Ab+`mO-Yz-ud@o3x z1-&qyXh=Ae+?!lROf4tctp+ApRVHM+BwSiY3u5W#2+1-GkP`!BNd?`UkCv@OqO=n4 z?i#$X>Dvd<_ZE})2m^<$Qb-iF&q>iT46q~{y`zbe#397liPD7he;J+1!vr zNa5~7srAf{Z!j{87%Tm}e;FN=cqcJdqBLEFn$dto#ZjRr^fUfaGSHi7eVq12Wx_xI zF*-)WLTi+~nVy{Ql}R7RX)3#Na~9zi>G~};bafLQM@TWm#)tpM=Zp>E)crw4Gj#+2?x@|pdPZI zmNY~*1GJb=H(+Ack7jpnX6)T6++}o5xn|Fgr)pz!vNch+xCondbQEy?;Q0(el|%Bp zD*mL=V}gQGxzdia(V%#aU8S5;%_YgDX4%?ZYGLVAy;Whv&>t&jL!7t?NWkv z(-vCGiXKHP!QeYf@D? ze%Hd57^vR`GTh?#=b;e&QUTXwrSFyQ`c>s_)rhcrf?k>0i!dGw+O7#9va5C|Y4KNY zmn_j;eXCnr?{9w0zeY@{B{I>y=vyrQJFXcvnn=;=LTM(HOhUFvJs45-)n3YV=uaAI zf!cjWw^MI7Fz=k5IG*#VwfuC! z!|*FKrR0j3iRh2a=!EmoT5E;_06|KE;+XV_-iJ1P(OW=Wsb1nUw}d9wl;ccrk#z=* zi)dF7*gu)lL#`X%D4%Xd=P+P7I23QD{u%Hnhl}25E;`0rN(RQ$c+IhAtYg63XGiJT+k_ za7{5KXjlH|H3sZjUsDevdiqn^U%yBB*L=@y)Mt$q zfZAtJPbE=>43I`iO092E>|5)i-GFzF7l5Y0m+iW=mD*@^xwab(PsH7+_rvKi=YnwPv0wEs>ww!u8D zd6g~X%77HHKw$vblnqEw;oGeIEnMpwg@1^bbf;ojsO%=J`(|kqf8q)Q-N+Vt`6SX+ z6WtNh;8%5A)X*9{DhXnVEcnq?L1vs(*Is+E^qFGP@;03A(30vozf{WHc zp0u{k<*2A#VhGtBUETcdSIqlQ4?WjGVWbXGTQI*SEQg)8%7E<~K&i+en=U-*+Ke)I z!C~Ko>EZx>TDt@T`u#%dbW+lvl=^Eak3zT0QBwy^dvAS`VDPxec50aoki{YCVVbaQ zOz+M%I$%A7hYLN{3<==EwYX5@{m+ohXL4%oLHE1no^;;}k35w6WQz)%9TMBcyP*SW}V7n&8P zdM!LU^_O}cYd5%kreChA6Y>JVWawv@VDFA0Z?Px58KE@5IzVrrV*q})rkA?hp#B8? z<0kA`3HlEg?Q4_%dxk$olRsu1@r>H{eb*B(!+-4lZh9T&NgE!S60+Y9EoA^n3_ySe z%F(RbGs~}qimgj&1|5{zRhfrePoXN25~FF)RQY zfSfLZZoNSpy=^*uVffgS{5tm+LO~6`+cf1<{dV-xLuSbYi^vZy$ zvOF_T;Mosm3nk2?1TdjZ%R+~l5Ca#;*_nsrKoFP>2;cyH5^`Gk?G_c@q@SW+f{b5> zYp+l4wq0CF$R@V9r3nQeQW=KNmN->1Q4N z`CMXV)OCj7oV-rkiYBZi1c?=gD6fN_W3*vZAZ!28kj%5JsRSfke z&1>UOM`k{{42@(=K}|J@Zn7Pa2BfZZGf`?mjtdXM@Zl){mbZ@fmhH%og~YRvMCyb? zn2G}q$e|6w0kH7EB8t6>9t*{=5c%2z$HG*+NyxQ8bbKKA9FC*4gSH!py0-}72bNFF zG^?#?5S|D(Rpl*yivQ_9_gKi3myf=#{^6y}>m#g{6}C|0jF5aFeOMM+wREOpV zBbQmA6&&iK(W+n`tdR@t^n8sfS=i(*5RVW!{zya<;!$8h)MR8#$zVVU|KL;L0&C?0 zZCYwv2pKbW`_8K`8bAz%|5^Gge_FpBW37ls8`Q?UcW_?9QTQ4egAObqN`60E4e~XD zMh3t{53Z7ql;gl9mScZu0Rq(2oYGC*ApgwVMV*BJnh;ZuG&z>b_aBn$DJSr0gi z^spPy<`!v%V|g=x{5mM4_*DS=*H#Idhk-Z`PIyxI=f`Mc88N?UXd}`TC;%x(`m8G7%a%ciw*8K{4NYNmmTu_Z_FhWk zLg={FCltTA+9!F^aN}3K4ugvAGFClxGX>y>%AVreg3ak~-9l}s(@3xN z3Y(0E(${qpENWbmUXW>a@9;wV9c;2iqnA?odYK&V+U#@-E{S30;+?ltX9b@l2An#p zBK_*eh4KGCUDSa+1zM1UJvZ}JJa!&2+D$i>`~F|LD5K^lS69E;c`;@fNjJm4CT4yu zJ^4V2_xftMG%_x|a!Tn=lBm^qW&UX@n}kA)lYC2b3EEtSp2+x29Gc{7)~IKt$(AKo z0Hyb2|4smLD)^LDu-@Okl!LbkQ(h2!E3ThVKDkcI)$j}A+t2c=s?M*xrnMlymycqa zl5c(f)7`qiL5SOGlQuNLqIxwgkg}djd2xy+SF^OHb+bc)oP+G7gC{#@#PLIcb!LnB z&vSS61YFORYlvr;Ct`y)fW#QhO>-Ep|F90NSWR_l;r1!3@Ty|v!AJkAiyCwkrW8a} zCGJ!{nrU76OICm#`yXA@Yde)e#oHE>uYwV`!k6wEUHNwYTpXX7gY`h=VZ+iS7^Y(+ z?%+`JEL`ow_@hMgcY%~+-T2R?oc$KRxy5Snq$Ldhla`~x6NbnIc|DQ!>idRaRx<*S z^~d)Zq+AgoUoE=9xjJPsBC9=(g!>R{dJS_@*t(}|w0Iwud#TurG=fsf>cw1ns%0<~ zTf9-fSek?no-u`M$B&=v;m4o9mv;7h3nWiBzy^eWHDCr^B(3y>f3$-U@$*P@#SE8~8hl&fz+JP4h`T5zcmlx; zC?+;gaH-&^krB0o!34wc$Xf!f44D0Rn&8)Osm`b7_H_HaPz+-ANcyp|+{BW#OItXo z*t^J~iRH^DdXK)Qe$couT>@9WnL?jiCxCXm1kaQClr_K858|K^+LiAN<2P&5QLBLl z430;yqNv5dUirq}cB!0oIEY5Oc)`_HXe~QSBR-vKXM3WA?^kXpCM65sLOTGs9+aEJ zp|+Vxc$sE-#waV%a{{D%@w(g_O7(Fp{y$yR7l5mKc6`$K)@6{>5sZK3zl_dRo3-TN zBk*k$@@#gpv6Uh-r}Eu{3LNzADh*n}KAzOVNO03xRtlhSl#O^)+Ag$Do)~DC*Psgj z-K2=DXwpW;xoOhr%ko7Xr=+o(33mo7BwkP0%DE;{Wssy=Fm30{3X0IPCRfJ7CD2CSp>r?XK-C1FRtzFw-&F|$$jBD1W723 zHF}Y6xS^2f4q7xZSOYOP)h$C|n_W3K9BC@$2*%xTvIJ>D%445XmCfEWsO;Zp<$Yd` zToBmSzRR)ZtkeDG(c9O87jE4SQAc?1y&zIwl6;kzc+sVQ3mwUO4+rgm=w4Qkr2h*KN= zOH~x`^$Xv=C-OUv!D_58MXg4>uS^LJSnU&?zV#`afTYQ;`6eA;r1i;q)RwPSc8PVb zW6&j+K|%msH1^lwXQ$#Db=e3i?5%=|ZUE%w45t!B%!J*8Oun88!6Sid;HqSl${VC$s`Z5Qn1L4WSYc7D3i(W zIa6XqtfM{OJClmnl)vLLn${?$0q^im!svM?tDWG0q}jn>e@t?ul_KI$_^8c3ed`^# z8#m5AGgWdEE=)<{rkxGBb7D&*O?G9k>CM~bFLJU%Pp|A#NkAo23+_o@+smn*g&H{O zC@?p!gyvoCOB(-*)^`WBvd3)6PLCM%G?F<3ozk87$Ddb6 zOS&I%oX6;VswDRnx&wiF0>gqol)7R%osJ)Hz3Tr`P?X!c;*@u;-q{e5 zY2YMkrGzPKJxKlo(;E%I>gVNz`7q6Ovi)7y+0(OjA~j~3!BU@4Lw&(YM&y@gzkJU; ztwc-HlG}%8aPSFkU4Hi~0PFj_S-6xtGOf#~Os?|jg?_MgRMC^ff@Y6TU)N+X$WA%E zzB%LL{8h=_Ghn);fST43S4oz_yMU7VYXTTc4!aY=k$Ay|T#sf}wyf_mIv_MUcR}Zq z{8kkmS?v}B2#_3GjhAx;A)2&(zBTzS@n~8~uwU#vJwE#zE|fpxvQZH0zn( z#8W1bec?CF!nZ~_sAbxKG)K><-ARSpa`1D zmVwb8)WiI7Kz;{tXQ|nk)q2t$qOyf3Yj2t6XQD@?9>=BZ8$W`PNi8b`Ls)DU()7dI zBpKg=a(Yg*D2b=%Z&oQRyA!AS(Rc50vd*DhMn?wsgL%g}H-j)NpB8}%L*CF`(YaEY z@W-pQgI~NQID;C5uxc|dKh7R!>)g4jYn?9m;e1VMoFJer6;=uBzGhAm*h`R1qdGj< z#+rLc7BkrmdEPY*S4FJM&GifKxY(je(iT^cH||Z|?vCx+l;-yk=rlC6^jXQPy;e;b zeoo(i-6!4heEjt~oaS3#uTyMFZH}OWNT+gN_fK~-VtR_{N`~@PJ+Qy=#nG;flFp#W z3}b&O@ClMvxuAc14|%IQz|io5I7~e5RPRX`&L@c+_&H zg#6)Ve~$UhFfsmnj{PU{o@agS{{ZPJGqfo#Vs2kJploW>9BI>%Zu7Xvrt-W^Ynx5m zfX&k>n`b&kp|&N@1Z+7nw(V-R=R3(Awzgd!w%z`=J7Alhblbin+y0t?>ht6m1Ga-x zwnHnnFL!LY0(QePgLa$&XUX0V*xrk_LLY{$148WVTnEe5j@Aa-jpFT0?&MwTw0pNQ zILYqk&6QLhHy5%Hv$^*z?`nKX%H$y6cHmWfPe>cNcf+n?sc)jhZfRg>ux)UTV)w{) zP+`a3_OacXNA)+gW2;lDnYPD%ZrIIu^nY&a-}FEByXM$-+p#n8b{|N`Do2k6Z@hE_ zb62g%^$L_7owm)$mk>{`Pl)|xv8>DU-5LBtxzN6?QK7;-@<610L>u?$+y3{XlxiO? zYN=Tag4@uch#f9F56>Q}*Sv-Qka5XlNW^at+ePtg=--#5-_W;{)JDxhxrQ4Num`KF2@N^M}B|cj{6GggR?Z8xZ}Y}DGei&OnwV1@WDVO zo~=UnW1uev7yoL+LSJ=cWOR4Q)N_?>IO{8DiUf{yjeOkbITDYOY@r#4HtE3}Enp;{ z_J-N=33Kq*Fh$>v8GYaDAh+r{R>rGXxPA50xoV}i-G!BhHJV5 zaR(qo8l_#;B_pBmnFj*F8Mf)<;1$6?{&x2r&FBM`*277T+hdbBR#l`3K@6~1Zu~Y3$Rkn0r5JG^(#|)2?Sx+d4YP`B= zmeG0hv6XbuUFR!%EHx9{8lK`TNN@7K_vBj@$~v|)1KYz;4=aSLnS_L>WOvi>3ArJiI2l z^C{E$>j^?dU~IZU+kWNGf0DW%Ll#>^i?$H*fq+tEjvCSovI)pD%cBBKnTv z5nvb_kEXZf+IJh)5wM6C!XBi$#+$D;f+leUo1XD|0JG46J}X(2@okf6@XC z7gI=fcfW~{0mSVA(4_>+aS9T{sFn(hEyN<>L?rLcIN9ED@Rsmw%O&_eKE#le^o2OPxR9Aiu#%<{?#YttU~Lv%JuXA7Pb@|n*ZhO@3lprok~$oM#u z2oceQSW6B27=5Z&Nec}G9tI@sa;%~huqi#|Xb`lc*YK04$s1};3nN0*C#QU8qaFnP3BBWJsBa}ZT!dMhB42A0N{KQK07N4bdY3IuXSi` zaXz2J+8WUi1%S>!LoLDgTnQv0(uclPn z%^W%fwRA9*9FHAcqyM#Eb#sXu?E1oMiQAzf4Ez>v@ykpdabKs*iv zCqS!ma!17hgb6XyQeeGAncPX zGmb!cWBUA$0f)W+e0SA<6T11H83?{El-A;Oe&jEwLRj`vBb~q$G$qgi5>p77V9$U? zw;5=J3(c)ktU~lgJ<=!=7l2_=4W#2@kbVb!V+~wr&EkMPb@DiePRUe{+Jx9RWw`~S zAOxsje!*Bc>e$a`<$6KJY3un|$e~lDuXC4pa(iTOPYBWRsZF}|+h3w@?b^N6)`snasr(B8db~{MIB7w#dXHaH0_zEvaxROw@R_o-cuIMB zroHVi0>MJ4V!G<7NwN)e87@Nk+a&8} zb{IWH$|_bR{F|B%%`9oQNoRcYqmyLIuBuY-pf6%>f**pU?Sor$->yI2)`MducR#Mk zDi9LV_#kbEn% z%Hx^)4?raszsIzIEY2a6PXqPJhi$)~dq&ALE-nz3|1BE6v{T}7O({V zgPGG{a^UQ(q*du_AU6H-og;NFy|udEvMyam`(`&6dPOv+?7}(+?P7U5;nF|c#jyi) zb7H-$rm3Dw&3Iv~l2@IXqz(LupEnLe`yLm;SEoAa}~fZHnKf& zXs{-3OPR(f=eH;6C~SO@R}R~Joi6E3D+QD#T0J(K0W%OYukuH-Hc__UWcd-w*)6?|)tR^6Hou7_M zOlXZ$D$g#?_vatD{pRAS@1NF64nDm2=kS$NLbAkA?lA+O`1+y4KQ|Q3MU)$cZ4Rhzm|Ciz{V`%GZMsQGL*v9kVo9qF zW=II3_MoNUpO%9O7*tK(F?HQemOY`AH4cNI+Om-fMz?s}IM6@EUrhwMl5 zgAZbG)C{ZJXmtvugu1ko9q*D~gLDu{y+tq+PeF13g_wEj`O2`xB_YWqHr5RIwVRBS z0H+68nw%rvgdzjNH4}5y^jRHgTJ!5Y(nR7-volsYpX2#Xo*gz5(e7l^fUq|6FKPOP z^kc^lEP>fKB+=oOM6B2OlNE{$TC8`wqiDE&G2je9beI`ik!6v5}3!66E+;1CkXB`3iF zZzB9>^Qgk>l3KjS0r~cA#JiuvXptXx__e73{Mb6k!m2%1nP?(fNa1Ki(!%Z5VNQGw z24t~z#P04N#kUTU$Jxhc26ifw*5Q%sFC$I_CN&2Jg2>5>`ojvsDb$a;Ynns;dqfJZ z)l_!H%p+olzB|nwmdI0EH2a5OE9Bd&OhgcIBy=avHTD}_%O}G;u&wv9WmDIYZ*^JG zJ4!f+iq%)v9r2Z3MA1}fvRbl`c92L;sh>kyhQ+>|weXV5le0o(`+Abn;rYvYaAopu zRqYk5h|k}zMb8(MjK33ojCf*Nt-=Ae!l@;D4Vpe!X(Z;zmPuzb;u~bcFbCz!l-}=y zi71<5Rd2+^W$sHMKXX$&e!UPMe;ISNH#=1LaA0AQ8d{}Qg@#kYyPeTfArD;DJRUOQ zHIM&Qr}eZBV$VsRKcrjGf3o6{_)`z%rHZ({;^fmeU8c_N-$hujtb7O#l9E+SXrM$| zeS^rg&;cq7g2A*GJkU8SUO|Gx@m}(Bv6xWv*Il(_ht#+RdpVW)k^Ja$7hY^hODI3C zD{%?PJ^5kI*iXBRyGXw7)Ziw5zIyboc4L)&l&amB=s=a9NI`q2qEmv8owBKLR=CGr ztq<{I)@MVj6Yu-Ih~MHhJ6%D9y8m(UF+>fhEnc=$5}8oct#WStsC++6b|QJRy0521 zG$;K@wJ5p5$=A}-$`u*E`+!siX;JquUFp5z8P|KmjVsxH*B7tUplqvylWN@>?;rRZ zM8`7+uGe=e8poa2eo*UFc4Bou|CvAprndyOoO+?y&jAUVr^-**4ynfFcvNctGISaB zzI@Qv^`-*Gg_WdhZ)^?)PHpyE!Uos&z;v{xzDGE3ui6!M?cB^^pU=>;IzD4)Ll5hzB(lp`6oi#D?0rdzqq=l zdy^~}0eh}}aJ`$4-{B&!y5YJz?3}^;ed_Oar(CYTYl3nS74@R!hUl}p-VM(CVf}}k z-|4T8nnl_wsLTaE8dVD2obW;_JDnMQP#blwT49N(RWUE?moV|77^yqarWQfzZC^Q= zGnyzu@<{o}!l(Fcp3TMl@nrq?VQYGy=vEa-l!%lV%1p|JN zQ@E}gJ7Bh;dCd$pO-wq+8?4onu{K-wV0PsVk9^c?ef3~1^s@VdpUgdEb#L+S+QQ>%0#^kZgN zlk-Up@!W%FALneDoQ><%$E(kuI2!Rt1Zvd^mHl~QdN)s z`jU$({1Pe8dbp7~&W|)fM(|t)Vd+uF>@)yGLT`^!ixb&oSvS=uyU~cp0pwdo-UnPa z9I`9RJ2GX0l)x>2fZ5L1M7>@Tiao6m5^UX9M1tSXHW6wiy^)T)<=)ic?c*3QxTJSu z;@X3T+e*1{+ijgo9tD0wb+^z;Q}hBx$T=fFDhiZd**pC5s7S~NI;2cTULR+M>lPZ_ zaBSw4rks!{qU{cW%;#zNc#Hh2*MmEqDCW0k(pYm?oZ1tza~pZ>Xr;+mbBcTVnIu8Kqt6xcuh_kr{)5B7 zOEIZ-DFS>x>=WXfJQ1Zmt~%F8@O{S_V|~e^rYdJdwy+{vWP}=QLfq}demjwS0mr)& zj(b-*rZjNiy)>z3oX?T7W`iAIUrVn6=$_wV5(#5}vAK#1BgRY+O5g>aE~}E_+$}3o z9Ew6Q=u(RBk0ulV|B}3JYYj6;#f2m7bqq}S&61(OttPXx~+OytDvT~Cs(7H2hz zm|RpkKsFU3z|z%aeSF9I?Bvz#5TfT3-UPkI+$bmC!dq9&j}yR>H619Hnb5`%Dlir@ zFX$=RZ;UwxQe%U4I7S;N2{ATm!^cR61MVdqvu=Nn6jDxRK;}sXo9t2@Wni0~>=D;IKiXrrGvY9i4ZbhqDgU(VAt3zo3%EPk3 ziwSqIq*Y8iVH8kOHx;Y_v5Ppy4A8;rSs)zfAMux)qudW_Y@|b%ECmE_Sdh2kfweVa z7u8Hbo4^zEk3E~Fer*|$O_IQwZd45&PkI5yD<~j2vXL~g78pDoyc;MtwlX!=q4PFj zznRDW`CY!n&AL2FQW!X6|IWf__vXh~;Rs;-mB1;fULvq#rOl8Gf|R&G@fly-sgwAc>vn$iIbbVJ1kX%R$u@^ zR2qIUGuHZ~guu()x5g9uPYb;K)xdRDl%rEA5{5(Z!4_7YP+#udkSksBiE!j@6)2E? zz*QFc2NJ_}C?sKMR6%}N!htDB3cL%l&_fZ=y0e##E?G1-=PiQQxsZj$`2O8g7gzSd zOm_80Li(|=%8HZJLF4t^;JdG{nrSq&@-&j*?7=vdj?7x)>=SnbSC`*>rc%^hRius3 zX`Hv|ClQLk=?!#&-8HfBE0iOdFy3*PY3iiGpDsocDKa@w-Ybd4+1%=??B5BY=gMwihJ&6HPEYqhhs2F-GS{2@umkl zNeWbwKrdTrQ&q_EOeY=$FQ0`??H&hN(eD5hoR^!JdJ~AAEuFT6pj#{)|PtRD1=O4 z(GhrBVSQYSt%+d#9X>n_kq$lQ|9N){(%|N&Hcju=aUBc_E(s-G|c?KtPuT z07GH;B&HInE9TjE-%HnkLe^g#-syNwM520o1?Rh6A{UJP*+L%e3M>$W#unP?2-skA z&#wB-LnIlr)2aTV+!qQBCIVvTFOmf3P#m!DeS?8v;|&1b+hgJQ?wZb$1!1pp&8l&U z1$wliTtuCXtU-*M2{3pdX^&;T*0@tp3qitN)gR=>YPK;`HLeJdj#vA~$~5C_K(Gf* z3?qnq3PRPWOSdRHZnRsNC_|VwJ#eRJ8i~^QxoF?RZyE=_|D`r2w4=t!rQ$Tml&#=Y zoWbV#k|qvVj7GS%1jEx}Y(K&Az@A8UF_I%TPwVBot5O3|#>A#gk&f*%*=nbWuu0%R zQ*nlgba*$IN)-ub?-7U8KhFp~m*9Jhl6K>)}v`oPVtpA4y@84+2eo zCPkyF@n}kz-YPygB(J-J)d}}!^VxUHLP3bFnM%Oo)jf1K2}s z2fbi>`I`vg+bui*xJ$c*7>wqh_XQIRVC$5U`B#vjNGmXW*Q>?O42R1KO~K)6Y%DZ( zZ$Dd%n2d=8;56FrQ}fR~77#@69^U}87+jJies5Md7z-fxeD?D(5g7*}iLqbLnw%ur zEs1L=yCj~*z+LC#@RcxkDxgL?ceNY9=aR&Vpl|nG6d(d{250;<4N^o0HfRDfKp;Eu z1jf!CV|Ou9SuBihP}BV-**-|790-F;Ok*i3W;A})Z$_|j~h@@iLv6q z#@WV1Q|nze?Y*Uhn5h7ggQnAtZ=Q(R40hmVo6RR4_AU?B{A5uC2=%h%8`1zAU5T(} zJWf+k`fhrXm)Nb&o>8CA#vWR4^ zTvWH!cqykXva~4Q)XCQHNq= zlO(%S$pa8sYLI;jy-`6}gd9sQ;T053tsg5xPdI>^MaC1|RB#A56 zLPnP>s9rIVs^zGd2rI1n^B+t|^9vMeiN|ly05wa6DLT@>S;e`rGmjD!d5cC5cK<&V z-TOb2?;i*7``#I2bBH-^V~#n@F>;#aFvo@xqUKP9Y9y(Yot(uS5~3y)IyqI+X%0z9 zluA-fD3yGcPL$er-~V90?0UTK>w3MPuQHFsrf&}-D8b~%9!5o95iBg(nmD&>@5SUF zqCl55P<`4>9=Knq^Q!~`NBy7>a95FrUH&kRj%fCQh=m1qSAOSVGd{UagH~nA*R`JL zbBxz^87r7lzLb{x&((q`w*}7%Z8g+uj^|88FOHHtL$y>Y?{_6p*Su317en$4do=7N zej%(m&4nNMuGX&_`5sMg_TKH$F7KbS+bl0?rQLn<-3CNOMtU0}uZ|Vj=6BMdSreB# zr|ye_PCCd|-%M{>Ejz*RY%lNJt9knDwmgc3XMgIR#Fil0yaMu&3(1YB38<~vL~2kh zk^uKkD72NmgG3>$fsQZ}buClRPN+*^+lnV!{`+}#KX9ErTY1EjH3y(_yOm9a|JhGj zzh0+~z8_6s;|vFSZzpOdW;^1tciKO$s{t8HJ#c0(1Vss!bt6n~st^ItX|E6*5EC2~ z)tO~Y^*teAx}ey*yLYKw0^iwq$alF1+V^-AvgKix<;DAsQ<5=rKJ>$qF+Gx7l9e!G znjM@$F>$|o+xot5X|5jwFwFgfyDc04cm{dN(=7GSla~6wRgmPk|KLVqoPCe>8t?jb zavAWMq^iAd%OP|G1v5AQd-;Ypsz>_EG-+(GkgY$-(kFPkslWZOn&h8u8qzOi&yrOm zSjg7 zd4)GKKD#1)A)mCewHB)8I_^K!A4t7ZxYLpvC(17Pv+ei=G_LyVHD}n@Bsy%l&kNL6 z2T>Cg|I`N&sdxuVmSg%y^5a9a9lQ`_dHENR-)r1y*Uqmd60;n&`$Kx)pA>Z#3>>bV zm0DPu>0LKZm$>8-ENb)brXE9nvVQP6$K}A*)4oU2EU-hjo}^Bm73TBlRhK;LMah{i1SZuhB@~q77e{w)x~$=ykNW63HEs;jIIobISOs z@}1=h@0Mp$>DCV~|Cf7Q^K9%ql!K$JN)E{5gxYH@!&86=(ho5qNz?ZacC#JR@|V{7 z2%??x8P4cw`;z~P3NxJ(+75iUQh-M2mZiQVkn&tSc&OEGrq{V!nMZwoFoX=nTbYob z6MUQE9tax!b58Iidnn7xmR}PlEQ+kaS?TO+p7E8G=vseSj>PJ28XSO2y1s|v1d#-6 z#N?NYiXH>H0;=qfNkWXzU32Q-rJfBIJ5>)QTA81VPjD-Cw(6ei`exvZ0jVyq^g=dl z$khVs-Ey$Q+hrW#Ex85sGE{SA2Isb8xpI4``OVzW(EpD8iv*EIb{*{e0 z^-kf~`%eAa7JRwK*BTa&GKcyA@Vlc+1$5_TlutNohyg1&KQSyM^attyi`c zJN9^vFW5$yX4wvonj$Ddq1^{`w2=7f4S()V=5k_Arzs|SE)W6 zzD8QK2#rJ!UFyk3OJ6^^DXmf5ObTU`B56O;r1(JV;B?6Yonvc?gM_TLxHH5PPD&4T zUR5D`NwpbDLq=s0K|b7S(xvW5!?R=gVT?o4#AFr)GWmzIy{G3k&OBb&#B!Wcv{yK z)PeNmxc=iuZwNVr>jTgO-2%J+T%?tlTDe=c=4D>5gCHA`WOGhpDL}MD`lbNP1X=9)g_(;Ulhb-L=2J7#Y!8%i;W?ZZy|6{=`og6gI1lI1zk!V7 zf?nmhQH5GZ2BX_*WGx9Y(7>k$OEQlT&8)fMYhFsZuP$bl!FZwd6-Ouf0IsrA`Wz-V zOGpXDR@0&j;Qz!$V92h*y-+K3nI&KIY8l(f>$c;VK=Z`sQ30lV@Lhw!5pfh+{oi2p z{@MIZ^46H7?XzepU=fl{O`wR+G9@L{JDCB5D2(xrp`HyI7UueSPhP45J%?YF%w5L0 z2nhpPK8f$nN;F*tdl6jn!u4z_uM7BT?PJMkQMR1c?8;1H_7cFsKNkRmd3<}a?hP&F z}gUvsRu8j8W50xUf#)tB=as zPKDX>dy+gpSD|KR-H(|bXm~Rhx~QN4$34*f$YsAZIiddch8JoVF(_0_`RV>A5~A6 zCldhd^U8yb6uLC5){lr~vDXHA^NRTfV0)pPLh2I)7uO;4Eq;9C^KnEjsYm9sy&FcH zBN$uwYS-0Lc2*Pvr1A7EYTiFZASSvbwRPgjKuilXTDIxri=lR?e9N zkoyVpC^S9y0j{CJMA&?wy|oTkBh+iS2_!W+T-D}frIYyj$XRy|j{F$h+a+y}iy6&fV-#Bpc_PFQq@Bv9K+ezVsOm^2nKps%AQs9_>ie+c8BQWp-Y>e+t0+EGnd9RO< z9e0;9O#N-t0(=u{Tq%R+;wnEQjUYoum*lVJg+gUU#r&Hs3}hTi=&Hu@xf)M8*F(DC z{@ujFG`g%TLgPey${@v1A&C6t8eRdMRWz7?psg5-gyKU7C5P?lWW*ftn7mQ7?F2!_ zo&!C)7la0Wfr_|?CI|BPz-($X7_E0(J+XH2z2JHrrg!LEB$R6R#3eak-{ftre8KgF=jq` zyk@1}n?~N|KC4*URXJ=H>-}uGWF795Wv@dk>2_oQ~?g@(ww`$`{Wj-U^tqJE_&#kKs4F1xjLAXE% zVm7<&^-t(MbLWn(%IHl`4J%sV=wHk+n}@)N`D0hvuk1@F2i#d^{*qD=w>afe0@3-br-~7$fNpK2HkdLrOdrtBQ22}&UXi40$#+9 zz$O{1>R^P!rE`o2haXo61Yj%p)UU=s=HDueY|Kz4XpY57}8R&j#I;c!p zW@}u+k!Ve$$lc)M@Zl@ZaS=BUUt7cM#P;ro?dOc%*|CUWZqF`F=VB9f>9#(qpEe`| z-=2?YU(|$si`jN4`%Tu}%oP#7Ahbj;009AMR09P0r)yd*&yftAM=Zu%DzmZph>JBo z7g+CT?@YlX>6xnp9!3^?OhVC6PaS%6cW4>Td^!A>d`3+z=)s&V#ofxT3vgVzv6Fhm zZJ0Ij)~ga1^DD{{KUs%Oi!r#)0uvZn(eXQ$iC@Bt@7w!jt$aSdB?i+j`m;nZwbJcr zcr1Z1EdNmer|f&@7N5HNk4Yf>^&?qem#8a+*4I!toFAK+F(Z#-$o(XQp`xVy(0D@b zy-L#o9`ekSV(fDPR*Q)@V)lpvUjAfklqTj&$(ij0xuqEhQ-Ju{GpHMnN=D^OvWKGm z9!Fft>>kusAx_2$Wqt}!ul8kElT7Rv^#~9UKZl&Tj~X)Vjc(F5i0MH$aF?SL?W549 zY!J;zX%|6pLK)M#-S6x0|AcWh020E+{*1!k{SR*{IvF6`kOpQR%w?Wh8Ib2#(mS{M|FY>YA|7;aR#x#839VmEUBLW(|jazy5_MO z{)yhurSbf6{$T3y^IDLV*eV_h*T^Y~pOd1qz@#MDb9?{@X6VpiByRY9Q zXh%q{!K1``f(5)1Tkbl+ExJ)q6GXfgYaY)9tZHsPg3*J`P5B0wGy$qx_^kTTd(bCwI|;T*iL0doe& z3O^!R^Z{W!mbStOIy{#xB;#`*be+@f3m?feC`G>-ju>FUnuLk6L;$SUdtaxzViGIb z(-*5e7;?bHoS>LOv1+CuVhI~A`Ds{xRg4v;T_+fOFOC9z<~PwffEngDh#CL+^hTsX4)3@bTv7HkU8*D;k-1+KkOF8i(I|5SyhWaew0SCYbjKL4=2 zbfNIgLcW3#QZ`y{s-ATQHLIIv=4@0r-IVuy;oiT`T9HeJAGhSCmzInbjFT*osq>lL z^_1}T;!aYLsnUrN)Sb17)h^NK#Cf@dtE`C8&8IN4=v>T6OcBA`usGL8Xf}{ULnOlt zz7erMMUW|UW_yaEdw)I6_*J%1_L^Zp>6N?{`qsax`4Z+jowm7S)utb5wDjww;-Y84 z+ihRD^D?jV0`3pOU!@jn9pu@s(=J)}`pN>{(-UZ?hua#dR-w6?UnwYRR^z#rryIU4dns^9oVn(OG2=Lpy(o0 z*_|kl7W^<3qx9=6Z4_kIVmD+6R97yk*fF3-7>b@ziV>S*((tw$`L(XcdNdinNt-(6HX*~^@Ida zHk}8On+P^r`Zj(A@oyL=WQy!00y-!}MA*g40|(UrgEdvAwg51=;M@(w52wkK+~O~M zS*{ko2oPYG*pskBvh>Zs00UggR^G>w9U0{?A0exyjRw!vI??f7buylAKd!3@N*U?Z zAwQ}Gj;icU`GGcXga}oE+>y^{G$EcQ1b%|hCLtoE7ja93abaw<>r+BgWY0_>s9cMe zU~?=*sX+uwV!`ip0uraRv{sYMN_XywS<=4bF6?{AzCcDyX!bFZ-F^CwU66=*!@P;D zJ1XWhPhTrZMX8vT7V<)avqDcGu6b^`=2TjgCr0NBw;CO`H!DuZjVIDlx^kel<65@C zil~CwA5Y7#`OgOiABxXAjPq)Rp>0o^)RuZro($fD%byvX*VvO6d2r^FVeT=%!uI~+ zZ-qH^Xrm3!D3hgIXB3MnEJ~^-)tb@lH@MTk<9TZ~VUKZnu%Ks4Xfvh@fTf*p{H{+r$AUSr zV3ikloz31Y+4a-2DPLUzkiMCi#V#ayb}O_4&4fjh`WD_vBh zF&0B|HYTo@A$>(F4MSB0s<8}orQGJUY&oo6JOxnke5d)XN+~E$S`z^zee?b7jvuqb zOMJ_D47AG3*`)4@7=hZ69_VwDAnqk}B0*>O2mDePc7Lz7c;*j|B3l!Jf{Em-DWrd} z%}T;c3C+j^0-|yca?~B+Bsxsxz@9T?#SLmolwDiat5DhUXbZ#?MUApc$DB|jS-QW$=0>K^B`4vPBpVsrso3m|o`44`Axe>KAUmPqXnG~EiZ>8asNKb2bxa*FX`SG=?MN0ONeBH!$KSNMAQ}Tq2D(<=aDDkS z;*l4xsVL?^5$5oX7b`akx+Dt^LibFD%^u`c+LwWC247GG6QN$ax8{kFB_9+^l)vNx z$+^dxa;V99#zDN+TlB{T#Ami!EuKWw4VE?@)iDn1VxtJ`Tl0QLXC_YP6~5w^ZO!bq zzw^z{OW=6t;;Uk%mpSe3{cns|!pbtZR=)Y*+U<7Si;p+@Zr!*~lEXcAUxv^qCwa`S)rXkFqO1ZzNd{N)48$NDY6NCEQ|%y66_ry z$c`L=7G8L?! z{sH0nGzlSxWO*PK5%3TA@O~G|&Hr4tP=8dUKmocEP8_Joa$5rN-?yPqApU2M??vPW z?A5;FyM4o&#m-gtwA(lTLKVJ9%{z7XZe~MK!D+9CqpM=SaI?cR{kIAMtD+nKBuy^8 z&42D)y~R6syc8@cu3OOh_1pg!+~oP) z@N=GfU&+DSbu08$`#bC3Xqy!tADt-Eb0|2Id+)(%)}?>TA2mPLa>3^WMft5EkkogV-wVyFn)_lvedL$=;7Db;82W~L-PBpUlF5akkf-4qXwWI6gDL9MK0y8-Id^WPVA`vx=`tV&hF z#l=z+mpTdWjcScMWx7;~-8jf#R+#=O|97;~XiWRkVwY&JXWyIKX-gS0E2rE`b+6;z zBzZq^&n>L5UAo;vm<@DH%PM28{@Q{{`O<5F!}{v*e#Vw;@iv~w-PH<$yt&lcy}K$!yYKD#^{U8uw^~fv`d<4;rpvqc0j1i{n@GiK=Em=` zy%2E(zU=iC-NJ2YEAwo7ADQV&xdfSARa;ED^iJwQP8Anx4j9+u#kN0kgKq0^#498fp=oH=H29th-GxKW##w7`xrA)w$c_dnq+C5uwvE%R^ zwn>uv9+UL zbpnHupirbifT=CEZbI$xvkhEg{59k8(DZpGSJ|GC-=~Qu3n>T8z2Y=Nu61=&Fy@w& zLFuBtDPR`VaFU1C?7B7xA&{bk>eQVZ2Q(uoN7NL8{Zf~sS7<4GbiV&QPrmED*z0NO z$`7n#$nz)n+-WZ)9gPO<_U8g!{1qfsYDCQr_i=8L5|0mZ`3!jBx^V$4fLjY*apt@ z#**sDX{k{ddjhWx6^-Q?@rVi!Log6Z$>p9nFi`~CTxbZ>jG#CfMCJMTjB{OYHy{uI zXb3BX?U4bH-U~hA>=#AH4}XF5S>1=cuS0oMM(Jd&Y;kFzo-CacAXjnG2i^c04WH zb#M$cdJ^ff?1oA+rJ~|!RI|aRsx71Mr353;EJIJ7SAGupdB!jwKnu}RW;ET9Mg#J3ee|m2V6^w)wvy&GB zom;j_6ivi`-$N5a(P~Z<$ffTrFwP!CpoKtj%2059xI3Cj&%gUR3iL6mZ0zK4Ja*=~Q zuCn9s02~}|s|-PO0c8egkIpMq9CWPIqL`-0JcuFhySo*-6C2$V#t3rx-IE97UuW!+ z>EHi2A4-g^GdVAC2M4FKp6ZJp!B2Ba-|?RLotc432wde-an9r1@6f2bEZyl-wHaNr zJ9uIb<$qsyBPIQWjGH%G8ZAzI^z$0@`!gJz2Q+=8$91=?_$se5TU@u~G&MuNKMnSH z{WKgWqL7;0%qG8rN`-7}NDTxPKb385L&SSdi?o-7MU=7?sI7h9Myg`|4!#hGtY9Oj z1RQNXK?b*Ct10}=*5UW`-8qdeKYfm1XOi~j?u$X4 z+m<3qiuXPJ67=bBji&TsDs@4$P>5g(6@JXstJW}}>MCYlQCD7CMXdB?KY6O4u60iB z4se15RAJQz|6m^N+hpO?%35#oPC*CtOJ-8=Qa&A!2@9>f8pFpJ2S+3KGB$NZUTc9Z zvLxt&3O7i6LUCrNek%G5{NR~eMVZnZ)|Ww2Q%y$}9F2nAnWPNh>riPE(crFU74}ly z(u1DE-5j?GJwQiQ=p|^&Oj5RWFr^MlpZ2Peg5N9VHIkFA<)fQ`%=17rCY=!R_MD$G zg%1qmn`2vNVnbSyR<|$g-ZIKoNb<~5Njqil0r`UYVApzons)9bsdx`Wm0wIK>yo!U z`{L<~@d6mGN={})x=q4hsj}m(S0}yXqp|siI*IQ;5uyGC5_R2O543qPLRFOF13Fv9 zs3H5>>f_?$KW;8~t$%X-_uHKl%}4T{iLc(v9f-?>s*3O~3kfc&U%}tw3I&!DI0BGG zuwap62mOKLVPmlDaSV?vi;(vCiJ(%I3zrLWlQEqs5Yz&+I*5f|0i_sI7FjltqWz^6 zfv2OwT2Y8r#Pe^UArs;+lKV?fNARIMF|vaJC@>+7WAG)iS|Uq7Qy3>1gXepq9K^dx zsGV72j_2UkNISR#dA&a!Wp9P~gC*^01jMf~B%-&Eth<=W>{vLY#2 zJOQS33}!dT3ma2Np|Ndn$}V)y?Rl0(*ZMb4cQijEAEvRPp(q5OjSGc-2f4O<*xgq3 zKV-O}l$0XFC!+E)ay9GfQ2q?S7H}w=pcW8-Hf0IQMU2=_!A%f%BE;-Qa$cz@zGfls zI~XIdWJ&Eey?DT#hRR~#c0Px@hyYY5DsgOMf{_-FpJh7+S6$fXO@|VGVQk6pJqsJ_ z`Ho@C!h8|)SP8rl$b)mYzHW3ErBFkk=q8Gw9f&+Q9kpvB20{qx7*pUe@=M}@ENL4O znT=<$@1wRHX0WoFp4;8v{TLx^R-O7&INl zyKoG5F3sut9=|Zd(9-hH7s}18v=4HK1<4!Fvp~gDI!Ht7WZi&(QsT!MV%~N2nsMFK zcPERLU3+?Rq=Z+lB~Ec0G>Hu*2&1j?d`{0$cQmW>+;HyKT+t89zjl14+AM(z8^mcXokz5?3Tl_F*@4GYm+c|Gnbxqz? zI&p|QCJk@T>-G}!i_0X{ubVSo8lQ}KSN-p%Zdu()$6j^Jr;{O&n%i5epY{-KThsl8 zIdhW=D-66hUp@IH>Dt3;On%T1vP@mK3_g_MzO1{`jmA^-l46XN<7XYM0z`R4oRVS5 z>d8aiIQ3Eiz9nPIR<1)BbC+x|j1;&p3)YA0Ml1_7A?08DYI?@&3ts9veH5%5E=NFW z9A6shmtrC}AsWS%N2%6bG_sj*uF2m9tb^gWpvp(Kk>1 zc}becYdo=s^!>t_f}tj2iedg#Q;A7)nNPFxG6@%5y}Os_QhK&PCgosC{8U`EnQnEV zcT>o+VComKZc3u?S0wN~ToaM+lP}6T5KVfM*Sxn~uhB=l&PUs%H^)NP{&Y+Ih+*Bd z!}+vjU3mV*C2mX9p6V@mfejxU9!)ie=$26-b*-z(D|tT0ax24_@pT)u8>^cxJk8JLV(QZ}-=eJ~dw?C9U`P4Gt_u=w$ z3A$hP8u1@aeG|3(6`nAsp5#5)-l=!ho)gy_)$ynKLi$UCk;50L7fH6IB*&pjd{F0u zoAnP43;Zs&Z19$JzW&`}oT%HWacb>InI`pOuj2K{Ck9u%4Li$p{pAAl^7WG)P9wKp zjlFez7xnadU&BKm^>i+h^rp%RK3;zGQ6XZu^3d>Rqi1^@si?49$Mj$2SZzO*{;G^Q z%pdvfVzs{FeLO`MP}j)SipW6kR-gZj zyI&OCd3o{9tKmDZKi^rXBHo%wf4vpO`Ic!VHQxzPe=<%=Vg5yxM zGNBbJCq@Kfp*Z^ag!oMx=!p>4f&G^I)Z7p_qJ}LN_$5?0D(rI@+dos07^M#-wIX9} zH1WcI2kbz?!2TpUP^9L*$N)&Kd+kMFjFHTK!UG>65ZH?J7?jZ=WEkKcki>|~xzH~J z@BQEH?MDVrEDjcFpU8I&lr3Y7aTFwnQ4R92;91robLI-PmM!yCWNxW(T|r#KaY%lSsX=ijL_dP z+r^3=#1IDnVnt9~bqlbdnZ*jdnLRtD2zawMs*P4O@yCb$6#DSHh3ly8L+Kg;O`cRVL=Hxb@C6jO;onnuY0T1p^oonE;Vg$CSHua>DMS z&IANv2b?o2g~no`@R`dWlQHoT&pXPcR{b+OCdAZ`&JDDG9qK*n@l5AA{4XW;trL6; zKg^N=Ws}n_I8c9rz0>8%f=81lzDySHrO2sReCa}Z8bE70F{@)RgYok(lXG|sWBB{T z8XGw^Aw3eC{4!ilT1@t6UQV_irI?0@5yIK0eLj9&r(%mRq)&|fIKP_(O=5u`bqTq* zf$dmer&FG*io5d*1vJxrpcfz!U>DngcPb_XvTqCG@n&_2 zn5ZJKsx)%3b$GlTnMv@nY8~1Ig{+#%ob=dxjiF4%`fE}k`ng~Y->!fNOw~@l`|{30 zVb;=omOO1fZ)Ot2ij5F>>S)<&%?Fybo6LA>9O>L!VzVhMd=!awb&hW~N@gh{0qIn`25!dR(Ikpp`ZxM;blj+-BusiKr<8UGXZA-8c z%4|;sHvkYH`nG4C$UsKOYgKp_T_P*TH;j1Zwf-;uWA{j$Pf5)-mvKGjjMcRzpK z-3lO(4|v&Vs!c4dyM_q}dyQiRg(C;aHxLR9_u76fs$c!8`S`20EAh8j^S_h-_mSmV z0T(`8et(N)dNF(~^Opc~m^r^_jT!P{<&-a&$$0Sz`Y;4(GmxRbzaw1a}{s-qy72QwIBU<<%Y%#lth!2@}aw{uh-{ zw9)lM=GN&)gZu=&^5UPTidU;LDZrfIN|k2F5b>C9%?*tPBj4&`>+(Z;$~J~y$6u_~ zX}<*gCT3`yr1@S>3p%gHmrg!$JWl5OnA+;MwQHo+1l_d<#cK~AyQm%^H00N-4yo5x zXwQaUZr`u}spVoo_@yq(^Hzy}^$VI|7ccAmzF?hrF)w88W#a1ks(&i&|AsJ-6T|)-QHne&l_nE?=5|X>SB9uh!m5`-U<}IK@0e;mB!k95EE174rTn?cS4PS?9?8 zqWjMm_vE!JN7>L|L@h|4m=%;3e7L+#9 zf@g+r=)FB}y4o2TTx^+V;#8Av6xav7;Bvm&%9Qp{*ICtNW7(JIH=y|Q?u({S$bvGZCxH?^c(?PNe^6 z9WV{Ecj5gWi}XE|50mUpK2t1u_Tkj2>K!y4{S{l=(uSG~gONkx7iy#XQHP>NSD-TO zef#hB4sLH!Jtx|pOTMk5xY>X@%^qv~Zj&!Nz453pDgo_mRhN)fig4`>Q~~`nKx)k%r0D3*D=w=}+`g!MZ%Y*l8$-|Es_6iZ*pn zw;$~ho`0pnbgpyh?j1Xxg?Cjcsl>qxpJfx|ZP?fu??2!h<2i1$p zCa5;9tp0~~F)>eKIw`{fvAjtxTUix6VRc=){N!XFYs9;23tPE>1e3a0eP7J`9*mMm zM3c*ZolXxr$bE~tfKXpri7Ph4VXqNNqetRSV4jZ|^)_zNFqH#;iW{-&sw*)QaD0|{nWFI0rkPC=QCUNF zW^9w%ZNrzV@h%JZZ}}KreL!H#R@ocJI)0tD9IMso0*HJa;YE0Frr<`)aK`O7vmDn1 z0-J{k*+s}Um@KhAyUqGYaJJ{6Vy!iQcIMh@K6m;pCl`uKVHf|M$xgZKXmUY5`BAX|qSRHLeKn0(5yp8%bNaI;r zSY?^WrYtl?1a*5BElZuGU{t>jo2Je{`%U}pEU;Ypn)PzG*SsW_JykqR2Bp-tiT&TS z+au$Qz2M_Tsv5~HH*@7F=)j*xJ{IQLnsO@eD0g{Tb{pG{D3Gd3Pv39IhN0L=Vc0n1 z$?+_M8X@Qs8gJeK*ke{Xp5B!Z)HxQI_1>nWRC>`yN#K8@$70-cciP^@NXf`Ko0V9pmO2-I4 zVer9iahnA%&0D#75bPXMni{E4Qa+b9O!bYFtgT3~9isjC0DD}!tgKF;~ZJux< zlg?3|)dSUzus{=%l^nXY$MoMAPw5{KX%`A0!Vhzmnencl|Ku=l@lp0qE+S%B>@-)3 zj1}vGdFyZ0bxc0AV9-6p>SM3Tk6Szc{d{px0%x)mZ?JSi8&#b{Dd;Y7u`6~x_WyX) z6koa(_LQ}Ou?ez|#Un*nftHkB&7Xp49cf?`jl-kN$GGOE^5?9?fK2ond;Y|?j8D^) zjoK{e{6@+^62VOYjpf490hl+RgC$L8YnDgf+B*rZtMGgW(-a`S`nn%XNPdLtbc5^A zSZJ~sp~UNjLZtVJPOV&tQ3L~H$xI1&EC@g>vb9SmE3r%h*R-HR#+fX{O|=#g4!I#> zDDBm6`MFw2GY|y8Mjzpq93#!h?`CPrOpVE5>;=dV6Jmw5R<>h0Yb!}%WZ7>rCF@zSWaEcNcJ|vI+>O?Zs-JY4qPNaI4|T_q_iTz?`g8q6Bx^ELtxV> zx1=}Th^9M52Ti4A2808U{5G!gM6@EB#^QO4@8dnBT-Oi@Ab!OzM6-DSQfY^}`qlT%l1->m z!X~t=C^uR;l=0HTK>dgq#3ljI=O^6I_9d=Zm4b{jqrLDYdM3Ow)h63mnl^z5 zjwAQYL$zE}7E9@bkcBoMgF~m;vM*dVrAdg7(q>uhe$y1S=Y;iWqs`(|J6W~ZW?m-c zMyMP)3o1as3^1~7{$X%mp7=r zUlhFU!Q#go9v)lNL)zoa-`2MxZX9Jaw|E}lNZ24^uI#4D0PA}hTU8T^Wb%{&5adHP z4qbszw9%Cuc>qMmU*PNVS`*0UXE?Y)cKAw;j42P->RLVp{pSePXTnVEq4-KjSTams z1OpjJFc*SE32`*-voWmu8=)9li##B6R*|DNQA=9LL4MqDXuF9z&3tD%RDA{TVzDio z*v4H@%@x+z0Z!Kx7tU-1%VmxF0dU2ID!%)-9+Gp5HE}?SpmqE*7HEm#FVfGhb0kz86RJiRa5gaW%7K~<+j)n(a$M=|-V$85^}-c(MZ-BcUaS&lk$BU6i~G)a zSE<}pHOMaicEe^hXVUsskj?#I_xoG6+}~OwYs0Q>V6bdyFe@x44OJ;ehhcNs7#fG@ zs~whSO{BCvEn!24+13nhh#uJPV>$10+nEL-b%CMVxyT_%KjWvQCF$36>U+9s?g39`zukpwpOs22ApF7D0&Qvj=WLKL~S7 zOFLm5UN@9k&{>XSI@x{soFlHoY)s1<%d#f3r0)O*={)B?AfUBF-sWt7WzX5*+N*BX z;i<^7R~#)G?1W0k-ee^67S}_PnDge{JzP_X#@JoU32$#ovm@U*F4%D7WeK(Eq>?gc zRu>ON-IKaz8Vr`4y>`4G#9Rml(5wwnypyL5!kRB4G@;g&?o~!`1f|V9lx0TXDdV{C zrV==gOX;frQYn3t;nck1wzQR!LRraF1ITGbyVXjUUfsQeGLmdRDl?7=V@7M6IXJ=`MhN(_VxwH`F6G` z<1XCVp@`_LCDlDwa;Qx%!A32{3!76D29#d0jF^xYpE(+$K6jeey_mM!&1_b(XIlKA zau+L;`H`#|)VBB394-OR_p{+mMaXgYW34WDd;9?vYt8$c@2@8`6h3rrZ9Gvo-0|=CT&6>uYJdUILdF2Id4j@&c@qpfC&ybQ)Xj98+xWtuLbmTQu9-B2ImyxB=daaV4Y*X34WS0k z`F-hsk@4)svH2H^i=dC0D#q0CMA8Ik!xewx9A+35GH)F$6s9I{l!I$e7+2^p9!e`G zi4-R_g-IF0b! z9l$zA*xlB`6Gf0rQ@nHKQ|ARWr=zeQ0}Ns}zvk1V-K4iz4o&bv-I}PYC4{=$hSi@_*<`qe+T$NEE2pE1?nZz_HnB%xweApo| z`=hr1M$1mK*nV|I?QHRlU#U5yNvP$Y$w!I}ufG>fYAYUMQe&(;`LlNWeCfw1`Nt26 zkl7+sg=ou>024u5HuY4vh=U7$tHS`iA}%$f4T=2V!Pp!RA^UTTLDLov#)$PpWxbZz zQJ+Gh4zip30et~4HQd?sT7D2~?9m^BCAZabfkVZ;N<8X&KEGZCy73gBm&tG2Z@bLeYYHOS$#@=ju+WJzKVNfO278)R*pVrq$-KlZ5p-}>V{=Hqot#o5ieZKw#I;& zRM|tn*>=))1^(%0-LTw&CXkfUuRGEJ^%0IUfi2xXMhvn^UAMImy{Gg*dY4=AtK0e; z-=swc@02@ZS~Clz7u7p@{*k*gm%xdiz3ZIIp;khSN2%($k4(c^4hK0N4Cxvy?5;1% zN(nIJgZGo>-)C(^uds%Xp1rtr=Zg_gwoUfjAEbVK)X8?zz1dqhh8ceFDI`8B<`Xi2 z2CQE)q+8{k4mC!IS*CuQa*uGO=CEn%uoN^#gN45wZa(~rgpvWZf5>2Ad~2ns%=2S; z$j6hr71H<(&8%y;C2N2Z4oVdw4-Gc!f73fef3R8Z%q_DxB??Ewo_i3LMUR(St1Q{? zfJH$YiPfrmy6sa;$kL!OmLC{QH@D({B9z$@7qYC$T#_%)u&@0}W1vG`^kS4rTX#eK zaodZ3s@!pBapF!484gUd%+l+mfTkURd*%xS5gO6e13umY+ld0MU&%^))oHyQmL_f{ z5iB(Mw1ui1rz0Ew-b8x0KBX^YO+MsUYtYK9$K4saRzkoEV5c#>Z&W*D`Hk`m@UZ~W zra#_F-7c`;x+vclUkfz5M{>g_S=vnAx6&`BM*Bh@A+5Wl?W$R&(PoSvfZZf}T5B;i z5&Bo6jxTc>o*)X-+et?kuG>|Y{7|gNb%92SSN(hwFk;|`KL=H?FJO=pxT0=tm1RWc z!gH7Q++KR);DD`+DegE8TgW=R{gbKDbs+a$<>mJtmQW&1lo<~#E`yopauv~U1Y{%`~qeG_96@%)%kc!;P)UJ{+tkq{*7G!0)QJRM(+)+k- zq>k;_VfAhQr>ekEsH6&cz?f$$IB!e7aW#Q+sW!*hi1q9@v}fpY5V>WeVP2ZlKbLcP zq&UQe&`pMPdDO~p?Dh+rhd|XNh*@#2yA$bKPi}wWwwEy}^EElg1&tRH%&aBc<5>CP zmZG0sDOr_S5b@K2Pn^ztv*_Qf3)Sn*?wx0KBfFmHCk65JQZZ*IjXsOMO@DfHGv&o6 zLE|Uk|0p`ku%`Y744)-qbT^Fd91Y4gx<{uvx;rfx14*R>Np*nIAf+N0qeDbMR8;go z8Uc|K5S6{WAJ4~go$FlJInVEY?ngRoW=6afbn-g$nHtcf8=oL^16<#HV^ofAC!Y2@ z!;bPRb@zta+e0N3GzMF8A>tQ5@0-c-mZ*fxWEiMgZU03N-6ecul@#<6t73Jd0PPwv)K{~jV3YDR{Tp2rf5%tpLWjnb^yV*a8_rAAh6^&}M zBY?@>Od`6zwW6kTasmVN_yB;y+R zJGq3I|6{HSXuVgWeES-H!oH39qkhhv6#A-eoiB~K!F))mtg4?2EW>Z}D_EKSnB_U! zx0&~558JYIpy+R+%7j$QstQDnQK_0_(&g+20vqgkbCl>D?0^9g^m$_8f_Zne z3p>pd@iEY-7z^X~ZQ%?5p5HkZY$W7ZwX-;!CvMw%O=o{~^1fl7(skWm8y_C|yluU% zceMTORVs^elK$_#)rW=(Hck(X?p;;ZY&Em1exs1xUG5pO```7xTb8ZqCD{FWtxEHA z^y>Du1F8>3&qE*AWEvl}uU3RhFs=EoMcEJR!cn4(LPd7A zGHOL^dOtkr?JwX9%I;me`5S?{4r+A!;DJ4blJ#VV=oc(R?{YgiuI+xRyPpi^uP3Ln z)75-h#@RHL%r{=Yk4L*(-W328)r9ien$ce1ANibu?P=_b5|4YUsP>ZHv_-5Xq{H5BX>gv`ih~l8 z7Jeh}Stg^Mk*FcZ1;z(?W*4qeh?2C(LL%(+5CL!Z}YysD;ldj{yj0X~y4 zVJm7x2rPK$$^%!~VPR&docGhy2&G`yw^;W^Wb(Ax5=E7ZUuLl4RPqgZay*HtOt@w8 z+sY(}(wR@yS9Cx)qz(P_@Jq~pFOL386?u8QbUW{G>cS|71i;#MSwy$mApOh?&)JL_ zd5KPt!-w-2922+=i#WFq<{QSq&qjCQg?J+-a3o87DCWA(F&+K+sZ>m*D4fQSpThVp z@=g^W@r*43@tL)Oa0n^-gunqlWJ;d9x)p4p7~pz#g=LSVpPPfSvmi z^P&cHX9g2gDUKx?1qGccJ>JNPa5V)E$$P8jxX+96^p4&w86<*|^GT4?cB0W)&)hK| zC#KB?QCd$);K}r61dGx$hN9r+#}LS%%nhZ#ULt?$Q!4wHU1lOf`6P&_vgpIjcxJ(?oONsl zMv|x{KQ}(0fF#a54a516YlyIN$F@EL??^ag*^vDuYyUr`NIH8dEFyq6)gg>ElXO#p zAuqGBG?Whpn zN!)Cqzx^7FN4#UH%I$+Y5Jot+@smoP1jZI0Q^oZ~W=0|ksgn=Y^Nmbrm>2*8+CZY) zRe4XZVGt7en@lz;dA9z}?FsdLB86w^qymM}Iuk^Xu|$l9VS%$fhjnk2^mALgo$>O6 zJ14*4qR&$bImL7RHbegVv#9mzux{dBY zl1KZ+RN4@Y{%5puDNc`jIt?DM!1BG9D6zeeD@7nPY#$GRw=s+HmGKN*R#4#)eCEAj z47~*z$7nMJ!`)nfA8+>4M`CE+{|BCZTvPFXb~BWK8K9~NY!iadDNrNSc+Nqx1S*72 zNjekW!sxQs&u6Yo?yI8+XD+}tn36A=mH*~qgr6phpko`Ir~Dw;%q_=V1%TR{_49g1 zG9<)eGkDhfJ@%$2lTQ2IM3@aOIm$q%GzwnBv<(G5Pvt5PYFRXRcpZvppwl>q%KGBkhAUW-bD&R0U=qZ`cLQ>p*QTfL8nF(DsPxh}mM&%D!T z5Z?w#?lfeN$V_2m@2g5$rodfod-(S3a>`#_c=~db?qnN9ZSB(E&Az0+Bw*lwy%LUY z!p(!Zf$i&o<3c&8#6AXUss`^6#9JfVtQs~zx-x~^(lcko=l9SncVNy|#F#;S@`tHa_35XxPfjDs8JZ>+^E)#K-!!L} z7L8u3ga&C0n+@Jiwu2LnU;oAupcYi9J^547@RQOTEvO0n=(thK*h%|nXt(jhE?D|h z2I=^|ZC8flgt={|QJCQ9V>~i~@aAkKwN~31wn1gyBe0xM6V3`HMP@fxQJrlJy$5s_ z`9p=7(C1yL=LcWA&!(HHOf);D6?zWcSS(7|drP`6N_u-s1usfPdrMzglqPx0WG~7TddrqC%2s>JH7?3^c+2-J%J+LK zj4vw8cq@KhR9y5{+E`TD^Hx4tR0jK~AeU6weN_3ERK%sN&$-V_ z=N5g=Z!DeP^D#JCG64Hxkjof$Uo8JJR?HVCw~SNsHPl@;#Q7RoEYpnaeU06hjlF$M zf|pIAeNC?{o05FZvX{*Yea*|4&8vMa8ka3Pd@XyHE&F|~#+R*Te62q(TQBqu``a{rfTWGJq`iRTleJ`UAQ8DvWDiW?Ur!MWB+0Fl z)B;m=*HdwUX%_2g_JKFt*UzjK>A~yi(SaFP)-ysi%-*^TSj9f3JL z>pA^_H^sdHapZpI(0WYaUoq6n_c!HkKH#Pdxty; z-h2`r^7P8)Q&I?_b%X31Twfd9P(A$Y(EM3aaQF7Zo_lo9`A52YLW0Jd$X5N)X2k0G zkQa@9g20e&{-yyVCK{oD?*dm#G{1WJaCQhQQxDKsh#R$6f}h>n94wR@au0pQO-H$x z{^bS^tWIpS5AE@89tICdlx_?@k?-wLsJ8)g{7t3U06pQsFYhTBbb()}Z8=#Gk%(qd z;D!i6ZgS7?WnuGpV`HSm)|gmWzfyCYYiNU*;@E0)!;`JLdkXKv73zCHEYA(UXaKd_ zTLu!LFQ0%XHN)N?Han|f&sP1I&F)gR<$LY~b4^eTCWrz%sRCw{|0aQZx$Fc55oLboL*FkfwOi}v9w@a z0zh_?W`Fms3x`cRw|;j9ZA6EDF?on0o6t6y4Hq^-dx!gU>j4fk3bYG5`wxPgZ9Tga z$QCeYPduyd=;D9wd<%bbnu-i;Y_P%gU&Q_*h1ZgPyt5|Gw1#gAZvlAXxc`QP6);;& zgzo@T!jF)Fz@O99GbQU6`X2^B=#~YBb@Yb;=Bw-urBYLI+g;M&Z}Y4M5q?cM7^P@H zCeCkwnWhE|1aV)&b^z*@f%Z?`N^tOCA2Vy4NL$3Z9Nj1G?I1*`pbGZLU+z#!xz++h z-#j21s`Be3f}uo?3I9lb3bR?Rg0BZ)4>lH&E%X&Cwf4lrQ$qp#BT72%_u?b4%gUE@ z5@_GBZ|2AJJvb6D78E4WDE2=^fo4%Mz^iozFOWocRDL}H&G&#=Je6Y7Ha-<@ac~a2 zi~7N6^;6dqw0M47^Z+L~MFF~_1iDF$JrQ5Z+W0d1MN4;pZfyTHMR4sWyeUfF5!;6o zLfB$NGH`JCxO{{$3$73jNts!H(A>ur?v8oTfra@LqYb_Nk2NB`5__E z39kocvAZ;hv>n|dU~CVgR++B+wj;W<{hxQEfEAGveIWm~S(ZnM^$|oK6*c{&eTVr# zVu~`cje+baLTn=rPxe;!D6)dhZ`2MZY}D(WTbI=y8CX8#g}^v`H>Cf>s@H_jW_Ap^ z`z#+B3O1`sO{T$kR2E58kVp~xP+d-pS9yP?J@~~Q)16>3dvJ}a+-vYh%Xv9VpWUxhJ z9&NU~bTGXg`X;IUcq7*8sWRR%QU(#GjQR=rqvS2EX}1xpYNUqWdNdD@b#QqSnbyXC zDID=pmBE%I5*qpQb4%p&h(mkI;S=QvI5sFjX^OvXeCE)RB~p-Ki#c;wJV04nIh553 ztz9C=!k7x#+?AMUI5fE+z}pX}4Pf@SVgw$V(QWmO?@mM?)RspE-B15xq3Yz*xSt)i z(6}Y-5^*I!9iRBCt~xx1Ht;uGV-x-qI(xuo7{0t3_Hyr#XGuHKFuXpy6T%Y~)0+Z! zee%Uz{l7zWntc2zGv>_<1v*7UjM&lVVKN>@AJG*Exsk=Wr zHYdjuSzg7;9QRq-;&d))?@tE(`0%T5@t4a}bpu20PtsIOO z-S;i_)A^JU_vp{gDw6jfLmg9Y+IFCPE|*y9E`Hcw{DzKxka!ESeI<2gahrJB17>#! zgI)c-I!W>W5@Bu|(;)WSqwUz>Io{(FCP7j|K(?k{`In}!JeXBvQzA!xNLK<7#sls!kRulJ6wF6 z%%G6Wpgz^VD_R7w%xSRD^>L7iVz+;CvGm%V-!^!jD&!NY=AfK(NlD>Ig?6${={}17 zlfEOnzWwe8QJ%5QOS$>^9TobKAES+-FTowNLj8+{il;M=iUZUJ!HK!OS4a1??`(!y zLqe_gf0%yU3tDg65exqW|66F-8twV?!fOT25bfZbp@$YDS#O)55aXbw-l)Mt^@_-^ z$c)3o{f>afn}1YOGd2)E58k35_DJd6m&*uXiH+ji4Z;)2_lL7Gf>)GAQl-(+M*rG* zMxMF<3oc3c+$4_#&a-U2m=pIKyYsY`+mv<^9xZXb7detDe!i^aDb^tAa!lxu)W`}) zl4Ik}l5+FgyxoN*)x|S6c*V=5&d{Fh)9<&FzBO$Q^*6;toEq?i&p2GBy{l-6l=!{1 z>EFjp9F#JBc_-$|{`m;p>GScXEgo8Mqx`%3r)A2?2bQ!0hvZ)#v|m2Shat4XnB=3Y zw4>DI;~d)Y?d0DTwBI$!Crz}I&g4J6v_AvMe`)(e!XujjVWU<*mgEiM=V%FA2AIDb z+W7=*Djl2H@`$pRVFrtUTAFr&w{Z@Ss{d?vfsbjP2sWKl=j_w-wzOTXy9aml7C|yxFlVg zR5TL*>D~!->kOE#b?Utn=J8ZuD7aX~2Zc27m1b+kscchPg!pWtY5TS};6<^wl^%>n zetq@)y1ZDDURku?>k`#~56{ccMwJX)bf+IJa236mf2OZ6aK=*aVLhH+`TI;`t0~*# zhBITYMp!zUJ#fXv4?|Di@%u5q>s9tw^qc*wHs5-G_nUVnWZdgY03yD@$y#xtsIgxXfp%ok zr-j6fC8>plkv+_8Bl!mV%CwEJBgfv1IBlA&gO)8_Fm>?w9mOkN5yA;`2=NZI_mEWC zn)xzQ@z_Mf;jt4$i}7k5$obP?tn-M`KWQ7L=r0UrDdk0qkLI-}oWF!U`|;sRgldg- zs>6pMD-;v+?|{2_PJLTrCda_$_GWlve;$6E$rz=@PkHJoB_VfoAM{P3ulS(nHkI}A z$EpR9>(@EgmEtTBIcE?)Ykj*M$#sM^Ws&Nojr}a6l}i($a}CIdVF_v@bn>mxXOvayK4+R+ zE0m-X<9EaVnD;+JI%hi+f95TpyM=FKQsLKjzb?>g6}qkEU*spq_+0xJIS?FR_+8+J zrl(uk3PN(6cU$;YR}3A$Kj8kA{>on`vL=qc|CSv4+vEG%!0AZwpnwB*Ir%SH)GE>| z@514yphsWha{@h;Mjpm77m)B$_%CnClOE?5QzS}(8*=J0)1%2!^&}-u6HjRyVW}ws zoWC{F3TzlSC!dn9q3v!hgZjq16y5IC6aR5lWcrsu4zLw)a^ z0o2JLo=G~tce;ZcWQ2qv0_Pw{AW@B$TVK>uRAtfZEb({}-xMrUul|#S%>r(8J~ub6 zYe{Igbflhl97WqNgtu}+^|-d($Hrc>1m!pOU3h5VW|tDxNYODWZ8TA-!B*~ht5+5W zM1y4ocjt!k`=5Dv^OG@03MMstocRF|n#|3+%o6$LW*GZ0>Y@Q@$AUCLhW2fiYzWsr zym<}_F?mplIb61Ipf_TTiymMMc0+?rY%e7A@~PfB+o%_+1{EyULgA4xEM*zZEWq*^HE?j&Hhosj2V;Df{_@`vGJS#B`$VU*29^>qgSD+ZiGRp#O}^^a zXc;Y&uaU$EWDk5=tk|wbA?z3`&o5@kBU6RB@F?Zr=ehDZA0AAv7d%vq`)=vQ|E>@Z zc!bSV$$zFGxhnBsg^;)5W)f|rHaoxBV5jj9s*J*+()CjnDKj^hP*2WnDgD(ZlTNE_ zHHQ~iqefXmThXbBFU{{tlDTQe>uOrX8dfL{gzP1FI+$O@3(ORVF$ieua1dM!Vm6YB zGU`h8pMhNx$q`1<*}v^5Q@S7*NeJs6YX-?EBam^WjR3-u^y25$&BPJWZwmu_UDdbs zP%6u08Q@ zO;M>*4IdqsdR$$j`JDYFcHKC0-l7Gse!H>a%G_nC{PxwE4x36Yvs4cF1GbKW8#HoR zmreUbievVDwXI3$3C$4wcshC@eEr?33|%LyZ0Oy;)D)ytB+}@(MUUYkMR$`|z%oWQcT*%u3bZ?@b-_Sg$ zV!ONkh+IZ@>*7!7!NZ!^tUb;W@Ip-^Rf8l`bkU@c!aOSh`p_TvASwG3Q^{lI3BTej z7Q?sFm)n>PmV*Jc!FJ^5$cLhE$7Tt~s9F{y9)q^#fUfIwui>3)-0r_bX8&Y}9`d!E zH&?>H0A?0sT<+1>o0lg4W|!rWFWlwH3NK*LH+ra8zPWr?SEl24m4aijl$Oj$7--A{Ylxc+aVj^4ji0_iQ} z7Q1w3k*l8l{WDOXM?#9>X6 z{NDJym2-P$#@p9?xiHL|snY3V6)N_(sIuscOCUqFQCyI5*|_;f{;wvb5A{MqKc#$Y z*bhEu>zz+#KEK@p8gP0} zqgtp7J%}MaE2m13f>qp#9mx1S7hbELK&KP&d$-{JwH4)8qEiq2TJPyrit?H0GRqy} z4oSAD2h!PbB@|~fv_w33tSDFZMa8y%Zx9KlZ+RU3TSN`;%F*M+pua zEu_#6@5s`COI=HsyK)A1BB%sO9r%=P*Wz79aXsGZ?S9`o9|m83crYphI7Ww@xA4mV zVC57fE!^*Pwg2kGBmH9*+CIm>7{{SXDT#;NGUJZOq%C(|(FAg~T9gcSlJ|`NZlW z9P-_Ot`r;V1^jvDX{|P6(f%EVD6rlYAMW-kHogqae8ck>ee^&7@aEoS{o2I55Q%MN z#WU}^Bw6r&Of~Ue;u&kJ-H7BV82bx9ql7-S3w@1J z^Q5WhOZCeK8=oB_;JU>`F8Jmm(!@X8ip~$9Kj0IbYn0QfrB0`foyBqR2V6hx)&xmY zt5G;q^!f1?F(xaq|DwcoI>gWI$*RwYr!lmOkz{mtByjd9gMQ}MixPBu;$CV}e$i4v z9a3R?Qc-HsanaJ3JEX7gNvEjE+=!OR>X5m$CsUv%TO2K0)**X$Pqs=;?qRfCLx)_; zo?N?{{Nrf(XC3k(0lYsEEJ0xLFWwRkGxF1Fitjsc8|}IFY~m+TiYw7d-_>OPD~#V} zPcZ9H`rV=YZ$=0UVR%V^=A!aU0N`7lSZgHobOAti%H~p3(Tl*vJ!QpxHPv^r(KJ&A z_iRKg1#&J`q>U=lOcg<48Bl$)c(jHh2~7`X7p9`$s-c5AHN*DB=K-cns)$Xm?XR7qI6YJ)Y7vfwDqpPe|x11WZUVJa5O0md14>uDT_Y0ruQoT8X6y~kuD zjS=)ZNkd*t$FfU;FpK*3PHYw}s!NcHfdJWLNE<<2S>5c0qbw)Q(14a=;Da;#vM*uM zCHk$?oDFBl!KtT5krb~s_Bjw0 z0_qZzG3KJxmez~<=Cj&s1gjQxQHdI{DYT_|zs=WohSDS(x@rg|4|n^~vsfw!)rY(Y zFrCa=EB>;#twwC9V>MzibeuZ(9Z`k*CfH&uRs-u0Ygpi5nB~RHo5HqAV19yjdQ5hr zc`29?PG#ILXPUVQ9^I|(hwUKonQ;@lU>T6C1*(cr}V52NAjR62@)9HM! zSnEC7Y3;xxOOyj2gUJHvIB*NQk`X3U&??2ZH_p(Fs8U4*U36x!a&~gj@a-#hDA@6`C-MZK7z-k2(~OGxnrnwPVKCKfHqQ5c8Oi_;4^L^OVI zD1PtY;2e<0Wi-uYAe{z3-2UMSfo+U25#iCyYK$R^8G%C@yw$bZ?V>qsEFfP8${yxj z6bc~1Rsqd8fMIXOTQVWq7+*4*mhZKy3hsOn|nL8P7Wfn8y2`d++;@8^lV41-^H&iwm0Gzu>nREkb3` zYV<=xeQMf@RT{d-LAJMuR2D$`n;tl>sB=VE$*WO!bU+ha%r@4=-YC$qp;RrsSH*nXRdbrb}B-xD%h>t z=P@NdCjshS1?fq^xY6c(^tdznZr^Y^63IMNhgJJTBx-Ou;=QW11}Hk`65;azAWU#M z(}Y6K?{u?K*hQxH=CgFn@;g@|A#LrhRm-jC4u%TSa5hg%{5Dj=p9 zcCG7<2)Wpl4A~==cy%JL9A}hpl-$*U@`8|7RDkyganU(0fiJ+2h!8_V%gZXPyZ!g6 zey?erGR-JcIub(tY2stDf86Dq7F28=6`@N7no-aXmvbKfF8NaiLy1BOC9q}+GWvJf zts_AA2%Y+*jFxi6?x_P)u>!F_+T8~Z^;*3qlb5HE+>{$$9Spdd1uf=<|9hb44`fA# z3AH}3<{rM~I*f(>ARaud0K?>QDfI55Yr5MPnEO~A30@|K+!nQ!$5qDlsl{AGSS*=j z`>avkInxaQjqdyQ-cem^DK!LgVg{H@0Cvte6@YN3qRFc!o>_|5!-Ncrr7Dj)fLPt> zf}OP=Q_xMR`U5d=VN{cc7nBoYr$*@N$P^m|G5U69Josm#fjDWErz zBR$Xj^hC^Py`QVHw_?IjUJCVPFTuinM9ck=A5@1+f>wfx8<8!O+!c5B zwE020WSBEigq6U|{=5{T*GD&>NH>d&O@Jf*is)-Yol!X=DCj&nejB@ z>V%Dz{P-KK!htR=xmOxri*A>|P$ylFOS>{W`xCkmQ`CWi%j~*9mUMTbD9FhvVKfUs z0_1cLH@fU+Fe%U@Q;ascYRHiKK_LF@atwreToFTI;TRVAcxw#+`2%bgy%6=@k8cwv zyuk5ZnmSb<;vc($`rk1*1MP7H7mvzf>263Rt+JU5bG8mciO_121~Fw5VCB~l<^Nz} zha$r-Fg!eZU%(#oFtgF@w;ot-(#V_QFREJ`j_SZ8C3=`Q6qZPdE58-3yJ5Ux4iUR+ z@|W!An-xdORdHR=2N)`?B3=>rmtOda-Xq(dPg0IdCBWhdTK`t16EG1@_V0-Z6X2sB zWi3O{UW9P(Zf9asSF^y=_f6bRe0@;gyD$J~TO%SuML*iT_()6n&~OS1t@27Gz|XtV z=>kBsBV9UCwd}>MWWk~9U7ZgPMWj4NE|HYlbU0RtFwP#tc|rfXf(-fd?Qet_NEhU1 zg+QbH>}CQCx~Q$8cdFVYiEM-}5!#W639qWokq9f9v7h?B{e^;i)%(xZvo6_o`^BiF6KO51(^E!W3esKMyZCMl4}Vw1UxXCs`)@C3+FXVgFZ**%7pK2= zLE3Yds8LJ0oBNCZB3_hc0G$D3h!}UL3xK-VOd-|YUN|$*t)Ohs-5;l& zub2Ph&|>FTX^3_kdiDG-LMze%HWbQKwxq^4^%NUESoiKU$MU)M=cUox@|Px`KiglM zs7Fa!czvstGX_EVUXEcJG-*28Ab zj240v5_ef(UnV`Uz5_@Ibypc8n4WNw>=iisZ0X#WL2PNj`5iF7Yqu)S=`X-a!pQQa z<%6xB*+Ch0K(rkeZjN@9j6~tFxjrK`Ve;^01f~?lCO#YMV59eI7Au7Xsq|xLf^27S z&4ir$Ysf_=d5jAQ8@R4HU=aJbpZh}8590w2tUBwO-)*wWwC*$O#o-GBOd|uL@uve2 z1OC4bpF(JXCVkAc-nC$_DrT4YmeAG4&DQ6K8=H?PaQUsaLGF;|ctTLs5F1+ivxPiT ztz$~Ug=@h?KD@gxk69sBWenkt0cBnPv{yneE+dN=yY}fxHHQQTn9`5DO&HyFcfooa z7r3U;R5Ft0t6itCw6?ifo5MHcRJi)*ZmG7nt5Msyk59lvdN5zsZ2|L(h_^f~l;2y3 z9s99<1|dS<+s8tq1EUClS_fl82W}2Cn#wS+xQ>R6;rNz?wmX`PV03 z`6-_?O`i@sg}f!wDIHVOc*2htGNoG+qxIxpk3z&_^GDb;CsP<1#07VVT%tEs`XQ#J z0BqS)R&NACcdfO#LqQPpj5~(4;ABn9E4=@^cqswJV48ReFqBP9>#lVFHwoU5a;16o zJI7$WNUL74#8FlVd1~A~_^|N?7w4@=sQ3cTyWnSkO;Q@yWJvBG$l!7p?q^X>GI9N; z>vZoCWYP<^ELF+y+mMA|lyX{Co1r)vP-1RVsoz1#QYWLY+NHqR=O}r{Vd4y-WVkAV zXGw4;6~$PEFg5FEFW*Uopu3imj~TA@f(pIW6L!&z^jbF+#m zpuXA47tGgG0b!*dH00Ktj%5Lesj)kgMZ$$TD?`3f{1M-(LL#)ygT zUP1oN2NKfeV|kosEk8F=p}50Au_sY+S_i(a!7>BBDRu!S3at8>SPJ;-PO(;Kwa|N` z0g>(e+@}+M>>@}25U8ul`;UF51-)gOg?*2iXS!Y4@UIU^};aeh4M zn;M6ngbBkfS5xoN)CVO$m$vohk6FOdx^h?y4N65ve0JD#^kRpr?y4*aPVf7=Q^0P{fF|7W-|EhhYeUl`fpp7n zV1Z)_!Y0z^&DD$9tR@go%O8(-nhGk+f&N=o#qfBLI_&E40E)Ri)3Vg86F=9U)7U?E zkjagS?;en@>|<=)k$v5kIH*0@o|`b?^E3ap$Z4i!eu~1f7zbZa|FLPIv|g4}=flC# zpgr+_{!1K3$K$S(9e1#mW(p`&OoJY#bcAtLEzfNt(5AEeySEwyAFw+rSaqomHBD6=(7&C zDbR;s`Ef1p?uN&8Uj4eAoACTU>z|ju^nN>j`Sj)fo1fSJ^!^99Xth@Dz+&#LI0y;V zwwq*CdV1&gEuFV4rU~w5d;DGeA{xNOjLGn!eEA0ENqj}K-Xm5#UzRa=Hcq?1Lel%K z5Ro#-m6sJZbPslO=wL&*B{a$)hJOje(lf<1w|pzX^V{Ro#21G5Vr#YjeaGkZ%+}fb zYV`QG;ri-IZ-Dgt+G!YD*7!b$(^Yf$Fw3^!_Bpjyx#edmOJJX#HEqI zr@bYuM=d{vzWpLRrTU#arf{6@q}yIw;K@rImVddMpL}hRrgV9P=i>LqWALr%4jIi8 zxyq37&?kAFVcCR1JA+HT?z#l_(yxizZF&EOUXSrSxBd3hqU5NzAotI=wX^BpqjNhM z%6}K>E**_XpQkQZ)5#Q7AtQ8NGn#3}Un;)P`nC`8fvOZ9+VC1F;@-S9VteY?1k*@# zIX_y#65`e*_R*Z>FLi(W;284lc;mn8)N|WMUq-}#UXcy~GD9B2VenBfo{)GDkoddg zs>jFZOL%mpR@hjSIN^Xx+tiXqwB*yaJcbpIr7CG8r|A9dx4w?Y(7 zP^&X$*iLY=gIixxUFZS#a+;0ev2PX5Z*UsPj*?L}!{&OYc9od%%xYokO>z4^K~)a; zJJ>r>Tz$RZx!2_sWUqgvO93E@I* zm*0zW^ZT)B9N^@kT#qEUZ$a>*%eEKaYwM-ym{N^>ei`LQ;`gYw>Rfp7ST`CKN$iKh z*BtbYeVq<{dq;DE_fz|KNmbSAHL8$|9hNU6Y&6{)vb9602HL4ly;B+E)4IIfa%b3M zRFs^teiwLi7c>37n`Vg8!MyNNXF18MwOE(Bn)43tt+jof#JZ##_b{>Os9-}sdw-t# z1e^MdE0NQwE6X{?4Lp)6f`kESO_^IS*TXgsd`fnGt?6$h4|~2JaL_wa5F#7ptAG)7 zQA?$Ff*S~z0&~Bc&?yi&neEXoRj_lrFd96Nn01GK?M`Nv31jJPRHjrG_p`tsrgVdZ z^uojBf^^1Fm4bBoAX*CGmCqp6hNL6sC7aXz7nzsT5ctwGSGgzhD3F8 z^P{xltJKk~cL%V%X}f4sA9;%!b^SK=rcZ!NTY3BlZ-m|5Yj*PdCU=FG;p67=hJiMO z7+%5vgdgSC^u02AfW-*|TKXLsrK%~eLI>S&4!KN5jNdW+n6PI;XO{*u!%89Y=~nH; zE)&49)ci~NbYOOP;2pY~r5v<%QQci$c)kPtHV6DDv088=^QVlz-;RzcQ2l$o${Su? z4yk^Cf_qaC!tQV(6bg?ADQDLxu%6?72Qme8OfkqnP4FeM4q`oDmERwc6)WaaP@WO_ z-U|jlVKD+EAS4|jjNYFmT~pQvl>?a-OZwtdI@ocrq`0y(0Y-E0R`rzd{Y*^RlsB6*KAsAF&m2mXN=lv<$t!BU+chJkBme0S}Uq zT&!?NilR$9>+-UM5g_)71na|yZ>xb72nEY~3N}?i8$+Jr7)Jjr#kXn@*S1^s_UI!g z4y{x$dmGrBEMhGsrGN(kRA1*#u(3B^IHjH5n^n}_2AV>=gs}-p0ayUo;nO5Mrrgs) zh=tf@xXV(v50fXrVu=8VAI0}hiJ1h8PeJFia(wLIZq}0AQ+pI4&8h8WgCN7uA!uZ^ zVL+WWlM&WHn`ZzE+QjqU&sMKug{r|DIIuFtF$hV*B@Rr>O>fz76;Qe=B)jh>?WNbH zUOT>9eK+rCBbvT9bVQ-AM&D0bYQCmQZ-v6%#-F>-4oxEPlvT+!N6J-J$?{LZ%Sn7p zD!dmAQ>PZsZK?`R_Ft#E_teTet^_70l~i4B%N3V>XqGLhKmcEw0$~9$Y@wRC1@clf zv{fqoLIx0|TgbHoV=k-(_Hwyiv%~KaB_IDhO69pKj=)$>BLkB6n$&}m;GVM z&FO{!((HJ!sW?wfia-PV(+;wtEk%Gc5@{+9$`a6Yp+G_w?w9vL3K*JXfM?~RJia-6 zIqb#7UVIm8&Hz?*{z#-%8(;Wzz5Wh2HeX9of#LQP5bniywNNqKl1;-|Fho@or>Fk) zN>8NV$W6)CSebl$Tb*1C+7!id4qKMR4S(?tM9&V@J3Gnbqp(ntVs~D+Mgs1H8s0CX z_E%ZuiHN^Dut5w`Aqp^R18>cN6;#1Sdn|IV5e97x{X}pkEBFCX$7c71wogg;4y-W} zYQYBI-y7RXIlnDFx>inq{dvdpfXo`V@()-^78N=gZs^w|brX)2w(^k3YN#i#1Ed$c`v{oiQx#8LvZjPk9IOo~I8gqgY-IIReW8Gsl{`n}Aj@63Q0$ZLmZzrsgH}uY z@n}NS7a)mz_F9@nMx#Hg&0rmdb9znRjiyj@US<84^rEJRpJ} zr<@tK5Op|dC>esLoWE{GN261D^|eE^Nbuus%BXUVh`a#tmpqqp$iz&0n1mO*OcguV zUv^bh4*paL{RIw;DCeg$nPEF;UW=4HmdiPX%e{}w4oi1Q^$Hy)PeX@v{2E;_nx|p$ zaTX3@nJS?C{A~+q>OOAa_Rg1^IIVCzf0!ZPg$e zLS(N>J^~t)sYb8g2FX|ZTr3K*fB80knzyt4E623gx35|R*>6P`zu!8zF?e*xPQCC& z%)8hyRXPk(r;2^83X*m$Q1M9ErM=_l+BG1$ZqNg+5mh(l@ezS{NV9Mgr_9p_#&=+rDHuBVmgZw+HvR6iRx`NM5R*^cJfsZkzOUstjf0C6X#{Zty19 z$-JEQs_SRLs(|VXzxavsKe#1F@{)cSwGx%`rSi30yWIN2V4jLz8MF$|y@j>)+4|%T z=H@rtXh2@>i5h1+b50+3-e%K8eS8>2dY$vTV&HfE|Mtb9@47QWg!$2@ja!E)it;#aYJUX&~xbbfgB`{Wyaj-og)v3;G|b5E?Q`MnID@A7%Y> z6eJ>QU;97C?mL>z|NkF<7Ks&!Ju7C_Dypbap{lmnYP3;`4yvlED6vP47)4QyR@JV( zN9?UBs%o@R+S-j#Gvw#>9-r^{{qg(d#yXT>pIu$9NP98cOp^o#r}VPM2em6f4jB@6t`JD-2V8} zC{y9~Xj)Ov;1Kc}&z(?EY)?Cq^LGWtzk9G7%=(KX2+a&k=e*`qMd3vusOa#KlISy%m~{4 z_E$ai`$Au=uvygX)Yk3cmlq%Wn*F-%PRhHQB;ho@b7!K+`h(k?+BQ(FPd``Sx?;YR zweM1n?zyU5FUh7zCbLTxoN2S&kFw*>YV7sTH#`PYL}T0(1=I~;D$Z7$fphGEB;1?R7=6==@v9>U!`?kM>y4lD}M^lS9-(z!JllC~^4 z6siLg4!s43yz*Iq>2pPNYU`7eqjeZR`5B-UrO$9P3@0v;`Ike@h5>W)E;GMcrr|zE0 z{xJZdIR88Zv9CioF+LnqS+(KAD9J8{8gwE}jHPufM8%SIZVjS|5p;sOLp=<(SM``` zbUBbZ8M@T>S7pP+WvfB}(tZQulB*?(&e@N5uY0_G;b%{~TT;7gAa^vR)O@~Ykwt8^ zDJ`KL-_<5BjEH7#38iTRDCSi{@c?@;P%7BraB<3x50}+9mO^_0UAEeY$)P(xqBn zOj11OTCp!5mOdu7!4txfj{2p34Im;YAqLHp}Kl2?kQaSdW`0WF(M55|O z+D&So`7e7mzVh@dJsx8Bn|jFZvX(KMna9aNM*qs5e&C+?NQD-(Gj6N(m{^<%WMQ}S7=L`YT2Bj}+pKRtIJ#;f&a6Pt z0n;+I5g6y^^kT(N7sp<&?$>LnRgeK{fbS_3&>5x7o{I_Dq#;;ZaYlze^s~cF1`~fB zjsi@iw5zkDz4=>SeH>IGhPA8P>WaWOO!TG2Jb3HRGJ(?=LCv-KIlM5v`Ta1?Oc+^s zLcW`y4XK8a5eZrG1+Wa0AI#4%?K@V5LGPcZT`ch--5u0NZ`NWG?zy_~&+Y4}nhw}O zCeTnlZ-B-x^Q6E<7op?*YiN24eAs;;3q3j<#gT`<%Ht|3IMAm-aK_miyEwXe!<8W7 zl3BvftMzd73;xPkMO3>5!44 z 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

    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< diff --git a/sandbox/eventbus/lib/event_bus.dart b/sandbox/eventbus/lib/event_bus.dart deleted file mode 100644 index e19ecc6..0000000 --- a/sandbox/eventbus/lib/event_bus.dart +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 8182351..0000000 --- a/sandbox/eventbus/lib/res/app_event.dart +++ /dev/null @@ -1,29 +0,0 @@ -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 deleted file mode 100644 index d23bb2c..0000000 --- a/sandbox/eventbus/lib/res/event_bus.dart +++ /dev/null @@ -1,212 +0,0 @@ -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 deleted file mode 100644 index 65c7a11..0000000 --- a/sandbox/eventbus/lib/res/history_entry.dart +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index c2e36e1..0000000 --- a/sandbox/eventbus/lib/res/res.dart +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 74bbb41..0000000 --- a/sandbox/eventbus/lib/res/subscription.dart +++ /dev/null @@ -1,78 +0,0 @@ -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 deleted file mode 100644 index bb71c80..0000000 --- a/sandbox/eventbus/pubspec.yaml +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 6105911..0000000 --- a/sandbox/eventbus/test/completion_test.dart +++ /dev/null @@ -1,70 +0,0 @@ -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 deleted file mode 100644 index 5aeaf9f..0000000 --- a/sandbox/eventbus/test/distinct_test.dart +++ /dev/null @@ -1,58 +0,0 @@ -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 deleted file mode 100644 index 050505e..0000000 --- a/sandbox/eventbus/test/empty_event_test.dart +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 5d7a5b1..0000000 --- a/sandbox/eventbus/test/event_bus_test.dart +++ /dev/null @@ -1,63 +0,0 @@ -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 deleted file mode 100644 index 9eaf709..0000000 --- a/sandbox/eventbus/test/history_test.dart +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index 496aed7..0000000 --- a/sandbox/eventbus/test/mapping/map_ignore_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -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 deleted file mode 100644 index f83ef02..0000000 --- a/sandbox/eventbus/test/mapping/map_test.dart +++ /dev/null @@ -1,34 +0,0 @@ -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 deleted file mode 100644 index 899c50f..0000000 --- a/sandbox/eventbus/test/models.dart +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index 3c9b5cf..0000000 --- a/sandbox/eventbus/test/respond_test.dart +++ /dev/null @@ -1,74 +0,0 @@ -// 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 deleted file mode 100644 index 1cec696..0000000 --- a/sandbox/eventbus/test/streams_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -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 deleted file mode 100644 index a8dc0d0..0000000 --- a/sandbox/eventbus/test/timestamp_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -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 deleted file mode 100755 index 5313d46..0000000 --- a/sandbox/eventbus/tool/coverage.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/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 deleted file mode 100644 index b1c9c11..0000000 --- a/sandbox/mqueue/.github/workflows/action.yaml +++ /dev/null @@ -1,43 +0,0 @@ -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/CHANGELOG.md b/sandbox/mqueue/CHANGELOG.md deleted file mode 100644 index 70c0899..0000000 --- a/sandbox/mqueue/CHANGELOG.md +++ /dev/null @@ -1,19 +0,0 @@ -## 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 deleted file mode 100644 index 0c5e429..0000000 --- a/sandbox/mqueue/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 2563c78..0000000 --- a/sandbox/mqueue/README.md +++ /dev/null @@ -1,165 +0,0 @@ -# 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 deleted file mode 100644 index 662618b..0000000 --- a/sandbox/mqueue/analysis_options.yaml +++ /dev/null @@ -1,211 +0,0 @@ -# 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 deleted file mode 100644 index c0bf8458db1eca272316fec07d39592eaae9ea4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94259 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

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

    ;2iY&&*OHj2Y*uv8YP>TwVNP!F|O8q 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 S@KgZ}cqz+k$d$=j2K*mBg?*y{ diff --git a/sandbox/mqueue/assets/fanout-exchange.png b/sandbox/mqueue/assets/fanout-exchange.png deleted file mode 100644 index 823a250264b00b16ed712b510c3019df29037343..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26191 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 diff --git a/sandbox/mqueue/assets/simple-view.png b/sandbox/mqueue/assets/simple-view.png deleted file mode 100644 index b24e6b8b30222b1817ebf75e8fc8be7a7e7a4bcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36356 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 Fe*jrDWa0n- diff --git a/sandbox/mqueue/example/main.dart b/sandbox/mqueue/example/main.dart deleted file mode 100644 index 83f3e03..0000000 --- a/sandbox/mqueue/example/main.dart +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index c5945a7..0000000 --- a/sandbox/mqueue/example/message_filtering/main.dart +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 9c6aee9..0000000 --- a/sandbox/mqueue/example/message_filtering/task_manager.dart +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 788c6bb..0000000 --- a/sandbox/mqueue/example/message_filtering/worker_one.dart +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index a4cbd98..0000000 --- a/sandbox/mqueue/example/message_filtering/worker_two.dart +++ /dev/null @@ -1,24 +0,0 @@ -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 deleted file mode 100644 index 8b929a8..0000000 --- a/sandbox/mqueue/example/receiver.dart +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index e45bece..0000000 --- a/sandbox/mqueue/example/routing/debug_logger.dart +++ /dev/null @@ -1,39 +0,0 @@ -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 deleted file mode 100644 index 98f6e8c..0000000 --- a/sandbox/mqueue/example/routing/logger.dart +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 4136032..0000000 --- a/sandbox/mqueue/example/routing/main.dart +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index e7c345a..0000000 --- a/sandbox/mqueue/example/routing/production_logger.dart +++ /dev/null @@ -1,29 +0,0 @@ -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 deleted file mode 100644 index ba05996..0000000 --- a/sandbox/mqueue/example/rpc/main.dart +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index a2d4f97..0000000 --- a/sandbox/mqueue/example/rpc/service_one.dart +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 20e4ba2..0000000 --- a/sandbox/mqueue/example/rpc/service_two.dart +++ /dev/null @@ -1,46 +0,0 @@ -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 deleted file mode 100644 index 6d9b842..0000000 --- a/sandbox/mqueue/example/sender.dart +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index e3736c8..0000000 --- a/sandbox/mqueue/lib/mq.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// 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 deleted file mode 100644 index c93d94a..0000000 --- a/sandbox/mqueue/lib/src/binding/binding.dart +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index 18fd762..0000000 --- a/sandbox/mqueue/lib/src/binding/binding.interface.dart +++ /dev/null @@ -1,44 +0,0 @@ -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 deleted file mode 100644 index 8d42065..0000000 --- a/sandbox/mqueue/lib/src/consumer/consumer.dart +++ /dev/null @@ -1,95 +0,0 @@ -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 deleted file mode 100644 index 6890099..0000000 --- a/sandbox/mqueue/lib/src/consumer/consumer.interface.dart +++ /dev/null @@ -1,74 +0,0 @@ -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 deleted file mode 100644 index b3bc347..0000000 --- a/sandbox/mqueue/lib/src/consumer/consumer.mixin.dart +++ /dev/null @@ -1,92 +0,0 @@ -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 deleted file mode 100644 index 582d02c..0000000 --- a/sandbox/mqueue/lib/src/core/constants/enums.dart +++ /dev/null @@ -1,22 +0,0 @@ -/// 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 deleted file mode 100644 index 0ea4dc5..0000000 --- a/sandbox/mqueue/lib/src/core/constants/error_strings.dart +++ /dev/null @@ -1,99 +0,0 @@ -/// 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 deleted file mode 100644 index 898f5f1..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/binding_exceptions.dart +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index 9cd76cc..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/consumer_exceptions.dart +++ /dev/null @@ -1,73 +0,0 @@ -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 deleted file mode 100644 index 77c94ba..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/exceptions.dart +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index eb9336f..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/exchange_exceptions.dart +++ /dev/null @@ -1,44 +0,0 @@ -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 deleted file mode 100644 index bc2c819..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/mq_client_exceptions.dart +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 5a2947d..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/queue_exceptions.dart +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index c5ef09b..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/registrar_exceptions.dart +++ /dev/null @@ -1,43 +0,0 @@ -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 deleted file mode 100644 index 407b2f0..0000000 --- a/sandbox/mqueue/lib/src/core/exceptions/routing_key_exceptions.dart +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index 472d4c0..0000000 --- a/sandbox/mqueue/lib/src/core/registrar/simple_registrar.dart +++ /dev/null @@ -1,100 +0,0 @@ -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 deleted file mode 100644 index 4c20164..0000000 --- a/sandbox/mqueue/lib/src/exchange/default_exchange.dart +++ /dev/null @@ -1,86 +0,0 @@ -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 deleted file mode 100644 index 2560f29..0000000 --- a/sandbox/mqueue/lib/src/exchange/direct_exchange.dart +++ /dev/null @@ -1,89 +0,0 @@ -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 deleted file mode 100644 index 18e8184..0000000 --- a/sandbox/mqueue/lib/src/exchange/exchange.base.dart +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 638ca72..0000000 --- a/sandbox/mqueue/lib/src/exchange/exchange_interface.dart +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index a7a225e..0000000 --- a/sandbox/mqueue/lib/src/exchange/fanout_exchange.dart +++ /dev/null @@ -1,70 +0,0 @@ -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 deleted file mode 100644 index 57e101d..0000000 --- a/sandbox/mqueue/lib/src/message/message.base.dart +++ /dev/null @@ -1,43 +0,0 @@ -/// 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 deleted file mode 100644 index 053ab13..0000000 --- a/sandbox/mqueue/lib/src/message/message.dart +++ /dev/null @@ -1,86 +0,0 @@ -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 deleted file mode 100644 index 2acafd7..0000000 --- a/sandbox/mqueue/lib/src/mq/mq.base.dart +++ /dev/null @@ -1,14 +0,0 @@ -/// 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 deleted file mode 100644 index 1f48e6b..0000000 --- a/sandbox/mqueue/lib/src/mq/mq.dart +++ /dev/null @@ -1,256 +0,0 @@ -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 deleted file mode 100644 index a1301c1..0000000 --- a/sandbox/mqueue/lib/src/mq/mq.interface.dart +++ /dev/null @@ -1,115 +0,0 @@ -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 deleted file mode 100644 index 2ec6bb5..0000000 --- a/sandbox/mqueue/lib/src/producer/producer.dart +++ /dev/null @@ -1,91 +0,0 @@ -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 deleted file mode 100644 index 2fec00e..0000000 --- a/sandbox/mqueue/lib/src/producer/producer.interface.dart +++ /dev/null @@ -1,56 +0,0 @@ -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 deleted file mode 100644 index 5953fbb..0000000 --- a/sandbox/mqueue/lib/src/producer/producer.mixin.dart +++ /dev/null @@ -1,90 +0,0 @@ -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 deleted file mode 100644 index 5cb83f6..0000000 --- a/sandbox/mqueue/lib/src/queue/data_stream.base.dart +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index f03e00a..0000000 --- a/sandbox/mqueue/lib/src/queue/queue.dart +++ /dev/null @@ -1,60 +0,0 @@ -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 deleted file mode 100644 index 7985374..0000000 --- a/sandbox/mqueue/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 23d87c0..0000000 --- a/sandbox/mqueue/test/binding/binding_test.dart +++ /dev/null @@ -1,97 +0,0 @@ -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 deleted file mode 100644 index f7fb078..0000000 --- a/sandbox/mqueue/test/consumer/consumer_test.dart +++ /dev/null @@ -1,333 +0,0 @@ -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 deleted file mode 100644 index 8d0e1bd..0000000 --- a/sandbox/mqueue/test/core/exceptions/binding_exceptions_test.dart +++ /dev/null @@ -1,24 +0,0 @@ -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 deleted file mode 100644 index 0e302d2..0000000 --- a/sandbox/mqueue/test/core/exceptions/consumer_exceptions_test.dart +++ /dev/null @@ -1,60 +0,0 @@ -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 deleted file mode 100644 index da20214..0000000 --- a/sandbox/mqueue/test/core/exceptions/exchange_exceptions_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index d38a122..0000000 --- a/sandbox/mqueue/test/core/exceptions/mq_client_exceptions_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index a0be43a..0000000 --- a/sandbox/mqueue/test/core/exceptions/queue_exceptions_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index 8f1d3f9..0000000 --- a/sandbox/mqueue/test/core/exceptions/registrar_exceptions_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index de8f389..0000000 --- a/sandbox/mqueue/test/core/exceptions/routing_key_exceptionss_test.dart +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 975d699..0000000 --- a/sandbox/mqueue/test/core/registrar/simple_registrar_test.dart +++ /dev/null @@ -1,105 +0,0 @@ -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 deleted file mode 100644 index 547f9e1..0000000 --- a/sandbox/mqueue/test/exchange/default_exchange_test.dart +++ /dev/null @@ -1,79 +0,0 @@ -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 deleted file mode 100644 index 0f0de29..0000000 --- a/sandbox/mqueue/test/exchange/direct_exchange_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -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 deleted file mode 100644 index 3332216..0000000 --- a/sandbox/mqueue/test/exchange/fanout_exchange_test.dart +++ /dev/null @@ -1,69 +0,0 @@ -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 deleted file mode 100644 index 86cc658..0000000 --- a/sandbox/mqueue/test/message/message.base_test.dart +++ /dev/null @@ -1,59 +0,0 @@ -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 deleted file mode 100644 index 0c81eea..0000000 --- a/sandbox/mqueue/test/mq/mq_test.dart +++ /dev/null @@ -1,342 +0,0 @@ -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 deleted file mode 100644 index 1b3494c..0000000 --- a/sandbox/mqueue/test/producer/producer_test.dart +++ /dev/null @@ -1,111 +0,0 @@ -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 deleted file mode 100644 index 0b80082..0000000 --- a/sandbox/mqueue/test/queue/queue_test.dart +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 454fea2..0000000 --- a/sandbox/reactivex/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# 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 deleted file mode 100644 index 9c6e7a0..0000000 --- a/sandbox/reactivex/CHANGELOG.md +++ /dev/null @@ -1,775 +0,0 @@ -# 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 deleted file mode 100644 index 261eeb9..0000000 --- a/sandbox/reactivex/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - 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 deleted file mode 100644 index 4f6f0da..0000000 --- a/sandbox/reactivex/README.md +++ /dev/null @@ -1,277 +0,0 @@ -# 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 deleted file mode 100644 index 6f808f6..0000000 --- a/sandbox/reactivex/analysis_options.yaml +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 2003c7a..0000000 --- a/sandbox/reactivex/lib/angel3_reactivex.dart +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 113180e..0000000 --- a/sandbox/reactivex/lib/src/rx.dart +++ /dev/null @@ -1,1357 +0,0 @@ -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 deleted file mode 100644 index 9ed4331..0000000 --- a/sandbox/reactivex/lib/src/streams/combine_latest.dart +++ /dev/null @@ -1,352 +0,0 @@ -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 deleted file mode 100644 index a451e6a..0000000 --- a/sandbox/reactivex/lib/src/streams/concat.dart +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index 17beddd..0000000 --- a/sandbox/reactivex/lib/src/streams/concat_eager.dart +++ /dev/null @@ -1,88 +0,0 @@ -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 deleted file mode 100644 index bf4a5cb..0000000 --- a/sandbox/reactivex/lib/src/streams/connectable_stream.dart +++ /dev/null @@ -1,516 +0,0 @@ -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 deleted file mode 100644 index 25a8a12..0000000 --- a/sandbox/reactivex/lib/src/streams/defer.dart +++ /dev/null @@ -1,57 +0,0 @@ -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 deleted file mode 100644 index 349909e..0000000 --- a/sandbox/reactivex/lib/src/streams/fork_join.dart +++ /dev/null @@ -1,366 +0,0 @@ -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 deleted file mode 100644 index ee4a6ba..0000000 --- a/sandbox/reactivex/lib/src/streams/from_callable.dart +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index 2384052..0000000 --- a/sandbox/reactivex/lib/src/streams/merge.dart +++ /dev/null @@ -1,74 +0,0 @@ -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 deleted file mode 100644 index fc6b18b..0000000 --- a/sandbox/reactivex/lib/src/streams/never.dart +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 98b6333..0000000 --- a/sandbox/reactivex/lib/src/streams/race.dart +++ /dev/null @@ -1,70 +0,0 @@ -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 deleted file mode 100644 index 83b4c1e..0000000 --- a/sandbox/reactivex/lib/src/streams/range.dart +++ /dev/null @@ -1,41 +0,0 @@ -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 deleted file mode 100644 index 9f8f9c5..0000000 --- a/sandbox/reactivex/lib/src/streams/repeat.dart +++ /dev/null @@ -1,78 +0,0 @@ -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 deleted file mode 100644 index a9d7957..0000000 --- a/sandbox/reactivex/lib/src/streams/replay_stream.dart +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index f90cc97..0000000 --- a/sandbox/reactivex/lib/src/streams/retry.dart +++ /dev/null @@ -1,89 +0,0 @@ -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 deleted file mode 100644 index 05e6073..0000000 --- a/sandbox/reactivex/lib/src/streams/retry_when.dart +++ /dev/null @@ -1,142 +0,0 @@ -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 deleted file mode 100644 index 5fd8d11..0000000 --- a/sandbox/reactivex/lib/src/streams/sequence_equal.dart +++ /dev/null @@ -1,95 +0,0 @@ -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 deleted file mode 100644 index 87650ad..0000000 --- a/sandbox/reactivex/lib/src/streams/switch_latest.dart +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index c456b66..0000000 --- a/sandbox/reactivex/lib/src/streams/timer.dart +++ /dev/null @@ -1,69 +0,0 @@ -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 deleted file mode 100644 index 1cbed85..0000000 --- a/sandbox/reactivex/lib/src/streams/using.dart +++ /dev/null @@ -1,107 +0,0 @@ -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 deleted file mode 100644 index 2df9a86..0000000 --- a/sandbox/reactivex/lib/src/streams/value_stream.dart +++ /dev/null @@ -1,97 +0,0 @@ -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 deleted file mode 100644 index 5caf6eb..0000000 --- a/sandbox/reactivex/lib/src/streams/zip.dart +++ /dev/null @@ -1,388 +0,0 @@ -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 deleted file mode 100644 index 4a9f7d4..0000000 --- a/sandbox/reactivex/lib/src/subjects/behavior_subject.dart +++ /dev/null @@ -1,275 +0,0 @@ -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 deleted file mode 100644 index 35bbc6d..0000000 --- a/sandbox/reactivex/lib/src/subjects/publish_subject.dart +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index 5181a07..0000000 --- a/sandbox/reactivex/lib/src/subjects/replay_subject.dart +++ /dev/null @@ -1,204 +0,0 @@ -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 deleted file mode 100644 index 746188d..0000000 --- a/sandbox/reactivex/lib/src/subjects/subject.dart +++ /dev/null @@ -1,231 +0,0 @@ -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 deleted file mode 100644 index c4a544c..0000000 --- a/sandbox/reactivex/lib/src/transformers/backpressure/backpressure.dart +++ /dev/null @@ -1,357 +0,0 @@ -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 deleted file mode 100644 index 1b6044b..0000000 --- a/sandbox/reactivex/lib/src/transformers/backpressure/buffer.dart +++ /dev/null @@ -1,149 +0,0 @@ -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 deleted file mode 100644 index b9e9a9e..0000000 --- a/sandbox/reactivex/lib/src/transformers/backpressure/debounce.dart +++ /dev/null @@ -1,85 +0,0 @@ -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 deleted file mode 100644 index fa2320e..0000000 --- a/sandbox/reactivex/lib/src/transformers/backpressure/pairwise.dart +++ /dev/null @@ -1,35 +0,0 @@ -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 deleted file mode 100644 index b2c5545..0000000 --- a/sandbox/reactivex/lib/src/transformers/backpressure/sample.dart +++ /dev/null @@ -1,50 +0,0 @@ -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 deleted file mode 100644 index 523c180..0000000 --- a/sandbox/reactivex/lib/src/transformers/backpressure/throttle.dart +++ /dev/null @@ -1,79 +0,0 @@ -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 deleted file mode 100644 index 544a1b4..0000000 --- a/sandbox/reactivex/lib/src/transformers/backpressure/window.dart +++ /dev/null @@ -1,158 +0,0 @@ -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 deleted file mode 100644 index fb9deed..0000000 --- a/sandbox/reactivex/lib/src/transformers/default_if_empty.dart +++ /dev/null @@ -1,60 +0,0 @@ -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 deleted file mode 100644 index f2fd2b9..0000000 --- a/sandbox/reactivex/lib/src/transformers/delay.dart +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 5b80eb0..0000000 --- a/sandbox/reactivex/lib/src/transformers/delay_when.dart +++ /dev/null @@ -1,171 +0,0 @@ -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 deleted file mode 100644 index 685b8ce..0000000 --- a/sandbox/reactivex/lib/src/transformers/dematerialize.dart +++ /dev/null @@ -1,81 +0,0 @@ -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 deleted file mode 100644 index f3785df..0000000 --- a/sandbox/reactivex/lib/src/transformers/distinct_unique.dart +++ /dev/null @@ -1,92 +0,0 @@ -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 deleted file mode 100644 index 637505e..0000000 --- a/sandbox/reactivex/lib/src/transformers/do.dart +++ /dev/null @@ -1,305 +0,0 @@ -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 deleted file mode 100644 index c4f99ee..0000000 --- a/sandbox/reactivex/lib/src/transformers/end_with.dart +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index 050e456..0000000 --- a/sandbox/reactivex/lib/src/transformers/end_with_many.dart +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index d9c9bac..0000000 --- a/sandbox/reactivex/lib/src/transformers/exhaust_map.dart +++ /dev/null @@ -1,113 +0,0 @@ -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 deleted file mode 100644 index c5dff2a..0000000 --- a/sandbox/reactivex/lib/src/transformers/flat_map.dart +++ /dev/null @@ -1,148 +0,0 @@ -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 deleted file mode 100644 index e2d2edb..0000000 --- a/sandbox/reactivex/lib/src/transformers/group_by.dart +++ /dev/null @@ -1,157 +0,0 @@ -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 deleted file mode 100644 index a2f372b..0000000 --- a/sandbox/reactivex/lib/src/transformers/ignore_elements.dart +++ /dev/null @@ -1,61 +0,0 @@ -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 deleted file mode 100644 index 4366760..0000000 --- a/sandbox/reactivex/lib/src/transformers/interval.dart +++ /dev/null @@ -1,91 +0,0 @@ -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 deleted file mode 100644 index 724d6ba..0000000 --- a/sandbox/reactivex/lib/src/transformers/map_not_null.dart +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index d58d74a..0000000 --- a/sandbox/reactivex/lib/src/transformers/map_to.dart +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index e0f3d56..0000000 --- a/sandbox/reactivex/lib/src/transformers/materialize.dart +++ /dev/null @@ -1,68 +0,0 @@ -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 deleted file mode 100644 index ff66ae6..0000000 --- a/sandbox/reactivex/lib/src/transformers/max.dart +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 41caec1..0000000 --- a/sandbox/reactivex/lib/src/transformers/min.dart +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index ad574b0..0000000 --- a/sandbox/reactivex/lib/src/transformers/on_error_resume.dart +++ /dev/null @@ -1,181 +0,0 @@ -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 deleted file mode 100644 index a2d4e71..0000000 --- a/sandbox/reactivex/lib/src/transformers/scan.dart +++ /dev/null @@ -1,62 +0,0 @@ -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 deleted file mode 100644 index 1bbdfe6..0000000 --- a/sandbox/reactivex/lib/src/transformers/skip_last.dart +++ /dev/null @@ -1,79 +0,0 @@ -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 deleted file mode 100644 index accf206..0000000 --- a/sandbox/reactivex/lib/src/transformers/skip_until.dart +++ /dev/null @@ -1,82 +0,0 @@ -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 deleted file mode 100644 index 60e966c..0000000 --- a/sandbox/reactivex/lib/src/transformers/start_with.dart +++ /dev/null @@ -1,65 +0,0 @@ -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 deleted file mode 100644 index 7a74a08..0000000 --- a/sandbox/reactivex/lib/src/transformers/start_with_error.dart +++ /dev/null @@ -1,57 +0,0 @@ -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 deleted file mode 100644 index 7c8e401..0000000 --- a/sandbox/reactivex/lib/src/transformers/start_with_many.dart +++ /dev/null @@ -1,66 +0,0 @@ -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 deleted file mode 100644 index aa5f779..0000000 --- a/sandbox/reactivex/lib/src/transformers/switch_if_empty.dart +++ /dev/null @@ -1,119 +0,0 @@ -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 deleted file mode 100644 index 63b63ae..0000000 --- a/sandbox/reactivex/lib/src/transformers/switch_map.dart +++ /dev/null @@ -1,155 +0,0 @@ -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 deleted file mode 100644 index 56a11a7..0000000 --- a/sandbox/reactivex/lib/src/transformers/take_last.dart +++ /dev/null @@ -1,83 +0,0 @@ -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 deleted file mode 100644 index 54fe0d6..0000000 --- a/sandbox/reactivex/lib/src/transformers/take_until.dart +++ /dev/null @@ -1,80 +0,0 @@ -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 deleted file mode 100644 index 8471db1..0000000 --- a/sandbox/reactivex/lib/src/transformers/take_while_inclusive.dart +++ /dev/null @@ -1,74 +0,0 @@ -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 deleted file mode 100644 index b7e3c71..0000000 --- a/sandbox/reactivex/lib/src/transformers/time_interval.dart +++ /dev/null @@ -1,111 +0,0 @@ -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 deleted file mode 100644 index 0564402..0000000 --- a/sandbox/reactivex/lib/src/transformers/timestamp.dart +++ /dev/null @@ -1,87 +0,0 @@ -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 deleted file mode 100644 index 5fdcb4e..0000000 --- a/sandbox/reactivex/lib/src/transformers/where_not_null.dart +++ /dev/null @@ -1,65 +0,0 @@ -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 deleted file mode 100644 index 22a76a6..0000000 --- a/sandbox/reactivex/lib/src/transformers/where_type.dart +++ /dev/null @@ -1,71 +0,0 @@ -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 deleted file mode 100644 index 8e3013c..0000000 --- a/sandbox/reactivex/lib/src/transformers/with_latest_from.dart +++ /dev/null @@ -1,738 +0,0 @@ -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 deleted file mode 100644 index a58f9ee..0000000 --- a/sandbox/reactivex/lib/src/utils/collection_extensions.dart +++ /dev/null @@ -1,65 +0,0 @@ -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 deleted file mode 100644 index 7745b8d..0000000 --- a/sandbox/reactivex/lib/src/utils/composite_subscription.dart +++ /dev/null @@ -1,121 +0,0 @@ -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 deleted file mode 100644 index 04a7766..0000000 --- a/sandbox/reactivex/lib/src/utils/empty.dart +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 33a68c9..0000000 --- a/sandbox/reactivex/lib/src/utils/error_and_stacktrace.dart +++ /dev/null @@ -1,28 +0,0 @@ -/// 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 deleted file mode 100644 index 65adbd0..0000000 --- a/sandbox/reactivex/lib/src/utils/forwarding_sink.dart +++ /dev/null @@ -1,82 +0,0 @@ -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 deleted file mode 100644 index 9d414f4..0000000 --- a/sandbox/reactivex/lib/src/utils/forwarding_stream.dart +++ /dev/null @@ -1,165 +0,0 @@ -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 deleted file mode 100644 index 77e241f..0000000 --- a/sandbox/reactivex/lib/src/utils/future.dart +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 729d44c..0000000 --- a/sandbox/reactivex/lib/src/utils/min_max.dart +++ /dev/null @@ -1,76 +0,0 @@ -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 deleted file mode 100644 index fec6172..0000000 --- a/sandbox/reactivex/lib/src/utils/notification.dart +++ /dev/null @@ -1,169 +0,0 @@ -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 deleted file mode 100644 index d3500d9..0000000 --- a/sandbox/reactivex/lib/src/utils/subscription.dart +++ /dev/null @@ -1,34 +0,0 @@ -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 deleted file mode 100644 index 79f57b3..0000000 --- a/sandbox/reactivex/lib/streams.dart +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index 77bc472..0000000 --- a/sandbox/reactivex/lib/subjects.dart +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index e6ff971..0000000 --- a/sandbox/reactivex/lib/transformers.dart +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index 5892516..0000000 --- a/sandbox/reactivex/lib/utils.dart +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index e54c0bf..0000000 --- a/sandbox/reactivex/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 1ba0f821e5f05f48a09b5989fec38d80eee05aaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54748 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 diff --git a/sandbox/reactivex/test/rxdart_test.dart b/sandbox/reactivex/test/rxdart_test.dart deleted file mode 100644 index ef41ddc..0000000 --- a/sandbox/reactivex/test/rxdart_test.dart +++ /dev/null @@ -1,187 +0,0 @@ -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 deleted file mode 100644 index bd03e09..0000000 --- a/sandbox/reactivex/test/streams/combine_latest_test.dart +++ /dev/null @@ -1,394 +0,0 @@ -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 deleted file mode 100644 index bb77624..0000000 --- a/sandbox/reactivex/test/streams/concat_eager_test.dart +++ /dev/null @@ -1,185 +0,0 @@ -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 deleted file mode 100644 index daacc24..0000000 --- a/sandbox/reactivex/test/streams/concat_test.dart +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 5ff00cc..0000000 --- a/sandbox/reactivex/test/streams/defer_test.dart +++ /dev/null @@ -1,128 +0,0 @@ -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 deleted file mode 100644 index 5708581..0000000 --- a/sandbox/reactivex/test/streams/fork_join_test.dart +++ /dev/null @@ -1,452 +0,0 @@ -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 deleted file mode 100644 index 69b7dca..0000000 --- a/sandbox/reactivex/test/streams/from_callable_test.dart +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index b70975e..0000000 --- a/sandbox/reactivex/test/streams/merge_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -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 deleted file mode 100644 index 4254963..0000000 --- a/sandbox/reactivex/test/streams/never_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index 4e1e793..0000000 --- a/sandbox/reactivex/test/streams/publish_connectable_stream_test.dart +++ /dev/null @@ -1,164 +0,0 @@ -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 deleted file mode 100644 index ef932e4..0000000 --- a/sandbox/reactivex/test/streams/race_test.dart +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index e57739f..0000000 --- a/sandbox/reactivex/test/streams/range_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index f16196f..0000000 --- a/sandbox/reactivex/test/streams/repeat_test.dart +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index 54b1527..0000000 --- a/sandbox/reactivex/test/streams/replay_connectable_stream_test.dart +++ /dev/null @@ -1,229 +0,0 @@ -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 deleted file mode 100644 index 10ee4fd..0000000 --- a/sandbox/reactivex/test/streams/retry_test.dart +++ /dev/null @@ -1,142 +0,0 @@ -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 deleted file mode 100644 index 3d139b6..0000000 --- a/sandbox/reactivex/test/streams/retry_when_test.dart +++ /dev/null @@ -1,224 +0,0 @@ -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 deleted file mode 100644 index 4cbc1d7..0000000 --- a/sandbox/reactivex/test/streams/sequence_equals_test.dart +++ /dev/null @@ -1,112 +0,0 @@ -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 deleted file mode 100644 index ea3f055..0000000 --- a/sandbox/reactivex/test/streams/switch_latest_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -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 deleted file mode 100644 index 4f5f62e..0000000 --- a/sandbox/reactivex/test/streams/timer_test.dart +++ /dev/null @@ -1,140 +0,0 @@ -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 deleted file mode 100644 index fcce284..0000000 --- a/sandbox/reactivex/test/streams/using_test.dart +++ /dev/null @@ -1,378 +0,0 @@ -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 deleted file mode 100644 index e27def1..0000000 --- a/sandbox/reactivex/test/streams/value_connectable_stream_test.dart +++ /dev/null @@ -1,295 +0,0 @@ -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 deleted file mode 100644 index feb7949..0000000 --- a/sandbox/reactivex/test/streams/zip_test.dart +++ /dev/null @@ -1,395 +0,0 @@ -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 deleted file mode 100644 index 5f51cb3..0000000 --- a/sandbox/reactivex/test/subject/behavior_subject_test.dart +++ /dev/null @@ -1,1475 +0,0 @@ -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 deleted file mode 100644 index 1561109..0000000 --- a/sandbox/reactivex/test/subject/publish_subject_test.dart +++ /dev/null @@ -1,323 +0,0 @@ -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 deleted file mode 100644 index 1d9e949..0000000 --- a/sandbox/reactivex/test/subject/replay_subject_test.dart +++ /dev/null @@ -1,478 +0,0 @@ -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 deleted file mode 100644 index 5e05ade..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/buffer_count_test.dart +++ /dev/null @@ -1,125 +0,0 @@ -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 deleted file mode 100644 index 095d657..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/buffer_test.dart +++ /dev/null @@ -1,118 +0,0 @@ -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 deleted file mode 100644 index 0d08c4c..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/buffer_test_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index 8feea7d..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/buffer_time_test.dart +++ /dev/null @@ -1,96 +0,0 @@ -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 deleted file mode 100644 index e8bc075..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/debounce_test.dart +++ /dev/null @@ -1,145 +0,0 @@ -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 deleted file mode 100644 index 8501763..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/debounce_time_test.dart +++ /dev/null @@ -1,126 +0,0 @@ -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 deleted file mode 100644 index da89fa0..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/pairwise_test.dart +++ /dev/null @@ -1,78 +0,0 @@ -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 deleted file mode 100644 index b0137d3..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/sample_test.dart +++ /dev/null @@ -1,109 +0,0 @@ -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 deleted file mode 100644 index f6c0386..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/sample_time_test.dart +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index 3a125e8..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/throttle_test.dart +++ /dev/null @@ -1,160 +0,0 @@ -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 deleted file mode 100644 index a0d55bf..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/throttle_time_test.dart +++ /dev/null @@ -1,102 +0,0 @@ -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 deleted file mode 100644 index 58d252f..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/window_count_test.dart +++ /dev/null @@ -1,125 +0,0 @@ -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 deleted file mode 100644 index 33dba73..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/window_test.dart +++ /dev/null @@ -1,123 +0,0 @@ -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 deleted file mode 100644 index b59f8f7..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/window_test_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index 8c0e1f4..0000000 --- a/sandbox/reactivex/test/transformers/backpressure/window_time_test.dart +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index 6535b42..0000000 --- a/sandbox/reactivex/test/transformers/concat_with_test.dart +++ /dev/null @@ -1,39 +0,0 @@ -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 deleted file mode 100644 index d6325a1..0000000 --- a/sandbox/reactivex/test/transformers/default_if_empty_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -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 deleted file mode 100644 index 3c24d34..0000000 --- a/sandbox/reactivex/test/transformers/delay_test.dart +++ /dev/null @@ -1,127 +0,0 @@ -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 deleted file mode 100644 index 2e37a11..0000000 --- a/sandbox/reactivex/test/transformers/delay_when_test.dart +++ /dev/null @@ -1,280 +0,0 @@ -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 deleted file mode 100644 index c4fdb57..0000000 --- a/sandbox/reactivex/test/transformers/dematerialize_test.dart +++ /dev/null @@ -1,105 +0,0 @@ -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 deleted file mode 100644 index 0775b7f..0000000 --- a/sandbox/reactivex/test/transformers/distinct_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 6c4c9dd..0000000 --- a/sandbox/reactivex/test/transformers/distinct_unique_test.dart +++ /dev/null @@ -1,157 +0,0 @@ -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 deleted file mode 100644 index b99fe28..0000000 --- a/sandbox/reactivex/test/transformers/do_test.dart +++ /dev/null @@ -1,489 +0,0 @@ -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 deleted file mode 100644 index ab28437..0000000 --- a/sandbox/reactivex/test/transformers/end_with_many_test.dart +++ /dev/null @@ -1,78 +0,0 @@ -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 deleted file mode 100644 index d54562b..0000000 --- a/sandbox/reactivex/test/transformers/end_with_test.dart +++ /dev/null @@ -1,76 +0,0 @@ -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 deleted file mode 100644 index 0f9137f..0000000 --- a/sandbox/reactivex/test/transformers/exhaust_map_test.dart +++ /dev/null @@ -1,110 +0,0 @@ -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 deleted file mode 100644 index e1cb944..0000000 --- a/sandbox/reactivex/test/transformers/flat_map_iterable_test.dart +++ /dev/null @@ -1,35 +0,0 @@ -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 deleted file mode 100644 index db994f0..0000000 --- a/sandbox/reactivex/test/transformers/flat_map_test.dart +++ /dev/null @@ -1,267 +0,0 @@ -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 deleted file mode 100644 index 9b896ea..0000000 --- a/sandbox/reactivex/test/transformers/group_by_test.dart +++ /dev/null @@ -1,312 +0,0 @@ -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 deleted file mode 100644 index 9673be5..0000000 --- a/sandbox/reactivex/test/transformers/ignore_elements_test.dart +++ /dev/null @@ -1,126 +0,0 @@ -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 deleted file mode 100644 index 0fa9315..0000000 --- a/sandbox/reactivex/test/transformers/interval_test.dart +++ /dev/null @@ -1,87 +0,0 @@ -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 deleted file mode 100644 index 008d2b5..0000000 --- a/sandbox/reactivex/test/transformers/join_test.dart +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 7f900be..0000000 --- a/sandbox/reactivex/test/transformers/map_not_null_test.dart +++ /dev/null @@ -1,100 +0,0 @@ -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 deleted file mode 100644 index 6e7febf..0000000 --- a/sandbox/reactivex/test/transformers/map_to_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index bcb81c4..0000000 --- a/sandbox/reactivex/test/transformers/materialize_test.dart +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index cacd395..0000000 --- a/sandbox/reactivex/test/transformers/max_test.dart +++ /dev/null @@ -1,124 +0,0 @@ -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 deleted file mode 100644 index ed6efdb..0000000 --- a/sandbox/reactivex/test/transformers/merge_with_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -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 deleted file mode 100644 index 6c2c772..0000000 --- a/sandbox/reactivex/test/transformers/min_test.dart +++ /dev/null @@ -1,117 +0,0 @@ -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 deleted file mode 100644 index ce9253c..0000000 --- a/sandbox/reactivex/test/transformers/on_error_resume_test.dart +++ /dev/null @@ -1,209 +0,0 @@ -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 deleted file mode 100644 index d4d0644..0000000 --- a/sandbox/reactivex/test/transformers/on_error_return_test.dart +++ /dev/null @@ -1,80 +0,0 @@ -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 deleted file mode 100644 index 7ffc726..0000000 --- a/sandbox/reactivex/test/transformers/on_error_return_with_test.dart +++ /dev/null @@ -1,82 +0,0 @@ -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 deleted file mode 100644 index 3913017..0000000 --- a/sandbox/reactivex/test/transformers/scan_test.dart +++ /dev/null @@ -1,85 +0,0 @@ -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 deleted file mode 100644 index 6c5349c..0000000 --- a/sandbox/reactivex/test/transformers/skip_last_test.dart +++ /dev/null @@ -1,110 +0,0 @@ -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 deleted file mode 100644 index fa3a97c..0000000 --- a/sandbox/reactivex/test/transformers/skip_until_test.dart +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index 7a61c09..0000000 --- a/sandbox/reactivex/test/transformers/start_with_error_test.dart +++ /dev/null @@ -1,86 +0,0 @@ -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 deleted file mode 100644 index 7159e3b..0000000 --- a/sandbox/reactivex/test/transformers/start_with_many_test.dart +++ /dev/null @@ -1,87 +0,0 @@ -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 deleted file mode 100644 index 235b6ff..0000000 --- a/sandbox/reactivex/test/transformers/start_with_test.dart +++ /dev/null @@ -1,102 +0,0 @@ -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 deleted file mode 100644 index c1f15be..0000000 --- a/sandbox/reactivex/test/transformers/switch_if_empty_test.dart +++ /dev/null @@ -1,96 +0,0 @@ -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 deleted file mode 100644 index cb86396..0000000 --- a/sandbox/reactivex/test/transformers/switch_map_test.dart +++ /dev/null @@ -1,359 +0,0 @@ -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 deleted file mode 100644 index 64474c6..0000000 --- a/sandbox/reactivex/test/transformers/take_last_test.dart +++ /dev/null @@ -1,109 +0,0 @@ -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 deleted file mode 100644 index 23efaf2..0000000 --- a/sandbox/reactivex/test/transformers/take_until_test.dart +++ /dev/null @@ -1,120 +0,0 @@ -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 deleted file mode 100644 index 7b2f774..0000000 --- a/sandbox/reactivex/test/transformers/take_while_inclusive_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -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 deleted file mode 100644 index 9c1d1f4..0000000 --- a/sandbox/reactivex/test/transformers/time_interval_test.dart +++ /dev/null @@ -1,112 +0,0 @@ -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 deleted file mode 100644 index 5460b1d..0000000 --- a/sandbox/reactivex/test/transformers/timeout_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 0a4cccf..0000000 --- a/sandbox/reactivex/test/transformers/timestamp_test.dart +++ /dev/null @@ -1,105 +0,0 @@ -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 deleted file mode 100644 index fd9c77e..0000000 --- a/sandbox/reactivex/test/transformers/where_not_null_test.dart +++ /dev/null @@ -1,87 +0,0 @@ -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 deleted file mode 100644 index 2eb0158..0000000 --- a/sandbox/reactivex/test/transformers/where_type_test.dart +++ /dev/null @@ -1,94 +0,0 @@ -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 deleted file mode 100644 index 5191440..0000000 --- a/sandbox/reactivex/test/transformers/with_latest_from_test.dart +++ /dev/null @@ -1,541 +0,0 @@ -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 deleted file mode 100644 index 36839c9..0000000 --- a/sandbox/reactivex/test/transformers/zip_with_test.dart +++ /dev/null @@ -1,63 +0,0 @@ -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 deleted file mode 100644 index 2a8f4fd..0000000 --- a/sandbox/reactivex/test/utils.dart +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 66a01e3..0000000 --- a/sandbox/reactivex/test/utils/composite_subscription_test.dart +++ /dev/null @@ -1,316 +0,0 @@ -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 deleted file mode 100644 index 45191f9..0000000 --- a/sandbox/reactivex/test/utils/notification_test.dart +++ /dev/null @@ -1,234 +0,0 @@ -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=* 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≫^W%bmcoP`+kd0y}6MDOTKj~bub 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Ⓢ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%0Dd*Q@IfXn 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