From 7d061ff84f33a93d3f2201dcd72800703872f775 Mon Sep 17 00:00:00 2001
From: Chryseis Liu <130321313+Chryseisliu@users.noreply.github.com>
Date: Wed, 19 Aug 2026 12:04:26 -0700
Subject: [PATCH 1/3] Add DeltaSignal pathway perturbation UI
---
documentation/PathwayBrowser/deltasignal.md | 59 +++
.../PathwayBrowser/pathway-browser.md | 3 +
.../deltasignal-panel.component.html | 211 +++++++++
.../deltasignal-panel.component.scss | 404 ++++++++++++++++++
.../deltasignal-panel.component.ts | 60 +++
.../src/app/deltasignal/deltasignal.model.ts | 62 +++
.../app/deltasignal/deltasignal.service.ts | 193 +++++++++
.../app/deltasignal/deltasignal.utils.spec.ts | 91 ++++
.../src/app/deltasignal/deltasignal.utils.ts | 84 ++++
.../src/app/diagram/diagram.component.ts | 46 +-
.../src/app/viewport/viewport.component.html | 23 +
.../src/app/viewport/viewport.component.ts | 8 +-
proxy.conf.js | 6 +
13 files changed, 1248 insertions(+), 2 deletions(-)
create mode 100644 documentation/PathwayBrowser/deltasignal.md
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal-panel.component.html
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal-panel.component.scss
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal-panel.component.ts
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal.model.ts
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal.service.ts
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal.utils.spec.ts
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal.utils.ts
diff --git a/documentation/PathwayBrowser/deltasignal.md b/documentation/PathwayBrowser/deltasignal.md
new file mode 100644
index 00000000..e76b3987
--- /dev/null
+++ b/documentation/PathwayBrowser/deltasignal.md
@@ -0,0 +1,59 @@
+# DeltaSignal pathway perturbation prototype
+
+The Pathway Browser's **Perturb** action is a focused end-to-end integration
+with the DeltaSignal steady-state solver. It lets a user select an entity on a
+Reactome pathway, define one or more perturbations, run the solver, and view the
+predicted response on the existing Reactome diagram.
+
+## User flow
+
+1. Open a pathway for which DeltaSignal has a generated network.
+2. Select a physical entity on the diagram.
+3. Choose **Perturb**.
+4. Set activity on the 0–100 DeltaSignal input scale and add the perturbation.
+5. Repeat for any additional inputs, then choose **Run DeltaSignal**.
+6. Inspect convergence, predicted activities, changes from baseline, influence
+ scores, and the diverging diagram overlay.
+
+One Reactome entity can map to several logic-network UUIDs. The same input is
+applied to all matching UUIDs. Result rows are aggregated to one row per
+Reactome stable identifier for readability, while the diagram preserves all
+member values and renders them as a gradient.
+
+## API and scale
+
+The client uses the DeltaSignal API without sharing implementation code:
+
+- `GET /api/pathways`
+- `POST /api/parse { pathway_id }`
+- `POST /api/solve { network_id, observations }`
+
+Input activity uses the solver's 0–100 UI scale, where `0` is a knockout and
+`1` is normal baseline activity. Solver output is returned on a 0–1 internal
+scale and is multiplied by 100 before display. Diagram colour represents the
+change from each node's own baseline, not its absolute activity.
+
+## Local development
+
+Run the DeltaSignal server on port 8080 with a generated pathway catalog, then
+start this workspace with separate Reactome and DeltaSignal backends:
+
+```sh
+DS_PATHWAY_CATALOG=/path/to/logic-network-generator/output \
+ julia --project=/path/to/deltasignal /path/to/deltasignal/src/api/server.jl \
+ --host=127.0.0.1 --port=8080
+
+REACTOME_BACKEND=https://reactome.org \
+DELTASIGNAL_BACKEND=http://127.0.0.1:8080 \
+npm run start:simple -- --host 127.0.0.1
+```
+
+The Angular development proxy sends `/api` to `DELTASIGNAL_BACKEND`. If the
+variable is omitted, it defaults to `http://localhost:8080`.
+
+## Deliberate scope
+
+This prototype covers one pathway and steady-state prediction. It does not yet
+join several pathways, overlay results on ReacFoam, represent temporal order,
+or expose model benchmarking. Those are follow-on features rather than hidden
+behaviour in this UI.
diff --git a/documentation/PathwayBrowser/pathway-browser.md b/documentation/PathwayBrowser/pathway-browser.md
index dc0c37a2..163f3b70 100644
--- a/documentation/PathwayBrowser/pathway-browser.md
+++ b/documentation/PathwayBrowser/pathway-browser.md
@@ -1,4 +1,7 @@
# PathwayBrowser
[Userguide](http://localhost:4200/documentation/userguide/pathway-browser)
+
+[DeltaSignal pathway perturbation prototype](./deltasignal.md)
+
Dev docs loading...
diff --git a/projects/pathway-browser/src/app/deltasignal/deltasignal-panel.component.html b/projects/pathway-browser/src/app/deltasignal/deltasignal-panel.component.html
new file mode 100644
index 00000000..fa35fc67
--- /dev/null
+++ b/projects/pathway-browser/src/app/deltasignal/deltasignal-panel.component.html
@@ -0,0 +1,211 @@
+
+
+
Pathway perturbation prototype
+
DeltaSignal
+
Change one or more entities, solve the steady state, and overlay the predicted response.
+
+
+
+
+@if (service.status() === 'loading') {
+
+
+ Preparing the pathway network…
+
+} @else if (service.error() && !service.network()) {
+
+ error_outline
+
+ Network unavailable
+ {{ service.error() }}
+
+
+} @else if (service.network(); as network) {
+
+
+
+ Select a molecule on the pathway diagram
+
+ @if (selectedStId()) {
+ {{ selectedStId() }} is not represented in this DeltaSignal network. Choose another entity.
+ } @else {
+ The selected Reactome entity will be matched to its logic-network node or nodes.
+ }
+
+
+
+ }
+
+
+
+
+
+
+ × baseline
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
Run prediction
+
+ @if (service.perturbations().length) {
+
+ }
+
+
+ @if (service.perturbations().length) {
+
+ @for (item of service.perturbations(); track item.reactomeId) {
+
(null);
+ dropdown = signal<'analysis' | 'compare' | 'deltasignal' | null>(null);
toggleAnalysis() {
this.dropdown.set(this.dropdown() ? null : 'analysis');
if (this.dropdown() !== 'analysis') this.closeAnalysis();
}
+ toggleDeltaSignal() {
+ this.dropdown.update((open) => (open === 'deltasignal' ? null : 'deltasignal'));
+ }
+
closeAnalysis() {
this.dropdown.set(null);
if (this.state.analysisTab()) this.state.analysisTab.set(null);
diff --git a/proxy.conf.js b/proxy.conf.js
index 7d8048a6..c3b72807 100644
--- a/proxy.conf.js
+++ b/proxy.conf.js
@@ -13,10 +13,16 @@
*/
const backend = process.env.REACTOME_BACKEND || 'http://localhost:8080';
const secure = backend.startsWith('https');
+const deltaSignalBackend = process.env.DELTASIGNAL_BACKEND || 'http://localhost:8080';
const localService = (context) => [context, { target: backend, secure, changeOrigin: true }];
module.exports = {
+ '/api': {
+ target: deltaSignalBackend,
+ secure: deltaSignalBackend.startsWith('https'),
+ changeOrigin: true,
+ },
'/reactome': {
target: 'https://download.reactome.org',
secure: true,
From cef689b4bcbbef5610029e320d4fa08241cbecab Mon Sep 17 00:00:00 2001
From: Chryseis Liu <130321313+Chryseisliu@users.noreply.github.com>
Date: Thu, 20 Aug 2026 01:17:48 -0700
Subject: [PATCH 2/3] Fix DeltaSignal dead-code check
---
.../pathway-browser/src/app/deltasignal/deltasignal.model.ts | 4 ++--
.../pathway-browser/src/app/deltasignal/deltasignal.utils.ts | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/projects/pathway-browser/src/app/deltasignal/deltasignal.model.ts b/projects/pathway-browser/src/app/deltasignal/deltasignal.model.ts
index 14f07903..6a189b89 100644
--- a/projects/pathway-browser/src/app/deltasignal/deltasignal.model.ts
+++ b/projects/pathway-browser/src/app/deltasignal/deltasignal.model.ts
@@ -4,7 +4,7 @@ export interface DeltaSignalPathway {
name: string;
}
-export interface DeltaSignalNode {
+interface DeltaSignalNode {
uuid: string;
name: string;
reactome_id: string;
@@ -13,7 +13,7 @@ export interface DeltaSignalNode {
set_id: string | null;
}
-export interface DeltaSignalEdge {
+interface DeltaSignalEdge {
parent_uuid: string;
child_uuid: string;
is_and: boolean;
diff --git a/projects/pathway-browser/src/app/deltasignal/deltasignal.utils.ts b/projects/pathway-browser/src/app/deltasignal/deltasignal.utils.ts
index 7bdd3811..753dd510 100644
--- a/projects/pathway-browser/src/app/deltasignal/deltasignal.utils.ts
+++ b/projects/pathway-browser/src/app/deltasignal/deltasignal.utils.ts
@@ -5,7 +5,7 @@ import {
DeltaSignalSolveResult,
} from './deltasignal.model';
-export const toDisplayActivity = (activity: number) => activity * 100;
+const toDisplayActivity = (activity: number) => activity * 100;
export function buildObservations(
perturbations: Iterable
From d20ccc2afa0d939937b8465ba99ee0e04fd8a7f7 Mon Sep 17 00:00:00 2001
From: Chryseis Liu <130321313+Chryseisliu@users.noreply.github.com>
Date: Sat, 22 Aug 2026 11:49:59 -0700
Subject: [PATCH 3/3] Add logic-network view to DeltaSignal prototype
Keep LNG UUIDs separate in an interactive top-response graph, leave the Reactome diagram accessible beside the controls, and document the complete demo workflow.
---
documentation/PathwayBrowser/deltasignal.md | 204 +++++++++++++---
.../images/deltasignal-diagram-overlay.png | Bin 0 -> 418235 bytes
.../images/deltasignal-logic-network.png | Bin 0 -> 405161 bytes
.../deltasignal-logic-graph.component.html | 72 ++++++
.../deltasignal-logic-graph.component.scss | 147 ++++++++++++
.../deltasignal-logic-graph.component.ts | 221 ++++++++++++++++++
.../deltasignal-panel.component.html | 81 ++++---
.../deltasignal-panel.component.scss | 43 ++++
.../deltasignal-panel.component.ts | 12 +-
.../src/app/deltasignal/deltasignal.model.ts | 2 +-
.../app/deltasignal/deltasignal.utils.spec.ts | 21 +-
.../src/app/deltasignal/deltasignal.utils.ts | 55 +++++
.../src/app/viewport/viewport.component.html | 2 +-
.../src/app/viewport/viewport.component.scss | 20 ++
14 files changed, 814 insertions(+), 66 deletions(-)
create mode 100644 documentation/PathwayBrowser/images/deltasignal-diagram-overlay.png
create mode 100644 documentation/PathwayBrowser/images/deltasignal-logic-network.png
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal-logic-graph.component.html
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal-logic-graph.component.scss
create mode 100644 projects/pathway-browser/src/app/deltasignal/deltasignal-logic-graph.component.ts
diff --git a/documentation/PathwayBrowser/deltasignal.md b/documentation/PathwayBrowser/deltasignal.md
index e76b3987..dde79294 100644
--- a/documentation/PathwayBrowser/deltasignal.md
+++ b/documentation/PathwayBrowser/deltasignal.md
@@ -1,59 +1,193 @@
# DeltaSignal pathway perturbation prototype
-The Pathway Browser's **Perturb** action is a focused end-to-end integration
-with the DeltaSignal steady-state solver. It lets a user select an entity on a
-Reactome pathway, define one or more perturbations, run the solver, and view the
-predicted response on the existing Reactome diagram.
+This prototype connects the Reactome Pathway Browser to the DeltaSignal
+steady-state solver. A user can change one or more molecules, run a prediction,
+and inspect the response in two complementary views:
-## User flow
+1. the familiar Reactome diagram, coloured by predicted change; and
+2. the underlying LNG logic nodes and edges, where position-aware UUIDs remain
+ separate.
-1. Open a pathway for which DeltaSignal has a generated network.
-2. Select a physical entity on the diagram.
-3. Choose **Perturb**.
-4. Set activity on the 0–100 DeltaSignal input scale and add the perturbation.
-5. Repeat for any additional inputs, then choose **Run DeltaSignal**.
-6. Inspect convergence, predicted activities, changes from baseline, influence
- scores, and the diverging diagram overlay.
+The feature is an interface to an existing model. It does not change
+DeltaSignal's propagation rules, and the visualization is not evidence that a
+prediction is biologically correct.
-One Reactome entity can map to several logic-network UUIDs. The same input is
-applied to all matching UUIDs. Result rows are aggregated to one row per
-Reactome stable identifier for readability, while the diagram preserves all
-member values and renders them as a gradient.
+
-## API and scale
+## Run a prediction
-The client uses the DeltaSignal API without sharing implementation code:
+1. Open a pathway for which the DeltaSignal API has a generated LNG network.
+2. Choose **Perturb** in the Pathway Browser toolbar.
+3. Select a physical entity on the diagram, not an event in the pathway tree.
+4. Set its activity and choose **Add perturbation**.
+5. Repeat the selection step if the prediction needs more than one input.
+6. Choose **Run DeltaSignal**.
+7. Check the convergence message before interpreting the result.
+8. Use **Reactome diagram** or **Logic nodes & edges** to change the result
+ view.
-- `GET /api/pathways`
-- `POST /api/parse { pathway_id }`
-- `POST /api/solve { network_id, observations }`
+The panel is a side drawer, so the pathway diagram remains visible and
+interactive while the controls are open. On a narrow screen the drawer expands
+to the full viewport.
-Input activity uses the solver's 0–100 UI scale, where `0` is a knockout and
-`1` is normal baseline activity. Solver output is returned on a 0–1 internal
-scale and is multiplied by 100 before display. Diagram colour represents the
-change from each node's own baseline, not its absolute activity.
+If the panel says that an entity is not represented, the selected Reactome
+stable identifier has no matching node in the parsed LNG network. The UI does
+not substitute another molecule or silently drop the selection.
+
+## Activity scale
+
+The input control uses DeltaSignal's activity scale:
+
+| Value | Meaning |
+| ---------------: | ----------------------------- |
+| `0` | knockout or no input activity |
+| `1` | normal baseline activity |
+| greater than `1` | activation above baseline |
+
+The quick activation preset is `80`, which is intentionally a strong
+perturbation. The number is a relative model input, not a measured expression
+fold change. It should not be described as 80-fold RNA expression.
+
+The solver returns internal activities on a 0 to 1 scale. The client multiplies
+them by 100 for display, so a displayed baseline of `100x` corresponds to the
+internal baseline value `1.0`.
+
+## Reactome diagram view
+
+Diagram colour shows the predicted change from each logic node's own baseline:
+
+- blue means lower activity;
+- near-white means little change;
+- red means higher activity.
+
+A Reactome entity can expand into several LNG logic nodes. This occurs when the
+same stable identifier has different positional or logical roles in the
+generated network. The diagram keeps every member value and renders a gradient
+when those values differ. The accompanying result table is intentionally more
+compact: it shows one row per Reactome stable identifier, uses the mean member
+activity and change, and keeps the largest member influence score.
+
+The table is limited to the 40 largest absolute changes. This is a display
+limit, not a solver limit. The complete result remains available in the API
+response.
+
+## Logic nodes and edges view
+
+
+
+This view exposes the graph that DeltaSignal actually solved. It is useful for
+checking how Reactome entities were expanded by LNG and for following a
+prediction through reactions, complexes, sets, and sequence entities.
+
+The graph contains the 40 UUID-level nodes with the largest absolute predicted
+changes, plus every perturbed input even if it falls outside that limit. An
+edge is drawn only when both endpoints are visible. The view therefore never
+draws an apparent direct connection through an omitted node.
+
+### Reading the graph
+
+- Node colour uses the same lower/neutral/higher scale as the diagram overlay.
+- Node size increases with the absolute influence score.
+- A thick amber border marks a perturbed input.
+- Diamonds are reactions.
+- Rounded rectangles are complexes or sets.
+- Hexagons are DNA or RNA sequence entities.
+- Teal arrows are positive edges.
+- Magenta arrows are negative edges.
+- Solid edges are AND relationships.
+- Dashed edges are OR relationships.
+
+Selecting a node opens its Reactome stable identifier, exact LNG UUID, entity
+kind, baseline, predicted activity, change, influence, and mapping
+multiplicity. Mapping multiplicity is the number of UUIDs in the solved network
+that share that Reactome stable identifier.
+
+The layout is an interactive Cytoscape view. Users can pan, zoom, select nodes,
+and use the fit button to restore the full subgraph.
+
+## API contract
+
+The Angular client calls the DeltaSignal API through the development or
+production proxy:
+
+- `GET /api/pathways` lists available generated pathways;
+- `POST /api/parse { pathway_id }` parses one network and returns nodes, edges,
+ and mappings;
+- `POST /api/solve { network_id, observations }` returns activities, influence
+ scores, convergence status, iteration count, and solve time.
+
+When one selected Reactome entity maps to several UUIDs, the same observation
+is sent to every matching UUID. The UUIDs are not merged before solving.
## Local development
-Run the DeltaSignal server on port 8080 with a generated pathway catalog, then
-start this workspace with separate Reactome and DeltaSignal backends:
+Clone the three repositories in any convenient locations:
```sh
-DS_PATHWAY_CATALOG=/path/to/logic-network-generator/output \
- julia --project=/path/to/deltasignal /path/to/deltasignal/src/api/server.jl \
+git clone git@github.com:reactome/WebsiteAngular.git
+git clone git@github.com:reactome/deltasignal.git
+git clone git@github.com:reactome/logic-network-generator.git
+```
+
+Generate or obtain an LNG catalog containing one directory per pathway. Each
+pathway directory must contain `logic_network.csv` and
+`stid_to_uuid_mapping.csv`.
+
+Start the DeltaSignal API:
+
+```sh
+DS_PATHWAY_CATALOG=/path/to/lng/output \
+ julia --project=/path/to/deltasignal \
+ /path/to/deltasignal/src/api/server.jl \
--host=127.0.0.1 --port=8080
+```
+Then start the Pathway Browser:
+
+```sh
REACTOME_BACKEND=https://reactome.org \
DELTASIGNAL_BACKEND=http://127.0.0.1:8080 \
npm run start:simple -- --host 127.0.0.1
```
-The Angular development proxy sends `/api` to `DELTASIGNAL_BACKEND`. If the
+Open a pathway available in the generated catalog. For example:
+
+```text
+http://127.0.0.1:4200/PathwayBrowser/R-HSA-69620
+```
+
+The Angular development proxy sends `/api` to `DELTASIGNAL_BACKEND`. If this
variable is omitted, it defaults to `http://localhost:8080`.
-## Deliberate scope
+## Verification
+
+The graph-selection and truncation behavior is covered by focused unit tests:
+
+```sh
+npx vitest run \
+ projects/pathway-browser/src/app/deltasignal/deltasignal.utils.spec.ts
+```
+
+The complete development build is checked with:
+
+```sh
+npx ng build --configuration development
+```
+
+The manual browser check used Cell Cycle Checkpoints (`R-HSA-69620`), selected
+TP53, set activity to `0`, ran DeltaSignal, inspected the Reactome overlay, and
+then selected the TP53 UUID in the logic graph. The run converged in 175
+iterations and the graph displayed 40 nodes and 40 retained edges.
+
+## Current boundary
+
+The prototype solves and visualizes one generated pathway at a time. It does
+not yet join neighboring pathway networks or calculate one defensible activity
+score for every ReacFoam region. A ReacFoam overlay would first require an
+explicit cross-pathway aggregation rule and a catalog broad enough to support
+it. Adding coloured regions before those choices are defined would make the UI
+look more complete than the model underneath it.
-This prototype covers one pathway and steady-state prediction. It does not yet
-join several pathways, overlay results on ReacFoam, represent temporal order,
-or expose model benchmarking. Those are follow-on features rather than hidden
-behaviour in this UI.
+The current nodes-and-edges view was therefore implemented first. It exposes
+the exact graph already returned by DeltaSignal and gives a direct way to audit
+LNG expansion, edge signs, logic relationships, and UUID mappings.
diff --git a/documentation/PathwayBrowser/images/deltasignal-diagram-overlay.png b/documentation/PathwayBrowser/images/deltasignal-diagram-overlay.png
new file mode 100644
index 0000000000000000000000000000000000000000..8426b140fb6939cc7b72b451185287af52166204
GIT binary patch
literal 418235
zcmZ6yV{~Of*EJd&9lK-Owr$(CZL`CUZQDu5wr$%^?s=Z~zIS}zJ%7$PwfCt}dso$5
zYt1<;QbA4}9tIl*2nYyXQbI%t2na#|2nb9D3Ixz1$2?j91oR6?QbbV2BkM97TmXj~
zbELMZt+R8(AQ;*h$JzbApPkIk&QAL}#=yPnYqg^7mu5)aKoIaKx?cDABd2y9y0mT5
z9}<0u)hb#{kU)!|I(gf}cId`dBPcMCKmmeZ|NUZ7mH=G*-(UZ2oQn_yLI1zo3KWCE
zX#S6X0qzqign-ugKYJqh6(I(XT=zfS{=dBw{EEdUF(CZE+pt+B{t5kmH~h~itP%o3
z|L;NA{2@W2WmQ!*DQ3Qh4NhFpw5g&b3j6O=m
zYAfn$vx>x|-iT}QBM^Uwm=r|d}vl4_6B;;OVZvJHPi+l0YO?j
z%d*m{T$CXxC`wL`!OBm0oa5Zj)3YEhDPe=idTOG$no1)7*-=*1LblEz0EP_|P?4pU
zRD-3I5m#O7n_k}BR1p(X6BE;t($dO$yy+2Uv)k-)y)dh47cgg_5ETs#twRe56@7h$
zEHXKHSE}P*g!o-nNk`5+JT^Qfvm>RA7nPlyoQxSrFdQoIx&p4kmT5b--*2W&ksQ=7
z^fRdPG8(e6-FNmD`aiQAab8GB-`S)dE?Fa|v|m=QLoM)>w4&5Ft8{T5jw3P>Vjfocxh7N3QG>`yDZVKh;a+bvGaU7WAmMY
z;^6F@oZn#H(H{o~__(-_Y~6K&CNv2(B~6X^*A~SUWkB;O
zMJCEuloi|p{lredtwkXr1wla-4Nlf5!I8F?*Wb|Xj|2E)|6O4g5E>R0&kclwM(JSzEPaq^Z;0oWX!&Kvc%c;@<^
zuk-wH)_RNPNN5m_jEsOep#^W3^77t`NXmC(r$(`?QTX7bc{bL7TRtT;XlyZn0xN*-
z=WG6RLN>V_6^ZRiRGG_@U)(HOd%eZN%E};OnXv{{6(u1l>HGBjm77p^VnUOoD$j&2
z-=UP6rmUnw@-+bZWd)HfH#0RcL3R=x<9eNG?}h{}{GU}{0L|3yTN%o$6T6gB35S)P
z@|FD
zem;xG&?c>o<6_009jn_FQKGnLKLB$rbm?rn00UNKAJL&e72kuu(lZ+a(i`6G`@S
z+;d#WVE^Y?&t})=J$6QW%rYv3!XUx-W>>!-I@+t+9`=pt7se;BaCYZs|_za76ye_mk`D`S5B2h0j+rj@Gl)xwO$5z^Aq27W=oF|#mWvU`#2
zT?cmx&gms{E!HI$k;Wt3%ngg^>#C~Cz*Q${Qww}AEH7s564~YFH{5P-WD%KgqWuR_
zWr3gzR%?*DOWhoXD-fad5HVypex6=h$Zwo0ANDRR3?Fx11u+YHfGEi+xogdo4)og!
zQfd-~_#rFfj>X8ZsURw(cG1$(QPNZ2SZR(!^(~C#ev28T!Hpxs&u(;hd)$=cSu2Uq
zHZ5LH;kfTz+@QJZ1?2@tLSZ>3hL%uKD5O9#uP9jB7HJRXaU*Urq^1U42GQ9HoN#?^
zGgGqTSK`ea#{xf{N7`H1s9k?f+t$e9+%M9*j6~PUh518DPP$stQd55K%GWU<5&Z|d
zk_)<7tOer{cst!i?}3BxJw4yBlE^W;Jlzk!TJc3)mDnVVj7G#B9hw;w)s*^w6#)4S
zVOv?%D1c)v`@YAf!J%V^{|DwH#A2hW9+$9)H!`t|nhmtXPo`7Jd=Ydd$YHHvo!m}Z
zNQf%lm+|xBCmpPng@L1q#T>r@puEXZxA7=fJ%QUgHy2al*Sb6EVEI(m33~!3OGWa?3_xOeshMd%4=RH1+$V0tBgX8Z&XHEu%$cF?+7NX
zqU!ON_=R3e$?N05&+xOh+l#D;7#kTFH>CTOjbYRE9OP!g^1vD~>!E3>zAs4cX;n~x
zAh~^TX?G1oNcu+m(|7BRy*Kzixe)(FRL&LQWH3KrzYf%Y*3v%xGIAAROG&qvi||D!
z;W((3#El+rqSAtsFY&n%-CjlxovjR9f)}ZiN^;6ZCXV2si={M
zMg^@c@{qskCKpp6xwZaKvgnddi!w{oXqz58<05!ve3A#rK={Y|yaqx;CZ;1ni7-}(
zJpTe+x-%9ddV*0zQeYd7!{(b5P}P(%G0t%mYiYt>SeMgP)!+t+u*xqf09k`gkNKb1
zL4kyU!p&rtCs729J6nekcTG<>m>dL*pjP&*{Uea`Vr>|yigB$2=<2L>qBPhG5XV}0
z{B|r?&Sc}adGDa*#t8=?;$jhZ0#BC7@lR#Y!Mra`E-JeOnzTEcd=
zg!ayS4Rq}%_8C^x#9SB&x1lLoIy!D^S~bk;(#Gy#U3s0+9ftlly@@)b9{J7d6M@Q<
z8C!;GNm-604DpnPQ5*oSUyHW2Q9(srcy5dbj8$1s)zqb}{p4ibL-0!oZ
zeOXK!{)JIVHAHt6wTPr{Smdo}88PF&!6U595ksLCAA(z>9}SXIr57nefQ9Kf=5nFN
zZJ}X&VPF}qpqgn_ft(v|?w1PpiFBC4Rt~qCz9=IBVe`WELimms12|R^$c(W4X6Ft6
z2}W)~ZH0&NvV|UvM(irA=;9&}3Z;U`3yh)&wV=Tk7LOns_MXW>S*@z)(fXKzw~Vzn
zJm*>zNCZ-yCSJDEGo5kn`m5a?n5Sf){^#Ro|7i>^7PKQd=vAPOuG7dw?OG`6Oc@v>
z2%+7|eu1&IBaU|YVXyHuLi{uYOFU2!Beio|U~cww~G;j+)f(
zfQfED!ARB2`M|?_t`Qe{1s^P??Ks$!#X#86o)uy^y)!Ym*x)10ooTo@ZuXbq6c^|+REIfJ%K($S7Yi9G4~
z+S#6wA^X9_=M!A10V2l4E`hov!2Y8b`*Wg3zFubw2y*_^_$KSf1%1UT>(WvZ{>3>ZNkybeJW5MTr-p_)
z!w8rFncv&<=LMzskBNp6{y?T!lrLz?Hcd;Od|#JSf@{E@#X~L1JejCJDpFQr%JRLV
zYqPZr6z19vujD0o=<5#9aczJ9W+j6q4UHGhGJpla{t;MZD>6^%gDLDihS;Qy`WYLQ
zCXyJHvgDS!;26hrPh@l`{~VkO_EM=qkccc)#Df=pa>`-$Ovt07Z)`J%T;2G71eNbr
zN=uU^#|RJ>7K~#@l#>*rDop@EfNHsTE0qoIpuJk!YY10I?`o=SC(HlqAlfu+^LtS@
z1SB=E!RY85EqE;K8uMsz(p+cHAw2k|$NqZ9)5UtatmA{U
zn?r`p`#gmlQ(gAG#|k@ptmBIth`-6!0K>81uepj4)yo=mq(b(|ZSfjsTjj`jd6F)!
zpkGo_vcv2`*5N)7-!6SzDwQxn21j+V#`LtDl&cNThqee!m<64MrDcnon-wW(km{A0
zyG1z#xi|@Oz1Bao#vT7RY&@KBLaHzkqH;BR@_!XneRu
z>vT;%9B8F2Ykeza4CAW+2~?
z0+C3xQiXmi%`+8KQU;;g`Mby?!(o;1Agr|}8J*-OGL-wKQ5%7W
zP$tfHJmx8fUpnm5_kW^qx`r!)6%tQU1G85ium2g;yY;yAUZA1=$uTXdVd@_UnLZ7(^O@#$&$XceYWhQk!NK(^ASM
zALyC5$jJC|hUlmZ0uw{MqmTw;9-m}mV;MxC6PBvsXGJ3YgF2bTcX>DT2M#)LyCxeE
z?+wQW0b6yPNvRei*1q`w?g-J)=6|^WwHKD00{)p$A&YN*bM2p2;v*WSaz_<49j
zU-E%IMNNHCDO;*Q6_)4I9d`Bi7Z72`mJra>FZ+n23#$o-3AczpsM7qJiU+2pscPbQ
zp77mQ=E7?m^e?-}rVQX&v$C&1eClYkF@!X_t(#K|RzoMLg%Aaq
zL!DDfaAvBiLdW(Uj@3-2EjO#-f39h3Ae_;kmQkLr>NJ|Tqm)NK7Wb3r;vVvtW-mzI
zO;>h+er+Z@Sq|LdWy?%W`$soUD)GY_CXlFxo|G_PCG|d%olIiCWq5LSxY)#QeMIv?
z#VtQ%1;a|r^Rz_e8Bz4)Qss6C$&W^c8Lg-B>!}_Aj0T~lBjc8xrh0K=mYNM|u$;cq
zY`;^Po8yVoV~(CLlwZaJ<^)xH^BjFqH?*eP$|OHSE7B+=n|{ml91Zby?PJ~8HaG6qvH2uQ)%)s&6`-K1
zt|UQ(XRBR3tjy`ba6H}nn46|G~aL+T`%4PqpM~0S-{5N6U@Ws-B1W$`v
zmslF?PP3ie|CI~pg3T59V%GX)z@FEmQ_M>0V4aihVoCB<94s9xBV%rDTtxIVrLHGz
zr0X7WgR!af76d&R3rAWyDS79+DFY*?20e^PiB+?vGOw<#AXOHToqh99V(RnvggTUF
zaX?CT(!uwExZYR=g&EnftyYUojWm&zw3J{=?$32NVFvxhyUQS+vpo!hq2CI%gW*cc
zEF|~%+VgO&kuvJ7R}Y`-X`LF|zDQgE?7W~8UHi(MH85$?&^Z@r)V$J9>=kUz$!52?
zj`uKZVKqTon>pntE@0KSYz&lljY&rJ>aqZzzjqap9VL?Mdp**Tbj&w7cuic-V3(IG
zd