From 54d5aa609d3b9e2b69d5370dedc1c3d62b989dd9 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 12:57:23 +0200 Subject: [PATCH 01/12] docs: add MkDocs documentation site with GitLab Pages CI Add MkDocs Material documentation structured from the README content, split into logical sections: getting started, API reference (PHP, JS, HTTP), guides (Drush, decorators, cache, AI assistant), and development. Includes .gitlab-ci.yml with standard DrupalCI templates to enable automatic publishing to project.pages.drupalcode.org/rl/. Claude-Session: https://claude.ai/code/session_01Cbtzf2mpa3xQKCSkFzJuiR --- .gitlab-ci.yml | 14 ++++ docs/api/http.md | 101 ++++++++++++++++++++++++++ docs/api/javascript.md | 98 +++++++++++++++++++++++++ docs/api/php.md | 43 +++++++++++ docs/development/contributing.md | 31 ++++++++ docs/getting-started/configuration.md | 52 +++++++++++++ docs/getting-started/installation.md | 75 +++++++++++++++++++ docs/guides/ai-assistant.md | 37 ++++++++++ docs/guides/cache.md | 27 +++++++ docs/guides/decorators.md | 69 ++++++++++++++++++ docs/guides/drush.md | 54 ++++++++++++++ docs/index.md | 70 ++++++++++++++++++ mkdocs.yml | 32 ++++++++ 13 files changed, 703 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 docs/api/http.md create mode 100644 docs/api/javascript.md create mode 100644 docs/api/php.md create mode 100644 docs/development/contributing.md create mode 100644 docs/getting-started/configuration.md create mode 100644 docs/getting-started/installation.md create mode 100644 docs/guides/ai-assistant.md create mode 100644 docs/guides/cache.md create mode 100644 docs/guides/decorators.md create mode 100644 docs/guides/drush.md create mode 100644 docs/index.md create mode 100644 mkdocs.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e6d3a39 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,14 @@ +################ +# DrupalCI GitLab CI/CD template. +# +# Project: https://project.pages.drupalcode.org/gitlab_templates/ +# Source: https://git.drupalcode.org/project/gitlab_templates/ +################ + +include: + - project: $_GITLAB_TEMPLATES_REPO + ref: $_GITLAB_TEMPLATES_REF + file: + - '/includes/include.drupalci.main.yml' + - '/includes/include.drupalci.variables.yml' + - '/includes/include.drupalci.workflows.yml' diff --git a/docs/api/http.md b/docs/api/http.md new file mode 100644 index 0000000..6b0cce0 --- /dev/null +++ b/docs/api/http.md @@ -0,0 +1,101 @@ +# HTTP API (rl.php) + +`rl.php` is the low-level endpoint. It is reachable directly from any +client that can make an HTTP POST: browser pages, native mobile apps, +server-side workers, other CMSes, edge functions. Deciding is *not* +exposed here; it happens in PHP at render time as described in the +[PHP API](php.md). + +## Supported actions + +All actions are additive; adding `batch` did not deprecate the legacy +form actions, and `rl_sorting` and other production consumers keep +using them unchanged. + +| Action | Encoding | Purpose | +| --- | --- | --- | +| `ping` | form POST | Liveness check. Returns `pong`. | +| `turn` | form POST | Record one impression. | +| `turns` | form POST | Record impressions for many arms in one experiment. | +| `reward` | form POST | Record one conversion. | +| `batch` | JSON POST | Record turns and rewards across many experiments in one request. Used by `Drupal.rl`. | + +Experiment IDs and arm IDs must match `^[a-zA-Z0-9_-]+$`. Experiments +must already be registered via `ExperimentRegistryInterface::register()`; +unknown IDs are silently dropped so garbage writes cannot create +registry entries. + +## Legacy form actions + +```bash +# Turn +curl -X POST https://example.com/modules/contrib/rl/rl.php \ + -d 'action=turn&experiment_id=hero_cta&arm_id=v0' + +# Multiple arms in one experiment +curl -X POST https://example.com/modules/contrib/rl/rl.php \ + -d 'action=turns&experiment_id=hero_cta&arm_ids=v0,v1' + +# Reward +curl -X POST https://example.com/modules/contrib/rl/rl.php \ + -d 'action=reward&experiment_id=hero_cta&arm_id=v0' +``` + +## Batch action + +``` +POST /modules/contrib/rl/rl.php?action=batch +Content-Type: application/json + +{ + "decides": [ + {"id": "hero_cta", "arms": ["v0", "v1", "v2"]}, + {"id": "faq_sort", "arms": ["t0", "t1", "t2", "t3"], "rank": true} + ], + "turns": [ + {"id": "hero_cta", "arm": "v0"}, + {"id": "menu_main_5", "arm": "v1"} + ], + "rewards": [ + {"id": "hero_cta", "arm": "v0"} + ] +} +``` + +All three sections are optional. Invalid or unregistered entries are +dropped silently so one bad event does not poison the rest of the +batch. The response is: + +```json +{ + "ok": true, + "decisions": { + "hero_cta": {"armId": "v1"}, + "faq_sort": {"armId": "t2", "ranking": ["t2", "t0", "t3", "t1"]} + } +} +``` + +`decisions` contains only entries that had a successful Thompson +Sampling lookup. Missing keys mean "use the default variant". When +`"rank": true` is set on a decide entry, the response includes a +`ranking` array with all arm IDs sorted by Thompson Sampling score +(best first). The `armId` field is always present and equals +`ranking[0]` for backwards compatibility. Turns and rewards are +fire-and-forget writes with no per-event response. + +## Error responses + +| Status | When | +| --- | --- | +| `400` | Missing/invalid `action`, malformed JSON, or missing `experiment_id` on a legacy action. | +| `500` | Drupal kernel failed to boot. Error logged to the PHP error log. | + +## Performance notes + +`rl.php` bootstraps a minimal Drupal kernel per request (same pattern as +core's `statistics.php`), not the full stack that would run behind a +normal route. One kernel boot processes the whole batch, so the cheapest +way to use this endpoint is to send as many events as possible in one +request. `Drupal.rl` already does this on the browser side; non-browser +callers should coalesce events similarly when they can. diff --git a/docs/api/javascript.md b/docs/api/javascript.md new file mode 100644 index 0000000..1f3fd9d --- /dev/null +++ b/docs/api/javascript.md @@ -0,0 +1,98 @@ +# JavaScript API + +Attach the `rl/api` library to make `Drupal.rl` available. It is a thin +transport proxy that coalesces every decide, impression, and conversion +fired on the page into a single batched POST to `rl.php`, so N +experiments on the same page produce one or two requests instead of one +set per experiment. + +## Methods + +### `Drupal.rl.decide(experimentId, armIds)` + +Ask for a decision when the variant needs to be chosen client-side. +The arm list **must** be read from the DOM; see the discipline section below. + +```javascript +var container = document.querySelector('[data-rl-experiment="hero_cta"]'); +var armIds = container.dataset.rlArms.split(','); +Drupal.rl.decide('hero_cta', armIds).then(function (armId) { + showVariant(armId); +}); +``` + +### `Drupal.rl.rank(experimentId, armIds)` + +Ask for a full ranking when you need to sort, not just pick a winner. +Use case: reordering accordion items, FAQ lists, or any sortable +content by visitor engagement. + +```javascript +var items = document.querySelector('[data-rl-experiment="faq_sort"]'); +var faqArms = items.dataset.rlArms.split(','); +Drupal.rl.rank('faq_sort', faqArms).then(function (sorted) { + // sorted = ['t3', 't0', 't1', 't2'], all arms, best first + sorted.forEach(function (armId) { + items.appendChild(items.querySelector('[data-rl-arm="' + armId + '"]')); + }); +}); +``` + +### `Drupal.rl.turn(experimentId, armId)` + +Record an impression when the variant becomes visible. + +```javascript +Drupal.rl.turn('hero_cta', 'v0'); +``` + +### `Drupal.rl.reward(experimentId, armId)` + +Record a conversion when the user clicks, submits, or converts. + +```javascript +Drupal.rl.reward('hero_cta', 'v0'); +``` + +### `Drupal.rl.flush()` + +Force an immediate flush of the event queue. + +```javascript +Drupal.rl.flush(); +``` + +## Batching behaviour + +Events accumulate for 500 ms and then flush in one POST. Decide, +turn, and reward events share the same queue and the same request, so +a page with a DXPR Builder variant block plus tracking on other +elements ends up making a single round trip. Buffered tracking events +are also flushed via `navigator.sendBeacon` on `visibilitychange` and +`pagehide` so they survive navigation. + +## Discipline for `decide()` and `rank()` + +> **Never hardcode arm IDs in JS. Always read them from a DOM +> attribute that the server-side renderer emitted.** + +The DOM is downstream of the same server-render pipeline +that produced the decide's context. When the experiment manager adds +or removes a variant, the consumer's page cache is invalidated, the +next render emits the new attribute, and JS picks it up. JS never +asserts what the arm set is; it just echoes whatever the current +cached HTML says. This keeps `Drupal.rl.decide()` and +`Drupal.rl.rank()` drift-free without requiring the RL core to store +arm lists. + +The convention your builder uses internally (numeric `v0..vN`, UUIDs, +node IDs, anything matching `^[a-zA-Z0-9_-]+$`) is whatever you emit +into the attribute. The RL core is arm-agnostic. + +If the server returns no decision for an experiment (not registered, +no data, network error), the returned promise resolves to `armIds[0]` +so callers never need a `.catch()` for the common path. + +`Drupal.rl` is one transport among several. Modules that already ship +their own tracking JS (like `rl_sorting`, which batches turns on its +own 100 ms window and posts them as form data) keep working untouched. diff --git a/docs/api/php.md b/docs/api/php.md new file mode 100644 index 0000000..1b1497b --- /dev/null +++ b/docs/api/php.md @@ -0,0 +1,43 @@ +# PHP API + +## Experiment manager + +The `rl.experiment_manager` service is the primary entry point for recording +interactions and retrieving scores. + +```php +// Get experiment manager +$experiment_manager = \Drupal::service('rl.experiment_manager'); + +// Record a trial (content shown) +$experiment_manager->recordTurn('my-experiment', 'variant-a'); + +// Record a success (user clicked) +$experiment_manager->recordReward('my-experiment', 'variant-a'); + +// Get Thompson Sampling scores +$scores = $experiment_manager->getThompsonScores('my-experiment'); + +// Select best option +$ts_calculator = \Drupal::service('rl.ts_calculator'); +$best_option = $ts_calculator->selectBestArm($scores); +``` + +## Variant selection + +For modules that follow the "v0 = original, v1..vN = stored variants" +convention, the module provides reusable traits and base classes: + +- `VariantArmsTrait`: arm-id helpers (`getArmIds`, `getArmText`, + `buildVariantExperimentId`) +- `VariantSelectorBase`: reusable base class for variant selectors +- `VariantParser`: static helper for parsing textarea variant input into + normalised lists + +## Cache override + +```php +// Override page cache if experiment cache is shorter than site cache +$cache_manager = \Drupal::service('rl.cache_manager'); +$cache_manager->overridePageCacheIfShorter(60); // 60 seconds +``` diff --git a/docs/development/contributing.md b/docs/development/contributing.md new file mode 100644 index 0000000..a13183a --- /dev/null +++ b/docs/development/contributing.md @@ -0,0 +1,31 @@ +# Contributing + +## Linting and code standards + +Run coding standards checks: + +```bash +docker compose --profile lint run --rm drupal-lint +``` + +Auto-fix coding standard violations: + +```bash +docker compose --profile lint run --rm drupal-lint-auto-fix +``` + +Run Drupal compatibility checks: + +```bash +docker compose --profile lint run --rm drupal-check +``` + +## Issue queue + +Report bugs and feature requests on the +[drupal.org issue queue](https://www.drupal.org/project/issues/rl). + +## Source code + +- [git.drupalcode.org/project/rl](https://git.drupalcode.org/project/rl) (primary) +- [github.com/dxpr/rl](https://github.com/dxpr/rl) (mirror) diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md new file mode 100644 index 0000000..4be705a --- /dev/null +++ b/docs/getting-started/configuration.md @@ -0,0 +1,52 @@ +# Configuration + +## Deciding which variant to show + +### Server-side (preferred) + +Pick the winning variant in PHP at render time whenever you can. Your +consumer already has the full arm set in hand (entity fields, view +filters, plugin config), so it can call the RL service directly: + +```php +$scores = $experiment_manager->getThompsonScores( + 'my_experiment', + NULL, + ['v0', 'v1', 'v2'] // arm ids owned by your domain +); +arsort($scores); +$best_arm = key($scores); +``` + +Deciding server-side keeps the arm list where it belongs (with the +experiment owner) and avoids a network round trip on every page load. +See `rl_sorting`'s Views sort plugin for the canonical pattern and +`VariantSelectorBase` in this module for a reusable base class. + +### Client-side (cache-friendly path) + +Some consumers have to decide in JS: full-page-cached builders that +render all variants into the HTML and swap them on the client so they +can keep Varnish/Fastly caching. For that case there is +`Drupal.rl.decide()`, documented in the [JavaScript API](../api/javascript.md). + +## Cache management + +RL provides optional cache management for web components: + +```php +// Override page cache if experiment cache is shorter than site cache +\Drupal::service('rl.cache_manager')->overridePageCacheIfShorter(30); +``` + +**How it works:** + +- If site cache is 300s and experiment needs 30s: overrides to 30s +- If site cache is 60s and experiment needs 300s: leaves at 60s +- If site cache is disabled: no override + +**Use cases:** + +- Views plugins using RL for content sorting +- Blocks displaying A/B tested content +- Components needing frequent RL score updates diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md new file mode 100644 index 0000000..da6ea9c --- /dev/null +++ b/docs/getting-started/installation.md @@ -0,0 +1,75 @@ +# Installation + +## Install the module + +```bash +composer require drupal/rl +drush en rl +``` + +## Plotly.js library (required for charts) + +The RL module uses Plotly.js for experiment charts. Install it via Composer using +[Asset Packagist](https://asset-packagist.org): + +```bash +# Add Asset Packagist repository (if not already configured) +composer config repositories.asset-packagist composer https://asset-packagist.org + +# Install the Composer plugin for npm assets (if not already installed) +composer require oomphinc/composer-installers-extender +composer config extra.installer-types --json '["npm-asset"]' +composer config extra.installer-paths.web/libraries/\{\$name\} --json '["type:npm-asset"]' + +# Install Plotly.js +composer require npm-asset/plotly.js-dist-min:^2.35 +``` + +This installs the library to `web/libraries/plotly.js-dist-min/`. + +## Post-installation: verify rl.php access + +The RL module includes a `.htaccess` file that allows direct access to +`rl.php` (following the same pattern as Drupal 11's contrib statistics +module). Test that it's working: + +```bash +curl -X POST -d "action=ping" http://example.com/modules/contrib/rl/rl.php +``` + +**If the test fails:** + +- **Apache**: ensure `.htaccess` files are processed (`AllowOverride All`) +- **Nginx**: add the configuration rules below to your server block +- **Security modules**: whitelist `/modules/contrib/rl/rl.php` + +If server policies prevent direct access to `rl.php`, use the Drupal +Routes API instead. + +### Nginx configuration + +Add these rules to your Nginx server block, **before** the main Drupal +location block: + +```nginx +# Allow direct access to rl.php for performance +location ~ ^/modules/contrib/rl/rl\.php$ { + fastcgi_split_path_info ^(.+?\.php)(|/.*)$; + try_files $uri =404; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param QUERY_STRING $query_string; + fastcgi_pass unix:/var/run/php/php-fpm.sock; # Adjust to your PHP-FPM socket +} + +# Block access to other PHP files in modules (except rl.php) +location ~ ^/modules/.*\.php$ { + deny all; +} +``` + +**Note:** Adjust `fastcgi_pass` to match your PHP-FPM configuration: + +- Socket: `unix:/var/run/php/php8.1-fpm.sock` (or your PHP version) +- TCP: `127.0.0.1:9000` diff --git a/docs/guides/ai-assistant.md b/docs/guides/ai-assistant.md new file mode 100644 index 0000000..32e30d3 --- /dev/null +++ b/docs/guides/ai-assistant.md @@ -0,0 +1,37 @@ +# AI assistant integration + +The RL module ships with a built-in skill file +(`.claude/skills/rl/SKILL.md`) that teaches AI coding assistants how +to manage experiments through natural language. Compatible with Claude Code, +Codex CLI, Gemini CLI, GitHub Copilot, Cursor, and any tool supporting the +[Agent Skills standard](https://agentskills.io/specification). + +## Quick setup + +```bash +# Install skill files for AI tool discovery +drush rl:setup-ai + +# Claude Code only +drush rl:setup-ai --host=claude + +# Codex/Gemini/Copilot/Cursor only +drush rl:setup-ai --host=agents +``` + +## Example prompts + +After installation, use the `/rl` slash command or ask naturally: + +``` +/rl list all experiments +/rl analyze hero_cta_test +/rl create experiment homepage_banner --module=my_module +``` + +Your assistant will respond to prompts like: + +- "List all running A/B tests" +- "Analyse the hero_cta_test experiment" +- "Create a new A/B test for the homepage banner" +- "What's the conversion rate for variant B?" diff --git a/docs/guides/cache.md b/docs/guides/cache.md new file mode 100644 index 0000000..98679d8 --- /dev/null +++ b/docs/guides/cache.md @@ -0,0 +1,27 @@ +# Cache management + +RL provides optional cache management for web components that run A/B tests. + +## Usage + +```php +// Override page cache if experiment cache is shorter than site cache +\Drupal::service('rl.cache_manager')->overridePageCacheIfShorter(30); +``` + +## How it works + +- If site cache is 300s and experiment needs 30s: overrides to 30s +- If site cache is 60s and experiment needs 300s: leaves at 60s +- If site cache is disabled: no override + +## When to use it + +- Views plugins using RL for content sorting +- Blocks displaying A/B tested content +- Components needing frequent RL score updates + +The cache manager only shortens the page cache lifetime; it never extends +it beyond what the site already has configured. This ensures that +experiments can refresh their data without interfering with the site's +overall caching strategy. diff --git a/docs/guides/decorators.md b/docs/guides/decorators.md new file mode 100644 index 0000000..9672efc --- /dev/null +++ b/docs/guides/decorators.md @@ -0,0 +1,69 @@ +# Experiment decorators + +Decorators customise how experiments and arms are displayed in the RL reports +interface. By default, experiments and arms show their raw IDs, but decorators +can provide human-readable labels. + +## Creating a decorator + +Implement the `ExperimentDecoratorInterface`: + +```php + 'My Custom Experiment Name']; + } + + public function decorateArm(string $experiment_id, string $arm_id): ?array { + if (!str_starts_with($experiment_id, 'my_module-')) { + return NULL; + } + $entity = \Drupal::entityTypeManager()->getStorage('node')->load($arm_id); + if ($entity) { + return [ + '#markup' => htmlspecialchars($entity->label()) . + ' (' . htmlspecialchars($arm_id) . ')', + ]; + } + return NULL; + } + +} +``` + +## Registering the decorator + +Add the decorator service to your module's `*.services.yml` with the +`rl_experiment_decorator` tag: + +```yaml +services: + my_module.experiment_decorator: + class: Drupal\my_module\Decorator\MyExperimentDecorator + arguments: ['@entity_type.manager'] + tags: + - { name: rl_experiment_decorator } +``` + +The decorator manager automatically discovers all tagged services and calls +them in order until one returns a non-NULL value. + +## Best practices + +- **Check experiment prefix**: return `NULL` early for experiments your + decorator does not handle. +- **Handle missing entities**: entities may be deleted; return `NULL` if the + entity cannot be loaded. +- **Use render arrays**: return proper Drupal render arrays for consistent + theming and security. +- **Escape output**: use `htmlspecialchars()` for any user-provided content. diff --git a/docs/guides/drush.md b/docs/guides/drush.md new file mode 100644 index 0000000..d0afe53 --- /dev/null +++ b/docs/guides/drush.md @@ -0,0 +1,54 @@ +# Drush commands + +## Discovery and analysis + +| Command | Alias | Description | +|---------|-------|-------------| +| `rl:list` | `rll` | Lists all experiments with summary stats | +| `rl:status ` | `rlst` | Detailed status: phase, confidence, traffic distribution | +| `rl:performance ` | `rlp` | Arm-level performance with human-readable labels | +| `rl:trends ` | `rlt` | Historical trends with period aggregation | +| `rl:export ` | `rle` | Exports complete experiment data | +| `rl:analyze ` | `rla` | Full analysis with actionable recommendations | + +## Experiment lifecycle + +| Command | Alias | Description | +|---------|-------|-------------| +| `rl:experiment:create ` | `rl-ec` | Creates experiment (`--module`, `--name`, `--dry-run`) | +| `rl:experiment:update ` | `rl-eu` | Updates name/module (`--module`, `--name`, `--dry-run`) | +| `rl:experiment:delete ` | `rl-ed` | Deletes experiment + all data (`--dry-run`) | + +## Configuration + +| Command | Alias | Description | +|---------|-------|-------------| +| `rl:config:get [key]` | `rl-cg` | Gets one or all settings | +| `rl:config:set ` | `rl-cs` | Sets a setting with validation (`--dry-run`) | +| `rl:config:list` | `rl-cl` | Lists all settings with current values | +| `rl:config:reset` | `rl-cr` | Resets all settings to defaults (`--dry-run`) | +| `rl:event-log:clear` | `rl-elc` | Clears all snapshots (`--dry-run`) | + +## Setup + +| Command | Alias | Description | +|---------|-------|-------------| +| `rl:setup-ai` | `rl-sa` | Installs AI skill files for Claude Code (`--host`, `--check`) | + +## Examples + +```bash +# Create a new A/B test +drush rl:experiment:create hero_cta_test \ + --module=my_module \ + --name="Hero CTA Button Color Test" + +# Check status after data collection +drush rl:status hero_cta_test + +# Get detailed performance breakdown +drush rl:performance hero_cta_test --format=yaml + +# Full analysis with recommendations +drush rl:analyze hero_cta_test +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..ca3e9e0 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,70 @@ +# RL: A/B & Multivariate Testing for Drupal + +A/B and multivariate testing for Drupal using reinforcement learning. Each page +view is a trial, each conversion is a reward, and the algorithm continuously +shifts traffic to whichever variant is winning. RLHF-style feedback loop, no +fixed horizons, no third-party SaaS. + +## What you can A/B test + +- **[RL: A/B Test Views Content](https://www.drupal.org/project/rl_sorting)** + (`rl_sorting`): the order of items in any Drupal View +- **RL: A/B Test Page Titles** (`rl_page_title`, bundled submodule): + page titles for nodes, View pages, and any controller +- **RL: A/B Test Menu Links** (`rl_menu_link`, bundled submodule): + labels in any menu link +- **DXPR Builder** integration: variant slots inside builder blocks + +## Features + +- **Multivariate by default**: 2 to thousands of variants, no manual configuration +- **Real-time RLHF loop**: visitor clicks update the model on every page +- **Fast HTTP REST API**: optimised JSON endpoint at `rl.php` +- **Admin reports**: per-experiment performance, traffic, and confidence at + `/admin/reports/rl` +- **Service-based architecture**: extensible decorators, custom variant selectors +- **Data sovereignty**: no cloud, no SaaS, all data stays in your Drupal database +- **GDPR-friendly tracking**: only anonymous interaction counts, no user IDs or + cookies + +## Why RL instead of fixed-horizon A/B testing? + +Traditional A/B tests run for a fixed window (say two weeks) and split traffic +50/50 the whole time, even when one variant is obviously losing. RL turns the +experiment into a feedback loop: every click adjusts the model, traffic shifts +toward the leader as soon as evidence emerges, and the test never has to "end". +You can run dozens or thousands of variants simultaneously (true multivariate +testing), and a newly added variant is in play on the next render with no +manual setup. + +## How it works + +RL uses a multi-armed bandit (Thompson Sampling). Each variant has a reward +distribution; on each render the algorithm samples from the distributions and +picks the highest sample. Wins update the distribution toward higher rewards; +losses update toward lower. Algorithm details: +[ThompsonCalculator.php](https://git.drupalcode.org/project/rl/-/blob/1.x/src/Service/ThompsonCalculator.php). + +## Use cases + +- **A/B test any content variation** without third-party SaaS +- **Multivariate test** dozens or thousands of variants at once +- **Continuous optimisation**: tests never end, the model keeps learning +- **Recommendations**: rank items by real engagement +- **Smart sorting**: reorder lists, accordions, or FAQs by visitor engagement +- **Feature flags**: route users to variants based on observed reward, not coin flip + +## Related modules + +- [RL: A/B Test Views Content](https://www.drupal.org/project/rl_sorting) (`rl_sorting`): + A/B test the order of any Drupal View +- [Analyze](https://www.drupal.org/project/analyze): content analysis and + quality scoring for Drupal +- [AI Content Strategy](https://www.drupal.org/project/ai_content_strategy): + AI-driven content strategy recommendations for Drupal + +## Resources + +- [Multi-Armed Bandit Problem](https://en.wikipedia.org/wiki/Multi-armed_bandit) (Wikipedia) +- [Thompson Sampling Paper](https://www.jstor.org/stable/2332286) (original research) +- [Finite-time Analysis](https://homes.di.unimi.it/~cesa-bianchi/Pubblicazioni/ml-02.pdf) (mathematical foundations) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..3d88476 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,32 @@ +site_name: 'RL: A/B & Multivariate Testing - Documentation' +site_url: 'https://project.pages.drupalcode.org/rl/' +repo_url: https://git.drupalcode.org/project/rl +repo_name: drupal/rl +edit_uri: /-/edit/1.x/docs/ + +theme: + name: material + features: + - navigation.footer + +plugins: + - search + - privacy: + enabled: !ENV [CI, false] + +nav: + - Home: 'index.md' + - Getting Started: + - Installation: 'getting-started/installation.md' + - Configuration: 'getting-started/configuration.md' + - API Reference: + - PHP API: 'api/php.md' + - JavaScript API: 'api/javascript.md' + - HTTP API: 'api/http.md' + - Guides: + - Drush Commands: 'guides/drush.md' + - Experiment Decorators: 'guides/decorators.md' + - Cache Management: 'guides/cache.md' + - AI Assistant Integration: 'guides/ai-assistant.md' + - Development: + - Contributing: 'development/contributing.md' From b3295a0aa8d8f561706858f52b87d3ac5fb2e380 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:06:13 +0200 Subject: [PATCH 02/12] fix: make PHP example in decorators.md pass Drupal coding standards Add doc comments and fix concat operator spacing in the decorator code example so phpcs passes on documentation markdown files. Claude-Session: https://claude.ai/code/session_01Cbtzf2mpa3xQKCSkFzJuiR --- docs/guides/decorators.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/guides/decorators.md b/docs/guides/decorators.md index 9672efc..6a62b51 100644 --- a/docs/guides/decorators.md +++ b/docs/guides/decorators.md @@ -15,8 +15,14 @@ namespace Drupal\my_module\Decorator; use Drupal\rl\Decorator\ExperimentDecoratorInterface; +/** + * Decorates experiments owned by my_module. + */ class MyExperimentDecorator implements ExperimentDecoratorInterface { + /** + * {@inheritdoc} + */ public function decorateExperiment(string $experiment_id): ?array { if (!str_starts_with($experiment_id, 'my_module-')) { return NULL; @@ -24,15 +30,19 @@ class MyExperimentDecorator implements ExperimentDecoratorInterface { return ['#markup' => 'My Custom Experiment Name']; } + /** + * {@inheritdoc} + */ public function decorateArm(string $experiment_id, string $arm_id): ?array { if (!str_starts_with($experiment_id, 'my_module-')) { return NULL; } $entity = \Drupal::entityTypeManager()->getStorage('node')->load($arm_id); if ($entity) { + $label = htmlspecialchars($entity->label()); + $id = htmlspecialchars($arm_id); return [ - '#markup' => htmlspecialchars($entity->label()) . - ' (' . htmlspecialchars($arm_id) . ')', + '#markup' => $label . ' (' . $id . ')', ]; } return NULL; From 7e19ce63589314f297acc88c9a81ba0983787676 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:12:39 +0200 Subject: [PATCH 03/12] fix: remove Date: Mon, 31 Aug 2026 13:43:28 +0200 Subject: [PATCH 04/12] docs: add FAQ, fix duplication, add image placeholders, expand thin pages - Add FAQ page with common questions from the README - Fix Configuration page: add actual module settings content, report viewing section, and image placeholders for settings form and reports - Expand PHP API page with experiment registry examples, remove duplicated cache content (now links to canonical cache guide) - Expand cache guide with client-side alternative section - Expand contributing page with branch conventions, architecture overview, and test instructions - Add image/diagram placeholders throughout for later insertion - Add cross-links between installation and configuration pages Claude-Session: https://claude.ai/code/session_01Cbtzf2mpa3xQKCSkFzJuiR --- docs/api/php.md | 44 +++++++++++++------ docs/development/contributing.md | 63 +++++++++++++++++++++++---- docs/getting-started/configuration.md | 52 ++++++++++++++-------- docs/getting-started/installation.md | 3 ++ docs/guides/ai-assistant.md | 2 + docs/guides/cache.md | 29 +++++++++--- docs/guides/drush.md | 2 + docs/guides/faq.md | 62 ++++++++++++++++++++++++++ docs/index.md | 4 ++ mkdocs.yml | 1 + 10 files changed, 214 insertions(+), 48 deletions(-) create mode 100644 docs/guides/faq.md diff --git a/docs/api/php.md b/docs/api/php.md index 1b1497b..4fddeb4 100644 --- a/docs/api/php.md +++ b/docs/api/php.md @@ -6,24 +6,45 @@ The `rl.experiment_manager` service is the primary entry point for recording interactions and retrieving scores. ```php -// Get experiment manager $experiment_manager = \Drupal::service('rl.experiment_manager'); -// Record a trial (content shown) +// Record a trial (content shown to visitor). $experiment_manager->recordTurn('my-experiment', 'variant-a'); -// Record a success (user clicked) +// Record a success (visitor clicked/converted). $experiment_manager->recordReward('my-experiment', 'variant-a'); -// Get Thompson Sampling scores -$scores = $experiment_manager->getThompsonScores('my-experiment'); +// Get Thompson Sampling scores for specific arms. +$scores = $experiment_manager->getThompsonScores( + 'my-experiment', + NULL, + ['variant-a', 'variant-b', 'variant-c'], +); -// Select best option +// Select the best option. $ts_calculator = \Drupal::service('rl.ts_calculator'); $best_option = $ts_calculator->selectBestArm($scores); ``` -## Variant selection +## Experiment registry + +Experiments must be registered before they can receive data. Unknown +experiment IDs sent to `rl.php` are silently dropped. + +```php +$registry = \Drupal::service('rl.experiment_registry'); + +// Register a new experiment. +$registry->register('my-experiment', 'my_module', 'Homepage Hero Test'); + +// Check if an experiment exists. +$exists = $registry->exists('my-experiment'); + +// Remove an experiment and all its data. +$registry->delete('my-experiment'); +``` + +## Variant selection helpers For modules that follow the "v0 = original, v1..vN = stored variants" convention, the module provides reusable traits and base classes: @@ -34,10 +55,7 @@ convention, the module provides reusable traits and base classes: - `VariantParser`: static helper for parsing textarea variant input into normalised lists -## Cache override +## Cache management -```php -// Override page cache if experiment cache is shorter than site cache -$cache_manager = \Drupal::service('rl.cache_manager'); -$cache_manager->overridePageCacheIfShorter(60); // 60 seconds -``` +See the [cache management guide](../guides/cache.md) for controlling page +cache lifetimes on pages running experiments. diff --git a/docs/development/contributing.md b/docs/development/contributing.md index a13183a..32dcbbb 100644 --- a/docs/development/contributing.md +++ b/docs/development/contributing.md @@ -1,8 +1,29 @@ # Contributing -## Linting and code standards +## Issue queue + +Report bugs and feature requests on the +[drupal.org issue queue](https://www.drupal.org/project/issues/rl). + +## Source code + +- [git.drupalcode.org/project/rl](https://git.drupalcode.org/project/rl) (primary) +- [github.com/dxpr/rl](https://github.com/dxpr/rl) (mirror) + +Pull requests are accepted on GitHub and mirrored to drupal.org. + +## Branch conventions + +- `1.x`: main development branch +- Feature branches: `feat/` or `feature/` +- Bug fixes: `fix/` -Run coding standards checks: +## Coding standards + +The project enforces Drupal coding standards and ESLint for JavaScript. +All checks run automatically on pull requests. + +### PHP (Drupal coding standards) ```bash docker compose --profile lint run --rm drupal-lint @@ -14,18 +35,42 @@ Auto-fix coding standard violations: docker compose --profile lint run --rm drupal-lint-auto-fix ``` -Run Drupal compatibility checks: +### Drupal compatibility ```bash docker compose --profile lint run --rm drupal-check ``` -## Issue queue +### JavaScript (ESLint) -Report bugs and feature requests on the -[drupal.org issue queue](https://www.drupal.org/project/issues/rl). +```bash +npm ci +npx eslint . +``` -## Source code +## Running tests -- [git.drupalcode.org/project/rl](https://git.drupalcode.org/project/rl) (primary) -- [github.com/dxpr/rl](https://github.com/dxpr/rl) (mirror) +The project uses end-to-end tests via Drush commands against a real Drupal +site. To run the full test suite locally: + +```bash +docker compose --profile test run --rm e2e-test +``` + + + +## Architecture overview + +The module is built around these core services: + +- `rl.experiment_manager`: records turns (impressions) and rewards (conversions) +- `rl.ts_calculator`: Thompson Sampling algorithm implementation +- `rl.experiment_registry`: experiment registration and lookup +- `rl.cache_manager`: page cache lifetime management +- `rl.analyzer`: experiment analysis and recommendations + +Consumer modules (like `rl_sorting`, `rl_page_title`, `rl_menu_link`) extend +the core by registering experiments and implementing variant selectors and +decorators. + + diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 4be705a..8aa66be 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -1,6 +1,31 @@ # Configuration -## Deciding which variant to show +## Module settings + +After enabling the module, visit **Administration > Configuration > System > +RL Settings** (`/admin/config/system/rl`) to configure the module. + + + +You can also manage settings via Drush: + +```bash +# List all settings with current values +drush rl:config:list + +# Get a specific setting +drush rl:config:get exploration_rate + +# Set a specific setting +drush rl:config:set exploration_rate 0.1 +``` + +See the [Drush commands guide](../guides/drush.md) for the full reference. + +## Choosing a variant selection strategy + +RL supports two approaches for deciding which variant to show. Pick the one +that fits your caching setup. ### Server-side (preferred) @@ -12,7 +37,7 @@ filters, plugin config), so it can call the RL service directly: $scores = $experiment_manager->getThompsonScores( 'my_experiment', NULL, - ['v0', 'v1', 'v2'] // arm ids owned by your domain + ['v0', 'v1', 'v2'], ); arsort($scores); $best_arm = key($scores); @@ -30,23 +55,12 @@ render all variants into the HTML and swap them on the client so they can keep Varnish/Fastly caching. For that case there is `Drupal.rl.decide()`, documented in the [JavaScript API](../api/javascript.md). -## Cache management - -RL provides optional cache management for web components: - -```php -// Override page cache if experiment cache is shorter than site cache -\Drupal::service('rl.cache_manager')->overridePageCacheIfShorter(30); -``` - -**How it works:** +## Viewing reports -- If site cache is 300s and experiment needs 30s: overrides to 30s -- If site cache is 60s and experiment needs 300s: leaves at 60s -- If site cache is disabled: no override +Once experiments are running and collecting data, visit +**Administration > Reports > RL** (`/admin/reports/rl`) to see +per-experiment performance, traffic distribution, and confidence levels. -**Use cases:** + -- Views plugins using RL for content sorting -- Blocks displaying A/B tested content -- Components needing frequent RL score updates + diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index da6ea9c..75ec64a 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -7,6 +7,9 @@ composer require drupal/rl drush en rl ``` +After enabling, visit `/admin/config/system/rl` to review the default settings, +then see [Configuration](configuration.md) for next steps. + ## Plotly.js library (required for charts) The RL module uses Plotly.js for experiment charts. Install it via Composer using diff --git a/docs/guides/ai-assistant.md b/docs/guides/ai-assistant.md index 32e30d3..77b35bb 100644 --- a/docs/guides/ai-assistant.md +++ b/docs/guides/ai-assistant.md @@ -35,3 +35,5 @@ Your assistant will respond to prompts like: - "Analyse the hero_cta_test experiment" - "Create a new A/B test for the homepage banner" - "What's the conversion rate for variant B?" + + diff --git a/docs/guides/cache.md b/docs/guides/cache.md index 98679d8..864eeaa 100644 --- a/docs/guides/cache.md +++ b/docs/guides/cache.md @@ -1,27 +1,42 @@ # Cache management RL provides optional cache management for web components that run A/B tests. +When an experiment needs to refresh more often than the site's page cache +allows, the cache manager shortens the cache lifetime for that page only. ## Usage ```php -// Override page cache if experiment cache is shorter than site cache +// Override page cache if experiment cache is shorter than site cache. \Drupal::service('rl.cache_manager')->overridePageCacheIfShorter(30); ``` +Call this in your module's render logic, before the response is sent. + ## How it works +The cache manager compares your requested lifetime against the site's +configured page cache maximum age: + - If site cache is 300s and experiment needs 30s: overrides to 30s - If site cache is 60s and experiment needs 300s: leaves at 60s -- If site cache is disabled: no override +- If site cache is disabled (0): no override + +The cache manager only shortens the page cache lifetime; it never extends +it beyond what the site already has configured. ## When to use it -- Views plugins using RL for content sorting +- Views plugins using RL for content sorting (e.g. `rl_sorting`) - Blocks displaying A/B tested content - Components needing frequent RL score updates -The cache manager only shortens the page cache lifetime; it never extends -it beyond what the site already has configured. This ensures that -experiments can refresh their data without interfering with the site's -overall caching strategy. +## Client-side alternative + +If you need full page caching (Varnish, Fastly, CDN) and still want +per-visitor variant selection, use the client-side approach instead: +render all variants into the HTML, cache the full page, and let +`Drupal.rl.decide()` swap variants in JavaScript after load. See the +[JavaScript API](../api/javascript.md) for details. + + diff --git a/docs/guides/drush.md b/docs/guides/drush.md index d0afe53..cee6849 100644 --- a/docs/guides/drush.md +++ b/docs/guides/drush.md @@ -52,3 +52,5 @@ drush rl:performance hero_cta_test --format=yaml # Full analysis with recommendations drush rl:analyze hero_cta_test ``` + + diff --git a/docs/guides/faq.md b/docs/guides/faq.md new file mode 100644 index 0000000..4aaee2c --- /dev/null +++ b/docs/guides/faq.md @@ -0,0 +1,62 @@ +# FAQ + +## Does RL store my A/B test's variants? + +**It stores their performance data, not the authoritative list.** Every variant +that has received traffic has a row in `rl_arm_data` with turn and reward +counts. But "which variants are in play right now" is owned by your module, +not RL. + +Different consumer modules keep the live variant list in different places: + +- **rl_sorting**: the content returned by a View +- **rl_page_title**: fields on a content entity +- **rl_menu_link**: labels on a menu link +- **DXPR Builder**: slots inside a block component + +On each call your module passes its current list +(`getThompsonScores($id, NULL, $arms)` in PHP or +`Drupal.rl.decide(id, arms)` in JS) and RL matches it against the stored +stats to pick a winner. A newly added variant is in play on the next render; +a removed one stops appearing. No second save step can drift out of sync +with your module's UI. + +## When do I pick a winner and end an A/B test? + +**Only when you want to.** RL has no fixed horizon and no significance gate +to wait out. It just shifts traffic to whatever variant is winning right now +and keeps adapting as evidence changes. + +Two patterns, depending on what you are testing: + +- **Converging tests**: a better page title, a clearer checkout button, a + stronger hero image. Once the report shows a confident winner, lock it in + and move on. +- **Evergreen experiments**: blog post lists, banner ads that fade as + returning visitors tune them out, seasonal calls to action. Leave them + running. RL follows the winner as it shifts. + +In both cases the loser of a pair just stops receiving traffic on its own, +so there is no urgency to declare a winner by hand. If you are used to +fixed-horizon A/B tools, this is the biggest mental shift: there is no +"test complete" flag to chase. + +## How many variants can I run at once? + +There is no hard limit. Thompson Sampling scales to thousands of arms per +experiment. The practical limit is how many variants you can create and +maintain. Two variants is a classic A/B test; dozens or hundreds is true +multivariate testing. + +## Does RL work with page caching? + +Yes. For server-side decisions, the cache lifetime determines how often +the algorithm re-evaluates. For client-side decisions (using `Drupal.rl`), +the page can be fully cached and the variant swap happens in JavaScript +after load. See the [cache management guide](cache.md) for details. + +## Does RL set cookies or track users? + +No. RL tracks only anonymous interaction counts (impressions and +conversions). It does not set cookies, store user IDs, or create visitor +profiles. This makes it GDPR-friendly by design. diff --git a/docs/index.md b/docs/index.md index ca3e9e0..1f70edb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -27,6 +27,8 @@ fixed horizons, no third-party SaaS. - **GDPR-friendly tracking**: only anonymous interaction counts, no user IDs or cookies + + ## Why RL instead of fixed-horizon A/B testing? Traditional A/B tests run for a fixed window (say two weeks) and split traffic @@ -45,6 +47,8 @@ picks the highest sample. Wins update the distribution toward higher rewards; losses update toward lower. Algorithm details: [ThompsonCalculator.php](https://git.drupalcode.org/project/rl/-/blob/1.x/src/Service/ThompsonCalculator.php). + + ## Use cases - **A/B test any content variation** without third-party SaaS diff --git a/mkdocs.yml b/mkdocs.yml index 3d88476..611e8f4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -28,5 +28,6 @@ nav: - Experiment Decorators: 'guides/decorators.md' - Cache Management: 'guides/cache.md' - AI Assistant Integration: 'guides/ai-assistant.md' + - FAQ: 'guides/faq.md' - Development: - Contributing: 'development/contributing.md' From 614aa085e7d4566e6c065f3f1d16f121447032b7 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:57:10 +0200 Subject: [PATCH 05/12] fix: address all 8 review comments on documentation accuracy - Fix settings route: /admin/config/services/reinforcement-learning (was /admin/config/system/rl which returns 404) - Fix Drush config examples: use valid settings debug_mode and event_log_max_rows (was nonexistent exploration_rate) - Fix registry API: use isRegistered() not exists(), use purgeExperiment() not delete() (matching actual interfaces) - Remove obsolete Plotly.js installation section (library is bundled in js/vendor/plotly.min.js) - Remove false "Drupal Routes API" fallback claim (no such route exists); document custom module proxy as the alternative - Document batch error responses: add errors array format and HTTP 422 status code to error table - Fix decorator example: add constructor injection for entity_type.manager to match the services.yml definition - Fix FAQ: Thompson Sampling preserves exploration, losing arms get less traffic but never zero; they stop only when removed Claude-Session: https://claude.ai/code/session_01Cbtzf2mpa3xQKCSkFzJuiR --- docs/api/http.md | 23 ++++++++++++++++++-- docs/api/php.md | 7 ++++--- docs/getting-started/configuration.md | 9 ++++---- docs/getting-started/installation.md | 30 ++++++--------------------- docs/guides/decorators.md | 10 ++++++++- docs/guides/faq.md | 10 +++++---- 6 files changed, 51 insertions(+), 38 deletions(-) diff --git a/docs/api/http.md b/docs/api/http.md index 6b0cce0..23d31fd 100644 --- a/docs/api/http.md +++ b/docs/api/http.md @@ -63,8 +63,8 @@ Content-Type: application/json ``` All three sections are optional. Invalid or unregistered entries are -dropped silently so one bad event does not poison the rest of the -batch. The response is: +rejected individually without poisoning the rest of the batch. A +successful response looks like: ```json { @@ -84,11 +84,30 @@ Sampling lookup. Missing keys mean "use the default variant". When `ranking[0]` for backwards compatibility. Turns and rewards are fire-and-forget writes with no per-event response. +When some entries are rejected (invalid IDs, unregistered experiments, +malformed entries), the response includes an `errors` array: + +```json +{ + "ok": false, + "errors": [ + {"kind": "decide", "id": "unknown_exp", "reason": "unknown_experiment"}, + {"kind": "turn", "id": "bad!", "reason": "invalid_id"} + ] +} +``` + +Each error includes the `kind` (decide, turn, or reward), the `id` that +failed, and a machine-readable `reason`. Partial successes return HTTP 200 +with both `decisions` and `errors`; the response is 422 only when every +entry in the batch was rejected. + ## Error responses | Status | When | | --- | --- | | `400` | Missing/invalid `action`, malformed JSON, or missing `experiment_id` on a legacy action. | +| `422` | Batch request where every entry was rejected (all invalid or unregistered). | | `500` | Drupal kernel failed to boot. Error logged to the PHP error log. | ## Performance notes diff --git a/docs/api/php.md b/docs/api/php.md index 4fddeb4..be96732 100644 --- a/docs/api/php.md +++ b/docs/api/php.md @@ -37,11 +37,12 @@ $registry = \Drupal::service('rl.experiment_registry'); // Register a new experiment. $registry->register('my-experiment', 'my_module', 'Homepage Hero Test'); -// Check if an experiment exists. -$exists = $registry->exists('my-experiment'); +// Check if an experiment is registered. +$registered = $registry->isRegistered('my-experiment'); // Remove an experiment and all its data. -$registry->delete('my-experiment'); +$experiment_manager = \Drupal::service('rl.experiment_manager'); +$experiment_manager->purgeExperiment('my-experiment'); ``` ## Variant selection helpers diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 8aa66be..2ba96c0 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -2,8 +2,9 @@ ## Module settings -After enabling the module, visit **Administration > Configuration > System > -RL Settings** (`/admin/config/system/rl`) to configure the module. +After enabling the module, visit **Administration > Configuration > +Web services > Reinforcement Learning** +(`/admin/config/services/reinforcement-learning`) to configure the module. @@ -14,10 +15,10 @@ You can also manage settings via Drush: drush rl:config:list # Get a specific setting -drush rl:config:get exploration_rate +drush rl:config:get debug_mode # Set a specific setting -drush rl:config:set exploration_rate 0.1 +drush rl:config:set event_log_max_rows 50000 ``` See the [Drush commands guide](../guides/drush.md) for the full reference. diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 75ec64a..6a0b818 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -7,28 +7,9 @@ composer require drupal/rl drush en rl ``` -After enabling, visit `/admin/config/system/rl` to review the default settings, -then see [Configuration](configuration.md) for next steps. - -## Plotly.js library (required for charts) - -The RL module uses Plotly.js for experiment charts. Install it via Composer using -[Asset Packagist](https://asset-packagist.org): - -```bash -# Add Asset Packagist repository (if not already configured) -composer config repositories.asset-packagist composer https://asset-packagist.org - -# Install the Composer plugin for npm assets (if not already installed) -composer require oomphinc/composer-installers-extender -composer config extra.installer-types --json '["npm-asset"]' -composer config extra.installer-paths.web/libraries/\{\$name\} --json '["type:npm-asset"]' - -# Install Plotly.js -composer require npm-asset/plotly.js-dist-min:^2.35 -``` - -This installs the library to `web/libraries/plotly.js-dist-min/`. +After enabling, visit `/admin/config/services/reinforcement-learning` to +review the default settings, then see [Configuration](configuration.md) +for next steps. ## Post-installation: verify rl.php access @@ -46,8 +27,9 @@ curl -X POST -d "action=ping" http://example.com/modules/contrib/rl/rl.php - **Nginx**: add the configuration rules below to your server block - **Security modules**: whitelist `/modules/contrib/rl/rl.php` -If server policies prevent direct access to `rl.php`, use the Drupal -Routes API instead. +Direct access to `rl.php` is required for the tracking endpoint. If your +server configuration prevents it, you will need to add a custom route in +your own module that proxies requests to the RL services. ### Nginx configuration diff --git a/docs/guides/decorators.md b/docs/guides/decorators.md index bca16a9..000462d 100644 --- a/docs/guides/decorators.md +++ b/docs/guides/decorators.md @@ -11,6 +11,7 @@ Implement the `ExperimentDecoratorInterface`: ```php namespace Drupal\my_module\Decorator; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\rl\Decorator\ExperimentDecoratorInterface; /** @@ -18,6 +19,13 @@ use Drupal\rl\Decorator\ExperimentDecoratorInterface; */ class MyExperimentDecorator implements ExperimentDecoratorInterface { + /** + * Constructs a MyExperimentDecorator. + */ + public function __construct( + protected readonly EntityTypeManagerInterface $entityTypeManager, + ) {} + /** * {@inheritdoc} */ @@ -35,7 +43,7 @@ class MyExperimentDecorator implements ExperimentDecoratorInterface { if (!str_starts_with($experiment_id, 'my_module-')) { return NULL; } - $entity = \Drupal::entityTypeManager()->getStorage('node')->load($arm_id); + $entity = $this->entityTypeManager->getStorage('node')->load($arm_id); if ($entity) { $label = htmlspecialchars($entity->label()); $id = htmlspecialchars($arm_id); diff --git a/docs/guides/faq.md b/docs/guides/faq.md index 4aaee2c..89d0c18 100644 --- a/docs/guides/faq.md +++ b/docs/guides/faq.md @@ -36,10 +36,12 @@ Two patterns, depending on what you are testing: returning visitors tune them out, seasonal calls to action. Leave them running. RL follows the winner as it shifts. -In both cases the loser of a pair just stops receiving traffic on its own, -so there is no urgency to declare a winner by hand. If you are used to -fixed-horizon A/B tools, this is the biggest mental shift: there is no -"test complete" flag to chase. +In both cases the loser of a pair receives progressively less traffic as +the winner's distribution strengthens, but it never drops to zero: Thompson +Sampling preserves exploration, so a losing arm always retains a small +chance of selection. Traffic only truly stops when the experiment owner +removes or locks the variant. If you are used to fixed-horizon A/B tools, +this is the biggest mental shift: there is no "test complete" flag to chase. ## How many variants can I run at once? From 63718e58800374a9ee7432fdb9a97fc634da3be2 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 14:04:33 +0200 Subject: [PATCH 06/12] docs: add screenshots of reports dashboard and 3D posterior landscape Add three screenshots from a live RL installation: - Experiment list with impressions, conversions, and variant counts - 3D Posterior Landscape chart (hero image on home page) - 2D Line Chart showing conversion scores over time Replace TODO image placeholders in index.md and configuration.md with the actual screenshots. Claude-Session: https://claude.ai/code/session_01Cbtzf2mpa3xQKCSkFzJuiR --- docs/getting-started/configuration.md | 9 +++++++-- docs/images/rl-2d-line-chart.jpg | Bin 0 -> 73526 bytes docs/images/rl-3d-posterior-landscape.jpg | Bin 0 -> 76411 bytes docs/images/rl-experiment-list.jpg | Bin 0 -> 87361 bytes docs/index.md | 3 ++- 5 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 docs/images/rl-2d-line-chart.jpg create mode 100644 docs/images/rl-3d-posterior-landscape.jpg create mode 100644 docs/images/rl-experiment-list.jpg diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index 2ba96c0..caaf3c7 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -62,6 +62,11 @@ Once experiments are running and collecting data, visit **Administration > Reports > RL** (`/admin/reports/rl`) to see per-experiment performance, traffic distribution, and confidence levels. - +![RL experiment list showing impressions, conversions, and variant counts](../images/rl-experiment-list.jpg) - +Click **View** on any experiment to see its detail page with interactive +charts. The 2D line chart shows conversion scores over time; the 3D +posterior landscape visualises how Thompson Sampling distributions evolve +across variants and impressions. + +![3D Posterior Landscape chart for experiment detail](../images/rl-3d-posterior-landscape.jpg) diff --git a/docs/images/rl-2d-line-chart.jpg b/docs/images/rl-2d-line-chart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d1317821ebf0920dead148ef548fa870374ad17 GIT binary patch literal 73526 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

9x}9%d0nC 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 K=;C!)E<|?1|lcT;a93`3_`k{k$O17hS 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 literal 0 HcmV?d00001 diff --git a/docs/images/rl-3d-posterior-landscape.jpg b/docs/images/rl-3d-posterior-landscape.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b6a18cf1fa84aa5f3550e27347e5463536b6e3d6 GIT binary patch literal 76411 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%0A-^HB$e8b-Yw5+yu_I1q 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 literal 0 HcmV?d00001 diff --git a/docs/images/rl-experiment-list.jpg b/docs/images/rl-experiment-list.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b95ebcdcbb95daf01778be4f625e7498019cd2b6 GIT binary patch literal 87361 zcmeFY1yo$k(kMDO2^QQ2hY&P4gM|=0xO|X>_z@LQ90{}QWxw~r0zoOSSFr>#?{YQ;IG;^?<%b)YV zNl3XDGk>H50Fzw*hUfnd{m9bF4UA+sM*iJhk&PoeYl(zOZ2kdz|A8(30mJ^lUhXdL zNS@3;u&cJFG!m{s!cT1e23!0M2D`Za;qONBh&wuX{Aue?`qN`vD<>T-=3h9AuK+;(M*x6g;a@oBOaOr30{~Dr z`Y+tS#@NN&)%-7Ue=?K{^narhJ(Bt#b)p9-0-OL~05^ahsS6KM6QPGiWZ$tdF|jZ) zu(7bP9zDW-j7x%ti-UtpNkmLQLPJGIOG5<&(lc|j(lc^00fEni**JN41q1}>SVbg2 zeB#{v0(^gjpgel?2p0#J0uPUZj{(TQ_y0IOv;zpS(f!a#(NGuxsDvnJgeVW)NCi*; zsAwpEEcl-Z6$1?&69o$!N!5A+KtV%8MZ>_vKtn}&gn@?lhZ`M(kca`3n3qIKLo=3< zPYW8CMapCzIL`k{8;gvbS;xXPDE@Qh1dD)BPL;HqyGL+`pe(q$=0q4I^8qQ88rj-E z(mz`Sp!^YviG?JB2$3zIpkSb5qhnzFqf;n^NGcHnuZEO)>@hKkCNwZ>e2tW^vIB#W zY2pNv|CLsp^uq!G7Y$jH5RDKZ3Anvsq-SJAW!!F7Tr47$vJ%w#E)AI<16jedjA2hJ5HS51u(Z_RqR!U->PpEBFC_O~gcQQGP z&7Y0z*ECA&oiFK$P*~B=3focm&f0HdjOPbYvm& zFowlO`s%+KyR@v$J%Y|Yex3P$HG$)rbR)lAGqd&lEP5FHLPcK4UG|%niM$M$R7d@# zmFK7KD$IQ^W!!VIkNx?b|8s-i$oIvHo1QhPC&M=4*eSnt<-3+XAtXd0{9E?QzyMb* zQ696WCrPBY0YA@g@$N-^TLff#V{mq7n6o^59w)R?g;>$)Wq()L=pgzIt8?x!4m*7u zC8hzB5>WCLPpeLcv7%c06U9!T_KrF{(EyJIyy5jUpHHc3GP0iaY=uTAu=YN0ZnH{> zj&?4>?#P|n8G>d#)ve%MBQ~Ja_RKxOTzz@C4Yaghp?EM>RISu^Mbg zNCJESkW6c9)lCD5X5`p8lwCcAY9|_-znTO9u@N)zHyFK2UJX^VvI1UBx#z@&#q4=e zv`R3|>ZIHTy9=YkCdsNByonV-w_U4(LQ8&)Datv^Pkpo2!aY(b!xGG_-(0`hU>hyl z=4KW0i5zPsd#Ru;KZ-3!(-&2fCkqZzdl_`}^(ZcpwP9<-jQPGnTaTa{0?MhFST25M zVf7?MSwrUdGAZ^DVh(EG#Wq2sn46msFfXG(JJYGBrL8w%U)0j>AIg5AYf+p?zilIG zOtA{&Uw@46vE(5rh}UXRWS8$A%X==$>f(a2mHefB)>n)ib$vWCP^`!V1h4%(yK9kW z#Ue{8{{v@gAw z4Fd77U|5l2=giyu!Z^dX%!0VF(GUbPm+jlZGhtoI!pO701nGy)j5!t@jgtF)}|eZ$mPxZC8+6)63#+VWa(>69L$GrhzO*3gu{T;|3!{m84ox2~Q+Hw)BIz z;P{k6Z-e;O+9*E0H*^WX%IX?ax#UdQV6+jGEW*Yi2AUlapP>xk97MxLTX1e(^_ru- zo`A}Zz|#XdZ1WEV58}KT-`U|ksa9}HJu>L3x(FB}FpeXIrE=NCH6~bpJ&cWxdfB7K z#57Bb1_a~dF=N))&;V%26dPP;1xdLWg5+cscu_*$GWnuV&`Xr#chJarsiKXLmlrl3 ze}~r@z4iTZdqV}4*@Y|kT6Ls7g-qsORQR}&P)CS7Nf zJ^g0MKdD*5YP376(iLz=8WDsDJEv0YQ)qfbQEqV6xRhFn9=lMrE^jKX z6^87{YsBE0P_p4Q*U5#AcE12`<%Hw{9-dQOVQb`C*sup#EY84Hz7IXa6nKw{wvvA*Dn6G*sln*Iq3ipC1ppuVfArY zvX3p>vck43y7kjK$_!fljU>VE2 zkO&hN+jz!d(nHGaoyei~J1je4@`b@5i&+N1LV}g0afzH@lGO^_<%JVDkXWVkLEr?= zKEDL+dn`?LLq?xFyeqQEV&h{^-Szf+S1X?Kep5iWGA! z4^11g6(J~1NT%JSbXY8{)4jV43I&I7J6xzYF@x)&1IyJXTsq%pj>etC(-KaU1Y~P5 zUr`OeIGzv|Z3>%v-#|U?vQBwxM(3zxfiL7Kjq-E7eZl!m?5K28uh_nN33uE2>KOY%#$ zeohy@hEUx2*>7627e>u$-elasvIcvwWn{9&?9o@Cv_ZzC2IU=TAxasZEdV6|%e6yC zR!x5wPsZm~Jlpmz8{mzO7C2k9zY;u!4vZ{_KomO)UD)dD64fGb{N; z$?yP6Fl!FYQQt^q9f3&V6Qve+9hkFD%&MB+C4{pntAQ2Fr#u8!53u(?ws@==a^&@- zSN15R&Rjf> z0&kK2rL8w;nzUk3<$EL~pPwftOh^-N4K@Z&R7Ruo@YE|12{Shkw)Rr51HIQF0rg$a zpQcSeab=HKwJ6G-Ad3WfoNOnp4`Zc8f)#y_f^G6B7d_++rK= zT*^5>_S2>=q_s~5_G)_>@CsvLZX5KKBW5m;PxMamo@A!&j;UX=1R~uvdO20Vsm20| zKZ71E(M@BhbcK}*CF}b?sp%rsQC_F=tSap%ZV44n0?8Me@$BG=ZBQ;nL~!*jAM(t= z)6S0Gx|tCFI!J7&*`O!loyo|9H+<}pML6^Ir8a~$a|)Bj*sO#O7e;?jr(bcGqjj! z!FX<|z(;uWc6jJM~XSq}gNX$S0MPp5L6;OIM!H2E_t4RfYS|uX|;0E?1?t|)uDBQ?g#|dso)vQ`GVIGAmDlaHLTUc;X z@`5@vS11Kby|`WiKi&u{=B_#CZB5UwOAd@_98C^S7x^*IU(Xwb@%_ta1OF_vs?H#q2@P66zYqgHNuz;KecSyE^(tPTkXDFV^9lqSo zcMJ~i8-dCnqXlp7C9H;o5C+lXCmlf*YHR$dw~wYImO=<89qsOXtYjHC~YT{^JzA}#+x zSk0F<&i6PZNo@hQtmKQ*&=`fu(DXOY8no8C-DhQ~dd7CEao)LwCF$6~^zJaQNOZa! zZp;!4^T^ecT3Es-LSjG(ro&ZO;3%QPx&3IvGPNhv4iX5d;KMPV9P`+%5dP>;noCle zJ&7GwDIla5G*i2EIN=r}9Y!D78#U;&;*?iA>FJ{@Qp)`t>brC)(OZ(bLuBl)sqVJjF(3D@Z;-qDg>p4&!j)V7p>t4MVCOKf~}C;XiY7HuuH?#LQhX@jn@ zsaQaW&5Lyc;rXtxLEp=Bsf-WY!qjP`mbKe@JqwWnlS&G9LzTPc)0vl+P5$HZ5s(r# zI_r?A{3;Y3!`(aqs62CCHl=AuXl>UIuv`60?JK!?6QpkxUZDtdE}T|Uy(!RkWyH0` z#rN`*u8`ERa;qNyL5XI+C}b9&LcCTOM_#$0(N-VqCAA1KY$(m_Rgpm~WN}GF4uRiXH1Lr5%AXFV zq=``MRxe$JZ!IhgQ0dRh(u|~s8zw0W#_d$A6DDq`(iDhRryrd=-!IjAD(Bkt`0~2{czzRt3+qWr#Iob2Kx4K+qj_SK z%^1-5wwOD~iJ@_Pe7OxTXn_%nRpaNIbsy?=l^Y*CWC!`D@z zqepDky^-RI?D;i+exo)V;+JtNYUa8NJ^}|0nnw1x;Pdd;=@|zHXSNyV!iP>wTnZiZ z*uU7bt-Qhz*FI@n6{-5vTZ3kFchtW~ODzEOfjrC5bacY=(@=a($@J-M>>-%qbX$OT z-q$Ts8vV!x4mV`C2jzxi2OBU)C#=S~?ld&^`V*-Rw9=B-NU2GP+2y+P%Q5oyYcMVJ zpvBB!fp!5$0vi+*yQHM$>k(hdqh=N*L>j*?6VE{uK4!`>;}dLc2I2GO0;BO}Qhz($ zc)`n#n-US;`U9Gtj?x8ws)JpM6F5Ero|I@T22(CpaD&1@8VzcOgkKWt`ET5#-OvQx zJRp4l{1&0zdNthnVNh^oNDreWlX8?DM1OsIH8^HO@eer;Sj@E8gf$tmiknZmT;5>W`zG&c)`Ho}LPjzaxm(yk;@{nQJ z<@(9v^W7294s5G`5cDqb{AoNxZkOOQUGm%*;h(auy5pQ_RxC$WNquv~^g6WXdr&k)EdCeLglbj^~1` zrsi-twoS)MFgYkwJ&Zx}lpISdv2Q!k3`~gyjr=5n)$(fDtZu<3&IbhSf73x*FmSnN zCW7ab?OxA(z(d9=!Pc8Z*VdM!K`HagfNQ{Xk1l!A=yThIq~O+Qe5o54uGec{t7FUp z&Y%%cO&E6KdrA3o-mk7`%JWu53^@mX>gmX8h)*iI4N{U-Cds_Z|Amb^-vFowN41$4 z1DgeX>oq3FJ1~k*(49ZGv)dVVsa`gze~#NIL2qJc7#WOL`9YmgaU$C}WnGj=RcK(U z@U(Ed5jN4&rdvQ>lO$#)hfVGDxTS4&5K^hD`;x*sGQFqG9h8dtbIgYI49Bq7s*EMK-zpPtEI+F+%wM*n->l4kxurck47gU8aC~U zRns!?csIe1Z-ibNCGr-YJVu#SM)k-AOIKmhwW2NT$e}E1&XME+5Z3x$!^TlOW|BCU zV0Liyf-q8KbPrw;{IT@xL|cw6H=&l$)pUWK`OBx@kBVW!<^WEJt^3g0yK-%Wd%*a!k7p+v#oe*h%UVR+p{3vnnmoB%Xd1 z7LJr5&l3gLiyeubw!$MFoh5pRceq$sa#{>uzG&P`&++Lt3hdVB(S>|%fv&`7!VK6l zXcGJzRJkM0kt?h=&ld!hvYc^3k=MR-l$hDCW@<+vOEW$3gNx7X_k|iDiBs^J+>O;#M3*(%IjQ8l6 zqmVQGYtaS)@-8iipNUJPh^U-6{+-r{ZQK32BAvaI0MjOanp0L5ZbtD2^=}t&{ zsSVVAT3AqT#F*MX7-?3JEZ3y;!8|&)qo5&{He=bexaquDsSJl&O=EtaZOc)XbFR-a zvX7ExHONpt@R`WK4>}LQqo|PdkaS-O=?FTRMPGEN3=_(z-?9e+je0X`16J~$d`Gi& z-!{%>n5MN*UiF%;sFPK$w>CFzBu&P73ANkFSe@YcT_a)9n9(RX%KWb-Xr%t`yQNDj z{kbyDg*_HQou|d{;y3TK=i1!{rCr9C#;5?aD44YuhZ+uz^NYk!6WPOZEi0udeACgL zn8pG;wKIO&?QIuFo{jpQF418K2-0^mM#jkfDy)o_FosrM!ULKp3-=K0b_kYe?V1s{ zY)^#=B_*{{3!gIfDB3z5O5l~HWgOBAu2f@oCL+Tm0?wi?)n-1y#?Tn`Z`zM^@gw2( zwP&+^tL@e-JD6z43W-R|O?_|V3&#y?y<MTy6ZP%kty zuQalN%Tb0ah9Jg;gVk1&;3zHgwP|(xU%W_^&be&)b2n8lvsKQbWtlc!wNZH1JEhnOuK>B3DC6x|vwIne<0c ztSlG)u?q6H%SNI(_7ffX`wvLcMx{HZUxsj+)oNLWuw-`|zjK2D3v&x<+ls#oa)F@h zw%mR4f3;bL`XQ&xNCcLxSJ!R9pDYh|x5D!e_OA>{0;Kgm0IF}Z)yR5l+JDLJ{0KQ{ z(SJa;dGphE1ONM$IY?E+mGhB~Cbl{K=GD{V(La~p@Xs|rRiq?wij%K}nQ^+h zzMjfzHsW^jwdE$MRkc2H;1}G)|4L6n{l}30GJvx3b!wHm+{x*gUSLP^(h@mY{r5TA zzUz{w65qgYda(q%7}__V1pcw4EYr7{bxI_HTCoCclOdpG=BPVqsz<&1AE@UZ1=Kuy z?s=OgQ*$;cRwKiAWfgX!fEAS#0KHk$r~ie*LtYp>gx>xpn}8=`>L1|%#_zmvmv%PH z-J*8%2NW~6>_3iUX>RxdF2uN?G;<>Rv6B@t!1H1s_zRYjDs4SA6KXrgl5m5C_6vmX z!gkyk3T+>g!;!yiL3c}?(WZ-LUB3D=mKb?F-=Y8)x0g`*0H4c4_`YtMRq-;^m(IjF zuhQu4_w&;6!m915z%y0`0(;Ym%rU?gEDHftUTBnKQ&w0GhS{t%e^?S}x~3 zHOP=2;;f=4-znYfDZng^_|u0p^#EK;4-?KAUn`lDQ3-gQK{iTd%W+L(fIA?zjy!+d zk$;r8euC1*&S7-3UOV6%AGG8*WU`lZ9htpFN5P3<4dON)yqbfEcAUBHK?bUm}>7A zx%B3_GPVfdj(NjpzQ#2v)%a9s zEoDBJ{mxAVStFh%GD z4+JvAHVrFr8&6wDMg)klrc>Ok9UF%o)OZjsKVBW!O)+!Yn3B%dm}k;qd>Efdc2l*> z+HCy3ErF&8^~{D&iq>Br1;?geyTz5S=#A!EiN{Uv=9{_rZ^_f6?C8=opu=#19*8Qw z2Y?@p(#E4@ycds4Cerdb#_-oIxYTnH*ThCD@UX&!b&YIf>gHQlk(l(a@;6EzP4vO> zu(U8b_>ip~HvL4q6hvR1(`hEP#xIaLaQQRP*ZET4cAxGw8@jgkuj!WRN6hZYHlOYA zpD!|`d37B1bXk;Ny5uG{Oz_e7=qe8RE?h_G&*gZ!L$D}4Z#-#DPT|g7yTQyh;DSjG z9A;;>246+y;JVc$(8l=-c2cqwM4yCPOg~h7SEcXM2??VG zCAo2|ql%cqtV@}wolxID`wgF1&LVNkLCLoYy^Z2E(ak9@hTO#dYE z?0M2-F)Iuco(!@D`kllB3v#b<0xQKI(jwg%Kg zFbAk$RylppDqwCkHUl*nFAffgEM^Z6sjRk-6A^hkVcgsJ0roSvfWsd3&7Ng{$6LH> zytZEhsp{X+1f;2%td(jiGjZeN{9P6AW=p|fGq4;$s>>LGnC~XXH)s&-Y)z)H$Iu`- zMp#u#{VEj>DlJY(iAYWA>lh~%0kLn z_O(ju)y0U^XHg!R4*(ResCJKI9L=gOr;?BcPX&wQI`S?q8K{7Q;acz^*ng!1L+s}z zyH{(Xy!xPc(ARM_Y9J#_`E8_6j#W?sWe|N4C?T{yjA7Z!uGUqRIXKyDD(;y{@^pE<<`QzPns6&?U5+enmUneiB-aVww{zj8{^WXUqMp4q6#kowWdW&UlM}Nc6c((i@Zs+ zoU0Il62+^fTwJK1$hBN_EPIe@yVs7p7VoX6i|;6x;!~b<=x^07?u0zc%gT>?=AYjy zGeLPuF>kKD{s7S49~S4bv`#eW#s^j>f_h62BuT!tI$V_eM(c^$F*D>Z zSTO|~oU4C604DmqTzbC0p>{+mJq!uYsP%Kw^0@No@nN1>c>IYm$e!JfF%;OaLabyE z^@U;{gGQofjnway(kw3a67wZkG4MToNwh2o;A+Et}`S#+d6hS4v7$nMdo2KI~NTNOET;LGDKXsks7BI1NfEIcW zal-K+6>yA7k4k?k_`9bz7Bk=gtlqvKb^di+?y~YIvfP(HuiLU-0=gQU@BnaK0%wOC zFa{~IXB8w9k~sZth19IIH!bumANDU=rHi#}XN^x*ey$kJ&Kh;EB%&GQ-RqLROWp54 zPc=8CdMqqEAP_@wZNY`f8;OeVsw{^{GodL!G1|cmG5i}JNFvuo zG8CEDVk-7>-6#%rhzZm0Zc_b{>JdeDN4$dHJcBWn(3Zy3UJzzjMjoqu3(;vh^t`4c zUXgyi(>*q~WNycamPze^I?N?N3=-96ifuO|uONm6N2?PIp#z65Q{oG){h|UZ)kwh> zo3+D!P7&%@x;d#KSGYhnt(9^?p}J8uVrqs|>Havry&PLRmJz3X1avL{zkSDJoQhqK zhiCGYp`dv_Z(zxf^ZwB&?Wc9>+M$nji}LXC@Cm{SMBQMUUX~l%L3JB?3s=h8LUM^y zLQh*xHu0Xj8Lsm;%%wLK-+o-z2Yn6U*Ib}t?L{xMblL*-No4P!1QzfjLqhhv%adQf zervm|u$wZ!G-3e5#RK(ViaMmlrNlC0Vh?HBeCZsM{xz!?<$D?ww5Vmug1{cu7dR69 zKHieoy<0fJ<5q_PaIC=U2EX6(jtkn5RUV)UOA+gHn;VlGg0?R?*XQd#04(xmsc!{D zbKKHfk3@4=MiIzKOx?((^Iwh7qV6@)ru4%kTcXjE~ z#QAw4#Ul3WX3VWmKx)gL0gpDKyKRHC#YD;lRKNa1HSay&Tes7dE$-LL) zvuQ)k-2%~7*IZ(wQ_{h){CJyqwj$EUY|vChoAKApG!S~MP<1rL0o8`)+$?R>0aBK}*PZExE$JL;`n zKe#Idt=|co)sdw^H$kYOn5Dp%*&US?;Rc5AK09rqKRoR)faj81gCE!HLe6$QSstHDlqY00V<{c4JDIL-aZ1(b46T9uWs5R=hepktpL)JeA zg9FhWZwS|eW9tUxxg=Or1jhKPIGQbzlPLw^$&YXhccX)qq*v-(0iz4F*Gdlm@0T~!CZhdL zR!sa27J}X9pIEk6H0jUL&PfhVyy*&y{`>X+%rL)xEUBS7N*;IHj~NSz!E$ zlpQ_tY5p(WS^hQ=2EzVdO$r~N;-$iM=K0@a!AV_O7YSb1`OvNDm%qR%z@O(7;Qz6e zQ^21T^1`;`IYY15Mw8Xf^r+T*p2>1v{$6-%sTDu;$*wG7$w!BO>;Zu7EVRmJ|1~;R z`{D=l>R_#sT_NO9b7Ui=_n>y<1>nh}yTr4ER7o0y7-t&H*vf|Y^EPkM@X}7f?mKeP zg`15vN!_-u2}|;}HZ3L;chSccO%V=Um*pA+^DCV{gd!j<`|lX8J6G1gLLAcYg+jHF zw2aO(^F7HOQ%u$gPc3!myMVJs*|VlAO`w5=1UK)E*wvev#VgN6SuQIp4ESSPqhduG z)pjZgGHPkin_D^iL-(15Vwcm-t5qkokViC<8VET5om1s6D{(yw8Yf;Ku`3O6Q!^ST z4J4%R+#BNUI>|D!BPCBGU{%IaQwC*D1pugv2bvxLH~vzZ2>V&XA_NtRpQaXIdlQvU z;Oa?j)K3U8wVLI|ubXnoAL1|k?+VB#ey%A%9X}y^y8Cktvfw{|*&}gLSbA>$WriVK zm~1Csj!)9PS@J`J&$B#uheNJqITtv$z_~`=v%~#9TJf6S$kf=66|o4^u$15?yrEl@ zIWdWBapH|ej#B0W0O^$$Fy%Ss+^_oY>DBdl+h4v~SoC0l=YQ?4Q5f)Cjh!vjx-oeG zu#}aQzaT#M_U;W`oY{Hu0I2%8<_#JRjaJGvRcia#;6MhR8Gq^j0Qj2G`RlI5itfI* z{sFM|^*7tyi}SLaa!JV&edtHzfPY60_?rhnlY`{1&u^mc$!rWtHCjqN>K0}tm+b-r zG7<;ic2}?QnS(<&bF;`r*7Nnj9`U9{_AdYR2#Vb!TtkT@L_}KcgbK zd_izM@H}s&bMZIk=mS6iX{IBza9{{+cYu3Jrby1bSZffPp=AxBg$c9Nm zN#+TZKDo~23zfCD;gXDr2d>1Tj z8C)_hPcE%))`#xBukQQ&i`ov9k#$*Nt}xqQ)3I zZX?t>Q3=7R6(H^)$!q5`55)!2rV!TaU{T&z%nWNd)w;A$w{7W#*HuK{;4yu>%bvU? zEodjiCwKs8I5*Q8AN7kF>B*L!Q|yYX#z)^iuF9X+xzF)05f)+Njvv!9V0t32rOJ1F ztk5n(G1!=Lh4JnCk{EQA<9mEWZmaHcBdJP=jrP$+#pWIstA$|n%DJ{j214(CuI;!0 zr+&fF#M!RU_6iz#C*_~LSO?eQXq%H4xRGCQq<}O%j3KeGLvfD#niDRoB?YrYvhHQVebGwFy;BUS>W&k` zBV?H48vGarotQ7$GhRr9$qz%(eR`k-o1LIBTm;s#U6|mwu!7{TG}=>=z>7wOfIe{R~2* zyqd8WAyj0oqBdGQJ-rq*UC;op7kQ?7E9L4Zz*L5I&lCsz92=o>gPg4{LQiaz(wuqxufc1Q76=8v$ozh1J9+lvphXH;lNSmS99Grdi$`l_pS<~1)i@q zxk-(g9eYYXen*UUAH@hJBD@q_?)2$Xy=^EYtFj*ecQ2E|kiyg(-dIb^<7~#3*L~;q z;O&)iv+fP9yYNlYxL8G zcU{o7sP6YAD`(Fi00BD>fRj`IGhV-&W%F+>{sotB%VOX@$vA68n>Cg#SzkajJ1)>0 zQhCR>8fD*xC>O%uh}RJd=|=z_zsgGa2r&^?Mv zfie=oN|*ooI)fIv@11ccS(=wqZEWtVtXlR?#?U}5jJm?pi)9Y&tbhI;(d+}@qBY_H z&{z5ZxMHw*KFEo9ujqW-`vAZj_n(ryPH-v)fgb=NyKM-%-vjjqlfPp|qHn!#Gi7A! zrT*@h{102!{+AWWg)Li*_8gx`3CevnD&ZR2fHkDA!exvF1%9RGh(FEe27UikeziN) zz1&%2dKj9AG;^+%PU`c@oTmkU-W5BmWYd;&7LW?_-wl3Oy=SlL{i%!8cv$kv@Mz-= zZ8X>gN&6E20C>Gi=-I;`J^r1)6Y`-HLV zDOHJz_^5hojWx-o9sd<^kg6ndhux+kQk*jM8-duLnHrDed>^5gH{thw=;)Ak%75Fx zQ4ZAE>7(a=YKmlhrOLauJ~7V`XotWhVEWUM>^B*TC%4>3ZMAgQ8AomfQQnThbe~p{ z_gE-W7D})9^U`Kx%xoT$`OQ(Jl6x9TUAb3xNnS<^(U0zT#O|-w>T%yQ#Q5KJ|E1&c zF14}H1K@}m>FmPMHBWY(_I>~A@B`q-Z?Oje$p7>Ysn|O@tSrfhbE>YDIc`z^fC53O z`fIY`R)S!!?Ov%)HUrvJb}0Yh0pPZ-M-_2Ns$MnjzwRreJFLRr8kGp<>?mNeXcrA! zJ2jOmT<1Uo`51Z7ycy2rc{QTdD`#iBcWPq6X+^256CYCgT@~5Bjy$ga@iM`kG}0B) z-3{L$CB**%Zi0cwWMuO{{13ZS|Eu^vZQT9mkeG5c=lK*W{ZP{$XF2TJ>c9>*lQW+e7X8 z67z~z&UHVuQj`ZOn7+oDZHh;JqCS&aWZVG_C@$J(MX`tN4PCP9(_S%idWH_nG+^QN zbeFM}x^&36tr3Qs`*cAp5V2v+`}Pf7UE=gFnK zs72*l$2z#EV!Az$#l;1dBnXEd{6bke3a*sxHNL9bSHb9Pjha{CstYNoYMjs}8@R;6 zZ0yKtm;ge9TwT<5oxOv0ZzZzMp%*V#w`)YpGo`6rp>YRvFZq1vYh=4MPg)!uX+XKz zxye;ZMfE_{wMW0>pT!U@ZBQ)IN@nkRzu(tz&o3tZeA1z(sCi?TLOeKUJciB1j1~mM zU&E;4CYrs^s@rqTv*aCz$5nYvc2bI^iD6IY{j`ojQ*?gm*@vhrY8WWbr%vP=j)KT? ze*1?1c4B@pjkjWB0bQU;qP@QPfF_(CHtu zlh%O_3zF2zQoGN7ee-(WR7IL8r*7EvNnW9QV7^fBU`!&6I5vn6pCDvyC3^#cTq9yn zwlBWXpVzpuax^jzD%$2@B78E73)u0M_j6pHehF10qP#{OcHS2KU`(X~u3*~Le;4f! zx)c3bx3-YI#x059u!t?o4vFW=3a>pZDRg)8jv*HkGB4n6N4N;nirJKIa3n@V>cHpK zxJWU8I#r@?hn#(BJ5OfnIXjC1cT3SjtQlblVLn{TE zMyIY-NTEyBq4iiTjF=LDp^K%H$cv<iLmG85nqK`}!okDyd9>vMp|&kc6*scA1kKF1=sbyEX;yx>=@cDS7E?Q`h!@P$c=?~Sz{yQ z4l+IE8*|G1LTHGFK(@F&7rID6`SR*z-p@~0;ncDV=@hnhPBr`!_h3u6b$88XfSe(| zD~>|1a_mxYlWe~pRL2A39>;jIL|&E}*H02ti5xRbMv*q#Ijij!lV zI>~di6W>T&xyKq9zHfGo@TA-;*77!zairx830}Fl2qS_UWIHvXEgqfOJ`@J_9?GA! zw6$I&7ftdBSJc?Xb~L;=UT)m=myN;~EYDdxqICop(m)%=A1A44aO8aA5lm^qV>OEC zX$P0zI?>#)E9nt-nRaGG4HJe4$un)6iPoGB23L6YT_|EXz}R=MviAUimtt1pxTSe< z*+~iNZw$BjO}Uk8oQzuK&?s#n$iO!tycg-c}uCL6~qcY_OLJB|IPUEqm3SK z%%iZem9D&52TJ~=!x&+sF)=L!LbpUXSwzn53UyV_iZHu(&Xlh&z#m8aJ{_03vPwZ! zL@!9;fGK-Jj9_>_Fcqa{vR6~?Ge;K0;?tC5H8hl7FMPSBkBrk!8B&E~0 zz|To%7x5;j%it(FN@}DsoO!8@Rbg*-7bc9ygUcF5M1l98M7xby)QFZH>YF~QoMI!F zOf#oG*|EB9#QfrsSmil7*l6|(MJ^7jBNtlw;K||H*~tmDyceROFN9H#Cwj>R%-dtz zq|-NP*17Dlbm5Uv4f5z7tfF7h2Iqw5P+zh-k2_@kfBV^}I3skA9h97SfBlqHdrUM9 zhEIiK?23%X_xG^>^uqUh+un6~exXp8K(#S8 z+hjzGGeuGot)xcPSEmANC!~tM~_>jgcNS)!nH&Vy0~>1^DTgU zvw)6}!;0T^=cAhC8d#$Z!5^K3*>48y4Mjf{*&}k&MjgEmb}&AUx_eK5n}30vF@S`* zHx4IniY&qvw+rGPrHJ#tG%6Ra2QjJBpEIG;7Jq-@Hf7A9D9`C8S_jXzo=pji^QuW2 zFy8{MW!g=+1;Xeitsqj4AwM5*#$r0=;} zF{}B-YCJMz1gE7w0GzTVvZa+G>^trUj7hBnoT zbQ8ktneqoqWq{wm1sAOrd@yD&;i%C_)|Jv?GVasA2)L+MK;Oi*>Q414EnA~lme!Ni z@`g`qjVjy-RT-pw%5mxFp%N6M0p7_^?PSZ4lGD=UHnv11D=rwwOFS7{l?aoTj@tNE z!Mi+bkg#oAvRl9ewIruUp!5Cw)oKcRa35Z(rK-oMxK@439cj)|xQF}{ zkiX5&d5Ry=DQ7q2lD};hm-`rM^EumFh>2(p6#XtRd^1-HI8YI=ZRZBROms#KP@u#r zT}K;}QAr!{=n4$?u2=FRZo6rIGqHO?57g%mNQ9FzpNHvEZS@4|2q!EkGF0w}AAvlP zaU?HhzdN%_KABN@X|y3NI@Tc1q#`sLqugxab6;-zy1)?STcZ%c>Epq+Lz86rHMAs$ z=U@sRbJv@0u?0zrE2i5BHXJexPx>D{#W=w1h;gNF({vM+ zHhghi+?I;>*lPRz(esweZ>Qj0>}<#desHT+U3ay{{*BnxUuJEtm1_pYbk3_1(jR%km8V0T)Fve60gjdneke3>U_+Bdrq#R~+w zBwrB5^)jFX$Zg8?tW1jQ4R#e{TDfY!T2%CUdQ0j}2Kmd)ud#OJ@=hHMP;|^Ma8wbx zwLuaenfi0A-`CmLFT>jOi3q4g6H5K?x?Bj&4Hq{-M7DPM{@nv)aC|f;thl;t;S3HcmN0vTv=S<`9;-T(+8|;*@Y83Ggmt=Uha%3^O+zgqqae@4ZHwW~C~$O?2%gfV%JU(}{z2&RNF8m?;JrGXB{Ca* zzL)IN=n(V1*<~oh!_TI+>|deUlEyjdh31OR<8tSt0-sK^rwSsR+~q~$@2`D|LoW;* z)vVqdAYY($LRN!5oDyl+I(DWc0he)FAjuwF??_zS7m0FfCPv4_*BuMVV~4T>*n;^a z8Qqg>2#rD4n9eS1De-0KK$dSBBBRh4oWn+KPmBm^gRq_5(K!zkdU+KscH@`^vg%2OPkc1Q2}gE~{5FIdDHWJP|AG7ehF zVg(S?t92dJfuP!iVeoq&4fbPR?b`8eqodu0kOWxuc0=p1ghO3Wg?f)u5t2Lpv*z<& zS$~?acWJK;iuaP<+o?d+`%6kKMtUSbXNFIyTv-!t?~8@SZn%uUWpe ztGi@GxxHLgl&SUfM!ckotNx#?+{Fuj^TfQsOxg7*yjm6(!8OQt+WJko@0sboPoDc* z3--i?Lh7zeFIdl>?7QtV-vak%$1lUg!Q3}3D&I@K(9^`pACjco*HVHJs0XX73IynC#lfUqBG#|3@|ch)TO;A!y#mJU1tG6zI@UUYC~ zCgT}ac(NyV-o$y%+)u!lw~xP%H(y{pTWu!yv3_~&kNO}W$r0UsE_1=lK*y9cDv7~h z_T66MW^7zQ=OL| zI``}+AR-to&c`L9a;q*)m=Zs)xPr~1nv-`4*L(8Qk@i0S7m z`%8*T=-blR*Mb`cW4Rl-xugK^`>FR0FFR5v$O9jYqiy4^2_U}r#u7l!S3?u8W^ z#61fY+Be6~yoHDJuZoqeq;yHnqbdzt&mXrx?!EM7|8eHPX_bKRuuUCYB#nsbk~^|A zn0f!Htt%`!Sw!9{Hp(?RFpt)*t}O2dSMIfGSjyz3890KHrISV~=A?6v?)ZA9bGBk$ zujzI9n8uK-I-N8>GR$&N=RBE2%Xu2fQobg5dV1xmGr8_GvM|pAI_-`(Dwb=;|8=wA_@$`S8HeYltf@a#*bFGWx61V5?9l?f#$n616Lx#bpMcfAKZY|~oKsu4%lGPG8a%ObrgzIgJfjG|^YROYRQe?PoYjlp zy34*Ce2DfFN_7}%`Ip2k|7GdR|BPQn9lKwOu5y2CTJS*i=&PtP1Iz0*B5WiR))pn^ zuzpO9P<}{9UW<zt*ik53UydlkS|~ z@>E^>J-&imrN+zlJX`+eciNHm-3blo{%zUUK|%@R8P)7fbF441`smgr>yL+#x1MOU zj_BFh-htNASoSAC6ph#g(_j6g zgZRmBSi@w;5hZh%vcqR$T#+$;fBXDf-}P_AYL51GiZymjNwa%bvHjhMoS6 zgcvRpx2%;rYY_8zybCa_FDHCnvXcNCBz?O0?thk{`_tt8Z|U#tnPTqw7}_h3{JVL* z7VplU^g5tFUZD?uegE&l|F*&ZE8`&dm4mzNLD|8Sm3V>axRl19mc?_;Ukkm8%w3Ao zd3g|*m^S9n&C#2kD7|?>91}SH2d4ecg5Ce6KlCylH*H-qoSA%HvN)*V;PdXknedmA z&i?ahq;I!%6K@251hoAGxEA%_etrvmt;ziBSzdgeE)U8!YdQiIvsaLJV+Dh6FkPZ>-`>OjW-t$QGj>C!)|FRP-#SGnCzY7& z``8mkXM0vg2^{NJ`KX&@PNm1s=KvZJm+C@KM&qUEoI`nYVtXW!BSUueWsr4 z?98?^WxD!5C>7LoI->CylGc5Bo9XxkyDXl#BT-FxCrF(Pw^DD@9*@@8lxxU;?y+#J zhGbar2=5BmO^K5e%(4HWJh64spc7?gYp%z@a2PA$cf;n7h_DeWj&%-;=PC#$>(;6>t zOsf2RXEG%Ye?8_1&MKGtQpaf@^!ta!neUpIS*9~;oC*(#$}ypY7hbSJ>%y=-e&GSl z$s~rJ6wHq){vgY~#559-CKG`!L@LnY=t z+3tyK*_E#o*q5`EN=7{%%~ie znyPv?#E>$-3ZSxrI)?>`vt{R1-JAPrUyf2V=Fx)OF%o@mdnB_QIo0YQaBUrB9(N?_ zZZwVmGRoxis|Q1=w94&HX;}WY(qya($8WEnHe+?_8PT1L;`N>oajaYw`YQPdh6#?2 zk+8%*=XvO5vAM7|AF%$QxNcM0JOKv`iJ+8!u;x_kFZj! z2S3Lu^|5Q^@`h{>=CyS%KEDQ^Qw_n`_<#!dBuprS+cw-a{Q*1~;?sKYB7cpGHXDY= z+Njpq8`4n*>3(`n79shqTReoDR8u6>wg^?exSR5{&>Jh_V*;<9o?+p-zp@vH>ahp0 zhMLBtv}cwtSRmCkKrP7n!sYbf_yFn}mZZ#4D(Mi^q|nG@_4R0Uvl?4FM-ei zHRoj{QQ^$@is0@10vne4QQp)dO6a4gR}#X}S45`^ivjDD5iUlZjW8mcASf=whn+i& z1dS;VMTJIfB zRes3E#kdNPU_#($8|)caScc7E8xGdNLWV#^5xME25T5nyO-#F*IolQ6@nZ|(k*VsS z+(UT^_2kKFRyhpjcFr>_hpY5j>46tco5Y$*?%`7c#BCd2$Ault$db*Qn6&iQqTID( zDeo!d(6Vh=o95@eb?u=oCn6%wz+#v|=X}ts5s3h2&Zs*Ty)g&#+rwosKKb*N9qKuxPvR^2TpEHfQE!ZS*Mf~@3yRgqi_n4lDr?J{_#3tkkToyJBO zX)0{C(}A7*E!1Kh|fgmG{WD1C~?GJc%-HaC3mkdLE!HMq#i+)G=KQ zdp0Rtn*FP(O#0qdbpN2N(^%Sq-d~YiPLame>d%~RJ;#aE@+zPMQ)T=>8pC&6WwZd^LaouCYOx)K(Q@Fl?`hhIeZu7s;@KM+?C_x8^+=w*&=5_Y+Z!uwEF$*XGB~1$ za3Iw!o}#ilix<{mXX)ai24QruV%qPe1c%}C8x#vZoIM~@AjBZ{p=6m`CwmrOJ5)JX zSA&I726@(W^OAgarAnYWwLIyq8~+6P0PnW#Kt!!aRiMAfpa9hUV?yrQF2TgaHy6#j z%;{lItRJF7ME#G%raaad$li^=MKy;t!M$d~9_N|vSOqGM1lD7g>!+pOBSf<(p~H+s z?=Vb0FaCR1FfM}L;8k&u`BlditMZjmkC>R1i_S(cCAf6}D*#W#)KOb8MBJ2>$f#%@ z+HRj|$86W}Il@q*0=(zn_ar>(E>=werfKrqdg#)2&S+8+nsL;s#$*Y~DhQoWSC@|O z-Ntj^_7LRe9CeDqS@D&oDElJWdO`CT@~#rhUpinYt)wK+1>DDZT2RlD zd71qPwlA`gwXeyiI)n)-N^(M^tapgZ3POaa(AaN8&6PDXjOZ;%!^g^+5Ky|CzWu8@ znm0zb`bkzD$~MWgQP3VN%!Reeq93G&k}kQ$h$NU~FOsh;sj~WcD9zqe(gXjyJ*_u_ zhNH}piG3~FTl?@3OT=U2;+%9?%=1nab_4!;R?b%2{v(?}kHeRWbb`ODZ)rQBL$Qr$ z>-5uIXu*cSQkiW$LLzT`CR7{(xMotAFV> zb&)X)hG0vwVo$P;kRm`NB|RGYWJGmNsDovSWiLvRLyx7Y_QfdzmQ9#n)@An|JkL@NU4v`xppa4pMTS=bA ze~tEcR>ot^-E|4}e6?*_H^=G|8`Dacgzu~Ta9_zsFT_PGStz@nc6qO!TmkF%=KH5M z-)hIw<<-0PuzL`@3C{btN(zpVJc|8v850x||3I8Y2+7Le4T?U+^kMFMe>l~rKc{EM zALlrr#0klC4c~AMojLIbVhpwrTOijx^5H_a_sfRN(h+v*uk55X6%Zg&4F&P90NzVM zm(r0>{?DX`86W?i>*n64u%a`{K0eFsG%^syQ>8?COoF%)F^nZbh_+>5X!i2#H2c=h z!>ivOHE9~81vs0=it-a%EYf^V-LH!qRC8=5(Q|Op-&(0rdRj5wamhN>LkKT81V9Ay ziR|?wE-p)oGOHm9egG8(sAqaiIUj{xYU&*MK2~EcWU&hpdB@-`;DVFpEufCpSKoTI zrcYywA%Kb5SEKH|!$gW%AmvBb!0gTZ8DHl6U4yyHgOA`{3cxDeY!dYMjsJ@w}YixzBf=6jE`HN*Uqna#YTq;ra_$O_Wg|w_PzZ!yYWP z)(E`ZI;1F9!}GhJT9->@u-b_W?X@)FJcmhuQl6P-sI_RrbuG8^(H!g=g|h*ybTeXo!i@g;sH8q^ zH&{UK0zZ!d=NV%zCWJ-sni*+YhQfjzJd^ecfgpB?$qfs#5Xi!sd$W4qZJs<%09ws5 z5n&_WrbyMR3AMIjVwhGrns+AMNO}~(!@JoLyVkEl>JOPJe=hJ`YEEvu$SF* z5Z?OtMta)0m+Icz` zl<*vd_uR|gb|{7}?q zW_)fK<$TwX0eN%(i(3#3xnz==Rg!NmZNP)0z)qVjw3M#(IP6YIlU`<%PGPZ&9i0YO zNZJ!7(`z98j1D7ls``-wX=^*M#^6bIwjmRXk6mJfeN<;Rjln>mvcw>i?o!v& zA%IKkb6hS0sV5sIWb@V2wj_Efb>qP@$}Eb;S$^(@_GvZvQxODObl_G_c zJQV`|AXtGfb?ScS`kI122ZZ`q|C1v{rvmuo(`V_y6137NE2RjbDOQH<;HUScTbWfkkWw5_EtR5k0c9_mq|`gJ&00SjDO9Ez!LUw~BCk z4LAOH;XVV^Bx5@$CmZYjZtX5pjqY~?H{+GDYUTPwD_^v1TXFt2$B%=w z_8h9;$Ccrgf%eH!Q*D1JM2DHE98N?D1i+D>N_msuj}xq4hn7)=jN=15o&s%+*76RT zlES8!xqgtkmB0_Ct)C=PNcZBW@Vy_EIXMRx^E6bNXU)tEfC2*};KIuH8s;`L>PGQB zR-bB)D}l%+R5%=Li)?t!9l5wM0(}`stfE%wr0JJ@t}i^uE)pk$(~z%o~if z*A_KpAgu`My(IlZG=O3r3gw&%I)HBhI|sC7IY{e%lax$t8&<}E^c)#L!q6g^+0Kewvxdqp?0!q1NR2(!$(jL4AZfb-X_ zP9k*B0r!#-*9U_S8&uIL0an1$oa(yPcGxz9rtY~Ylvo5hW11thD{`x@L#qqZ58Y7K zo=Mx@Ma6Xk%528wV4!O`A)|mv`)9bt)#sJGJg*)~LMIUTjI4IjIV!~7@>S=}o)WvpazLj${+1;iqU-rukJ2coR+yR-e4b#1P=p@B z1v|R(bt`LYt;+pRa^s=*E20asSF-~>G-@p#w=?Q&vv+k)Q> zNoUw1#g*_c9XRB>(1rhU((JS_GLHV48IAF;jwTboI<41!O3e%vY%#6sn%K1Zpu^!d z*T4Xe8@Su=?lj5cK95VLZI7cgn0|8)Jv#WIOdSnF;; z^MB5nR_KtwUsq7+;#~R~iH-LB0Io6i82NGzLfAA>PVvaHtcP6VrKpk$7FyN3eMM%*~jT)asW*_8;&7 z(mzaLY4ZX*-!nA0pc^Ou%K_i`%W?f!OiH7|z#?n4yMT?^!K5h1CA}L{sw}y|;>_mV zQm@ugn+qz^OIdTk^6SfqrW^!txj}B~Eh=7UfW9lmp2!nyv7rw;}U1EJ4Ko_hL zv5f`Q0gcGQT&oyC>gg6dDjQh5abQ6GU{@ho8~2a?w}Vc_frY9`mIbT41MH09rrh3v z5w34&Gi>Q$L(^*gYy@IL`4Nv|n{UuEp%R0L@A13ZUZP`4R=eUx)df3}1@^Tf*e-rw z!nBlcs#fJQ0;WQzd~aP5!i%=%hH(X1Q$~fq>;N$Uy$w}J=Ui+Ln89S zJ!kq_`Z?0R8>a-Ye)7Y>n0bI6J-&g*;e0G*NG)xn`T3k% zZo+(qhc${fHE9O;s7+3uX5K(1eWOOb2Uo6zwpg!leOcY0ebjjB;5~ zvP>UumiL0ABdTd1B8Cr0odsv>_si>qbLTTU&dStB^qJm^q)~HD8mxkGF^Xq!ZHBmbuZ*(dEigj}67O!e%r zux;OJ1H?8#i6$fVP8c~o`*XNT)`eAx6H zvzw;W3wh@11q!ou6mUR|`mV#fa}~sF`2rjJpGZ}$UddDMhf z|Fj9#ofAAjT1*^;8@LlDTqiG8DxZSRa;#gy!*jFYgz z+UlTpeN{XQ+W{~anfj57ASX9BDYk|7kXNP(HR#^r@NTEF$cM#_LQU*cwTJv^Lc*h( za@GbQLE|MTnZPa^cu;rmd9U@A&Q1ZV*^wM?50g6-zo+oY_Rf=n^-qdbTpS-z;vg@EZgCqa z?eWF2Ppv(Ur=9j|R1*g{0+cK_>Q0|oyH(aI3f4FtQekHfk_qP76C%RRz_!qSsjdxk zal1xBOoP|Wq@=%;{ce(MrY7#ux@nrcF2mxES9U6tW2HAQtt=r?&@?N_`%sqyPmANyvm+ru+q<*8mFR!WMoBfa=ZfFAm?IdOJ|)p}9>%KO?=qazCXm@H;| ziWnFzrsqAKKH7Xr7L8hJvjwlq-7&3elra2+1@Th1-k3yhgSLk%70OU_YH*v0y0E%9 zIMm4Aeb(#MfvcS@v6*NMuVOMBGv2(eE+vl6tt+HxGAsz{SUWnVc)nx99EBOa_AGsH z=2*|;fV)a(&&`8!yqzyS&vyS^IiU*CVB|P1slOxYdhYegjxs~GSP*J_Hq)$JNuyJk zWIE-cQG0!oqXAEhJd-_QqiM+zbwsC$Oq#ennPChQ>YEf~1bgI%q*HNT9!hg;{_$Gg`p9@YiIsh+KI>EOU?b=G)OuIV2Br3SSusL4Bn(z= z{f6^ceKgD~1ikxt4P^E9kKPpHDI0R%mMr@iZaZqkHQBD-moz~YlQTqRX`dn$ctwQh zL>xL~5`)1`Qq&mv?lq>Q0T>>AjU0?*_C{AyUd|Jt zp^p5z+3ztoN{+5@KDo{5>`a)TM#t*q$0VnUQjE@yv{Vwe(PIZ4L4u57p>jGA-_nEw;w^bbezjvnY7kP~P)Q7^_IyBM+tCus z%+}*b``$k(mpWE!SbXkDE!J61qmz0==z|=^FIC3f_4j?Sn%%6QSAx<3g^_|>;~)BT zMDYuLVwbGh-4|*UgqB%1O1mRaU&uYpf&Jm~g`zE6i45*M)k9r-c`i+}MS~GF>>tFQ z#4`uzVmjlhpHNea;b@BT)dwF;&DQPcbx9iPb&VzIS&UQit9Ojbg+pp)ZGygU6*{bz zpM1A>S1=#fxc7#^Y=2DoNFGWEfMQONE%uBwmRw1C65`O;XHO5G_yab5M z|E=zv7-gKOq-7S8A53|dT8qZWgzLOrQX#Y}2*dH7sBDdvH)Tz{?r$>F%Y_YYN00}H5kX0^8d z0(EW?TyAObljItQX{v-hQP$o8ufT$iJ}Rcqqk#W>H-}TPjfX2F8*A(M(&3s*E2zu! z!6IEYe10p%CN(1l)kjTik{1^djdFK1I1dMsF7nh(XRp*v@6SKMUnW1ytm;wHWHOj< z+x)FFHQ3Lpafa3$7b@Rz&bD(bDes=0nvbfK2KvWHfY!QbR5Ghya#u|Bsl8qH;_8!_ z-pWiYPK6i5gz7!%b9*Z2UYcy7MI=X$xC)SCWc07HSuYBTZ3==57o6~re{z0DcRNXZ zt6*hq$XpaKrODZppfM@HYy2L?FZO*JEiY+-AaW<-E^!r9XC>~v%xAX6h^@M#)${0e z&7IZBpr8mL)-F1CL+sR5u5)4hsPGQB2A8*p+9@1yU)0fFn0Gs8Y>i z_g*Jna=*Dm#gsdK0iNHIRg7rL_T}eg1U%7=a&0UEgh#-ZziH^9lc4@!DYvI5*$(fPxS{tDJHGO+dCEFFn(OcAMwjnszQdVRBYS)Amz zz@2;67&(E&))J7t-wKs;J>?$?THr&zK|ttoAZOLP{y?M^@LXw4yF zy6bH!E%x{o5shz}7uG{Uk*8Ca{F89LI>QT)_|l4=D=^kYMe(WVf$seNvs0O5Hd@{JY%e$p&lLt}V2C zbx$_Kl5mGai^8a84K5#|(-aV8e;Q`{^raf()eoyFh`#;!2Hrvxa9NJw4zDtFOC-uh z4`p8-(*(<0a|aKke;6L+mtf)~0#J&6-F-_NzDzhcS5$M&Ik?*ogPl%qBc3d%sNrwF zPp{nMG8yM@#tKh{eYQn@RwLW~AQ#;bGidx~+N#r~St-uECUkGg$_xgpDsf@jNKteF z%WhgZ(tQ32kTYY*tvgauQnyL3F;XIA_QkYBFuFaBjhd`2b}`I1wJ;6`!V*LZ>oq?g z_3nO9d6qcaFRL7GIYMP&aF`-wr1w2($SdFV!PVpdyKX-rhl^VUWPCxw+TN+&Sx~E6 z$fVr^?j)_WUQ;J{Drd@+w76ME1s&pq-S_7kPZ3FN1l&s{P4x;(pmyb`)SS3iyLCzZ z=B;G%WKZF1p@AMMR+j+YIUmHNG zP1};ZxF|Ws#QsMyLUn zwsbo<4KT(YYupPHlxIrnz1aQaqL?(b|Qvuf2pAE6=PAsk1w`ir+$O_(P2UQK&B<)Mm zieMRkb!}ZRoGn@k(l%gw^J8%Gm9VR+Oh~)%rq6b-_AztnjKQpM@1(RypuCk$h_O?< zLI{;H$k>{RZ35ayMB7ji#^%7;IMSRXNe!I55F2hIdSmMti;U&m057id8dR(L&zlb%C(s3TYq7h15_hu*W9sJM%x~i@B5ed&W;cKKMquBf`w8jUd z=P!yuh=}ZDSY=mfFTP|CAM_#ons9{QCzH!FDkwC!NIhL*H>&x1)M{t7aLlQY{Iw7$ zI^s^;cVq7sZcBHMd57@5rq~q9lBq0rQ;!k{H_r>y6_KDrf@8Bl(~2y4&D}IkX^sfg zST!P3-b~nIgFjqq`EcBg!Q8qPN!Jic>$o}5M{ZX@Xiv>FSMP_~o;LG| zpLC>5z#@$Z8~+I)X(;gsZeChgYR_RUJSseG-^yA>ukC5k@{9ucHlO0r$vkw6wrNr^ z+;L_O0dx~Pj7QcM&B^N%OH}zGq@*T)I1;SK=PcP-VAcpWtM!kbOB_lri6S&UG zEl1IMY|iotE8Gh${{K4uDn^z}Z}UetHM#lKFecS8cmB$85Xo996A1Z-=DE|rQeHBsO#C!J<5`=kmFgDhz6PhYr zO=>CmCZnKmZ@70Gv>{JAM)py1tux&)oWRWE5Jh)yNt?sD>r@(~sPc$ZYYBOOc5h7U zw@G0cA%ENe*~;_EZ#VaPi=zK+miXUfw*Tg2a+V}EPf)5AEl{np@$gNHjYJRV0$bN% zRbP6fqAsRF`%!>A=9&wT$|cyO<^EV;fB*z)8-|$ZaIc^HrmDoB+Vxaud{kz1p$2;Z za7OoF-^~qN9b`S*Bc*XvqY=rF!gRiXc9l-$B6Evka)sYWE+}!c7-P`T=ODYXlKfn0 z?;?y>y}?SubFYv#h^o4${1EVvy&JfsGah36^^RPt5e!uExn|{6RZ7WAcI9}hsqn3d z2;s7(#)3=f!9Cuj|OKKC;Hb-B`Z&PQfQ9zw4T)n-B5mVl7{1#R?8c7PQ+Jp z3L9pN%>_}e$vJhm%lCB8VAuT~|I7_UtLP3o+UW7hLjY`r4rICqCr!dMlilaC1Ffcs z1*z^knCgDp1n(boBREBstefPh9g?ivWCv_gl-OxD_E9cL7&{^pXzCm}zssaXH&b4K zpaOe0tAZY{@=`i9k=!)8yrYN8xyyeejYNye#%hNRVU-yxY;6Iq5X7D4vUI#AQMF|( zK+7}gHb3~mS6x%(BBV3CFWPS*(_l3bxj*P9y^D$&?5kO^FE%cmWE#tvmF(^|apw;< z^%WZ03Yef!{GswXw+`QSV!%$Tx>F|jLDfMgy!QL(6fpb_R0zL!k+nkqfH4438$Eu1 zSSJ2KY5f9`BaNPldnRwd0x8LVj9b+pk5W^(Ra3qrT521MBL?oyZ`N2s9XTpf={Lt- zC_N?ng8y_e0ksd?aOv`T(k33$)ICQ*!9IU=+p5nLygpiK~oW zFxeQNTQ@glM5OA1qX6FRK}_C;SFmiNk2`qpRwlf%>=Qa)IjxB`Q>QKTxDHz=5s=yIkDdIY1!=+S}AS`nOF!WU;c|kzqe8aH;v?njQnQ z5G!k_jOn+Sadh0h`p{=NYpRvWgE&30QBiR|u&WOF*t_!&VfSpimrTK2?}4Q9+&=+O z=&O&Lu~W1I6hU*?zM9NRVuKT`oTY6#Tfk{>q>UPyW<>U`Nz}1ib>Yx?_915#x$ChW zXXS}d)zjLIj17_#{3=4iP8ftVpR|W4IM{AE= z9F;RN(v2-}eZHI6&6f!F+LKdy(n}{ku_91%weN<@R*Kg9ShWWMmJq7D(T>^*7bGL| zOO|B{Ej6I%E7bWe>0<5@RIZE@1!S+`kh? z>t-&@;b;M=;l5>-I9c5>+Nqx%tJ!Tz%+Q!e8UREmk~(mIPItwf;$%2_=CX2t9u{8K z&)I#r^V~#BKY_AarW)d{Y2@ykWZ}9WPC2BHp~X(oQn>V&k9q$&rGxZUuj@Fby>F8} z=|R>z2ZNU^A>A~K8j&D^h?{qd0XLN3cG1bj?22fV7y$bBW8sx4#FIxF@c6^;F6{wk5831E}V{bpROBPF? z>N6Yq2yhX@SJde`bFB~$XG1g3*Y2ch1Bg6??C}n<9cCf0YoONix$N;O{tE@0ol8{- zQ&$yRyC{GgokRe1+F|6ehb8Kx+rh290q;(4FP@cyoewOC3g7T9Ng}|eicT_D8CPY> ze&H9EDqY~5Zax_LEoMMeO*G;)9)Z2%;QqKE;2Wg1jj-}1+Xp0Kh3j6rId!eDR`ypT;Is$fLw&>xJ$^LIRsn{3IBMRNEtZ zbi9AzKK`P#)HZQi79@SKPaL$PvulxlfmwM>0Mr|~BQj3q7IiFRCyQ|D*qxQUo29`oM|RkU^7;D^Tp z2t7YZTul zj0=|zw_Mca8wlFw7||wZw47dPw8M3tAz>&eR?HG31IH0m*PFkOf6|T`OM$-?Z5$Tw zb1ilGXz$Y2sXkVlE$n>yuJ6=gicVz8Dx3wqM_E<)=H7W6fpr%1MW4U4N1B9de5+rL zzc%4^c%vEQ+S)! z1?_&ZE$@2ikeQWUa=*Xry!?4x%a5R{Mo0Skl$*h64@8JLd`VYdaksMEaLLyt@wE?! z3rpx}u+6A`egv-0TgL?k4-;Q=o+j_n&Xis>+Y_feptjN(*Q}w9xw~}^D{{Z(c`qc)&`om#Gbj*#}z z9N#A$QBZKGdC{2bF5!gyZDeF{bYAdUf_gsLmypB}_~<1**W|Tb%$cTJ^*vmdwR{^F z8QpXlJRAL-4r>~s+d=QRc;M3hIGp`UYNiXFn^K*c5^a*7*pN*EEq&rlXS-AMYTZ1# z7xoOY}zm?QmL=i6x-fr58Ocqr=6&TQMw|{o+r7)Lc zM&nz9t9h#b^r6~AB4i-dZu!+KkDSOfqr*wIMaECT-o8x%No)x_Trb4-BhKyzObH0U zve%2p4*@iS+bWJR`gUC*)7O>7bqY@RM`r2p>FI2M)9ucqqegdWwKMlvc(rzw%2k~JGELtW_ic&j4Q{}=H>VPeg9 zLYu~||||5#JT*h4BqwoKFv`({)1wnOa~c~*43JKNZX`3SvovFhd9 zFCH@|oxCYK>vNP{Z93zj3Cp8_VdhyieRQ2HLry`py3ZUXuHtD%TA>Wx-pW&Jjq0-rA{qr1!SW}CGZ7DZXUrWR z&CZmLLOXGI-oe5&elSi7L}_TKqa;PgiCIDFqL`No zSMT;5k!E2JjW~Z;lg?V$(o;7L?xc?zWw&pmlSzOIc(f5Zb0fwXYflCO#?*8jSXLZO zTvcV+X{M@*v6|IWf@++~gyuQU#YqLc>O4-jmI(RnVd933(Y;497(R)hD1m7~p#@{n z`=|ER5?8&t8`UbNO98QPy9H}xg_KvFqTVo=i1|E{*(%14u2TfW~e{k|TJp%RV20!#&; zG5sZL=1Si7u8?RNdfHFDNvzOiae0&~XRtxn2h>?9XwK+XOZ%`lL8?Nwl|;?2 z+OgbKn_vq{s9cU<&gsHNiH9wasC{WYhveH>UV|dTss?=JV=`r%WCdvqj0_BbPoF{u zTiGGM^}J+ysjkF6#91aEmZ-;K>O1n7=*Q6Y8|{#QuUW0<&onfomPjO z+`@cB5JL|Fla~FRNYEYH8mPaDba}{=?eBU+&!<0Aum_qX$*)?a{>J1zt+UTi4|q_! z*gb8*aHslFx&HQAO*xI@i2eI^`FPaHOtv7MZ?Qk^x(*`|%|I*Jh!X{2uV-_9vhRijT(l>$g_fCoaI@a<$Lrk|G>4-%Z4g0tzMBT+5+~BjWz?i20iM#%q**mB3I~>oFpRBy-0xhsMZoWK zjeK$38_^I^5?LamEk3a4fyW$&6Y8PGUtfkGFZ9J0lW)1n&nI1Ducf_gS6}PvQh9C-Y;*IF~L!UZaJml{n(t zzbh#g!=HPM;XWU}D@@H&1g@pq2YJxndkhKwXj5E8xl`eln<5go8MkY;+ItyIfS3Jt?!)~Kn>07C7C-D=B*Bh z^C)D}2+T~OPBu8s5?r0~OVrG6hz|{7>ezIh!V1~36BL@ARiAhn-k5El14n&xuOVW* z#Lo8yfz1Z&1;_>X%gz~jHK4{xH?86&FKrRT7$Xl9m~D}_Q+6ypyZahx)^|oE>A4fROLbjc67o{i~EHC5jTu4zo7^8@L1 zsjDiG;T7XN{So6^B-BxA*@=%1abFx$X0tNMw|rDyRsy&%Gk2*$QXm?%RDJ@gBp+Mr zFu^Iu@Ias?BwEUMV`Tct;{kyL8pHk^3;6JP-e!stxe`E9gr##d@-@E?- zw|D!091{P<&-8y7vA+P4$EUxB`V0HLzt7A2`?T{B+uV$t99dBCDIQ-AdzzJ+fheuu zE??$fr;>lPPWZ2uRQ$V*MZ@jNiKvRz`L&{>1KbEbjg_ldWj?`FYy;w*YSRZ=(jLKAL{?5%?i!R&VN zBC&BGEops67oov1atZLjYgjNrmr<}ddoPh_ehHDSMy2xr7#PQY+$xf)w^0d^Wzl;o zC-(ob_ufHGb^X66NbkKDK|rKRF9B4fi*!N6bJ3F&y&suBm^(~*G6DDwB541pP!OJ%``wI;IrIzV_o{CogURJVDX;S&{oRL zkH4}TLEM$?yg&0%D3rha}(EY(LX(s`6Av&8l6!*GRCN@Eqwra9U zwa1N$T9wK*3I@xHa^ey4^>(Y1d9pN#J(@4Pd9Ho%BEfy9vTD@8;HHclK!z(-Hi6UV z$rwwo``|-QInc^Vwp;IWuYVT`@92yBJ^Wq*v1ay`ge>`Sl5XOkp)!%ifpIhL3D1gz zYBOa1NKsm>6%OnuF&Mj1@*}x{;wHOIj+V9AU2v(KtF)Z#q#7LN)D`B$0f2S#{NVef zrF$%jt@*sL>22pcA`+vrmwP*?$XQAUnx1^Q$f4XO7BU@D^wAVoklG)s`xLGW5|8lZ zvDwaP-`l68*)+fSY2edf2ccdr{!$Nxo6)FjdP(^67jNb55l8PDY2}T`m3mM7&LDN3sZFZ25x_6ao-v7g*8VT^N6gjXg>m|K!fJo?_BsI4V8 z^y)a4t(nv2>Q!;kX6R8`wu?cwfe-xn0IZ^4Q+BbY4q`|0gW8a~ov%;b<1K z9HJhUgecs&^NAw1qz13^oZyB6ITe&dlxoTX)O0v{+FQcYYX;fa&CJh)TIcokP1Mx9 zDbTR$v}Wxb1ES^4^UEaP@nk%TU0Bzf6pF;mM z+*nd_Ik*xV&Pl!zP(p`BAipVs3_M--X7W@vvO-@?|rQvQl}edj&aoEI^Mu zYf~Fhvc~=U#B94w*SxZIc9P6*{5bQjm+dpYn6{*i%+xhD!32mMgMaD7+u!&TPD<#% znXVdFo4K|ypJwFj(G!+v&c!IH&^F%)nI~P4q%BO|-&kwq!9-ve07->8!|;5Jv^Hn2 z(kj`F01X|7i&<+_5xTD3OajPbRz%X_DfP^VLunEY`Q%Wh_#dq_7QFP6nJ+9cH}*~u zrm~#*ltORpv&(2;PI4a&2u5c1s==IfxBSrZ5pG^=7sJpouut(i06_g^6O81Yt>fuY z@1gZmU#fWhuNnNi`ij7EMN~GJ^_o~#!IW?2HwjXwuaX)rW;^mNYK{6$e?c7p1B%Px ziKW#zDbZcMExj^E+bBcsCEup2IIXdNHutGnf`&g7!E+`IxE!ROP{*X)6sGCeRx-@h zS;0)F&d!d4lRIEJ_3}n@kNbMG)j4ho zMa}z^*4c`n&yyvha;3Qll?7?PK>GKM5-D3{P`N3w@8#u2V@=E+EqjH~@|bYxj_y<3 z#I>7rGj@74PA6J0=>@@FDw;3W;v3ow>1sow_b4ymLF3zzo=bRe4@rk3I+3U3B z@rB%#tZHRyZ(wa(SmG?ABG|@NUKt*#>ZE| zcW+6pzc>mdoOEVJAd_C3+etr1>;P3860AhaSAKSvSS_8hk0g&h;NW?nJg_KjG2!n` zBFBbYSonS$9{z0*Z#6GMH=zuP<=&+cSO|d|&RYa=^K1B`OS3ZM;bs$RCq;!BM^cl@ z^Tbu8(c@jz=`RhX^1as>z)eQBB$xXeCdQt^Fb%4AVjsDmg;$XhaAJv^xzUIVKMbbe zqs6_i1~kC#Qw5L!kM8zCAP1Y6#RDaxEa?6(wlPUdX)k9Vx!`(0KYQ`(KHIOoT9#~N zCR$IpJ8Bvyv`q1||17RP=b}tcBE!nCOwvq8-mP)I*QS9^&Pa!0Z`z5oIO;2gCG&A+ zVomjmz+hVmU`ih7iPaphBN)dam&5n_n;l;KgE~Ury{NSEBk*#;Lj~eP9r?BdY_pd9 zfV6pq1ii?=Gr*Wx0tI76d*+@K668rB>a-Q=ppf9aDY6! zuUUEtqwS~5pMskqYhicOb@zPOD8owQYNy(b?l6q<>P@WL_)kF_$jCT$>rc2@G{TVO z+t@YT0i2V*8H+d?EaXV6sO+)isV1EpC*aI-MJt7yc-Nw(hC$efJ@z*+-kDOagxIq~ zqDkR0glf7YgQd8M(I?&!%=M!MK`~7^$%DwDsMV!&p(c*w5eVYVl7xmD%Sy(?6si4F z21AW^h*#_>^NXNYpL1r0kB51_460#lP-p!(q!1%3vSOH~X^e8;1 z`xta;Kg)MRc5J8F1;j?B@lDMDQ?p@juP@8qqu^sk%^B*Eg6LU|jsmRKIf1wZDDoRS zg=ThyfDzuYHX8!ON6Af{HX0f>ilN$guR*m?^`U78G4V^o+vs|WS>R$G{p5s^%FxLX z?K5W#v^iAH)6Fi~z>mwt&abGR-a&L%^nGZohGG9Z{lKhrxIDeHbFzQ$D>wfh1+mEV z*B-02!yaXgvlhmBYughEb~mfo}K>m-%ROgqk#20=vf8ZMRj{imHeGFeJ=ZA zWZmXg+r{ZXqg{PZ`Q?hDx7QosWZQx79RM=pOLD}}Dk6$>MXYu7wcDGn?o*JdEB`a! zW|O5d6>rr~a0>AEX!Yc_wP8P%y67cSNUyYeE^~DO72S#VDM zt+X&N+QPiw#|;`8X$rz{!izjgOuO!k?ARHFP^|3i#7K8BhtJ8+mcIzlT9C;}7fXk* zdwJx3#PsS*3@a_>5dyl`lH9Ru6bs7%%FtY1{kIce9*n0K`Bn+@feJo4&^!iF@36ls zjc{GRt*L3{uBk~<8ro2E;)=ocedz&C_7mj->XeI{exSS5`we{XmQnHs)b$Gciiu9l zGNyXB%LR#Dy5~rxY{)x<87h<)!xtoJnz|Mjw+icC`6XsSix35#vAnjq_81+4!_>7n z>eVZ5-_Lke6f!^i1&H~>0{18K^3PBuh0lXdlGEM}xk^S7=WMlYfUx8i7L7jKvfAI~ zJ2B-5l$(Ko_k{!mG>;}6&DCx?ZsU4Mx~v*LrO&Ol-wSD->h>!vEX4xv-LB4HG;al< zOt}NgH0}D|C3or(IPahqaDKx*IG2 zSOiTp#8x;8ELAg=s+e+gn$Le(1|)!@Dp$i3eAy^&mFAZhHJT^J^_u}zcvy#NeMRE* ze=Wmop(oiA^GX4SVf781{#tqz<&487MylwDGt!MrL8Y;sAkMGZgfH0~6P~`d^$E7D z0QNN0NKZwT!xh++qIhitdUWh1K40u*Xc)A!$ThgaMm5yvD}x=&5U5CydTM_uoZK~U zqqcS#K4BS_XtnyJ{i<+p$u6Zb8u0UEX<`5Gq5`aNdgs_ci?t z^hZ^yJ)y&p-o*-nwBbuT5MToks_ZJ|KZ`mXx8)|ud?o7sUQgeWgrTG`<`j#rH*2*f zbb>N)@TcVn?vUUWyOtY#tNfXKQ~_e|y$(Z+FTpV-!5& zDGOe>MSHKHy^H={OPxG3%guyI9hS$_TEjsB3iqtj(C++gP#$HUUq32Tcw+U{da#C| zCq{zIW8F=6yBZty@2vWLCl2c zHt{leoZ}Qwfa9sMPrv*4ik{lwK6(7#!V}7#R9e3WJ1xQiWQ*J7g&tmKk9QQ5)kkrs z6E^C-mnV%Ds`4JlQO_Xxy9v`w=K5xQuNk;_1O}6=b53PbW-G%R|3TCKJJuyJ>SD#A zE{&%aKU0CrM71<;dBxtJ59IEpry!_5ULuN4PHfa{z}2yMs7Gq-*$`Z|Xod@f??XDmC^uPfdWi&_y_kG;Iw~DBm8mi~q^}%(3(Zn{KU$_EYGiEo?dG45e9T4?g|o4M6~yPCWr-mZQAnXc$wUMWO^I^)ci^!8nvH+=*@vl&w9?9yLC zGL>}}55iEkIVH%=`J%imI91nOn5c)IM{*imHfrt2V@hf)uxgk`?LMP1&|k}lu5;qcI8lMT0zOoQ4lUbmFDQD};g}qvLnM zPqT+HQ8v%Gn8#-Jk`Du`^Md*I``U@4LiVdw65jfA~mU8U1a9a4 zkgzk=05WaKO{6%oHSQp|iddU4pS^2qXcH@-66f__AMA(Ewj0ShmZ6=Mqc~`#W>u7b zufYk4R8ny)UwMV1#Ooe@HC#;AupfYB19Bg(E}MR>`$4lP=^CIPa@BAhaO1zj zU8w#p-tr>c1dcaahdz zi@>jSQcwtX*ij%N@2o4&+6dyJ5Bl|}JuutWr)kP;($boJ)?UQ!vWI(h%vwO-zG)Fu z{P~j2p4)#=VyW?ouiha@`E61xIFx}a*<1pad)sVSUemvC?^ih&1I^6LhMytil7Qz6 zmVX^Aq~U2#Gl5Wl+$q=%Cn_$i_++g5uoS(P5bZ6;tn4B$-&&G3xp|{kEg5VND}qzZ zyIVDSq9-Rb0*e~S%gf$B+A#-q?4EANB6?BZORE~&Stwb1QT zZg8|W%!`P8Hl9J^60~T*ukjGLfEx-sn9VP>u%^_b=@3;1f;G=nQi2HE7vEvjz)Qm@|wOg#?pI!@7b{ahGfSDdeVY=~ZX^DzX#o4edJ%H}y`&mBkX^+p}!Z)l# zaMPv}HM%Q<5!F3A_2}{lCbbjjHy50?ZqG&=nsZR=_{25>t)OF)*jL6u9bmu!88XXM zZPt$`R^-|73Oyvk_%c~72e7UM7t5Du(8s-%2Xl}#p3NOy-xUqZ?bdN{7nPh!o35)b zVS6Nh!~azZQ(6P?!EfHmpSMeHPblX8zU2aWj@|4MwK;k=n#zN_0yPCT^t%={%v#UW zuxJQNZ_VuvdldPFqS#(V#Gwe|haQ>=C z{IQ{@o%>~KU~Umj!?LISw{VDeb`o>2tofid_jCZxV$e)LyQ})EOMV+6^pMm)Dr(oC zCu=4>hz;P-!IL*S#Hmr6d|&klR?*`x57UomAhq|P5tO8cJKdR>r6>1^c%I*2KTBf- zZnCjj%n9NY^!_&8uJ89D$zJ2hV*%bdz_XY8d@sgT&c$qCpZ!|_TY<%;;_!FzH2USc zD1oW9d1Pn)F(*}fh+)V`es0X2=eKgNz!jw>xw&fwg221dZEJUa_CmJ`yP$YsYzy>a z!V%WCxaPC9i1RF2Q?;X)TwV72Nu`@IEN*nR`{*&ULHF{Yj7%~k{)+NMJ$_O()yX2# zs33f^4o8nF{Jrq@XN$=u2DZO(_!J`J>E4$vaRD-?Abs#lBEZx)JjjBs@Nd z>^eCxJ3yU)z)qDuNL8gPAW7_U%)6zX7h&hS>=~uIEFieu$kA!QtheFeo>U%qJ1H+^OiPU*AW*#vCLy zvUpdzeONO4Af)7i@HHv*6=QTk@p=V~7tnNKx%@T^AuB%O{4!R`P4X{-is~h=LORB= z>6r%$k5J0xH#RJnC!N5y-+(WEn5&z2{!B(HMj_f1qj52oNfZO*k^ zeKIt*{v9_H?A?afdBcI)f=!~bxB2NoX&rE~_FYkR&8PJI;?gnz&yx0HUSrAnI~o@W zEuh*0LRaLatXd7V6z}WbagFC<4yDjT<9SIoEASdB>J_qt`GhvaACdB|xjAved9C@P zy&-f^-9gI$3$UPy(Nf91!rE&-l`TfMEB%_)dcJmj5EIG};%+r}aQF}=oJqi=;5r8@ zBs}`evkM5P+=t{4%h$mvM7DiOR6}D-oYqm0i;*2IX1e%sz4(=lG~;1IC&&u}|CUb; z`?UsY^GgEab%^i$%^_|Iq8`q!wzs8ZR@ax@B3tg;XR3kMs7h(=#evMTA{eR3u6@zB zo6aV?F`X7w4~W;b>yGW77hZ1y-qFlG@shLD?r>r;p&)iysM~2)+wV5^t49?iMM+%Z zw(n8Kntmy!PW5zZC!_T^xQ@b<=Xpzr%N<3ecs&La6+H`#C*lx1Hrme{_?rk^UvVrK zg2Q{SPjwp*>5}T%7dao24SkcyQ16-ort7;`78V_08Y}`oKjNLq;siltCe}$y4*L3e zXm{1>&%A5)B#dEUnhY~CaEjM2v7xxzeFUfX#@Ww&57B#IkqTRZ@)BosqK@X5&Q#vX zIJ&nglJs*Yz?q73x;h1zZOeo*=(elUL~nuWP*C${4<|mllU@^CL#^LbZ`^K~*k@Y} zdD=3KZkj2gaiJe2K*=2u9^m#jZNqSfwKIiF)?3szrLJ- z73B>jJ)8}1Sg{r>6IISGCGDG)9tx!3;J|an1^lrG&;Om55i)o#Ny;HmiojXJIVTUA zDRpJRRRVn9*pFbDbV5Qucm#H&x8Ux^*j-kY&5CFY2EQVRQY9Z){HK!IpA_9nObp-c z37DQ9>hoClDee3Eax5Ak!R4|Z^_3ZJJUYanqM3}(*QMvk{;<}c(ysab6YWR?PJXV2 zS_Jx`{JquW3=t1W4H3}nNED|3Il2i5;B3|?TL5j#XdBKW6*)kCL>fIhwVxt?NWgB_ z-}~Olrefzy4M*jiRgdg)YtR3ZDO2(sG%@Oup4I9+oAY>@FE^<-muyU4^yR8YtKyf89IhIV>VHKl|M)vU2is&wVYcuw0Z1 zRJ^R#fTT6NQ;X#>oZ#xdAXz|spOb`=az8P*lh@oGQTGbp33ILd3`+r3VPim6e?rsT zQL~*?=)Bp(yTRE`i$2+ERvsQ((#Gy(rP2>4YfJsMJ@4}6R3A1t!5`7goI!F-=U-5# zpT^Bxvd#u-Kf`^0HV)n0hH%!-Mu36=t-`1RjOwD?5LN*LkhSw7JaYTbe)?txX*tP@VoQ@x#HxJ)Hfo-e6kN_Q#mGiz8_noVvZY<7Ue_fEDXE~ z-h?o)XmZ#5jt!0G^A`}-_s8y(&nY^u_vZv7b72$Ls7K+i4CID#3Jf5g;z=A3+cM|P zASE)Y(kJretJh@*7-KW5r|^=RZ867|uU0fF`kkX@A6S1pkS`=tn-}}kxF{l7*O7}= z)T8$cBRqEfaa9++679{(X=CMH4k{`2@G?o3@bC{I8#=DVKP}NbTAJo{6H|{*`wE;O zOAzFr@`J)Xp^E0Iu6eI7W|Ky23LNiLoF%yE=WWQg8lzKXAXfwR&0~=wE|m@7@rClu zXv<79{lF``7u0?iK$eABF{MZ`S$B_{Bz8jx#gJb5G3lbMPQGTd)4=5>^AI-3%er~+ zv9|1;qEdJuyV7)i@!V*LUm?%>>xp6242B+&Rj&)ek>5#F!7iUm2+z%b+V}>Wvs@yn zbUdS46HaCFYpb)fc)2H>Y5DdDq7j=H?7QVB2*@GB=iQ^3*3UdMGXw71Of}M6i(GRW z(eWx#?#~4u8G1HvCNX&pkq1bRMcfF>U z)U4%e5>4hbf%E}`*BmRpSgcCIa5@d(-;nBEo3Kmo`6R;Q~GS zHam{lSKLG~DsfEHw)@+V!^ubv63w6qV5@O2n`#}IjEoxg#wkVLt{*Lnfj#o;yide^ znveHjtu50xK4p*ft;5v?Uk#6-9Wx1EMOXJ(V{Tp9b|*i7LN{Y>!hC zve5onBC?zL!jiLRYGUOvlr(+$ApHYt>N=4+nc8Ay-t6KYCJ0kf0c~ZY*VkBDd0)nt zH?LKxrDfz(2t#DVr1s`WNaB&Dc+By>MaO>;{o&Ro#sbCl>81?jb;u}}MEJri(_!;F zC^Se6gUEK1ZINeS+eug6lIG^|l)Ry`<${W`ea;M@qU$ayD9IVe<&SsGeShu9{jqM} zz5n=gLFz|4q4L@(yS**&9vG!z=NNQ5L;;~g=C0hn1odrnNHH1BIo-H^7I)u>_5zek z?)g;Oh)D>#ico7JBNOm_YiE!duM~A4p-{HzC4WBpLiY5k`VDNd{IzN`qhfQjF#CSJ zdu2nSB-a|w#7siVpo8r3K4Kgf+S60tI+FUlFq6*x{bJAs_qyl$Z?#{`lRtRh^9Jw4 zO`mH5Bh>6|{c3yVJ95U%W|0G^4 z!9UYFGau5D7iIoMke64j)wu{h$r#hp@IVz5GqVm@+wGUx3#*+t@iB7C)za+C1iUc# z)p$m8R`uD(yk@Lh52OUoI%_&Emq@7jwAeR69?5l>(_>_Z7unKk$LsI?qRv)-VxT7A z?#=!WZI@#e`lIDXm&_3%zqn0euZAkY;%>$Zy{g>GL zPjw&hJe^ipAhV?0(0c6I)|TD1;&}6-I^%1SdB#UA{qDz!-;FX2Xas%a;Nx|>)R)1^ zU3E$aPDGNQ)mFtQMNx*_Y>tD^sw`!aYrY7kj_TqSKI?SHM%{BX<)HGt0zT*Y=gf9m zh}DCinMpikhek3F2`W1>fD+a;~mD=5?XRBsQ}8i0=aBI#s}KA-@g?xG9VG8i9)ik#k^Bc zTHqZ2LKtxjUyCUC(9|}7)3G!^BQ{UT?syzdBSxDyY|Aaj?S`>968aIpmQgb^Z9Hs5 zvy5#LfMpE_<&V%X?pXf~s1^XV{fe6FHT@}0$-xte(%TiwT`(M(i-)V$FW6U_Og(?^j)w^;Hsq~8T4;Vj z*)Q_C^*|h2PS~R1l(87*(^H{QwV$*Vvbc14%_(|qB{DCEpk&pe_wbT#wH_qod*LoQ z>JW`u`GCVyP=38YS0cHf=Lp^6xD1AP6`B5*+xwv}!jADXA#*o(u$x;?#~asbWiJw& zQLApI)^tAXh3tIntlVqd-lsg$i#m3{^&vJHT3HS&DGm58kc620^k69)R0<>=xWy+4 zNiKwZb2(uESgn?q^5LO2`et`8Tq!nu6e83cl|_#-pxBI6o=SL|3^hy6uBTyLGd$K_MDE;`_WbiTLb6|C`& zLvS-{TaM?dhtB-wW33(=4ewd8Vhmz?fRYoOP4g;cVl}vD7LbF(IcL9AB+x~RMDyZv?6m$fwvsQ$ zAKtPzN#>xvo=s=FtJd-YHh)*_zCYPymYb_xIIPYxVT8UN)6RHt8=~{ zxIgD$8&Jy6VAlTS|5FBqI$|+~$8IrqW)hJ?b#fd=6iMD*CN+O;n4bD4%It6Hiv2%j z`#-LR|I400z@@N|`QQp~pq)(C;>|k%K!U)aY&H)q2gjL3e0}UQCq?K~QI`>gMStgI zxwpTq0T+iJRrI>Eb5+k;W1!sxxk^s^$WFI*W*j;w0%jmRO@tsPleMF~wya)v)v2PCipa#VS7X%?;^BPPX1cTl&TOFTXb*6><9l(b_Z zQSs>=5+#OF0r@U~^tGLQ!+D6#6Bf}CrW#8NN>rlwCu%y73q&B@s2Tk-_7l&-D@)xd z9E1g1!UZ**^mOTNpVqLAlZvg6{^aX|<^mPWR}_?1CZ|pH4uOQ6hdBi3K+(vMQ$Mmx zTXMX=8cPi%*r3%$yIhq$46QlLJQb7yrtK`eS6hlG;UQu$>~E=Ghx|^%?0$8L~Ivd`>+tE zq-MjdEA_rJz>X8Y|IcMfOwNSqWaE=D%1ID42{-o)T=p!zKw6=m&szJa2blmno`zSF z8H<)PnXKV7LxxA2_qJL#Z9kppxKe`K1vRF)zppa>$=Gm4JNbJP_vQP?k>Qf}na~}b z^LmftgY3|q;DGo$-q{>ZwNvWyEKG&LN~*EAXS{t0?2=%+^|5t|ej;Jvu1b$EK&MUs ztTp#_O@YW0ah)7~FP|`eyd6k!UL5yJ>CaOn;qfAi9awGC5W}`fGLScIT+0YI0&cTB z>MyucxnHQ$VPV5$4k`+QRm7zk?tDgwSM-^elMQvwy#3{$G5nNRRV2U36(^&6JxM*^g6vyQ+zK_AD$UV6qG@ zrLB@tz&DmxV~eg!E-5K?PpN~Ch-*4Iek zy8!vW2qt=f1AL|2Vy@mxOWhntw;e+MoRo&S{qtQtlW36PXG@*v%s(as7^2J`Sm2o2d~vD`DL^2js6v{zAvb5st6G2-=> z8ve)>phoUIuW}_r%TZ4zKq{!IlL+7V<)z%BHyiH2dL~t_o0_DXI(uQbXX95cH}sd; z0o-e^qO|dUS^L+5`u`zBqSX~8B~$b_nL)?w_swPb`)j|Z#)LeJ* zw4FTC(8{VV^6WNH`{C z$At&#a%BwuMbLawcis?Yw>@ZPL?bvgF*OEwr#cVyp@lYPdsojLM=-{XPZq50H^zSV z$ldZTL&8wiuma|K?r1Kq1(%@6#b6$!jbU%(dsKN-Yb)ZQOB|=K=NA!#9h<}>o#m!J zt+*D(-7tFLCpvZ=Ajx+2^ccf|F?fGHU8 z;Ay58qwL0Ple^iVts`~`C9)15)dN~mhg{o~<(OVFN`2`o^j8j{pdOhMT)Xp}kd08i z+Y&X$;X|7!`dxA~j|IqFjI^3lUVz%Pd{Il4z5boV{Lwa|SYF}#P2!8Fqd9@H(xSjl zE0M0^rK-cGWo_A)ddCzRyYWq!o0XsJJZwA*oNrV1>Im$MJfTAIji+u`y?2@CM2C;>|tX77wY*nx?U4#N7S+a_+>0aR2n=Prx=mo>N{y)$gdJlhfAf@lm`{u$g>U ztW;B;Qb6|jA^g6W+CE)r!M4&Zx8C15Hm>7>qu%TxvBx`UIkAv|-SU!PEpb@@2Y(P0 zJY)(oqu`kEPfHsoHUAr2r=`=S$hlzc9mIOo$zsq`)Fzx2bCiHi{-U(k*WW2c3i-Me zb;gFL`DfY+-DO@XEh{ZU#2#>=G^~pZ=%eU02!-|g_+F(Sd9PHWBlPSgV6Y8&EUIxf z&WOvMvsZz<|B`*(L1tANuJQ#z6Pa>CJxTts3X%BW)n;QARVm)zWk46Tq_OkAP-g3Lpy8mqd00Cj_qMNlw z&W6z3R9%EMG+udcQfZF{X<458GFqD2d@Ha3@cpo>)-ft?8Hp8!IH#@?DiOS05<+V*n{;jRa@QYu9Wze5a7sJhFP3Rz30ntb&xCC5{V9+D6Aj z4U#dDeO&nrVc<}XGedfQzfB!9A<);mm)l%Hg+{>*MWeXHK}jSpoXf?gv5erpJ4 zFV5A8wvnIka2Fe%iMwwM7D^lKPcAMm?{SJXy{h;65Gd-DoC4+=@PRL@QFz>&DUHm! zcIhd>Al~X}J=mYue<__{%S-xWYw^V|WAB1aeZfi7ULh^z(u_{Y_>U@jr+srD2L42v zm7jpa>YWXM0jI3hB7{|M60$>QNmAgoh%?sy!vt_l1_{n!TAJTGuopvdbIvjubB|F~ zH~I;a36#)3=V7_YHZb0v{a~h#Xx=-gi>UEugX6CZjc>77*kqSWEZ+eTC7Sr$;P+Rm zoTD&k9pB-2psJ$S_Bt&;WJLe{WB(;t!w%Fj7Nw_zBKPj`s7$GV)f7}uFuLz`##*OU zfur?_RKDo#y}=K`JByBf3APadNbX&^Ov_%QyHeWbN^%uQZ}z);xc3Cp>rR)Ykeu&--}l(F7ZT#Ac*_v~I@$F_U=7V1n{zXBbCX^P zph$7n{4_;aWX^~p7f-{lng6PS@g&a1-Pc?jwqZEGH;7#CWmF^+@W(BgTZ(N3tDPZm zRJLG2x#i;S>09E87TMHwo4?nBCVG_zzbp6h27h%^j!)UPG4d@guZTjqYiz%&baqaE zdGqBOEKZ5XBIi@=kp(WzM9=WDZ-#wiR(9ojHL@WANOw}W& zG8a7>Xz1?sq2=nkoqsQ&ssRhMeAWes5*L-2*kVNw6{rjQpi&Q1YA2m06TJ0pC zFT1>(%)M*fso=g^`s$51!z3`I56OMv>XlwmxgWAO=^fSoqG33w)mm1hwa}jH`sn8a*xZs~BRvx8kErtD zNHiH@UWW8lS{&`!$_J5eCEY-Mc>}ctxGtXrV@u5qjU!8%Va@b*>*Vdf@Hlx|nrgF}Vsug3cA3s-M7>PkcV(Zcp{5bR)!!{r z00PFV?imP;YR&Xibbsz0A&{bY&}-2B+c`StH-(x5K8`IM)-0nu1zZFKw#k|nG-?!x z)OH;2dD77&F6@U+B7Fy*TcHDko1aB@y;_cF;|}^I)dXoE8Vzn~4b}33kxloS?#EIP zH#&LrKzHu~g1!P)&#m#6gr?p=>EZduEQ}fk`m$Lpy8hGRNbd1hzp^}pf2Z!^tWU5g z3t%fGM%Ak@(AIcIm5?iEyy#nYGVWLvxGp<3bu7EZz}jSRnWD##o5T;YRgh zFl^7G@S`cE=iJhz{JJ))?(Rx23Lh--J}t|=;sPvx+8kf2!N}|y|F+(0u7^BOtDzK zCqrTG9)9U2kee^n@^j<72RfZs!){ZqEQz_ ztm)_Rc+unEmWt~E7w*&eyW$x6WttxI;oMT%ue3PO4V?R}Jy%DE>wS((TBe7Sva$qG z`I+UN=tuJ&1+`}VM(SJzF<$@<)@dU&!kEL`(yDtOPfCh4Hg?2R$DG7-S8yN30KQG|Kg;#r#r(xxbn`{O`xH$AFMo@~mLIZ6M3MhRK;zP(w`hD5uiCBzG9lvg7(u^5FWGwG zmQf;iQ2a=85nJPH#3Q)|Nk0jJX2PcaV}6n^qR7ZQ)xZgJpxJV{P}Ex@x#U#(ws59v z-i)%=SlqGf6sB%dbMX?MB7+jj1dI00q=it)gNBfle=qCui ze=PRq-w`H>PFL{7o9%fG-;AoMCC~3S+@w_AjP>^I5QGR*^SOCtpTvZrP7rbSc_mUn zP8*!wqKU!1WTzB@x~(S8SKw^&zJqDfPjoXgt*AY(M#F`y-P>SWV|I3z)A zys?_;+4jgrYf1U1)nn~6<}9QN)gz$61snVTX%wowR0!S0kr=tvnj6o|;CV2^A1YB^ z{y5#WE$OscfX&Q)h+<%ZU^X1{PuYLs+lk6+aE`b0x6+C$L9rUI=Au+tTuNin3VNUA zX=E40-U`eLj=rgXxhY+|x#znp#rn(J2vmqDOq1JI*wms5R@-T#V;NQNq08+iaa%K0 zz!l&gk(V_M3l8+Ea(~JrkRB0!9y_n@6tISWjKo%`L)8kM+H@7syXW$W1cwV01jEQ%}}7@2!~mOapL(C{zsP~&=)9eiwVZ#rgXq6ZXG zwYdpYyay`FF`Ag!3B(S&w=KE=4cf6bkFI7Wd##yAv!^~8bmU2YVS?++@7=#8y*%#G z40ZN8DN`u@O+B#Ev40#kJ+vKAA8>YzceUS9`_{4lhJ`3r{HXc&9g+K6b|aw|PX@O^ zoOp;%<;`X2?+UUXfB{LfB@Q0vVA6tU0*yQL&!?V*S>GK|HFM%k*f*+qw z>)6i;6v)VrM!c?*V^l-@SUi5vzLZyuJ8j9mFke7kPJFMsqb#bVjK86=UiZu*jBAaSy(A)l7Hos!P!P#Ma~D)t;l3+V(9-=PD(zeg`>v zw#+kcH%kxz>orDI);bDydqmpd1{v9lC;7K(8$1ndr*Gc-{rkHbsl4S*+_+IE>vsvP z?izx_DQ!YetPtVax1FhkCzliEe0^0lYKmcC%T(P_EfqNm?ooW2r>Pb5cb(6_{->f} zqpi{il#mLO?wYl=LB}2cu2uG>-7HP-VZ~bQvNLQ4D1>MY&+`72sDuGlDc5+0Y%oCG zeeK}1GDHEbuM_9KU)-m0kod`E>B{`8rUcnaS%!Lsrp16=or`jG++I$Mf{9#DV3|K{ zeVd+y0ZI~IeK7?Bd*)U;*w@*A<<2^9;MXYkQMEmzP)hEMU(O}OjX~zobz(w=r^uqA zG!>nsEW`E<0s`oL(5gcJiizLF`n4t zJE!$!0%&J^4l_M{kx|d;|7hUdw2))WM9;cFax!gTmF_fR^Ht8Z8)~U(&T}*O*B$Jz z@j&9fCo*!>bgq~rt%`%)aN(7&jw5&YWf?*VU>i!`wrD?rS-I{n+xMh%y&F?co2dPA zwy`dLD4I-3fWJ2az0U;_$P^-TEq=3u(-%I^}=vPVV!0cs(*D@!^6Z@@0 z!HcAM6F=3Z=W=SX+I}*m8>oXfH>pi=ih5kUyUXP;ojiA90BfKkhfR?T?hq9_ktm(p^Pf!?x&@xC-EVY{lVLT&uso8pf20mQ5tFC z48nJ?MxYwMw)W~&Q-Dn1=2m4$jtkmT^m4Kay;6KE&{{w>Y z4=Bxls#*SxfW~LJ@v!cYq6X7xEp5RM`7P5H*mrNoTw`^HmSKLh2^z7wd(km?kqOsH zo$w>ztd2Sf_w+@Y^7&*gsIU}7B#qz>q@~z@FdANt!2^*UkbG;%M~`Cd=FRU)0Ti~S zPIuh?BB;9?7|p!lu(pjr4yQp^j<>=iK2j%Py(ShDT2}= zN()7$6CiX5ph%M{E%YY6g{}yQ;(g+M@8{loyl3ol&a((i+pB)Vrw8puuS# zs(CITe3vJL{{P}DYQMh{_xX2QZj|7c-~A~3?mj|0|IdE@?Edntq~HBq|K0WlZ>;j~ zQycz&`xTANKSyTp@0pCRe~yg*-!rm+KPT?`|3d@(-`MQkUk1qgpBmuCU+YBXUtK5v z=gYkP*E(_fcdnB^mBEL8udLfPwUqx71Shs+ej_fH9Q#BgE~1(+}ICoNfw_~V(bmzG94qBUk}I_Bra_i5b6&+NEm&ugPkack~WJ+aeC@orKd zW%BDKsDTNx;0U_`Cq!i)+k`f88V?jf%x1 zvvA>6IP{D=xPop=4`TT1gm%8H7wJLl=9*mY(UW^Vz%KNh!bJU#{J!)Y- zB)qM`Zby{8GHq2L<@HSi$;2lcYJMiCydN8T=XPB)syWYc+{~8)ct#Lf1V%pi)JfGh z?#n{(C1C7VEsZR_V{_i8yfVfs$-Y8S)_>{WU~bB!WK%p=4p9xH(XfSk z%f#eJ4Bt9GU~jQ(Fe?JL(ZjsOA|ceAyUPV!yGI9*SJ@_Fw^x!MJbqNtIKb#Ieyvqi zUgFZoq%BTK>DmX+A$sqvlIJ&O6Y3_fn^KkR=46b0csIN8de#071LP>l zcF8fAF88L(k;+Nl&`z+#oy6=(-K{~G=Pee*d>BGgFR_itM4FF$qoK<23m$@1s7%qE z%@mMm>!;stv6zA9I}J1fP*?Rij+%*&B~A`vqJw*0iWtjI;I%R3flrR_IzHK7JO6p^ z9{Ej(SQO(NyYHK3f(_^Y+hLo zgtQ-56lCI0N@&#$ueIpdas#t%fhpCC$1~)y;*f7$H>f}f4S}p~uPS#3bCPiBkKcYA zV&efMbf>&*VvFv-eiYxZQ|Ilc6g-NX%e3S*uU33}^ua8$+e(rsrI`2!U`EjAMF{~{ zGhx6XGJ7729Rpwz>RugW&gXoPh>lS6JJ^|juWSkT3E|*SD#oPMFq^A8zx7U#1T85i zOR%r#QrDRWOLwWg*cL9@m6drHn`ztiNo=BU-(8j4qhS@dH(&W5z5?ci$pf7yMfMZ! z$zOS|X#hx_S7Iea?To0s6-WahhMf zV+ZUjnho(=+c$%UoCte7Ag(*HaZyBs?l&7zX>)5rzUzH0#YIVeN=G)}Wxlq9=kcTk zyF_}6Wmme8>%26wsjd4CMAw<$?qLpZeL${mWD6yK{0&+5PVtzWIBvUYU$qSh8t5cgB>A z?LCG@KvZeRZ4$!g*B()t#wB?$LVF#?$4q}wod4>gfDHo%`WQA95%xW`N#2_(11kNe z!3|SV0i}YO?jgbEp7)^!>h1fq8#0jvwkYqE95I2Lf(u(X9T4lr3wE)QFyS7aam{$4+z6G&-uekn^m%>p)OF;^sQ#G~r zBSc%=32-f*dpE^$5x!QB_%^gk4f*aY#Fvxs^gg6xiB72jvbUnhZ#+4yls)EA=mxe( zV_?H~T)guoC+`r>0xz7h*H30tN3dyi-9k``Urnf7oUnja`VF`t1<x1AAQ6re4Sjh3YsYP<+yPxhTGm2n3d_M$WUT=+eA+OEYS&KJzFA zrMaJE7fyM4#p&N8_kp1ksj+zAbW3jb#Wt2+Iiu($h!&~GDM$GOs(o?Ka>o?Aeo)dBFNWhk|{&mUeEX>ltCosW4`w6h#IEdc(?TU4}ejb2075oqLX(J zLt7eZv|$p~{o>qbjPYsl`wvMv-CRF!gZ}_LAkwd5Cj#Hi3=VZM<+$aWK^lLsbs7N` zRMa)vtN+|*yTF7V+Bj7dyr|PrzM4?DK!Vg}y^tr0{HMe&eDp$$r}_P2S3eo0;w~#J zPdT^>03ht#lkX`-rp#j=F9nq?c%>YT;7@SQcJ^-N=r*h$?#Jb6x+&$H2xTHXHu_n=|b8)s=YY{b6EalN!DlPAkaWUaG}b9;QW z!3fsCiZ5Bty1?h{Swh{a25dNho*Fcj{_$#(LG_?2NA6wE#l+p*Wyb3MyU}nCm)uu6 zMxRh8b1xJV6^OD;tHtjN3;Z2Fy!T3PH19gc0`oA%nJ+)H8Ve07=M~T9)ZlCr_`*>8 zPl)C76CsAqdBss*jd*Uw%B8Cu5b1K1raD{9QS$UNaA8&>J^#jG=@VB^^XehL&^BPI z=4(d8SN}vMC_|0F*qCKak^dU6i=EX`c;Zi-zqiPPgHFCQW@E&$v5Aa%gR^a-rCBU7 znuLV$P`ojm+xKms@gC^7$I5#Z9l5a>HgWjz>WYuFG2UEiAI=TeAG*5b)&2OYqftQTlP|+6Dm%T#zkIGFK$(a|Y<4F)|VYT>+5t z=B_6SV*=*c8IQDA*&RrdC`Em}Tht-YTCS2$09gSVdH%l5e``!R%N_%k|qV` z#pgc&4lT)}iF=I;t*Snm$ysngms@OECR#RWHBV9+8`yT~wZbWd=aWfzm*~F4UVZ(v z3iGicv%L>hl?}NL*J%Z1@V#y5yRS3GiEdP(1`Gi9C*|jVdl(g#?v3CNvy8 z4n!k!OwBc?j1YM~j1$RV%eyaS65(95>hIcQDNs|iqQCHp zNfW-j;ql4Rqk)Bq!aE(O@C1X_9phQHmS-|wRFy9kxj0pAKEKpcD}Lgc&{IF<;Ahup z2@!H~QZN_IPo&Ij5`TH?@$QeCUF$6^yxE)VA_b~L5BH{Gw+mv~lvMf`WFEaoujmm4 zYX`zh^+^^cFF0N4JiuNZw9_}?XEyNyG`#&8CB_%Ha95d-EhJ_801hY z(KNJf_GNlXHq-s!MB;J}%!VU1s^yuG0UEU!RFGdGLo#C8%RWgT5+6^a1R#x%k3U`Z z-b&-RB&a3>rmu10v#(Zms3d0AFRxG$3bdVglL7On$Z^Q=#Ia9;U8&1bwhl{bv;t|p z#4b>Bp%I*(b1l1#&k-b}OcX<)6#%SarRe?us?tkq3x?vI`)k0nh}$%$D`i`SZ)odlwF zn-NnwM&@l((JhLwYVOELoQf(3IB&!Ci=NL4W}s6@xU}RW(7PI40;68{51Lwg#YV7YC6yl{&*U#n-Yxfb@MHYAyq6Oc&7x$lf!?gkkPw!n;B5!Tl7mD@OacojE zlGPLYHoyHgs_;OvS%^m*uDLIEo02s6QbhNdfAKq2k>x}uhX^&sL&F6r^+S@*XzeXk zG6t%fR^ooqS+W`(-+V)4jz=ubCE9_zq5*b1aG$iCITRhqB0xOmzZ9T5&+nU0#s$~c zyCY(iX(XGoHyKDFBZ??(fPX5k1lNGh3sRRhZ99(<5)mSNqB$*a^^zR|_+?+ZcSJ%l zQFKZ^^G%}RN-PBPcvMzakMu#?a#~Id84yTsbYCeIy;1I-w%&EBG*VbvR1hM{m>in{ zyS^^!orJ6dU839oNXfUugn#c{ep?Cq0g@R~WjR|AkWi0M6ti{I;jv2^*~hra1vPz8 zMYc#SP}=AD08K`kh8QRn3YtC+vfUezSU7swygga#E+d}rV+R)+6hUGpda!?bU8cVXnfm|A2iAQ6%(&YP!Pm!Ja5~_ja?1 zT&1xi_qc>k$uS!;`&Vo{vkmlw(DJEPQC_b3-FVL%lv;pEEhP`uD$vnY*hTLlLt`9& z^OPCH#p+>y@l)4i#kAKvH{;iB-+dFX_(2nPL+>mHfD7e>m$o>wwcM3`_sM^I$O0dk z;6Vecs~K|0|4Exp0^uFs4{%D)zBN{CD7)k`u^(@zRN6Y#h4Mu1*N#CjrFnkhF_q;h z(YeyKIr*4R`dBQQ?M3@Is|aa#Fv7xKmFiJ!E^{ZDek?zYY`l{b=`o4H?<9UWw8XAy zmaxUos{y874&d-^D&YD#CHrLg$2&`Q{q&pevD6yU+eC^dYpYq&85j}DQDX{v};Gk!3`E#8Zq z3sbvzxu2ty*n%Mn5-#%ne4INf_71<`wpWlcVdx)h2nT)&n@m=vyO5j;jjJpuFRUzf z)8NpTrEgh4-FRO2^TiB&IH+#S!dGGcl?m9MPCu0f{w0u>cQZIjvoLMc#Jveh;14!* zFnLxbfzo_|?#xc2f9hcV;~|62$KmE-0~btD%zQI{YmFwG|Im>4{YxJYmmltQo9qtLzi5quA00rofF+z`lsoj{<@n&@8-7t z09<9B`>0)l4xoN^h++e>jYzESt{0?41Rb^rqalI4`m)9v%Ia%17L+o-K02tglx{B- zgjboV0VU-X?GoNruqsSnop4aU_iw5&^O}gyf6BE|U!{1v!!V$Y`452QH<&KIymoe9 zss^&-#$g`M0^ba;6yrc#W*47TOnEkV@=-EZTC%-EYSl!;W%tBUd%y=q&=x9)+I7D* zTGAkJcLvZq6&7d*TBH_bni3y%@v)Y@ZVDC7qVlfpyXjOIKpPOhYN5l?!vdQhmr0d* zk{D>kSHw-Hw@RMDLGiLCp1J>u)ly<^ESmqG-dp%BI8m(nvO7grgyv_yz)jb&jMr4>x#NhIb~c=e##>_jMKq5p#Z$=(>&-EbrW1-I`bq zMEAEadQ_&MhGuvjC2J(l(NoD%*1LqZ_8x!Xb-RdMHY-+gWs^>73Ra*SEnF*%G_Us^ zTc)Pf-4&ySTr9 zxElM?W!VPw9&9{j@Wky=YGS+&Pp2KQp=pp?_HEZH>vpSDgX<0UieK9<_NUIP;dQ2; zz8X%-fLRDMt^w1_SSLDeyUK`NjB5j?U(g9t@d}B*4~V_Y4bNmDCDqezBL?WJ`gNTO ziQvetK2|QFN;p8w@fGKCqaiV*w?LNO{GpBW*R4vY7W46TC9CPfZVBy;tpT~aX(R$F zMh4ZBhdB-~$Ez-wjPY?b6EmYhe_AOjqI8BKg_N2mf+=6@*yIJ7xA!jNKJx7tJ+Njs z!lt2XZIe^rqXTiCoIWAcfcoOd0XruraZkP;(sw8wm9;k?iPZ~@UGVMvXum4tTln_` z=L6QZ-ivfv(ft~{=X(F5-sQ4_(yNhQx>z3Cl~3k zC(dHrc%1#c2ycEu`}-G{SDl>4rL(W`8wGeE9^Q+5UjC|TfL0|pLa;FCArC82b9kSU zJDFmQqbFiIZAKMTdfmiKTR4n~CLk*ML|yiQ)ov^9m&X7eL|5O zH$7R%XZ8gEOO7FpP;)b=m^siAQC#-^-uV?Pp2e}fG%)pD7*F4YI z%T{%EJ1JT<;ERAvX|J++d$_kbRB(2M1eI0cc`Z8;#+@d$2x>-oUJEhU)szo+!`vC_-k7RJY{?uW*^ZR)& zp8bH}kGsy}gaEo}cgmJ9Wnd`$J!Hc7T=?95&{~IF9T3@%mN+2_tSGrQnEz*1(_i7M zfulkP4asUX^1+i03+SAY%TT|bJ*y$aiuCzwMlRXncf@_uHdepn+JsK$ zG08W+$ZMB{sbTzzK{r2sX7?9sCiJ&*zB`iDVCuIiG~i1Vx)q{om%}QhjaV5WA^p6F zJ9`vDrvz&i{O&n|ug*>}Dy*ubGv4}Sw=lmq=5vKz3^P3?7crxy3tSMVzc*>`2m*1) z3)yXcUGR^Hp7XubiclgIh}K2N1~}M9-&=6I_S7z1MN>+S&>E+zeJ(7g$_LZ1nL|A( z;eOwheNaHM#r$3+Vo;0h&lBCon(U z$X@Fa!Mb$1^8}X48__*r6_u;25>!E)6<4#n2VE6a z*{I*|M=JC|o@mX8Bj<&%76Z?~^3^nT(dqiT-brwYDT06*1)XFBTc8hYkB>u)Tw17P zd!;x$k|vg!LiPi zy+fP99{@oHwy=Oe8N%dfTF%j%>*u%2D{eY9P-iy9g>YB$7`d!9X2sjFRp-X}kX-vm z*@ab!id#sD3AVo2RoF52YvWB7N|q7zYO$`|>5DT*=wn_*}V0eYZH#Hg30K zi}+0srsD~$lhY^Z4rkkSb5QdWukOst1gKKqg|X+Z4E+%$eYE+Yp6cM+@pBHfU#3v6 zMO)5%6vsKoWMSVy&BASY3_P`_R-P*0m;wI_!B^eQGDYb11&Ey>klPER#wK&lQL^N` zj8!sg8f1?WDA(ky3To&0aW$)A%_-kTUtMnRwq{^p*@w6?FL=dCaP|j+@NP3 z4t5)3%F>(xZ0Fr)(dk6jjNxIJn}*v<3i{S81G7dY>oMzD|W0ZWBhZN`CMSbzj2goRPC#> z&DQJ8l|}XI|9|tpXQuXlo0++}VfT3WJ`v>j+jK_1?MWm&{x;ojd%ob0<@#;9-}dB2 z3;wqB_22gV&*qN*T=Rdj_kXSV?`5ugmw5de{67+gq5qN?#x*ImOm;dl!+!B1hn<%ftgYK4L*aR&Bl=_HiBz7~RZYX)#T?8E* z?L~y%3TsovLGo5LbUy9LzB>HUsrMa4u}!B4F*KY}y2=pgK=h=;CoM}F4LI?`iGWC5l?-a zgz_zU;NPs@>Kz;2k=poIi zh|Ipt;q}HX$ce*7Uj!&Cm)-yQ5$DaOe%b;^4YcGYHZdA9`vlx8)ypBGo<#hh&qn*N zFlL+udR^7pM24}xZfuaGtNNn|bZa;=Oo6MJw!k>eYANcg0gqiwf_Tv9KiPnRGNxwm%%DCQ0X@(Xx zeK?siuQtbzP2PWmi4a=hW$3d4;#GU6&#t9TX_-n4eThq4L@KN*XwkWIN^h<%lw@S>w@-s4CAgplFf>aK&TFzNrJ-kG z`@&s^0jJ5a@sduqN{P?8tad?TZpVMCSzCHi5(_&P?*0URxFEMG>0{@QInwQJm5-Q` z?Y!Ccjm+;EaHP4@{SSa)UfG@|4{d`y@)q1ah%StTR)B0RvBe*2a9Xwpl<((Uux6}Q z)eyanNn_oV>X1fryq1q6q6!?8Mkr1 zeOlL7ifTvH*gMs-IHZaGq&+nd`|?~8X>)!uZXVkpw12YkSs+bv8ra{TR@ItX`)O;< zcMuT9o{|z~6j50oJUKVaAje);KOCJq+b%i_JnO`8r7-{~9j}jp5D#@x(I`j#ZD-q{ z;&=^7Z`({3>FAa&TEpqH*Gy$bohL5Z9JI1U5iHqkz~1fYk)^2{^4zqCE82$wLUxI= z>HgoRJi1+=)3`8`EB7b8;^|6UHHv435WA5%Rm_ExKOnO%bI*Uo>bgu<-ik?^%;*fb z?_0~J=W|0L_jCF29qO&3MRhw#w60f=-mutuJgcnBRD95En8HrZl#1uls&@+;Ix7-p zxV@VBY1cERiYSP82eGILk?ZzsFn+w+DQ(l)otu*C^-GeIJE)WN4}kE4g2*J!oc@NQ z+~z(lL|IDFoXScw)tiF)jL#d%^IY!tCMiLr>2|ghQkH&V%1m@IV`{)?fv-HbofJ7D zWND5;ypG?5nd)THg)Q+@rk!Sne*gl7GC0S+QrdGVzWuPkU&u@-%N|b&1)X0OdB|&& zCfEfW={S^exqTvQcf8Zw`D?kkK2=60-Fau(=g_#OIw`7#>LVyL8W+~KvRrJ!evr@$ z`{+T7Z^aX+q23K!3*14O96*m)eVRwRJajCiZ9jNI(v-BWm>Am#Z|$(t2Eq9^&E<4` z8w5DSoSc&0IMFzfhQ`>bJr@@DVO&v)ntDYDid(UJD9X^M94K`wxz_ejN6B_MUqyF% z1+7iMG9x)0fbuK_C|xVK-R;Rc750bxK+C`Ae z;j*y{lW?1gh}j*tn{P-jy=wbxd~oU+B^>0?ic<778yUOb@A`!uXy6p5;=SaS`;#y6 ze)Ar(c;&MHqf{aozQ6ZLVHT;G5S4g(3p-2h;vWFeM5Ue=wgQviaA%#5hDn|}BSigX zLQs<#eJ@&@+nxa#pFE5{;LtN9G=LSU67*QC`r;@W>Q=cq-vDVpXjGa!sh=2aM&-@v z$VwMTHM4TVGal&hP4lqwzRYdnqr8r2hS`_Z&6e!fPPOyNs$(niP*nCgpOR&0K8T&D zD%O4DQKE?&Ih-)?@nNbdYTc&Z^bzTLHL57k@R$>jZibwfrv(k978;<&Y}A;Tz%_}1 z+SLOQ+H4!r91?hmyAHXES3rfaR@>b6$vu4ud-0dL-F74A7or#Bs1)?p*&lXIfW48k z7~#45y@V2R18%Q+<>!(=w#m{-t0_rA9VHF-Zl~)ixPifGE@qu0t%6Hp$gJ;4_yt2s zF|Lr7bU#E5#C56MmBqtwy^e+0Vx!c9U=b+2(A`OU$H?ei z&&0%dT%{qaN|&p>O6y(VEzVQ=y&~$b;2H9rnY9^BTA&~trbg5txaCshJl_4{^WkLr zB@!f>J=^bW*;|j?fk~_*^|-!nWPI$y=h!Ed^@|d|s$T;GXXC&hVnv+Yhs#O}-fQw8 z>t0%^8`ma#C(MU@3O@h@TWZ)fer##f&2uC$Y1Cwe$^ zj?5kQ)iwT({xNYePnwTT!=^VRj7&_(MV^rIi@TP`;~d{nGTeo7ztb3mkev((mDis1 zqcLh)9Oh4o)Oc1sgV4(*`>Ji+oLQ&hsegAy3E z-r44@^f#m7`jV#lga8-9Qo&|pxf|-<6v*)d+3L5Oq59DGI3tuyA$+q!ldgiYCkwGG4&N_g(V&yU;J z5kF}O>kK+n(k@*J$2YUsC5+w8ylHpuwl84Zb9{;9<@}`z59-4oA{utC7Tpt<74kfF zSo}kgWfs!e2d{u?HafrNij#>Yr<_EzB+ctzQ(3czOF>6{!xu@Tka;1oM$Vf*g=fgb zP{Lc-8^SAITWiknEOw~h*UWim~Gu$RPTHgxnL!aPASoalbA6PUttY;_yl328smQh*;CZJ z$1?YAZhPvwCu8SfH$L+l%?WC0L1}Y=by$N{^rR1~j~j3=2tiV?nr=btoh~@yqnaaW zZ#(Z+pH$PA^lVV+hz@V(Oxpim{+6Dk1iR&y{H=Q5BE0USv8e}<#ayj7u63Biiloy@ z9@K+RvXGy|^PY8|`$kt~<3L~8e94mODt?@t-^b_I&WVi;s?av0(AJ3#!4ma}0T5pDqcn910f6ca zfiTEbvvQKJuvCZK8P8nS9k=mR>3c}Vm-nZdrT+k^r__9D7;tIQpDC-T^D(WDmTUEA zJEh2pQ{{QvH}_3duk*Hd`mdWoiO@|vD%i;JaV5^w#$8$M3|vEH!wVjTii5k>M|<&8 za&owXirIT@GZo*%T0o`FODLV25rT{SvQ6=T7E)5sP8i_3@b-Uem@N=`ROi>?3M=2W zP?_6~uZ+H_XHT9W?zYU2#``(82oD|TxZxJPY7-ZirzG{-U3K+=_Liclzd<(4j7 z{5r8zWknz{R0LeDja#{LQ+w}KGH7?}OSw_P`%Fp(`v3-RK!OjrHvaBpj zE+y49P3Q;J_-wb~HC3)`S*mz8erE5gXr5zL z<1yfRf^>NjM5Xx6-r0G$1a=a#u-&{qH<6%+z3S|r$3JI}UZ;Lj7F{yhXGA5H-cNBa zo+SMe9w@gxl}9HKU4)sOHQF{GC-Tzx?J~}wz1d%=KID$CyB zoF{BYW}iJyZbDO&c+`!shtd7oztBBNf96PAu%V@6I0{xCtGQg5yd6yU;?eNJ(7gQ* z9@3(@^F}#Hc4ZQmpU~Nl>`Kd2G47Q)H?!<%8;h04-Xl*k_n5>y%&zgw?QgH<#*tI9 z;K!#+#INHgKFZqu#8}+l<_#d_ts+U6xw=0sM#s6#mId>Q!64C$L35JgHQI`0{TDA_TYcFpA7e4}Ke2|2KLi@5ucTG598WY>tU zk>d{lU9L*Z`!XV}G-M&6b=kl>FAL;^^;^tap zUg@n`4U{UM$cF?Te}M+>8=19Us(V1I-7THbnQqrAZxY<~7r(U3vz&Ry&EQeA^|Ncu zhERR+pejXxVrpHrdH0h-G=DPiL?K^A>OP(B$8L?ED(>YimkY5t>DNrM9AxNcfe=GB z>KLbSmG|MjZ5H`)ds5@Zs`}@##Z&71&s0fY@4Dcjd+&+-zf~?-YrW2?EDe>!KvFdo z2d0WN!i(b6-GphHlZ->WFVgU1OXNb->*u(~m|;Xw3EJO*Ha|^4kAyW%=MxsMl!dyt zsKUhAm{g8Zl&h{kkZRhEG+->yKgm`o=MGZ$$o3;$@(glqGF{j^vNU-=6rsOF zpY&&nC6DJcze+?MHx<(id(WPIe4e&Vf|T`RAR$XifmSqp589h@gkjw1=k}z%2=DE|Jm^Rkn@XO-)SQpBbR$kZl^lF4LP+0|ji_$+%K z)pj!>cVzBIhA(AtAZ^i6YQY%Th`T(@w0ow|{MF5B-g_4M|uO((IQj_l_2#LLt zWn!$GU|PtlC0O;y43W_@^RzvLpvM0E+N1n^CLiNLH>^`(UW7BL+gI6cN0-SFpd!he z@bR^89n~vAd`1k1bqziG&W<_d3@naF2!&5=aG!ta!`WT0b}&ODkA2W*gTZNcy3_;#3q9;m#)zdg0hnUrU?o&D6F z;l_u9x!W?DxHEMZq015;Sf{sMI#D$9r8s;`C%A%Vgr^;r{Q>1II z&6M8{ojP{WnoHNJxiIbUWfy|( zj}X@{_^+(iU`rDqB$Ca+oz$*(p6-h$QLd?jw&$oKr*2$YVnP=lpAf-Pn!61>8{))& zvZqI8pE0?)Hk&>Ww6WAYRlKz+^SrA16VebkC9_l)LB)-|6=bk6(dGM6eO7_MVTr`h zr0l~vfJsE9sz@Dp)xjkx$#ZP&bGKBve%2qZDR;1#BHhv^g^?-c9~DDu0Km}9&gY1Q zzvE7SRULvGv-X&xg#$$NKYYo2c1@1xS$TaEp3O$8s-UP_11)Cjfu1L_%WZTK(qL+{ z{JoF5uG@pcw1@SVR(b43DaOw5qa2Jrbh41w;OXy|GJkFi7JN{BB6XRRXG0l${J+xN zE%_*E7WkUY7U1>;4rbVh2LHUEI97J&9BK$2LY;%-O;-AOsqyEN)wAcsicdFafbs%I zagI^Gp=Tvav(6js`#J=lTAl~EoyzE?_p=1|oa z*(=XWcvW-9&>BwU>83UEh+in*HD3~Y&ITdpb5QRlO4F#%tT`BntOUeoQ%2)1X$C9$ zEklhhYF0J-GnPwYl7`q#t|goen@+h)pJN3Pu#Q0XIQzl|{J4?+tp9v}f6T!9s!fK? z9~FvPHEc$NmNhbUW9CBqoPl4%u&Tur%M$>Hcqdx57opNcPj!b|tWFi|T&>}fn^*eH z2V9>@Qh_Qe9lSjP)_IK#NRaM_I6Js*lDy0yPhh|!cJnz);`uM`+QHiD~qO;tgT>*~pn_r5YurNMy)98#9b}Mh1v9*^a zX8DOG1eBzdcb9Y6I(}~J@v3RCc2DUugMn?BRD2xlkwg7YVpwk3si|}0E~%3G*#ck2 zi@_7n7vAL#eEMmtt`5OI@g?qWl^{LOqbckRy(B9w@B8-CT7#O`Z^&((mDoIqT|W!T z6ZdoaRVnyEVeG)8n02hx(gg?ke5Dk(_*&LL?9Etnbt->-0-{6|9vLZPXIK%bpE;Dh z+ftDHpO4*-OHo#(Pf#rSU#g=%y#UF)Z*!f`i4L^K8orLj77d!7qlHzyZy0sHjTQnv zrc*>fSDOF~Isiw*Ht~;MUWXq&^ReqjhW)jEKXp@v`ku@pruI^jfpm%vCbb$*v9W>Y z>^WR_8WIjYJRaTBUI)RCaqBp-P(Kju5CM1Ora%AC+9`4UNuh&^nb2xMf`r~2lZn5DFL15#e98^+X`}*v<1|3|v{r6b@ z$s^)eh~Z(`T-$8oSpLbQ>7UEQbO7|Qgdy?V|KyRY-H(6v#Q)0a{__G|LlMMa_n>2j z0CCX&gCqEFB6L3S`$9772|VqTWi+3^-u21+6U$J3>6RGx-?fere=7{!_)+-8@p$eF zwN&YUQHCk`^A`VS5L45-(B358;Q-;p3SxgfLH3`w*uTV)|Gwk?zx(!IP-G9d=p+hW z6Ll2?Rm^Llj`=ISrNVq3kID;?Z+c19tFzxZeuIZE_Ji?7EACuC4OcfoObBmzXoF$* zS|fLTX9-~n6#9K1=IuyJ7=HD$WqOEkv{BONNv@vQI5{;jz#;2YhDp3*Luz9H6*;5iS*P1Bv%nM6Z6hPf%Wz)k=0H)LR2mxXVg~Sd z*T*)wsxU{=N{PW&A7<8p)lUc2c#S(A+eUxx%{@d&oe}|jk`2ko=5Iqb;#Nauz`$U~ z;?As8m#*=EHG}SxX%~@Ov?+TI_~6Q{R5Cc3Oj;IjU(3e5#8T;Z^zNv z=?E~$cQQD`JI9r_Kyv$Hz?KnNUIYXLhm{#<(y1B@pfy13T^8*i8A!E zCo8^A?(N%>ifCtY^P``sc-cwrGla^u4)bt>9pB3Cmpw;N007s{1 z=)JER!LN8OhiAX3)fk+`4Mm)4xMCZdr46h_Q$FPIKkv5cQ4X8u(3+XIcWbU{^yEuB zFm>LW(uHI`dknj#eR*{C%i@WuQ*6=8m|gJ1N;GOuN5#a`DOQ1mH%zA|QRcOV>uEa4^@GiHY_#P0^DbRHDyRc7w~(6YL8(Aod`|!H#sAKic!xxHEBr2zl+pnKxW6$` z(s-%|8;W0zPB~Q5Grkpb;H&>h6h6l50VByIWqEYr-T=qCQ1|zh+ z$m^M`El$eA?XJ~_oWI+}a5wf=oze@T15b0~=5hl@SLdifq^3$j9ZrdxqdT`)q@tqO z2S#(en+x&NW6$7!v3!J5Sw2t1r1ft1R$$Fi_z|b*+pbmhh_W)8*HX^clzH(a+mOK3oZ66(kFN^PC>>t>eT+X!RXB$j$y18`{zAd5#i6vc-4=N=K*G@&aO+OI?N=^l{_csUC%X zcQ1*oiQ%Y7fUCmmX)dvhXeu@E2ug!J^PS-$R&KIM`EQ9^Rs$R8APurp0s$)tC(>c$ z2-yA6d55=>vm4P@(%-)s6!D>&Nht~cyz2dBO32Soa)WV{1Sr9RzS`}=3Db5Mhs}ad z;)0GRiaBiQo)oAa2alujp97>Mt~72FJT`*r6BW<+u|6ffVJJb^pAHvkoyI8=|I7gy=# zZG7@7nm^mXrddwRhy)b9*#Bm=W-O^~z(HMzaKuKC+527?`)*%|L!{V6@l1VuQ z%K#0hM$9u;Qob6`abt5j0Xm=ThA6{-))JU)F48uAHng+?cD*MU_lrxSjysGY$aDz; z+rtP=LoI^_$c;O+CAqrct}SRP;l16)amn!&(+vrb?4V+F`lEf0tGj;Y!e{Gs3l&G! zWiH(LMX^|n)qERI!k+jLb+{+sdie5}VO3ArvDpH-7;Xpi1P@`Ia8V~-hiMLNR&Kv+ z2O`w0?!!sQMmq5c@4P?!RbbP@v9as<6Y&QJj_lrqa;(MdY%V8i!2^e8OIN?;U=?TW zcu(71^K3|dPGMj56DN0ziP?kF)e47?hhQ@kyu|=DgzT%bF*Mzf2%Lj!qt2f$fNhBk|)4d}U6>t{sZa zl&1QZLF4TOl$uYysM-lN#)k>&!Lnwym6b(l(N_AdyLE|CyPos!n(%kcYFmw-LMsNq zvCY&?%`kUYEXM8blekoaJ~#^$xT0C?&{f~EM%zFo|D<(}7$|8Nu$Y`w4x5fM)KO8Y zA}+^&PlN*u8+cLSi!L&=7*}|yc*hq0DCi=4RX`g=M2N+qa0^aiTm;f5IPgaU_6i8Z z-dC2>Lv_V62*4?UZ z|3BKh`f#TAHtzMz+s2esCWJ;iR%7O6delJ?DF?GMdNDEYHS-e6ON^(Xi9$9SY34O; zLn0^QQDGs`DD=AJr4>mhI_sQHbv@T}oj;zZKc4Gc`{#FkzkmFGf85u7e}DJ)zCWMO zZDZ~s>f0@b5o{+TrmR3>0Au_>>LO=B42x*AUkozFhj!99p6bqe1J@B{hoFGtr4_O; zjG{g{^<5C1&R9MD#F0<_M-8?#)G;`sd)*j+smrxp|4Ee?KvvZd-S}(E($eUPAxodw ziTMP74NX96z^hTv*$R#wuBd5STzyY~mD9on5aS>tp_#+xeX;yZOhnk34Yk4Yjh)XQ+<0$lm`y|Vb$CRg8nv7-hwz@jJoe9R z-F9QfL_7L2_3TU}|_~xN&-T;*X=93LtHfM#UkSch29K{u670v!3c}vj(T%_LB z6M}eoj8zVWKZqK#lBJB%6sTi4SH0| zel|De!vOiN8Ean%p7tS`_+6-}_7n7&m~d0u8XR`lQiv8>Y*~ht*&x{Ppk8JA-IQc>r-k>*A`5Tr=2X3S8QL7C$(U6Zd_Eud0z1H)owjJ! z52+bZ@47uTe{^tveJ%z@#`jKxb~0} zio+~IxR>%xpDq6AOKH|ord;N3vlQnHV!B~Tn3U8|0dw#i671hK;$KV4@<+rFOEW3KT1+;T zIZn&y+}iEM{6?fvsWc;0Lz8bXBs@0MPdsIx9l3q$+W`1M=^o37;aOf@Sh`i1Cfm2V zp>pcJu>hZ39!OJ6F3!~{U(II%!}@=qS?`V`@+L?|e||Fs@oW?;>bnYXS-#E!aYsmuYwp&JwBsS6v6+j6;QWbuVj)Kp zbY}W2_QLgjEI0?%7|h7w78G?)9_*$BXwegAP{PJ#h*(S(H|7Ru7^cOfVQ|I;Wv(A~ zkjK@KU5SbW{gGb9e_=c$c{@7i!8^d2IeQNiQ_)gK;JKP==us!={6=0QTV&2!)b(#A zT)d}aUPD4w1)t|m^acW$vzV8O6H4#)Mm6w5&ao=1>-M0Fwe7qMO?zZEJMSBV>+j)3 zza@?~&l`NLYBSz`~cnPEDSjUd9`W;Qr~&sJHdv z4sH>}e_xLZNv(BFDW2-sfB*7h6QXN}+OgCd?IaHN$5DqPR~@v*FSR(nC^Z3?O7%!L z4MQFSLP&fCw6g!hG?D8fGvFB~oA(O)%qpwRl8BQg`~r}Ru7zu!Phg25T|wR|oGVJl zqSTzI&zlc6+?gJ@c{Iw(qyZg2|E3!#bC%16>5vLU)ZK1w*f)#vgUMd1V(p6mn^TmD~Ci+qIoA2FFXQ2OnK*S zuO@k2VmgW2e20)JdlVrSMgLSjPq~*C9$S3%PF>He*#bryyz2CqX<^&G)XJ5Y`mdP1 z4_%Zm@Hj_)sADKJ`h#Bcd)55^;E_a~{KQ9d9^8sOyio9K)$QLK0SCZf!dLPx_{2~3 z9n)?WPg5yX$4A2q$+dgR+V~EY4-8*((DtpEil3{?_O&qf!`#`Z*~%V8LG(gJjwFEx5MU^ ozsRw^9J_z!lwXf7$x31ziRXM%Y>)(mBp@UK@iz +![3D Posterior Landscape showing variant performance over time](images/rl-3d-posterior-landscape.jpg) ## Why RL instead of fixed-horizon A/B testing? @@ -49,6 +49,7 @@ losses update toward lower. Algorithm details: + ## Use cases - **A/B test any content variation** without third-party SaaS From c1b4b69d09ec236f06f61b583b70fefc88519076 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 14:08:10 +0200 Subject: [PATCH 07/12] docs: move 3D posterior landscape to top of home page Place the hero screenshot immediately after the intro paragraph for maximum visual impact on first visit. Claude-Session: https://claude.ai/code/session_01Cbtzf2mpa3xQKCSkFzJuiR --- docs/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index e99a625..a8284f9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,6 +5,8 @@ view is a trial, each conversion is a reward, and the algorithm continuously shifts traffic to whichever variant is winning. RLHF-style feedback loop, no fixed horizons, no third-party SaaS. +![3D Posterior Landscape showing variant performance over time](images/rl-3d-posterior-landscape.jpg) + ## What you can A/B test - **[RL: A/B Test Views Content](https://www.drupal.org/project/rl_sorting)** @@ -27,8 +29,6 @@ fixed horizons, no third-party SaaS. - **GDPR-friendly tracking**: only anonymous interaction counts, no user IDs or cookies -![3D Posterior Landscape showing variant performance over time](images/rl-3d-posterior-landscape.jpg) - ## Why RL instead of fixed-horizon A/B testing? Traditional A/B tests run for a fixed window (say two weeks) and split traffic From 489445e0bdcf3b6dbb4da2ae4418571a9f2b6f62 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 14:17:41 +0200 Subject: [PATCH 08/12] Add integrations guide with worked consumer module examples New guide walks through the full anatomy of a consumer module using rl_page_title and rl_menu_link as worked examples: experiment entity, variant selector, report decorator, hook integration, and tracking JS. Covers rl_sorting (Views) and DXPR Builder integration patterns. Enriches the home page "What you can A/B test" section with detail on how each integration works. Cross-references from configuration and contributing docs. --- docs/development/contributing.md | 5 +- docs/getting-started/configuration.md | 4 +- docs/guides/integrations.md | 343 ++++++++++++++++++++++++++ docs/index.md | 19 +- mkdocs.yml | 1 + 5 files changed, 366 insertions(+), 6 deletions(-) create mode 100644 docs/guides/integrations.md diff --git a/docs/development/contributing.md b/docs/development/contributing.md index 32dcbbb..68c3da5 100644 --- a/docs/development/contributing.md +++ b/docs/development/contributing.md @@ -71,6 +71,9 @@ The module is built around these core services: Consumer modules (like `rl_sorting`, `rl_page_title`, `rl_menu_link`) extend the core by registering experiments and implementing variant selectors and -decorators. +decorators. Each consumer provides an experiment entity, a selector service +extending `VariantSelectorBase`, a report decorator, and tracking JS. See the +[Building a Consumer Module](../guides/integrations.md) guide for a detailed +walkthrough using `rl_page_title` and `rl_menu_link` as worked examples. diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index caaf3c7..e2459cd 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -47,7 +47,9 @@ $best_arm = key($scores); Deciding server-side keeps the arm list where it belongs (with the experiment owner) and avoids a network round trip on every page load. See `rl_sorting`'s Views sort plugin for the canonical pattern and -`VariantSelectorBase` in this module for a reusable base class. +`VariantSelectorBase` in this module for a reusable base class. The +[Building a Consumer Module](../guides/integrations.md) guide walks +through both bundled submodules as worked examples. ### Client-side (cache-friendly path) diff --git a/docs/guides/integrations.md b/docs/guides/integrations.md new file mode 100644 index 0000000..cebd178 --- /dev/null +++ b/docs/guides/integrations.md @@ -0,0 +1,343 @@ +# Building a consumer module + +RL is a framework; on its own it stores experiment data and runs Thompson +Sampling. The actual "what gets tested" lives in consumer modules. This guide +walks through the architecture consumer modules share, using the two bundled +submodules (`rl_page_title` and `rl_menu_link`) as worked examples. + +## Integration patterns at a glance + +| Pattern | Server-side (recommended) | Client-side | +| --- | --- | --- | +| **Decision** | PHP at render time via `VariantSelectorBase` | JS via `Drupal.rl.decide()` after page load | +| **Turn** | JS on viewport entry or page load via `Drupal.rl.turn()` | Same | +| **Reward** | JS on conversion event via `Drupal.rl.reward()`, or PHP via `ExperimentManager::recordReward()` | Same | +| **Caching** | `CacheManager::overridePageCacheIfShorter()` ensures variants rotate | Full-page cache safe; all variants rendered, swapped client-side | +| **Examples** | `rl_page_title`, `rl_menu_link`, `rl_sorting` | DXPR Builder | + +## Anatomy of a consumer module + +A server-side consumer module typically provides five pieces: + +1. **Experiment entity**: a content entity implementing `VariantExperimentInterface` +2. **Variant selector service**: a service extending `VariantSelectorBase` +3. **Report decorator service**: a service extending `VariantExperimentDecoratorBase` +4. **Hook integration**: hooks that intercept Drupal's render pipeline and swap content +5. **Tracking JS**: a small Drupal behaviour that records turns and rewards via `Drupal.rl` + +### 1. Experiment entity + +The experiment entity holds the variant data. Both `rl_page_title` and +`rl_menu_link` follow the same pattern: a content entity with +`VariantExperimentInterface` and `VariantArmsTrait`. + +Key fields shared across both implementations: + +- `label`: human-readable name for admin UIs and reports +- `variants_data`: JSON-encoded list of variant text strings +- `lookup_hash`: computed `sha256(target|langcode)` backed by a UNIQUE index +- `enabled`: publish/unpublish toggle (via `EntityPublishedTrait`) +- `langcode`: scopes the experiment per language + +The arm convention enforced by `VariantArmsTrait`: + +- `v0` = original text (read live from the source, never stored) +- `v1`..`vN` = stored variant texts, indexed sequentially + +Each entity class provides two static helpers: + +- `computeLookupHash(target, langcode)`: the UNIQUE index key for O(1) runtime lookup +- `buildRlExperimentId(target, langcode)` (via `VariantArmsTrait::buildVariantExperimentId()`): + a deterministic `{module}-{12-char-sha1}` hash used as the key into RL's + analytics tables + +**rl_page_title** targets a normalised internal path (e.g. `/node/42`): + +```php +$fields['path'] = BaseFieldDefinition::create('string') + ->setLabel(t('Page URL or path')) + ->setRequired(TRUE) + ->setSetting('max_length', 2048); +``` + +**rl_menu_link** targets a menu link plugin ID (e.g. +`menu_link_content:some-uuid`): + +```php +$fields['menu_link_plugin_id'] = BaseFieldDefinition::create('string') + ->setLabel(t('Menu link plugin ID')) + ->setRequired(TRUE) + ->setSetting('max_length', 255); +``` + +Your module will have its own target identifier; the pattern stays the same. + +### 2. Variant selector service + +Extend `VariantSelectorBase` and implement four abstract methods. The base +class handles Thompson Sampling scoring, per-request caching, self-healing +registry registration, multilingual fallback, and page cache override. + +Here is `rl_page_title`'s selector, trimmed to the essentials: + +```php +class TitleVariantSelector extends VariantSelectorBase { + + protected function ownerModule(): string { + return 'rl_page_title'; + } + + protected function entityTypeId(): string { + return 'rl_page_title_experiment'; + } + + protected function entityClass(): string { + return PageTitleExperiment::class; + } + + protected function computeLookupHash( + string $target, + string $langcode + ): string { + return PageTitleExperiment::computeLookupHash($target, $langcode); + } + + public function selectForCurrentPage(): ?array { + return $this->selectForTarget( + $this->getCurrentInternalPath(), + $this->languageManager + ->getCurrentLanguage(LanguageInterface::TYPE_INTERFACE) + ->getId() + ); + } + +} +``` + +`rl_menu_link` is nearly identical; only the target identifier changes +from an internal path to a menu link plugin ID. + +The return value from `selectForTarget()` is either `NULL` (no active +experiment) or an array: + +```php +[ + 'experiment_id' => 'rl_page_title-a1b2c3d4e5f6', + 'arm_id' => 'v1', + 'text' => 'The winning variant text', +] +``` + +Register the service in `*.services.yml`: + +```yaml +services: + my_module.variant_selector: + class: Drupal\my_module\Service\MyVariantSelector + arguments: + - '@entity_type.manager' + - '@rl.experiment_manager' + - '@rl.cache_manager' + - '@rl.experiment_registry' +``` + +### 3. Report decorator service + +The RL reports page (`/admin/reports/rl`) shows raw experiment and arm IDs by +default. A decorator maps those IDs back to something human-readable. + +Extend `VariantExperimentDecoratorBase` and implement: + +- `experimentIdPrefix()`: the prefix your experiment IDs start with + (e.g. `rl_page_title-`) +- `entityTypeId()`, `entityClass()`: which entity to load +- `buildExperimentDisplay()`: render array for the experiment label +- `buildOriginalArmDisplay()`: render array for the v0 (original) arm + +Tag the service with `rl_experiment_decorator`: + +```yaml +services: + my_module.decorator: + class: Drupal\my_module\Decorator\MyDecorator + arguments: ['@entity_type.manager'] + tags: + - { name: rl_experiment_decorator } +``` + +See the [Experiment decorators guide](decorators.md) for a standalone +example that does not use the base class. + +### 4. Hook integration + +This is where consumer modules diverge most. The hooks depend on what you are +testing. + +**rl_page_title** uses `hook_preprocess_page_title()` and +`hook_preprocess_html()` to swap the visible and `` tag titles: + +```php +function rl_page_title_preprocess_page_title(array &$variables) { + $result = \Drupal::service('rl_page_title.variant_selector') + ->selectForCurrentPage(); + if ($result && $result['text'] !== NULL) { + $variables['title'] = $result['text']; + } +} +``` + +**rl_menu_link** uses `hook_preprocess_menu()` to walk the menu tree and +replace link titles: + +```php +function rl_menu_link_preprocess_menu(array &$variables) { + foreach ($variables['items'] as &$item) { + $plugin_id = $item['original_link']->getPluginId(); + $result = $selector->selectForPluginId($plugin_id); + if ($result && $result['text'] !== NULL) { + $item['title'] = $result['text']; + } + } +} +``` + +Both modules also use `hook_form_alter()` to add a "variant titles" vertical +tab on entity edit forms, so editors can manage experiments without visiting a +separate admin page. They attach the experiment data to the host entity's save +flow. + +Both implement `hook_entity_predelete()` to cascade-delete experiments and +purge analytics when the parent entity is removed. + +### 5. Tracking JavaScript + +Each consumer attaches a small JS behaviour that calls `Drupal.rl.turn()` and +`Drupal.rl.reward()`. The pattern varies by what counts as an impression and +what counts as a conversion: + +| Module | Turn (impression) | Reward (conversion) | +| --- | --- | --- | +| `rl_page_title` | Page load | Visitor stays 10+ seconds | +| `rl_menu_link` | Link enters viewport (IntersectionObserver) | Visitor clicks the link | +| `rl_example` | Form enters viewport | AJAX form submit (server-side `recordReward()`) | +| `rl_example_frontend` | Form enters viewport | Click event via `Drupal.rl.reward()` | + +Pass the experiment ID and arm ID to the page via `drupalSettings`: + +```php +$build['#attached']['drupalSettings']['myModule'] = [ + 'experimentId' => $result['experiment_id'], + 'armId' => $result['arm_id'], +]; +``` + +Then in your JS: + +```javascript +Drupal.behaviors.myModuleTracking = { + attach(context) { + once('my-module-tracking', '.my-element', context) + .forEach((el) => { + var config = drupalSettings.myModule; + Drupal.rl.turn(config.experimentId, config.armId); + + el.addEventListener('click', function () { + Drupal.rl.reward(config.experimentId, config.armId); + }); + }); + }, +}; +``` + +All `Drupal.rl` calls are batched (500ms window) and sent to `rl.php` in a +single request. See the [JavaScript API](../api/javascript.md) for the full +reference. + +## Without VariantSelectorBase: the direct API approach + +Not every integration needs a content entity and a selector service. For +simpler cases (a block, a form, a widget), you can use the RL services +directly. The bundled example modules demonstrate this. + +`rl_example` tests which button text gets more newsletter signups: + +```php +public function build() { + $this->experimentRegistry->register( + 'my_experiment', + 'my_module', + 'My A/B Test' + ); + + $scores = $this->experimentManager->getThompsonScores( + 'my_experiment', + NULL, + ['subscribe', 'updates', 'notify'] + ); + arsort($scores); + $best = key($scores); + $this->cacheManager->overridePageCacheIfShorter(60); + + return ['#markup' => $this->buttonTexts[$best]]; +} +``` + +The three required services: + +| Service | Purpose | +| --- | --- | +| `rl.experiment_registry` | Register your experiment so `rl.php` accepts tracking events for it | +| `rl.experiment_manager` | Get Thompson Sampling scores, record turns and rewards | +| `rl.cache_manager` | Shorten the page cache so variants rotate | + +## rl_sorting: Views integration + +[RL: A/B Test Views Content](https://www.drupal.org/project/rl_sorting) +(`rl_sorting`) is a separate project that integrates RL with Drupal Views. +It provides a Views sort plugin that reorders view results by Thompson +Sampling score, turning any View into an engagement-optimised ranking. + +The pattern is fully server-side: the sort plugin calls +`getThompsonScores()` with the content IDs from the View results as arm IDs, +then reorders the rows before rendering. Turns are batched via +`Drupal.rl.turn()` for all visible items; rewards fire when a visitor clicks +through to a listed item. + +## DXPR Builder integration + +[DXPR Builder](https://www.drupal.org/project/dxpr_builder) uses the +client-side pattern. All variants are rendered into the page HTML (so the page +can be served from Varnish or Fastly), and the builder's JS calls +`Drupal.rl.decide()` at page load to pick the winner and swap the visible +slot. This keeps the full-page cache intact while still running experiments. + +## Cache considerations + +Server-side selectors need the page cache to expire before variants can +rotate. `VariantSelectorBase` calls +`CacheManager::overridePageCacheIfShorter()` automatically. Both bundled +submodules default to 60 seconds; override `cacheTtl()` in your selector to +change it. + +Client-side integrations (DXPR Builder) are fully compatible with aggressive +page caching because the decision happens after load. + +See the [Cache management guide](cache.md) for details. + +## Putting it together: a checklist + +When building a new consumer module: + +1. **Define your experiment entity** implementing `VariantExperimentInterface` + with `VariantArmsTrait` +2. **Create a variant selector service** extending `VariantSelectorBase` +3. **Create a report decorator** extending `VariantExperimentDecoratorBase` + and tagging it with `rl_experiment_decorator` +4. **Hook into the render pipeline** to swap content with the winning variant +5. **Write tracking JS** that records turns on impression and rewards on + conversion +6. **Handle cleanup**: implement `hook_entity_predelete()` to cascade-delete + experiments when the parent entity is removed +7. **Register experiments**: the base class self-heals registration, but + explicit `register()` calls in form submit handlers ensure the registry + is in sync from the start diff --git a/docs/index.md b/docs/index.md index a8284f9..f09df70 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,12 +10,23 @@ fixed horizons, no third-party SaaS. ## What you can A/B test - **[RL: A/B Test Views Content](https://www.drupal.org/project/rl_sorting)** - (`rl_sorting`): the order of items in any Drupal View + (`rl_sorting`): reorders any Drupal View by engagement. A Views sort plugin + calls Thompson Sampling with content IDs as arms and reorders rows before + rendering; turns and rewards are tracked client-side. - **RL: A/B Test Page Titles** (`rl_page_title`, bundled submodule): - page titles for nodes, View pages, and any controller + tests page titles for nodes, Views pages, and any controller. Hooks into the + preprocess pipeline to swap the visible title and `<title>` tag. A vertical + tab on content entity edit forms lets editors manage variants inline. - **RL: A/B Test Menu Links** (`rl_menu_link`, bundled submodule): - labels in any menu link -- **DXPR Builder** integration: variant slots inside builder blocks + tests labels in any menu link. Walks the menu tree at render time and swaps + link titles with the winning variant. A vertical tab on the menu link edit + form lets editors add alternatives. +- **DXPR Builder** integration: renders all variant slots into the page HTML + (so the page stays fully cacheable) and uses `Drupal.rl.decide()` on the + client to pick and swap the winner. +- **Custom modules**: RL provides base classes and services for building your + own consumer modules. See the + [Building a Consumer Module](guides/integrations.md) guide. ## Features diff --git a/mkdocs.yml b/mkdocs.yml index 611e8f4..6a5fb07 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -24,6 +24,7 @@ nav: - JavaScript API: 'api/javascript.md' - HTTP API: 'api/http.md' - Guides: + - Building a Consumer Module: 'guides/integrations.md' - Drush Commands: 'guides/drush.md' - Experiment Decorators: 'guides/decorators.md' - Cache Management: 'guides/cache.md' From ee49f984d68705ea85030060f15664caa317daaa Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Mon, 31 Aug 2026 15:43:16 +0200 Subject: [PATCH 09/12] Fix five PR review blockers 1. Skip uncurated DrupalCI lint jobs (SKIP_* variables in .gitlab-ci.yml) 2. Fix edit_uri leading slash in mkdocs.yml (broken edit links) 3. Exclude rl_project_desc.html from Pages build (orphan page with referral link) 4. README drift: remove obsolete Plotly install, fix smoke test to use action=ping, fix getThompsonScores to three-arg form, add batch error/422 docs, fix decorator to use constructor injection, add docs site link, fix "Drupal Routes API" claim 5. Wording: remove nonexistent "locks" feature from faq.md and project desc, fix http.md ok:false example to show partial success correctly --- .gitlab-ci.yml | 8 ++++++ README.md | 71 +++++++++++++++++++++++----------------------- docs/api/http.md | 15 ++++++---- docs/guides/faq.md | 2 +- mkdocs.yml | 4 ++- 5 files changed, 57 insertions(+), 43 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e6d3a39..5b27e77 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,6 +5,14 @@ # Source: https://git.drupalcode.org/project/gitlab_templates/ ################ +variables: + SKIP_COMPOSER_LINT: '1' + SKIP_PHPCS: '1' + SKIP_PHPSTAN: '1' + SKIP_STYLELINT: '1' + SKIP_ESLINT: '1' + SKIP_CSPELL: '1' + include: - project: $_GITLAB_TEMPLATES_REPO ref: $_GITLAB_TEMPLATES_REF diff --git a/README.md b/README.md index 50c5fbc..99b58e7 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ # RL: A/B & Multivariate Testing for Drupal (Reinforcement Learning) +**[Full documentation](https://project.pages.drupalcode.org/rl/)** | This README covers the essentials; the docs site has guides, API reference, and worked examples. + A/B and multivariate testing for Drupal using reinforcement learning. Each page view is a trial, each conversion is a reward, and the algorithm continuously shifts traffic to whichever variant is winning. RLHF-style feedback loop, no @@ -70,26 +72,6 @@ composer require drupal/rl drush en rl ``` -### Plotly.js Library (Required for Charts) - -The RL module uses Plotly.js for experiment charts. Install it via Composer using -[Asset Packagist](https://asset-packagist.org): - -```bash -# Add Asset Packagist repository (if not already configured) -composer config repositories.asset-packagist composer https://asset-packagist.org - -# Install the Composer plugin for npm assets (if not already installed) -composer require oomphinc/composer-installers-extender -composer config extra.installer-types --json '["npm-asset"]' -composer config extra.installer-paths.web/libraries/\{\$name\} --json '["type:npm-asset"]' - -# Install Plotly.js -composer require npm-asset/plotly.js-dist-min:^2.35 -``` - -This installs the library to `web/libraries/plotly.js-dist-min/`. - ### Post-Installation: Verify rl.php Access The RL module includes a `.htaccess` file that allows direct access to @@ -98,7 +80,7 @@ module). Test that it's working: ```bash # Test if rl.php is accessible -curl -X POST -d "action=turns&experiment_id=test&arm_ids=1" \ +curl -X POST -d "action=ping" \ http://example.com/modules/contrib/rl/rl.php ``` @@ -134,8 +116,8 @@ location ~ ^/modules/.*\.php$ { - Socket: `unix:/var/run/php/php8.1-fpm.sock` (or your PHP version) - TCP: `127.0.0.1:9000` -If server policies prevent direct access to `rl.php`, use the Drupal -Routes API instead. +If server policies prevent direct access to `rl.php`, your consumer +module must implement its own Drupal route as an alternative endpoint. ## Drush Command Reference @@ -234,7 +216,7 @@ $experiment_manager->recordTurn('my-experiment', 'variant-a'); $experiment_manager->recordReward('my-experiment', 'variant-a'); // Get Thompson Sampling scores -$scores = $experiment_manager->getThompsonScores('my-experiment'); +$scores = $experiment_manager->getThompsonScores('my-experiment', NULL, ['variant-a', 'variant-b']); // Select best option $ts_calculator = \Drupal::service('rl.ts_calculator'); @@ -410,8 +392,8 @@ Content-Type: application/json ``` All three sections are optional. Invalid or unregistered entries are -dropped silently so one bad event does not poison the rest of the -batch. The response is +rejected individually without poisoning the rest of the batch. A +successful response looks like: ```json { @@ -431,6 +413,24 @@ Sampling lookup. Missing keys mean "use the default variant". When `ranking[0]` for backwards compatibility. Turns and rewards are fire-and-forget writes with no per-event response. +When some entries are rejected (invalid IDs, unregistered experiments, +malformed entries), the response includes an `errors` array: + +```json +{ + "ok": false, + "errors": [ + {"kind": "decide", "id": "unknown_exp", "reason": "unknown_experiment"}, + {"kind": "turn", "id": "bad!", "reason": "invalid_id"} + ] +} +``` + +Each error includes the `kind` (decide, turn, or reward), the `id` that +failed, and a machine-readable `reason`. Partial successes return HTTP 200 +with both `decisions` and `errors`; the response is 422 only when every +entry in the batch was rejected. + ### Curl examples ```bash @@ -449,6 +449,7 @@ curl -X POST 'https://example.com/modules/contrib/rl/rl.php' -d 'action=ping' | Status | When | | --- | --- | | `400` | Missing/invalid `action`, malformed JSON, or missing `experiment_id` on a legacy action. | +| `422` | Batch request where every entry was rejected (all invalid or unregistered). | | `500` | Drupal kernel failed to boot. Error logged to the PHP error log. | ### Performance notes @@ -499,31 +500,29 @@ Implement the `ExperimentDecoratorInterface`: namespace Drupal\my_module\Decorator; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\rl\Decorator\ExperimentDecoratorInterface; class MyExperimentDecorator implements ExperimentDecoratorInterface { - /** - * {@inheritdoc} - */ + protected EntityTypeManagerInterface $entityTypeManager; + + public function __construct(EntityTypeManagerInterface $entity_type_manager) { + $this->entityTypeManager = $entity_type_manager; + } + public function decorateExperiment(string $experiment_id): ?array { - // Return NULL to skip, or a render array for custom display. if (!str_starts_with($experiment_id, 'my_module-')) { return NULL; } return ['#markup' => 'My Custom Experiment Name']; } - /** - * {@inheritdoc} - */ public function decorateArm(string $experiment_id, string $arm_id): ?array { - // Return NULL to skip, or a render array for custom display. if (!str_starts_with($experiment_id, 'my_module-')) { return NULL; } - // Example: Load entity and return its label. - $entity = \Drupal::entityTypeManager()->getStorage('node')->load($arm_id); + $entity = $this->entityTypeManager->getStorage('node')->load($arm_id); if ($entity) { return [ '#markup' => htmlspecialchars($entity->label()) . diff --git a/docs/api/http.md b/docs/api/http.md index 23d31fd..eb787e2 100644 --- a/docs/api/http.md +++ b/docs/api/http.md @@ -85,11 +85,16 @@ Sampling lookup. Missing keys mean "use the default variant". When fire-and-forget writes with no per-event response. When some entries are rejected (invalid IDs, unregistered experiments, -malformed entries), the response includes an `errors` array: +malformed entries), the response includes an `errors` array alongside +any successful results. A partial success returns HTTP 200 with +`ok: true`: ```json { - "ok": false, + "ok": true, + "decisions": { + "hero_cta": {"armId": "v1"} + }, "errors": [ {"kind": "decide", "id": "unknown_exp", "reason": "unknown_experiment"}, {"kind": "turn", "id": "bad!", "reason": "invalid_id"} @@ -98,9 +103,9 @@ malformed entries), the response includes an `errors` array: ``` Each error includes the `kind` (decide, turn, or reward), the `id` that -failed, and a machine-readable `reason`. Partial successes return HTTP 200 -with both `decisions` and `errors`; the response is 422 only when every -entry in the batch was rejected. +failed, and a machine-readable `reason`. When *every* entry in the batch +is rejected, the response is HTTP 422 with `ok: false` and no +`decisions`. ## Error responses diff --git a/docs/guides/faq.md b/docs/guides/faq.md index 89d0c18..bd62e33 100644 --- a/docs/guides/faq.md +++ b/docs/guides/faq.md @@ -40,7 +40,7 @@ In both cases the loser of a pair receives progressively less traffic as the winner's distribution strengthens, but it never drops to zero: Thompson Sampling preserves exploration, so a losing arm always retains a small chance of selection. Traffic only truly stops when the experiment owner -removes or locks the variant. If you are used to fixed-horizon A/B tools, +removes the variant. If you are used to fixed-horizon A/B tools, this is the biggest mental shift: there is no "test complete" flag to chase. ## How many variants can I run at once? diff --git a/mkdocs.yml b/mkdocs.yml index 6a5fb07..7916e26 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,7 +2,9 @@ site_name: 'RL: A/B & Multivariate Testing - Documentation' site_url: 'https://project.pages.drupalcode.org/rl/' repo_url: https://git.drupalcode.org/project/rl repo_name: drupal/rl -edit_uri: /-/edit/1.x/docs/ +edit_uri: -/edit/1.x/docs/ +exclude_docs: | + rl_project_desc.html theme: name: material From 3a34531a66fe153a0e297413f3bd92cf571e6fff Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:17:10 +0200 Subject: [PATCH 10/12] Address remaining PR review feedback - Fix menu hook example: initialise $selector, add recursion via _rl_menu_link_process_items() to match the shipped implementation - Fix rl_sorting transport: uses sendBeacon() directly to rl.php, not Drupal.rl.turn() - Fix README batch error example: partial success is ok:true with both decisions and errors; 422 with ok:false only when all rejected - Fix configuration.md menu label: "RL: A/B Testing" per rl.links.menu.yml - Update desc.html to latest 1.x and re-add docs callout box - Remove nonexistent "Drupal Routes API" fallback claim from desc.html --- README.md | 9 +++++--- docs/getting-started/configuration.md | 2 +- docs/guides/integrations.md | 30 ++++++++++++++++++++------- docs/rl_project_desc.html | 2 +- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 99b58e7..98ea36b 100644 --- a/README.md +++ b/README.md @@ -418,7 +418,10 @@ malformed entries), the response includes an `errors` array: ```json { - "ok": false, + "ok": true, + "decisions": { + "hero_cta": "v1" + }, "errors": [ {"kind": "decide", "id": "unknown_exp", "reason": "unknown_experiment"}, {"kind": "turn", "id": "bad!", "reason": "invalid_id"} @@ -428,8 +431,8 @@ malformed entries), the response includes an `errors` array: Each error includes the `kind` (decide, turn, or reward), the `id` that failed, and a machine-readable `reason`. Partial successes return HTTP 200 -with both `decisions` and `errors`; the response is 422 only when every -entry in the batch was rejected. +with `ok: true` alongside both `decisions` and `errors`; the response is +422 with `ok: false` only when every entry in the batch was rejected. ### Curl examples diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md index e2459cd..bc05001 100644 --- a/docs/getting-started/configuration.md +++ b/docs/getting-started/configuration.md @@ -3,7 +3,7 @@ ## Module settings After enabling the module, visit **Administration > Configuration > -Web services > Reinforcement Learning** +Web services > RL: A/B Testing** (`/admin/config/services/reinforcement-learning`) to configure the module. <!-- TODO: screenshot of the RL settings form --> diff --git a/docs/guides/integrations.md b/docs/guides/integrations.md index cebd178..39eed9c 100644 --- a/docs/guides/integrations.md +++ b/docs/guides/integrations.md @@ -191,11 +191,24 @@ replace link titles: ```php function rl_menu_link_preprocess_menu(array &$variables) { - foreach ($variables['items'] as &$item) { - $plugin_id = $item['original_link']->getPluginId(); - $result = $selector->selectForPluginId($plugin_id); - if ($result && $result['text'] !== NULL) { - $item['title'] = $result['text']; + if (empty($variables['items'])) { + return; + } + _rl_menu_link_process_items($variables['items']); +} + +function _rl_menu_link_process_items(array &$items) { + $selector = \Drupal::service('rl_menu_link.variant_selector'); + foreach ($items as &$item) { + if (isset($item['original_link']) && method_exists($item['original_link'], 'getPluginId')) { + $plugin_id = $item['original_link']->getPluginId(); + $result = $selector->selectForPluginId($plugin_id); + if ($result && $result['text'] !== NULL) { + $item['title'] = $result['text']; + } + } + if (!empty($item['below'])) { + _rl_menu_link_process_items($item['below']); } } } @@ -299,9 +312,10 @@ Sampling score, turning any View into an engagement-optimised ranking. The pattern is fully server-side: the sort plugin calls `getThompsonScores()` with the content IDs from the View results as arm IDs, -then reorders the rows before rendering. Turns are batched via -`Drupal.rl.turn()` for all visible items; rewards fire when a visitor clicks -through to a listed item. +then reorders the rows before rendering. Turns are tracked client-side via +an `IntersectionObserver` that collects visible entity IDs, then sends an +`action=turns` payload directly to `rl.php` using `navigator.sendBeacon()`. +Rewards fire via `sendBeacon()` when a visitor clicks through to a listed item. ## DXPR Builder integration diff --git a/docs/rl_project_desc.html b/docs/rl_project_desc.html index 7317ef9..cdce469 100644 --- a/docs/rl_project_desc.html +++ b/docs/rl_project_desc.html @@ -78,7 +78,7 @@ <h3>Verify rl.php access</h3> <li><strong>Security modules</strong>: whitelist <code>/modules/contrib/rl/rl.php</code></li> </ul> -<p>If server policies prevent direct access, use the Drupal Routes API instead.</p> +<p>If server policies prevent direct PHP file access, consumer modules must implement their own tracking controller or proxy.</p> <h2>Drush command reference</h2> From 0d3fcb1bd4b5cf3979d526ff181456698e566a4c Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:40:40 +0200 Subject: [PATCH 11/12] Fix decision shape in README batch error example Match rl.php response format: decisions use {"armId": "v1"} objects, not bare strings. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 98ea36b..04f537f 100644 --- a/README.md +++ b/README.md @@ -420,7 +420,7 @@ malformed entries), the response includes an `errors` array: { "ok": true, "decisions": { - "hero_cta": "v1" + "hero_cta": {"armId": "v1"} }, "errors": [ {"kind": "decide", "id": "unknown_exp", "reason": "unknown_experiment"}, From aa60486c32b7bf170a0ab7cb67e57f2ec4c6a724 Mon Sep 17 00:00:00 2001 From: jjroelofs <904576+jjroelofs@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:47:14 +0200 Subject: [PATCH 12/12] Fix remaining review blockers: re-add docs callout, fix server-side wording Re-add documentation links callout box to desc.html after rebase dropped it. Fix "fully server-side" in integrations.md to correctly distinguish server-side decisions from client-side tracking. --- docs/guides/integrations.md | 12 ++++++------ docs/rl_project_desc.html | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/guides/integrations.md b/docs/guides/integrations.md index 39eed9c..4108fab 100644 --- a/docs/guides/integrations.md +++ b/docs/guides/integrations.md @@ -310,12 +310,12 @@ The three required services: It provides a Views sort plugin that reorders view results by Thompson Sampling score, turning any View into an engagement-optimised ranking. -The pattern is fully server-side: the sort plugin calls -`getThompsonScores()` with the content IDs from the View results as arm IDs, -then reorders the rows before rendering. Turns are tracked client-side via -an `IntersectionObserver` that collects visible entity IDs, then sends an -`action=turns` payload directly to `rl.php` using `navigator.sendBeacon()`. -Rewards fire via `sendBeacon()` when a visitor clicks through to a listed item. +The decision is server-side: the sort plugin calls `getThompsonScores()` +with the content IDs from the View results as arm IDs, then reorders the +rows before rendering. Tracking is client-side: an `IntersectionObserver` +collects visible entity IDs and sends an `action=turns` payload directly to +`rl.php` using `navigator.sendBeacon()`. Rewards fire via `sendBeacon()` +when a visitor clicks through to a listed item. ## DXPR Builder integration diff --git a/docs/rl_project_desc.html b/docs/rl_project_desc.html index cdce469..bdc87ef 100644 --- a/docs/rl_project_desc.html +++ b/docs/rl_project_desc.html @@ -131,6 +131,15 @@ <h2>AI coding assistant integration</h2> <li>"What's the conversion rate for variant B?"</li> </ul> +<div class="note-tip"> + <ul> + <li><a href="https://project.pages.drupalcode.org/rl/">Module documentation</a>: experiment management, cache strategies, and decorator patterns</li> + <li><a href="https://project.pages.drupalcode.org/rl/getting-started/installation/">Installation guide</a>: composer setup, rl.php verification, and Nginx configuration for the tracking endpoint</li> + <li><a href="https://project.pages.drupalcode.org/rl/api/php/">API reference</a>: PHP, JavaScript, and HTTP APIs for recording trials, rewards, and decisions</li> + <li><a href="https://project.pages.drupalcode.org/rl/guides/integrations/">Building a consumer module</a>: create your own A/B testable components using the RL framework</li> + </ul> +</div> + <h2>API</h2> <pre><code>// Get the experiment manager