From 057fdfa131828a9a626c05e19a2f8a0dd4ec0682 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 7 Nov 2022 10:01:17 +0000 Subject: [PATCH 01/55] First draft --- .../FDC3-1.2-Conformance-Test-Cases.md | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md new file mode 100644 index 000000000..855f5e6aa --- /dev/null +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -0,0 +1,177 @@ +# FDC3 1.2 Conformance Test Cases + +## 1. System / User Channels + +### User Channels Broadcast (Basic) + +| App | Step | Details | +|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| A | addContextListener |Call `fdc3.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| A | joinChannel |`fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | Broadcast | `fdc3.broadcast()` | +| A | Receive Context | Instrument object matches the one broadcast in 2 above. | + +- [ ] `UC Basic Usage 1` Perform above test +- [ ] `UC Basic Usage 2` Perform above test, but join channel first and then `fdc3.addContextListener()` +- [ ] `UC Basic Usage 3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining +- [ ] `UC Basic Usage 4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining + +### User Channels Broadcast (Filtered Context) + +| App | Step | Details | +|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| A | addContextListener | Call `fdc3.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| A | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | +| A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | + +- [ ] `UC Filtered Context 1`: Perform above test + +| App | Step | Details | +|-----|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| A | addContextListener | Call `addContextListener (“fdc3.instrument”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object
Call `addContextListener (“fdc3.contact”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object | +| A | joinChannel | Check that there is an unsubscribe function on the returned object | +| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | +| A | Receive Context | Instrument object matches the one broadcast in 2 above.
Contact object matches the one broadcast in 2 above. | + +- [ ] `UC Filtered Context 2`: Perform above test +- [ ] `UC Filtered Context 3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. +- [ ] `UC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- [ ] `UC Filtered Context 4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- [ ] `UC Filtered Context 5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- [ ] `UC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. +- [ ] `UC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. +- [ ] `UC Current Channel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. + +## 2. App Channels + +### App Channels Broadcast (Basic) + +| App | Step | Details | +|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| A | joinChannel |`fdc3.getOrCreateChannel("test-channel")` | +| A | addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| B | joinChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | Broadcast | `testChannel.broadcast()` | +| A | Receive Context | Instrument object matches the one broadcast in 2 above. | + +- [ ] `AC Basic Usage 1` Perform above test +- [ ] `AC Basic Usage 2` Perform above test, but join channel first and then `testChannel.addContextListener()` +- [ ] `AC Basic Usage 3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining + +### App Channels Broadcast (Filtered Context) + +| App | Step | Details | +|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| A | joinChannel |`fdc3.getOrCreateChannel("test-channel")` | +| A | addContextListener | Call `testChannel.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| B | joinChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | +| A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | + +- [ ] `AC Filtered Context 1`: Perform above test + +- [ ] `AC Filtered Context 2`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. +- [ ] `AC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- [ ] `AC Filtered Context 3`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- [ ] `AC Filtered Context 4`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- [ ] `AC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. +- [ ] `AC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. + +### App Channel History + +| App | Step | Details | +|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| A | joinChannel |`fdc3.getOrCreateChannel("test-channel")` | +| B | joinChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | +| A | Receive Context | `testChannel.getCurrentContext('fdc.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc.contact')` returns the last broadcast contact | + +- [ ] `AC Context History Typed`: Perform above test. +- [ ] `AC Context History Multiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. +- [ ] `AC Context History Last`: **A** calls `testChannel.getCurrentContext()` retrieves the last broadcast context item + +## 3. Open API + +### A Opens B + +- `AOpensB1`: [ ] **A** calls `fdc3.open(‘app B Name’)`, check app **B** opens +- `AOpensB1`: [ ] **A** calls `fdc3.open({name: “”})`, check app **B** opens +- `AOpensB1`: [ ] **A** calls `fdc3.open({name: “”, appId: “”}, check app **B** opens. (`FDC3 2.0`) + +### A Fails To Open B + +- `AFailsToOpenB`: Run the above 4 tests again with a non-existent app name/app id. Should return “App Not Found” Error from https://fdc3.finos.org/docs/api/ref/Errors#openerror + +### A Opens B With Context + +| App | Step | Description | +|-----|-----------------|----------------------------------------------------------| +| A | Opening App | various open methods as in `AOpensB1` except with a `` argument
check app opens | +| B | Context present | `fdc3.addContextListener()`
- receives `` from **A** | + +- [ ] `AOpensBWithContext`: Perform above tests +- [ ] `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.instrument`)` + + +### Specific Context + + +| App | Step | Description | +|-----|-----------------|-------------------------------------------------------------------------------------------------------------------------------| +| A | Opening App | `fdc3.open(‘app Name’, )`
check app opens | +| B | Context present | fdc3.addContextListener()
- receives from a | +| A | Promise | - receives a rejection from the open promise with “App Timeout’ from
https://fdc3.finos.org/docs/api/ref/Errors#openerror | + +- [ ] `AOpensBWithWrongContext`: As above +- [ ] `AOpensBNoListen`: Skip `fdc3.addContextListener() above. +- [ ] `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise completes successfully +- [ ] `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. + + + +## 4. Intents + +### Setup + +You will need to pre-populate the AppDirectory with the following items: + +| App | Required Metadata | +|-----|------------------------------------------------------------------------------------------------------------------------------------------------------| +| A | A’s AppD Record contains: `aTestingIntent` (with context type `testContextX`, `testContextZ`) and `sharedTestingIntent1` (with context type `testContextX`) | +| B | B’s AppD Record contains `bTestingIntent` (with context type `testContextY`) and `sharedTestingIntent1` (with context types `testContextX` and `testContextY`) | +| C | C’s AppD Record contains `cTestingIntent` (with context type `testContextX`) | + +Also we assume a fourth app **D** that is going to discover the intents in the other 3. + +### Find Intent From AppD + +- [ ] `IntentAppD`: Calls `fdc3.findIntent(‘aTestingIntent’)`. Receives promise containing an appIntent with metadata containing `aTestingIntent` and only **A** app metadata. +- [ ] `WrongIntentAppD`: Calls `fdc3.findIntent(‘nonExistentIntent’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror +- [ ] `IntentAppDRightContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextX’)`. Receives promise containing an appIntent with metadata containing `aTestingIntent` and only **A** app metadata. +- [ ] `IntentAppDWrongContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextY’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror +- [ ] `IntentAppDMultiple1`: Calls `fdc3.findIntent(‘sharedTestingIntent1’)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. +- [ ] `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextX`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. +- [ ] `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. + +### Find Intents By Context + +- [ ] `SingleContext`: Call `fdc3.findIntentsByContext(‘fdc3.testContextX’)`. Should return `aTestingIntent` (app **A**), `sharedTestingIntent` (**A**, **B**) and `cTestingIntent` (**C**) AND nothing else. +- [ ] `NoContext`: Call `fdc3.findIntentsByContext()`. Throws error of some kind? + +### Raise Intent + +| App | Step | Details | +|-----|----------------|---------------------------------------------------------------------------------------------------| +| D | Raise | `fdc3.raiseIntent(‘sharedTestingIntent1’, {testContextY})`
starts app B. | +| B | Gather Context | `fdc.addIntentListener(‘sharedTestingIntent1’)`
Receives testContextY, matching that sent by D | + +- [ ] `SingleResolve1`: Perform above test +- [ ] `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above +- [ ] `TargetedResolve2,3,4` Use the other ways of addressing apps (via ID, metadata) as described at the start of #18 +- [ ] `FailedResolve1-4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive No Apps Available Resolve Error +- [ ] `FailedResolve5-8` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` and variations. You will receive No Apps Available Resolve Error From bbd5268c853e2f70605e61621b66399321532c9b Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 7 Nov 2022 10:19:43 +0000 Subject: [PATCH 02/55] Added link onto community page --- .../FDC3-1.2-Conformance-Test-Cases.md | 100 +++++++++--------- toolbox/fdc3-conformance/README.md | 8 ++ website/data/community.json | 10 ++ website/static/img/community/conformance.png | Bin 0 -> 135254 bytes 4 files changed, 68 insertions(+), 50 deletions(-) create mode 100644 toolbox/fdc3-conformance/README.md create mode 100644 website/static/img/community/conformance.png diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 855f5e6aa..04da65e31 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -12,10 +12,10 @@ | B | Broadcast | `fdc3.broadcast()` | | A | Receive Context | Instrument object matches the one broadcast in 2 above. | -- [ ] `UC Basic Usage 1` Perform above test -- [ ] `UC Basic Usage 2` Perform above test, but join channel first and then `fdc3.addContextListener()` -- [ ] `UC Basic Usage 3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining -- [ ] `UC Basic Usage 4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining +- `UC Basic Usage 1` Perform above test +- `UC Basic Usage 2` Perform above test, but join channel first and then `fdc3.addContextListener()` +- `UC Basic Usage 3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining +- `UC Basic Usage 4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### User Channels Broadcast (Filtered Context) @@ -27,7 +27,7 @@ | B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | -- [ ] `UC Filtered Context 1`: Perform above test +- `UC Filtered Context 1`: Perform above test | App | Step | Details | |-----|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -37,14 +37,14 @@ | B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Contact object matches the one broadcast in 2 above. | -- [ ] `UC Filtered Context 2`: Perform above test -- [ ] `UC Filtered Context 3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. -- [ ] `UC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. -- [ ] `UC Filtered Context 4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- [ ] `UC Filtered Context 5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. -- [ ] `UC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. -- [ ] `UC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. -- [ ] `UC Current Channel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. +- `UC Filtered Context 2`: Perform above test +- `UC Filtered Context 3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. +- `UC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- `UC Filtered Context 4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- `UC Filtered Context 5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `UC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. +- `UC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. +- `UC Current Channel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. ## 2. App Channels @@ -58,9 +58,9 @@ | B | Broadcast | `testChannel.broadcast()` | | A | Receive Context | Instrument object matches the one broadcast in 2 above. | -- [ ] `AC Basic Usage 1` Perform above test -- [ ] `AC Basic Usage 2` Perform above test, but join channel first and then `testChannel.addContextListener()` -- [ ] `AC Basic Usage 3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining +- `AC Basic Usage 1` Perform above test +- `AC Basic Usage 2` Perform above test, but join channel first and then `testChannel.addContextListener()` +- `AC Basic Usage 3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### App Channels Broadcast (Filtered Context) @@ -72,14 +72,14 @@ | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | -- [ ] `AC Filtered Context 1`: Perform above test +- `AC Filtered Context 1`: Perform above test -- [ ] `AC Filtered Context 2`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. -- [ ] `AC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. -- [ ] `AC Filtered Context 3`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- [ ] `AC Filtered Context 4`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. -- [ ] `AC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. -- [ ] `AC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. +- `AC Filtered Context 2`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. +- `AC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- `AC Filtered Context 3`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- `AC Filtered Context 4`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `AC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. +- `AC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. ### App Channel History @@ -90,18 +90,18 @@ | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | `testChannel.getCurrentContext('fdc.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc.contact')` returns the last broadcast contact | -- [ ] `AC Context History Typed`: Perform above test. -- [ ] `AC Context History Multiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. -- [ ] `AC Context History Last`: **A** calls `testChannel.getCurrentContext()` retrieves the last broadcast context item +- `AC Context History Typed`: Perform above test. +- `AC Context History Multiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. +- `AC Context History Last`: **A** calls `testChannel.getCurrentContext()` retrieves the last broadcast context item ## 3. Open API ### A Opens B -- `AOpensB1`: [ ] **A** calls `fdc3.open(‘app B Name’)`, check app **B** opens -- `AOpensB1`: [ ] **A** calls `fdc3.open({name: “”})`, check app **B** opens -- `AOpensB1`: [ ] **A** calls `fdc3.open({name: “”, appId: “”}, check app **B** opens. (`FDC3 2.0`) +- `AOpensB1`: **A** calls `fdc3.open(‘app B Name’)`, check app **B** opens +- `AOpensB2`: **A** calls `fdc3.open({name: “”})`, check app **B** opens +- `AOpensB3`: **A** calls `fdc3.open({name: “”, appId: “”}, check app **B** opens. (`FDC3 2.0`) ### A Fails To Open B @@ -114,8 +114,8 @@ | A | Opening App | various open methods as in `AOpensB1` except with a `` argument
check app opens | | B | Context present | `fdc3.addContextListener()`
- receives `` from **A** | -- [ ] `AOpensBWithContext`: Perform above tests -- [ ] `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.instrument`)` +- `AOpensBWithContext`: Perform above tests +- `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.instrument`)` ### Specific Context @@ -127,10 +127,10 @@ | B | Context present | fdc3.addContextListener()
- receives from a | | A | Promise | - receives a rejection from the open promise with “App Timeout’ from
https://fdc3.finos.org/docs/api/ref/Errors#openerror | -- [ ] `AOpensBWithWrongContext`: As above -- [ ] `AOpensBNoListen`: Skip `fdc3.addContextListener() above. -- [ ] `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise completes successfully -- [ ] `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. +- `AOpensBWithWrongContext`: As above +- `AOpensBNoListen`: Skip `fdc3.addContextListener() above. +- `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise completes successfully +- `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. @@ -150,18 +150,18 @@ Also we assume a fourth app **D** that is going to discover the intents in the o ### Find Intent From AppD -- [ ] `IntentAppD`: Calls `fdc3.findIntent(‘aTestingIntent’)`. Receives promise containing an appIntent with metadata containing `aTestingIntent` and only **A** app metadata. -- [ ] `WrongIntentAppD`: Calls `fdc3.findIntent(‘nonExistentIntent’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror -- [ ] `IntentAppDRightContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextX’)`. Receives promise containing an appIntent with metadata containing `aTestingIntent` and only **A** app metadata. -- [ ] `IntentAppDWrongContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextY’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror -- [ ] `IntentAppDMultiple1`: Calls `fdc3.findIntent(‘sharedTestingIntent1’)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. -- [ ] `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextX`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. -- [ ] `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. +- `IntentAppD`: Calls `fdc3.findIntent(‘aTestingIntent’)`. Receives promise containing an appIntent with metadata containing `aTestingIntent` and only **A** app metadata. +- `WrongIntentAppD`: Calls `fdc3.findIntent(‘nonExistentIntent’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror +- `IntentAppDRightContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextX’)`. Receives promise containing an appIntent with metadata containing `aTestingIntent` and only **A** app metadata. +- `IntentAppDWrongContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextY’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror +- `IntentAppDMultiple1`: Calls `fdc3.findIntent(‘sharedTestingIntent1’)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. +- `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextX`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. +- `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. ### Find Intents By Context -- [ ] `SingleContext`: Call `fdc3.findIntentsByContext(‘fdc3.testContextX’)`. Should return `aTestingIntent` (app **A**), `sharedTestingIntent` (**A**, **B**) and `cTestingIntent` (**C**) AND nothing else. -- [ ] `NoContext`: Call `fdc3.findIntentsByContext()`. Throws error of some kind? +- `SingleContext`: Call `fdc3.findIntentsByContext(‘fdc3.testContextX’)`. Should return `aTestingIntent` (app **A**), `sharedTestingIntent` (**A**, **B**) and `cTestingIntent` (**C**) AND nothing else. +- `NoContext`: Call `fdc3.findIntentsByContext()`. Throws error of some kind? ### Raise Intent @@ -170,8 +170,8 @@ Also we assume a fourth app **D** that is going to discover the intents in the o | D | Raise | `fdc3.raiseIntent(‘sharedTestingIntent1’, {testContextY})`
starts app B. | | B | Gather Context | `fdc.addIntentListener(‘sharedTestingIntent1’)`
Receives testContextY, matching that sent by D | -- [ ] `SingleResolve1`: Perform above test -- [ ] `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above -- [ ] `TargetedResolve2,3,4` Use the other ways of addressing apps (via ID, metadata) as described at the start of #18 -- [ ] `FailedResolve1-4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive No Apps Available Resolve Error -- [ ] `FailedResolve5-8` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` and variations. You will receive No Apps Available Resolve Error +- `SingleResolve1`: Perform above test +- `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above +- `TargetedResolve2,3,4` Use the other ways of addressing apps (via ID, metadata) as described at the start of #18 +- `FailedResolve1-4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive No Apps Available Resolve Error +- `FailedResolve5-8` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` and variations. You will receive No Apps Available Resolve Error diff --git a/toolbox/fdc3-conformance/README.md b/toolbox/fdc3-conformance/README.md new file mode 100644 index 000000000..aa5109dde --- /dev/null +++ b/toolbox/fdc3-conformance/README.md @@ -0,0 +1,8 @@ +# FDC3 Conformance Testing + +This folder contains test packs (test definitions) for conformance with FDC3 1.2 and 2.0. + +You can find the implementation of these tests in the [FDC3 Conformance Testing](https://github.com/finos/FDC3-Conformance-Testing) project. + +- [FDC3 1.2 Conformance Pack](FDC3-1.2-Conformance-Test-Cases.md) +- FDC3 2.0 Conformance Pack (tbd) diff --git a/website/data/community.json b/website/data/community.json index 15e4af1ce..9a2132d0f 100644 --- a/website/data/community.json +++ b/website/data/community.json @@ -77,6 +77,16 @@ "badges": [], "description": "

When developing an FDC3-compliant app or desktop agent, you need to test. Because FDC3 is about communicating, you need at least one other app to communicate with. You could grab an existing app, but there may not be one available that uses the messaging you need to test.

Many developers end up writing their own helper tool that they discard when their app is done. So many devs have created these throwaway apps that the Finsemble team @ Cosaic decided to build and contribute a workbench (for any FDC3-compliant platform) that helps develop and test your app without writing throwaway code.

" }, + { + "title": "FDC3 Conformance Framework", + "publisher": "FDC3 / FINOS / ScottLogic", + "image": "/img/community/conformance.png", + "infoLink": "https://github.com/finos/FDC3-conformance-framework", + "docsLink": "https://github.com/finos/FDC3/blob/master/toolbox/fdc3-conformance/README.md", + "type": "examples-and-training", + "badges": [], + "description": "

As part of FINOS' commitment to the FDC3 standard, ScottLogic have been engaged to produce a conformance testing framework for desktop agent API compatibility. Delivered as a set of FDC3 Applications, this Conformance pack will test 1.2 and 2.0 compatibility by exercising a desktop agent's implementation of the FDC3 API.

" + }, { "title": "FDC3 eXplained", "publisher": "FDC3 / FINOS", diff --git a/website/static/img/community/conformance.png b/website/static/img/community/conformance.png new file mode 100644 index 0000000000000000000000000000000000000000..643c88139bd5eb2631cad3816aed638dfc44ff27 GIT binary patch literal 135254 zcmaHT2RxPi`~NLjMH(t2p%5)HLq?R05Rytp8D$G098OD92_;(tA){oAQ=V*5X144t zd;4FXa}MeIJpbSGdVR;sx$n=o#`}6-<9_a+Qa{14j&&V|VGPPj$FwkvZW8^6mKy%D zzJMYO{)f&^>6`x5yPnDVisr(Nm?nq-xlX1;X)F1Ov+rpwKEbFkwh z4OfA@((a-!H}H49)zh2XH+|vxCx4e7?Nj#s`#%<1@hEX#-zfhe^xZa^wGX?GJd23P zsI#=mqLtFV*RYT(IM(Pnw#W0a>teRS#-YZHfWV@LHnukR(S>a~I#gJ~c};(3-$rG7 zDdqO|@Wlq%Zw0bBk=x*u@Q;2+H}~*TSFY#u^lpx&c@1Tm)73LHF<6iPmn25~)j`^&E59nQwFS<%-xF|SoqSz6PkqFlD4XA zDxoagL1NOf+kRlmj~lyH0E;ml|EV-;O+Q0=AfjR3 z?cfOyJ)LWd1{?67jp}Fw-{xW$nv17Op6ERwJtJ2;Cs9;Wz+p2+*<tToO zKY93U?@Y_sF?QWzJL#F}0}UBFrZc`WM$j-%QjGs<)Avtvkm%C8*Fe4{USleNTeic# zW6Ey_)>M?l7!j~xu%z2*yS+qTRwVfnBX>O1KRoMjD<5Cu$N|?dIQ&k42G_D@#*dY> zjojS@OJ9!IzWGl~Skq@%B$%=HmAg;L(H5L2=?VP4$>EIb&xr@92xUS8ls)-*KO-1P zKc!1hdtlubl=XcjmvswLvPlxAQ3erQ48B2jBZ1WzzYg#Q>CMg=LC@%P~SI*I}S7jhQ z5OHEYq~vM~qZW379j?|dk{dLtp zqLG>Ez93URXRr>R*q$$g->1dYIi>vgQWe>r>AkX)AIo^0Sx3;dGv<(sW~?dEn>Fy9 zkJ?JQfzif{PmHbm(%&;i+so(+|+vi;!ABUxk{8<|=R z>1c?RT;il6L|-+A=k`7rZQvd@Ufy`ba)|f3Ayel&CM-N3ZoYo&@#|T9#T>r#!`x|1 zWC2gBrTJ#Vi`O*$(>k$fT-YzFY2UnLKDG>Z*Qo@uePH38<;rGpMEl77=8eO`d)q6s z2AL^csiEBr%vHp8n7 zH?oby1P3Um)sAa^+zZM z)J8sAb#!8|ku;k2PVsx5T4eWZRRo{71L9R)XH)^sH*e3mt#gojklVSMynN3(PxVnk zIwP|P2<@IG2kFmp0hz&X7Jdus<8NH7qoF_YT88v@e8OZ&`tV~WLIj+Zy1u}6zJA5T zdd!^tvIQP|;Gznbg#vFn^k7mioaQzW~ zL8hd?OC}-_JcP2~E!i(4qFJUWaOK+B1S59WW-boOEk z&gok_t$cM=$hV|_vvgjkJJA$#eRh$f!jnc%Q_OeAvML2D79Dg#)8NOa(JnV~zyU+K za}JRKz^K3ds~{!~5u%6fILQE4q)It_#us7GSk-fz<%8P2tzvd7;V`3fBrYQ7F;KZM9#qrthxgOrZMn*YodX4O!3~ilm zS!D{x-5S5weCoNjVnWmQY4$Teh2?Ys+FeyN{abhg&yd{!pD3cw)OnL$PJEO}phAk~ zjAnCD=a%dhAB&*$Q2+5Zb_@Wx=^t;LoWOPVWsAoo3;eQ4Yszc-Co2yvn}OWjrYUZL z3TwE#}MdkxFxoX#57L6!M{Z4PfRBDrE}7uYpM*XRRf=&?AiDWfD5zbtFr z0S`EDG3H1KcWQEz)0g=?CsQPDK~|L=gNM3(bnG`z-!n=cP zR|&B0*xhy-m{G`HvZWFjnB!u{ri3u@uW+d}*8}9gLpYS>sOYWRn-Y?c}kH^hYkTEPG0es)-D`GMzqyu*lKEr646)xpjgEE z`H&8EozNw2D!Wj0RKGhb=29UI=8|lMx9rT9iICc`J8c;_D?(S)QcJvnogNvVu%@0f zzQd+if**)DSoU6H4LMH9O~qxTFs2_w2fVSOjvl8LRqVoc@kt7CH`N4caMGx)A3%kCZM_a#bpD>TpMq$CFuNS60rMpS6#DN**1dOKEp^gb6%#!ZPYNz6XmK0)+$Q$~9IrA;Q zlIYI6!O{OBhn@a5Zt~wEG|E&kM_+)yIN2)?M%8__S7c&rj5siL#1?cW8r=ny86W=c)dpMeFh4tSOj)bfrG^^&F3B>O5OVsNNxnY z!DLc|^@PxD#tcg!dR4Ov9-q! z;Fn^`Wic|JV&ukhywK`Qo7P)cp2d98>!_m zM`+2|O)-)|KZjR$Q-&IMbAAz z%(vv9u-xK!9N{v&DA}31>~JG-LrR$YhCG=F?fIc)`AlDP<|d|<75t!a((8Cb=M!sM z9pKENzw(!XX63= zj!7=B3Ub2iBGK_u7I?Gb%N~i!Eb!*&vRO(rT1HAp_`P8w>AdF}n79lOtkz&gEa4x! z_^{4r)jNiVODv%38C_TEYQ@VR!+t3vrjPn~E09Nd<;k81%Qez0)kWu@u&8uoaS& zX?sYv-*JXKFc+DY3MI4du&#j)P7s**>=PmB>eAnf>d$r02w#Yst0x@-lZJc|!vJf3VBw(4U9jVahWgU8uib3(-BR8^ zhc|=#gq2kc50jRS=tk-o$?~$C0F8FJc&nAeO!j89DCCDoe=ob};O(&OZ+}Z?680o1cn&s{{xp zm>kDnlBMd6_{+^WNk=6-L)Yq|QP>?A>J|h7+JE3%|J6II&A>*1d;(PFz#^ib!CoD9 ziO)c#_7`6N1J4!k# zJ`qZGSjE28h*0}_y_$w7(gpwueQo0_@(J8okX{pX|9Du@cgpA6x*eSCeZby}D()@c zA4LkR=hA9Gu)+6>CW_U7rK>pD^D6U`*BntsTFtCjjb8jpjBKmji94vQ}o}`yVm$KAe zCDhNd5J}2^799oD<5k#wlk^|~5BVOJPW_iqP1>hE{oAbsjgU|i{uU~2xYd8T75zrE zf1Kc7LUn(?+N~OPl4NDH5h0f2=|2&Hmxew0KZJ^x0ltD&aQ$`EGwl}tfdCbE(NS}L zfc_`E0}x7%pVr=((D+|M?GZ*EU}$lLdwuyfWORERo{YEF|7EM2$sB3n6{3r+{TqB= zS?z(mPw+5+0f$*y3O|*8XYOL!Qdn*9(!Lqbr4#f-@%G3p8R&E~nqV?_*x*1ic|Fs| zHaw|U#5qQSOU4{juS8*N-7?Mti^N*D(AV~zYjHu=_ek`}brt6ZYwNC&x1r!&he$e$ zph0FhANKO;{v&#&pwX~W=^wYk4%NKvhDg%SCLnx4SdohOEZzV);z%6AEG_+zuCMhD z5?I3U|0vAT@S-}?Uh{*Ij~5QUg-<@~-hcs=%ECA{nFPqr7i?ZRL$ z(^t~Zl+WguAV7cD)~hvJ31Rl`i9v{3_sAZgk1k{Mmrx^yy+!+wGT=@6+DB(ePewE# z{Zqa>2@YKS)!g8nbil0}VSZdQ#H$P12 z{$DYoIyA=22k2iTZh&H|F@uKBmzMhf6=N$k6639lf1MHEBDh+N9%L~FBPSitK#qTU zd-V19lNUBjANwycwz8r{ah8CmAP;c-uXus+e~XbIiYU|Uw?77YHc$Ii1s!lJkUqpX zE^?vh!Xa>^2v2%%leV9iKq8|iLr-^BTm;ZX@d=n_p6KgyB(q503x+Jm!G~<>+SQ=# zmgSvLvi~nZN+JpMn1drp9I=21&QEZXs%`a;I5@ZA= zcpJVM5cJOFhlro}Wt?!83t+aaLTC>T$dbU)K(cW{ExNbsG34xES=ndZ4$?TrfXCT` z;Xd!R6GWIxa!*{|PaXjiAyO%_*|rKJ>(RGdZI9*}J;(ngNcUYx zkaPbd$o72J31q~$c2h4)#Y~bQM^2!v4{9M{^!*YMs0k~fz;zWhzD8sQ)Bqfn9B1aK z(W3jn>^s0in`)w%E4smeH9-7uL0>I0Zco#IW(eM_K%YQkKu=jLU0!XWF8Y_#c;#DPMCFu=HkYDTJfM+!jl$VebTAwe2Ojp&`-H7`ZvoRFVf z7n)LHY)yW&+O=Z zTOHSNP}jtI?zNql29!g__1Vh`9qkQTQ*5#A*=(1d0!^V3uxn zl5`(APsA#6POY{`yWN1O#Q?0^!Vdfil@;5Ogv!PKSR|(3_O*Tt0AV$ygPJ>7WVqF8 zi|kd6m;)?u0N8@GiJS_J?+4>)eZugUYs*1gSmiccq-3|k4Q<_`x!NMf{r}5t#_7?b zy54^*QclC|-)__6iZs)LxZH|Ge%ai^@h`X0hk5{(F7me^aptQ9nN1d?GcXDK4I+aO3J=h=C#xLJ`;47#cYmIAhA_3*+TkfIp!zl6>CtaNY{>;!^ji!+?80iaW9N zHUH)0=}dbnpDq$Y@x;nFO}Eo2$f@sE*`cA`Yt(oM>3&>4`3b#rUx z!nBh##H+@vrBh@#mxQJV=K8%t38hc~&X7Xw#Kfg%7}-MA)?pdzJI(t=LM4LJ+~Lg%ZUpIA%Y)SGyVYH=!O^J{Rbog5sOE78_~bz%E$^lzt$rlesBMV&g3>(wj^>5C0DRpAY5kY5@t2T0!QBF9hOVxlx(5_V zFvlBUpLz`qKP_`hAcT8k3q$Y*dJ*0yqtS>4cyB8&I6CYDhzZ4sJ_vyK;P6hszOo;`vUgyVR*;LJbT9GUA233Eq;_!i8Amw&Lz2`;;uri@ zpV99jHlO(~NeV`wGsgaXMgqrQlKf1PB(*nMGf+slMOqyKUF6s664woi2=BWVKOBZo+??{XOUkFJ?F|y(B{>4iOhgU~DD( z;!q3$Ru4rgsI!E9n#@ABl5Td4G?Y^D1l=djA88DT2BgX*6oeFzJSzCW+kc1#4zZk^ zicfQl2%ewV)_%oW^Wk|U|5E2Ce#^{voC17(`XtHMk$FMv*+|i|K{iLf9D>i(kSr4k ztRo7*9|+N`tf(}D%0$xDRh0MyVJMb>DTA#59SSEsIu2z;Y+At-xhOyj6r$|0iV2j_ z!{y-Z6{aEg1fmqa_29yX9gdCJl2sn8#P(m06PUSQq%~1Qvl{6Pa?&q!aL=e$t~&Nb0`af1fh# zzfQRw(8Z{=DQig(z+`^fNuM60&W8#KXaHf@a(*ti9d2V}#8BJ!v%dKo;7LAf824Hu z!GEC;{vecx2(2uCi}Hr}YEfp9MA-=KeT-V^FV7ia{EtHt7|`aN0Cj&3IZgQ=qO65$ z<8%Ik%JUmBnSy_bGF=fwIUWrW2x@s?UX|Kv(pc+yNOq7Ymo5+6-1=2oF4eMhwwG#M zmQMHDDARyY(Xyg^CrUbRbz^>0Ws@|1T5b_@(^q%bGWb*NBfRGch*+~eea&qds=e#8 zO7niS-`sS6r`TN?5zBk0$McoaRUXv8QpTr-T3y)@u6^-Wc{k6Snfhc*-P_eo286U+;7WU;Hdbul{JkK@plhhe-i%O zUy&Sm;3x)~#WgkCbg&Uu4sL$)WZ%bHbOUc3vlLo-#}3(V$MD>n&fSY$ybw3koT*I8 z$2oSX^-h*&gMhoXPxc1Ljs*^82`scdX`Y(uUrOh-&gYj3+gEVyY`9B1!@3*JvL|Yc zHP_u3bh5OxeC;EIxomQS83xXmk@Z#IJ#IYB!Z2=@%V7%6W|ZsHy~ZOQ%B*gp+zEf@ zO#{2e5QFTJgz}H40z3V=7c3?(Z~4_WSSWwGW#QqlvhSHoakIHg;hsNot*m;67u%wJ z|B-%oXQ6p`UaaLrtNwA*XX}1n$AAERmcit{jP8^zE7Zp@-;n6W1EBHH9FLT=`S))a z9-!?oGan1>**(G?^Yh)~y&5?AbCV|*YHSz1Lasl)ZI~%s{`-Bu`?f{5ZS!-(vNQKR zX3P6scNj)a!JBnkk#^|fCY~(%?7}dk&DLcMv+X$)(vPzl)u-Wc!egQ#ot^n6pP~9tR9I9Iq^@+S zn=PwqYH(O7_$rACD04Oq`HYQ)SAu9x25C<_RsIa}lhkt<#Vrk-s~e_S|8TZV!=t#! z0}kL~O+28L!pmN~)+El5eQ^8!-%NaPXQ7VV*fTBShcmD)e+$347SE@Wm=vD~yWqq` zXZnWzEwnImx8}|%ORv`p8dqC-n^W2C7u~3)2DdPJdgpClc}m| zP0PBtXyIMsiQKo9xx<~ua@a>cYvz0|^5M;K)0RDZwo1#z;C2q2W#lUIVBdV#{juww zoIw5%k@&ET7sEDJyx($d-35;AhNnP2^G7r?=8QSclJxs z`x3v5&3^v!%46Cud^0TtC%>9Rg1cx{_VE`2%Gu&o>>>2M4NEiZcNRzIjvN7WF}k|+ z0J>nlKij8cL0cx}60cfK?%f2GQw7a#eWnxprJW0n))_@4i|!E>YK;5pCO+Qt`9s(4 zi=kN+?{1xVm{Rau`3AOLIZf)cj&@>veEPQGCeEsWHvmm#C%w)4FP^-WXN%B4i}em@ zB#HAT6d$$E>gObaM!-WK>=*Q+#_*x1^&8&0Uw$cHNrCL!$0+3b2K_$k>d>Era;gP? zi`R1a-Z#B~!~l)w_2?{3(gS>76oSd0&vsVO)4QruUA3=iC<1I6+a?du+h{M?`e^8# z*aYi0z@@B`)eUnehstZ-ddmHvM!g87HNyr6L`1R z-FSN^xWR6)z`eUmA~l!rA6cT2EVhmB@0bE}fmPU#oZrvy{RPYF`E)}@BO~}`>z$1w z;5>rc!65MZ&LdaeH%1y5drX^Mz-`AB7uuT_dOkA)7d~ym729}ob9Hstch}MvTWo}r z8IR12!bvf@JdkwgPkd_XFSw>|X46qkJbRA7u8O<0$BD<>fsX0al&h{I04>+>gP>&chFB$1h6BrqLnG;1)n8o##^A1cn*+I;$W_?M~!K2pHeqy>V~2 zFswwPr7qGR=X58E(pQZB?9rg?0*(Ifw@gz+#VbGscRp-LK5ViojQZjQeiJ#699LPZ zp#W;$4ps?@$ayGZE^JfCx?$&m8h4X3?X}eAv>4!teV2rYhxJHPWyEBi5dXT7FF!gC zPFR4eBIBWP>J*+U;tt)Xp`j1OV7XVj5t(3ymqj@Ot3SW~n!n#jIAQWRuc=7}SpWBp z7{2$|wpWs;dvxv;yq00Frsy9F+nqH?oO9IS6S~JoD*?=y#j8Mw_vr{ihGSls&%P=*g zBo~)VB8T)@F*{$BGs$c~;3^L>QwszQuDL(5p8i~3lb-mq;r&$*A4Jw-J|Dr+ReoO9 z1proNqkh+Vxjhp2-xUxe{y5mL$6`(oXmaSGk6nHugT*eF(=PSEh?#%7t z76GF2KC(e$=g01GXyW5<9|ef;VKR%#7vTuh0SD!hUApS71Nifydxxf-&@oUy-M$YS zbu`aKg2>_zwuqZB04Jrs+hUfDCV`qK_P6TlXxr8~QX4r(7P-xTtU2>#)IW=##`jBP z^BJ%~iBI6-oJTjJD9!-H?BSFR^X%=ZzEPZx%MmbXa7YzUDqUn|swU_FtU7-`XLVF; zkSjpmwbU+d)IKJZv#<<_x=2zcjfI8&5J%jZv-j}Wj*w;mBOgv;SXSS4q>Vjj17FLz zw|(`BAP~U|(TRp`QGxI7hw=kn{y=q8_x-PUy)G7d(QexM=58fdfIik89>K81-Z1+#kd4MvE8Hikfq3K~;OBuc zht$?4@(Iu3xh&5m0r}gv>pBe==a1Vsn$+1`aiX`Xj{Gl_|RjaTCvkC_K501tP#_>g#p>`flo*DPqvE=dZ>?xZ9Ap1ziH8RF*`7Xwi4 zJ}}vw`K-yop%TImM6cU1KDTdDu&DjGf zrAK!&{U|Da1&|pMKhsj}X0~+~a^FEHxi&isP~O_Tc8>yt%9!C-8b~i*z{e0s1N%TY zh`-$iJiwY~-qDbz&f1)H$6^$O5`L-?F5qabV=PfeVZPKy2`Oj)<@x%EuHDI!E+6Y& zP+8?8qXw1(TpSiU1rb=`jsbZ8`6n#GnbJ)|6(DLzQx#P}2b>qZ4cV$%M;g4;Oz{%~ z?@cWr=LELMPd#!dyd2E-lB1+A%S(XTS3gyut$YT^NzXScInceu1TN2K=2 zECOF3=K&Ylykf*c=SBk@W6}^8z&QCs;w54P(mm9gWe>+ycg``bmEwitoNQ&E9K>(0 z0uvS&^3XK28T`>cZJ}k5=Q)$R7-!?Tbg<0*Xu)0;wJq)m3D#9_m)JMK7dhOUQQ%gU zf&c*S*9YpG%~@bq$luxg>6-S;x8b3)+TkE0aXiuu?v ze_fB^->80yhw$x}RkhDpk;)3O%1?92)xG`ET$s_NmAGJX_N@SLXK)*NI4YDE9(nwu z-XsjCHwXnN0)KthE_w3MbjV4U+b~Ri{}E6FZ1|9{Xw*#MyNhfap0vkV*qZxFci$ta zl6NyC^8g)NcRsn;{skB*!-m{=;PlKqfP+}&6-%3nVVwMhZLa_YeJ>zV8G2`(8qK3~a11M=_6R0rX|I4*`JO| zDJ&nnDjelz?iNF`prn9t(t#VKID1Z3s(oRgJmZ6+EP$E_uvG9z%*cYI9trk!iEm<~ z!sd95?mnWQ+B_soA$(^RC@>uij{B|wFT-T=3+)oShEGDgdFG!wx4!NXgdj4_2Y~XG z`@aJSKGIH-$za<{8KZ8%#J~ zlmY;#AaEBS;6s618{?z^@u2_<3>^{DcNd==&;|!WDNdNZIAA@7=eY_yF~Lq#7a%)o z9T7jCE|Br!K-J}{Fm?<}MAQ%y_^ds2#;P|J@t%U`=7p@VSnNoMmgYGg1`7OIEy%Ry z6-+h4r$x;MY(V@wrO%$xbD%_F8{Y{Ruz*mwiSzRb$ovL!z?12wcs3#PV}6KMPmF-r z0bEWNH`;KI;T{9Te;`P;Gx-MrDyUgU4Rrw6UoTP+nI}+sU=%a*Nb%Fy8t!R6P%Wgp zAbF$gPyVo>t~exFiB-CBy|Oc5VHF=sh{2(<&gGPTnIWoafIT@W0|Hg17z#UT3qshP z&1_)FK;zp-3X&ImGwTzJUsR?%y#g3YH^Ebcn{r=@1cxw*s3chd~wWM1`o46v7nZu4*V*`)=Z_V{L8H&WEuOie?vvdqzjZ>k8N4 z+0Q_lP%*B?l1di}5oC@^kvOR`*1$>7u=dS$?$aUpo7*nnl1H-FiK1+nE`+ zu5k@BCEvxS+y$P6{*NNKS?%ys&!zn~Mtp|om+_!Q#OfEty9tSzfr-h(IV#!|m@-k^ z4gY8lJ&$gThy1l(>LBX}iT9AgK{#t}F8~hj6NM4Pq#(V>vGpt~CW@IJJS7R)h9zyE zGxY5x0oZ)#buYngW#ig7|tZoH=t ziXfvlJ^~`_N^du|JcO*i8p1r-GlV~6=P%_Gzll42@2N!?^j3g$j6;VWK&6!Ze+B4nyqo8IR14$szrc-T+o<|L161yhGH^*ACiS}_sY^1XSdC0kDTmq)Xtku}8W%DbkPBNn)!C82v4hrN94{+t6DJ=(^zv?e z2D#&b8Xz-eAW@~w!#E#XY2E|U3;h-2b4!hoeJuujG$a-(qh%-POn(Yj*EGseFvzEu zvr1;>F4`pi?gRVBSsEQP{%l_2Wp*ZD*wS$(M{$92*lWJ-GA@T}NymG(kICzUJK;0A=CQ@fd)!tk3I8w&B z8O#O~j4Al76JPKO0+dJ}$0;{eKd{4(&Yr3E>s1^Fj)em66)*Y2I$z@c(Utopuj>e2%-3X>sFu! zY@=fw1-d}2xZS>O5(~x78h~j+$V9YCKgYI^byYO(M)dzE1aGn@^jVbi@$jgzoI7~a zBkK*|FGN(PFD8I^s4F3#jhq8r8?y2Pce?osPt;dH8mrUxn-8i0z~TLmX-uAfT)pw5 ziU|s>N*j=-1@8f@K{zo#I{WylpR(gUu*n#Gu4xY0Xo5 z1=ZNH%U$=+hDC&{Wl-@ziLGN1heB(y+q}pf!TV4~flz*w%Rmcm2q%NWgo9+uJ`bBI z{c(QNaD7IC>l8(%ww$ilmHGp7KJ(7_G#I` zoGW&v&XLM$c%deJDcHY_=ZI91Ov}0H4w>u1>Y4@xX7fca3?5R?gZ61Bcmz?b<3?pE zjQbubr}WLLvMgN_W^)*79#uq+c9Q=vixvcTz$p3#lW$kqYk)UFWM@WSD&uuOWV$cm zxMUS&ZNfpq^uh1&gWta|T)SS}#Po|wr&et5(y5=7egkxcR{Pdd&x6OaG=&gKH}?UQ zA4jgpf)u30xy%;m_x@M5iRV8eg^T#&P@KfjMJiog0s5I^0@R<7dQLxQ$zNBB`J&Tp<D<1My%3LU-Om;!O4H6AoYfL*nm{68JdvNxo#G%N_+9hu8 z2e(b4PH`j(WB6)>@tiln9#E+Ttgz%oSqGvWQJz6ecnO{_0b7T(5+QkEWf_X(0t=`U z1xp4;Gl}{Aq+t+2S=Pwbbx%cpjEBl_n7TZM{tHeYLq7A@TUG1Us z=(yTRqFZ_pwZ0j&j!Ivf==V0+lzLA?dX!l&3@ov&1gb75@rR@n+?+_QfgV0M(A1^M z1NY{BT$aA3R$w30Qy`ALEl^DtW)rmHpcdc->p3`)s&$VMdU?g*6YsO=1}|^X_O(7@ zYr?e`GL>Cb0WXmGIlX#(3W|$AP)_J$vbw!UOm`m(K-T0Bl!BD!7QSHU6oGzX4FE8? zDu!*Y@`5u6znbDHTig89Uy*CGW~|x`S@u^OIDSEf1z7>HY2o|X>;kE1r5r>P`^nSp z44~ckL5e`0ssIS~zz0N_Fe7uKKu|dk9Cks&e4w`FWU7JW%P5`|;b&kU> zA5oeFxhN{R0>o*Y7$0g1FOyzaZ`UPJ1XkTq6^=bIJfV^%~F`t%v)Lt*WZaHFFBu1#<1MJj5Kvp2Vc zGWslXi?5vCa{WV#s|pw`PiYWP0~YU~2qHgMCkBb9z~E2?JY#*CR&1G%Xyd1A!u)le-D%J}x~w{4wMR8(GXq?VfM6u4?X z>n7-0+ZbMUqd&m3T;kGnUKI$0b%L?NckMBNKWq$DTkv$NVtew>d6NtOG%x&w7z~A* zM4rPeD62*AD|MZdlp;gF398W;_M#rzSr9VqTw6{Yh8PZ1neX-up=8F9q-t&GKtjot z`I99DfCMV^&L|qI$L@f%MSoD&{MZ^HNDw}3tcIPCOHOYj3gJDu<_8ww6TWmfCl+k( zr^92u!z{13FawqUZy-O+fXY|Tzx3ibtf9d2W3Z8fdAAy_Y0&?u#?G4#TXW6p7K9!p zy#$U1#qFU!4e$NOCOT^lUfpH#>yYZ(a-Dfz<9{e12_~LG0;*3?zk5q;F?55~#*Vmv zdd;T`X|bZ0|5r5@&m%4I3F;ZB8OAXZDih9Jlr@)K@T5q4DAk=Ez)z=5;`qk=SHKrD zEI(Vy>)w9|Fo4w%Bk@C26@bnXa1Npc+$NR=^S7_TWT3!m2&4pptx2h0>;FdL3NN5Z z2)8bNni}!X>O6QLYGW3EbriVMbAh~a#aH&OLC*%yjLbR?*3#-0g|t(1`NBIg1Zy>vtr z_!q>+b?;Td_s`}~1NQ*n-z|@G`E~hof2iHtinz#;9j5AnNZU!RM z0DQkbw;}eE_LK&E`IEu#??O0AY}xr}8au~X^q~r3XD%nQHG@Vk@ChgPdE*bDwo{M$ z1@F{d1cQ5?;~|fmJ`5lWP-ju-IgzrY2l3zK6Ax$d?O6Z<6-2!Phzfs8O7KzZQY(mJ zU)`xIk`YjIgoNM~7rqFNiJE-Ny(LnHk2-^>=7QH1?Bl3-DKBux$MO0!n~<68SJZt< z9q;YCJv;JC?6j_1SIW&=@bsZ(Mx{)B#{P$)W^otQ7F=pk9cEP-()oMzqy4q1 zNA%ZmzK13gDwXIDvH)}UddCGp4O)8O^gI)0h?DxzqI3rWb4l&zz;2(Z=|ct^rFN-N z;%acT{(hAsd%=nl$A9h!q2H9PB1hD>7}9qu4$4{3@`cp!bY|0wvYRXQ<5z|9{!tk3 zDNr}5M@VdRK-CKrqc{5oIvJQz7DQs&DP`7NF}}!pm!np~&gSn;If{REh-434c2IoY ze`o5n@mFHPibK}k?tPIp-bH@ZsNCoKPtL$QC6v0=K!|g7akk<%YBd7?Alj_f2 z*6X4h*r7k82h&2&*?%IJW4LuvHudJ$yoUL9hlsl z4w&w2hNm{@5uBYzh0}~~LfRp<>kW`1=s=!?_Mf%&SEy5@LT7d#*cB}dvW&PR&?T&Q z=#qf$p%*mJ#0Kcb$r=4t*8{S@Xp}?{)dRW(aU5{!bTC}429OdmXkx#LfR*Qup09=? zR=zZo`7WJjxt2x!GWv6(`7bZswR#IxdjNppML)=qfX@2!-he{hRCdcV=(R#SVj(A@ zWv3pm0BBtXPxOvRwqfXUBKc`qd%bIeDH?F*99!Xa_(Ra9M2$rhP)pxNh-9dK0>)Gc z4LzdKFqihV4kn8T-&fk110PyVlqN%VL%msO;MfglmqXe&_23Y z(2@9e#k-CI6#1`I`5n+cqWHPfHJ7BIGMdtO&B3B2?rOj`y`i@FUBi05Vpn90uBtwi zjiN384$TXQBS8E6V9bR@_$V!gZ#sceVXHZYNmBgvVt>j34b!Dlfu!Z8c6iW4vguT0{U}OQB^c7G!g9M5eW*JH! zBRi|x1i5rjuJFWoS3MSdb#*T_5h%}c+B^4w1i^noFDHw2et4LQ*@2MyDSIeR9Jp34 z4#QH2%si zLLU+zNZdCoY9+WfM+En;RL>Q|9#G3%f&L%RsR{jY<>0FdHLWm|0qG}{Ac$7<;*?tn zhu+Y!g<|8KtV@SH8uYKkxDD@N{6RsWvC7{XLa%wZ)-EPZ2eP0%URnw)sR`u}czsl0 zhi(vrVIs1^>S#6u9G-Pe36L37TZQ}*aVaXj%%+#5eAd3}Y7i2xkpbK2;^%X!`o957 z_^TEBWmRI!v>2UJW^;~~Q@FpmKivF=HnAwM`;=9$So9RMdC`b1{Hw{jW+CN(eCXnC zbKp;CdIu_}o$BkcF#dn_V@VSTXf_2iLbUvVvu{qVwtTznO_)ghE>!CZCAo`?RTN4a zWM><4qiGvDv~1&eZ|Z{P&`2t&P%h{Xu#5V|u^;(f(sw(`D52D30h(-vt+K zKqZjru5g%UdvOV-<~AcR^4SQHkUS48WcJ!^bu_(U4i#%eT)~|Gqd$wCeV(E?Dmk{J z_-be6BqJ0Pi~=hg`pZ*_U(obp+@xL2q(lW5k7?ZO#vB-O$GYUQ-y@9RV{l82&3vgQQjEU1Jcn{XWjfH$Ne8_Lt-> zKQ5S}@$;f|;R;yVFSp5w@aq#B6mp_ruICM!q{FyFE^AbvJ|Pqd+rmi!5Gq#JxyPDUu~iSrJ!GfagrR7ZWwGRb!R@L z7%D2lMpSH&eqI?~v{Ln^l^=y_E}DgeEDuN&>j$sDgBf;2_sVRPsd|a+!fV+#Z5n9c zIF%=1EO=2fh@my|$m2wz<7RiEkp>lm7xECbb`tL}&>e_vpl z?lv)OaBp477h&kiSYClx-<6028HI%$`|=hle9%XFX?{y=LCYGI?&?+QHXD8e)nRo8 z!1GFu9MhfdH%xNRW%T%Le!sutqYReVXXApBnv%Sh3Q+1Du#WvGI&$)p%C+yHf6HHO zMp!4tM2b_8^qAAqgXVNeT|qQN#i@qsb;D>NBml;9fcBfl>u*1BH5B?2sqTp_vkT$} zuI7F-$6*FKM7?DZ0=p~Hvd;5FYSP2R7BOP@)~~c|MG;|K6{U=7(O3ke3Q*U-Xvkz@ z#(|pJ%f(r&HRW7ql}yQ#cD0mVC=ON{@H)kj9uf>_m4Vrc;3r|^@)2v69?aT8^B?t65WT_%3UMi0)d!PD4;xH<7YJHpjo*BVDk(2_%j-w& zO{n~~c{fZu-uEJ6b13iDOTvi1(?tA6KnT+_ZbGT zfF3N@)(MY4$nzCvw!2iqL`HR$F7vs2tWIBKFh5)v3{5j#4Db|pd&2P=pyM_XI$qTL zS3Va21qX9l19BM^Lc<}e+ZwAPkHi(!F2=K8ex^P5?(k!A;W>w>-2AAej&?PABR#<% zZc|X@^VhOwT7&rr5+$b%I&!=$hHA0M(v@Le5b8fYr(Wtlr4ln9xddVJ-xT)>R4suoaZWKo-G+3qoz)>22KrE($QHwcpU7U9@#lz z^GZ$BxNeIxlyZ>|K^E|Rqx+kcy6At-|6pFUYAqrQqOQeFP>BC{+OTY=*^!ny9_#$; zl$3R1X}O*Oy9Pc$uvZ_1A}eV(tv|8F_XqviHtfh;uoz;79t5dlRJ*|sX4)O5uO z*(0OF=u=)oN>OPT**_MZqOPiK9VNR-#_=H_g;io9qvx?r^n@6IiDT~rVE7x`2f6Fp zLI{28wH{?JG^2^hS1*7WF1ozntv0dX;hCW0Y|G-zdK}aQi5Bu3A}8Uz_=qYxJS52Y zQsmdA&lPi@oBaJOhc+6Ua9Nb@+=6NAJvr_?PVpOta-IU)I|NMR`}-w7?Xwh^7aH@# z_LqQXL%=~}198J_=izZ218Le5QkcFOKQox^63Le*w@n|hWbA_il7r!*FM@q~bXmG? zn12Le#Bg|7TH3hS+h9fjd z@J+z5(I*&a2rs9S2ilR)kqVOR=q`1DsYa}f24jAJfPz3{Q*)U(tnvy1phC^aUxiP8 z-i<4>M9{Q_=`$#RlcrT}JuOG#@GbO$R(as;x+m_xBYLx5_|2WuHf-tK*Pg9Iakdy_ zfiQd65ejSnd}NH>zBs%6iWn#Wp)MwKd!;#PT&EO5EOw#^mPpflwilW!GwZ7wlPlR4 zXYcKk9v0zShpHE+vM<1n@ouuM-s=b-pe_jR@&l9?wZ7dmGAD?d5~DwkC{C*caBAQI{p!KK3nwcTaXv6Cox88oC(E4n;fLvVxg4{B*ap+x(FhKIVC8f-O%p|8)h{NH{U*L8OcYAbt3J<14Hk2(8ell*` zcKy~G!rgQjFMtm!&e#e0SJi5cb3Cp%iQz92(Kwr%G_(w{@Q~H%Z&2=ph828F^22AX zUCw(|{<#6@yK`GJC*2f*ZrcuS2In^!?>+?pZMS$S|8HTY} zo{1|4!r_wZF(qPk2If0}1i}2$bLb6`idn=@oPMgw`toW1pOs4NMXlM97zGNBg3^~1 z!r_Y39ikbZ=eA&BmI^R}sn*xhZYGP{hWVtEu7rx#kh7xH+<03Oi!Ss=0e$JRB+wUB z&}~CsYY@j-tW=bh=PH(Ua4nd1*)r-1Ch=#&_0ci)G$}~*QSIs55wYh;uP<6k zJ+rL)`h_j85K5yr1ucluVGVmS@^IhEJs)pdgVCeGZ_G%_W?*awO4^SJUa3=@C-nx= z>^&f^iyA~M#Cu>Q0R~_J(ax#1WkerM_wF_*AVCkM<)tukvwl0Y?*QF<=Y`%RDM*H-}fHA zbtH3n769V*=c0-PLp`W(AZsBK{((1W{0JC3OnDN5(Z2~D-wA_<;u90NU*6&;oz;MS z@p`H)-V^7=vLBVDXM5U-^*#?ZEq?x%pb;w|{ z-v9(x)!^UkSqY@R_0JSPI>?St%fI=@$6K`%?teb0%+5eMJ6mtl)Xv&gxScU*D9EGN z+p%)8zvyrgL$g0N;tQAv6T!M#@qsk)6qq9V900y3ML7Uza36Vn93+M;=MvbZI={X3 z8*rL6`LdG2g*|3$#*qg1(KjwoqHaEg_S|pVmKbo-%{n(|;asIYF_1+K)*9aFzOJx_ zu&-}!(i#1`_63LqL&AnX#mh5L+P149joL!nzQL)uDY-TH>7Jj`Qh|cIOH$&ar_fvi zxtQs24hC=GVtO@B*LtubulnERFbOQzi8>49+xGwsTEt`v?RmVDC2Q2Ees+ff> z2WCY4;1F{vLLX@9(e=YbBxD7Jtnifz*n^>4B{xJb7yxO%Y0Ck@2zH&W-yKME^Z^~etrF(Kup}y?x(T{<%*5E? z^b>u^&=Lq!8zeQ8r)v%QX;C=}IyaEj@t!pm2fdD~y!^VVZkhQfjM^e@giZ4W|F)KX z&o0%U<}oG?a_>K6a2FfN41fK(Xd|RQtrA4bXGR$c@f#yu|8_~MLRN(Q#8IE8+neQL zAk~8IqG_qQlYkivmMYw7-aeZQok-xNFmZDQynw4;Elmnd;y|w7QED6lB`Uaa$nfIV zsnRUN5eVY_t|wi?Rbf0jwcsCTTi&wsWs_2@m=EzACyW_N6E(o2h>+X(4V<0yjlgI| z^v=_@VyuT>O?E=(RvU_H#94>LH}t4=|&G zg{koQe?HbuE+sqXe%5K3`qV1RB#Y-8{CK0VH}yVG{XeN2y}3`UHM@CW_`&)^8TYo< zTDBWl)t%3zt^a4}?8%peP^yD{m|v^aOfsLoNh7rb?z{bIy+iGlqMk=YQ`Vh0@avx( z<^7w|g3l_dck@1&;5<1=vF-g9!um*(@X@TgcJ(B(+BWcUtf3 z-_N{E-+PqB)>XQ4b|%@WgbqMhp32T%$zyXG5bAhpQBs%bMN=J|M+}fH~Xx;)-$}H z_w!!s>~p#-=Y8|@*uml~mxu@7?MnQ(nWN10lkV*%gsEIqiMdwep)$0(^qs%kT=JH2 zB4k=cam{p5X1gsBWA8ZW7P$rM;M9gwLkRl*FH!by-{dPvu6>H46>hdSRlr z9Hp^g7wD^Yo-eI!JHb5I_;UO#4CxbaPWHro>wQ(capa41*j80&=9?D7SJ{sF`2-Cmq%YP=KB#VM{8 z(eZulZa(6AhxrAOlknQ6vmoM@Z@U-Kv^(~wtYL%L#O?b8~8hv`ty>US`PjJuNy(e-=kG%q>erpm!BfOFx~fsD$D-A=V zuF9KPsIxp_eXKIEZ@nRn!Xa+&R;NNbV;z^b7J-oAd{N?>-Haq`T+U%Ctm@I+-Qnh3 z#q7}yF@bH5gd(TPBwQMAQt|a7`)!R%i#lABH+OQVZQeITHQ|~dCz#Ms`K9NC#f@xL zP;~WnEjD*3-@%AkFn4Rk!iB^ZJBJ{85^Bbb;xVw^ii(m%&F4=ZaZ~4@z1z z{G8K(X>&u#cZ~@Duk!;%wBF|0u#Dqjb4F;{@4)zkRehW?tetaU^y%SNhFp^P4p$v! zI+gC=II506QBHGQKw*KbbbRXl!ITL0fI+_K*M|kon|6Yg_6{&KY=8tI@c&>gTvFMK zb-!Zfp4z1K@s)HoFI#0|;&^ZR$W^h9x9jw@(P;F9oI7tUdp|Q8Kn{5pY&Mow;Pkt) zi3^1Y#1JREq5$KIfgtBuL)fLhOe_*oA7IXi(w9TI;90VdI#y%kmyV@~kJ{CSPi)2bcu;U`IQP?v zL7e678+<)NE@*FM&b;OepMm^p_!D)iP}lzonrjO zuF5VGmm{O%Q%i+cNhdHqbF>P~tp&$wnX9vh{|m7iMr*IZ}NqPS4Rv~Ep_&tNX_C%IpY%V_gYIA zW70sD>29UHE%Pb3z&>RH(RRYENAp@eD6~-yA@4&F2}kz7bm~3Tc;9#;qn?q@aweNy zXA@Q$1b~3?_hiO03=IWszk(2tAUgRYp5;upcI$F|*LAAW4^S{r`n1u1z{do{Mj#5{ z(S11rc@tTBu~x@_X;H#niZZ3*6t~M(HSeq^Ibnb0P!@tGUrr%uonZO?|0~hSMP~{-!*n~IY#-s3JvmMjJU8x=sD0&BQ#7}0(Y`|O(1p^@;3wWud5%hGzOK^^ zOl8?E|S66)?(+}OWK7*BA-`o%nR{b2w_3>s_i}X+%NNo1d5zAX^Wft z+CA;sW>qFH>lO|)&a}4AN-J=2drE}3I_c5G@I^Nkv3eQ597OKqhJLHVVSlt`^IkoyE`f+&qfs`-TN zUMygnE28z%($#a$SESyHq-MS7a3etc1f;m8_p^J34~w+B)lv1m8c%D!gU!w@ov-yg zno`hVd`nwBMub`HQYFJ-Q0)(6~!$~LBd ze%axSG|h%pgfLY2C8hK17T>+-y!Dv$?H+^34K#6euprdf$0OI+`sQZp{e`v5kIK7f z*B0h}3YT3&C0T=>)A3*~XO^1ZxMDIF(WTWeSJpo8#F^q@clYg4EkE$k zD`+muC}WB$z!YU})@3-RC?`$7&$VWGk(TB97nq^L%eW9gx2MB_N`K^qcKCO)0ozV)P^Q(rjCKHCfwg?i=e zVwVmWI2fk0W^uxgh?Ji~4ss?oET=(1voz>y&g)g)4F_-}Bj!Ibjw*I*hicmHH+mE? zH0bHFuC87i|@YwC^>xQdodBn)(a@P{Mx5fBE43^!LDyfFg7Tpp4Q~ zId?wL^QPs5r@xyv*!iobT}jvbQ0liSGtbK!)>9F}UVy2A3VhA5Q8}`he0h^V{Bhgi zF?SI#w{vi}>Dk=n_yhdu&ZL&?;s`Z|rePiFay5|*H?is0d$z0zK5TK#?`GReR;*kO zkGAvkx}%;RQN`8imPOkHPk;qER*0#D>%zn0>hZ3~g3vG4Ig3XN`%c}?6JS#G)m0f` zXJdo({maxvehb!p7&mJoFb3OEmm_rPh!i0ZN59{|L0q2n)Y>MZ^&q2V(?W-{LG9I3 zMO%5L{roEnN+o& zb&HBD0wmFqDK}-TashLDMM-kIzN*-shjojhX(XGpx0yL;jUYmWh|gX$htm&)(hel) z1$3KTuxp!^<7My8fBWT?tqmB1;ndA0VDVpRM;O;&!paENX@mTG#G_#>Lbu%bqt^;{ z;~8u7U6#U&BN~lkf*kkm-3v}RMA{ypU?=!wXCb^ob^I1W+eVJaN*8&E5Ue7woBJvX z-QxE*7J43filt;PSGDS#J{=0dGqWBXPK~WYJBER1^La0NzlPB zt3;+Q-MkkBM;EcJ1J>J*ZWYlYNlbB=$3)WX&pe(QrSHkOb!%^TDm%Yn?}D`X*`BDm zlJF3Y1Xee)Lk=N!URH6Lk7FjJXpLQ4=AVdsX*CL%{1Qjkq7F2>5}IZ?=G zHi?i;zzIt_*M&wcc06MmP26bIdX(38_{%P+JDb;G$#vH4j)$Ok;a-nfwZG_;4nF+g z!Y$^0vEY8$wDB4dwxloXJguJ<@-loDgPOh2hq$!lR=v{d*^hNLCn3IeYy4P+T`$@! zmM%i6#+I}5u|J!FWb~D^fa^U+&6OveD_Rx=L;AV6N0;6m=H1WHpm*&;?ulNW3!Gk} zvGwaD#nlkr#6XUfJl4?lD2lIlqArYrQ#@yY4xyTd=B2eES<$wY77 z90-AOCzPl@afnt-R*%dyX&HB=9%%3>Zw#}k&6}Cc&HqvP(Uuv-$_7-@<6a&-Gvs_A zSLuLl21~)BZB*p@gz@h>XAiD-Pc?Kp6Zoh-yq~M|A?xS+egh7q1Cw4(*alw|zt4LO zS>}`IW>2tib8bb6N0pdM8j-Fgg^w1(WF2erBKp&vW}cP6Sga5Or_`?~q70JR{Ix#q zDDocT-281SNjAid(Iw3Ny(eDUV*AbkZD{kD0E+#=iDZsV1pR>P%lxJ~V#ByKAWMr+2yHe#d4 z|F_epNu^R7N+}TzqX1vYq?qiF>NBy(V(|LxR8@h7m zmLSvcI#Su~is;n5)Qh{GUsE2u8FC`&1b_&w#^|bm%gAAHNh&?Lp#7lV)SjJfuBPD8 zjP>E$it_2=y5H|mv)!G0o@5hztNmcb4P!%FMVDg&;wEQUFlt0B(N!*YW^m-pq%$xG z>1Wq=<{US*T5O6;o_x2eaID}~J7gPMUD9paqkzI8xq4U6sW%i?7|O0$CHZ!RW?G$9 zadzk#msYm#zi#|Ctk>JkPW0o%XYQA%_0ZAkaEB=@b}S(?Gzm0H_lsq7iSKQY|6p;uIy6sEY~BiGLNM~lzf;|@co4<{sgL#!G?q2zYe zfRVT+sU&{}!C&e{?4A+45YIQ;-W{@;3>OQU*}-cba(H}vm4?8FP+!1A74?hTkg`!0 zDzvdj3}C&~=kbK0%BAp=EZA)nn{WjfA{_vjfMmTYsArpNuWAeBVr6wc;Sv)_E#`x!JU+??s z&^@|U!tj%j;;QF8i~9CeFbg9VB}V`WmQt0TWYvPT)QEL6?QX# zE{QH-Lsd&>v*w&)|E4;doDRQ?!RC|$uBE6;zf`5Map1`nz3!=SvF#{f=HD)Ute*)w z_}EqUT#&NASM8&+If2A+^9YbtHcQxXETzsXOolmJ@`QJR-d|bv(MQ~iw4RYaI@P`1 zsqHc#$JiisA)7oSCfXYtq_q+aSol=ewrfm!qnZZL<0)b>f7#hc^C~KwOL}v|!V~!d zVE?{?Db-zWvzHM!=$~&3^>W6pyRW#pg)ja%v;mK1_&5I8*`_~V=y32yNdYJ}r<&`Q z74K6s3BZ%1Vhee}l+yEWbr)s>Kc#ti#N|!+d3a=jn8wD|*`+4Iz_s&{&zJVX*eS_8 zsG0V_rcNnOPtAO5wkV^mp)Hmi%|2M%c>?ocSjn>k^zSkXJl^HqwfmB)v7E}<`!Xez z1@g-&{wBYG^Co-883~bQ-bD*VU;l#9$irU1%q~qdE@r-sECum^YBiAwVLG}>b#Go9 zuM3D4?653*Sk|8_ zW-yHUklgY9hB4@`x80Yw;HwfCMXN%q|9RVUa}Wzb8O(obq_fz^y?JS8nCP_C<(!Ru zIh{y&fo575jhnFI3YGKp_cS99$9W!YZ8~kY$8xgqGG9S~sjie_o@rSxC?B2uR3KcU z78YGHpG&!yg`sjW)K`ZtcP{&QNZoVu{Ti`kK`meby2(OMug&H?5M6jP0w2(;r|{*3 zj$U)+{Eo4dva@bL0=gsf9@6rM(`{Txp3m zj&o-dI*i1D9{{)n7a3P89_CRwOpTRWuEelMC}=dsI^5MsHg{~3hEDJ3e_tB&D4bfz z4s`%f*QoTWL2Bkg4Lp)xfro<@#wxpFUUn0(+l}208LY;Uxq9(tE<)cb8ZvH$W+U3~ z=HgvstPrSC>xmQ~5Toem=BLfoMnKC|S((6kPOoJ4S{+Vb`UgOqq5TtGC8YmUh#5eZ zzNH0VgcOj7T|f6JXVYS=nJZz;-eC}L0dm-_u(phX`*n3TQLLHMr=*cM3>sL^ zUOnkTAzsr9J7B`|AKX-b`>as>t1~WibhJWCSHCm}Sv9u{*k?*c&TNqe+%HDzs1@bAZ+rMe;XSAUM`TfTp zOwVT}JT#7h01Rz~-<)8a^AWqZpFm$Z;K3gVJRh*8!}#c=r@QhE=Ll z?+>nQKz4kNT2?%GUO*K<&B3L7rya>1yWLRFf28%IR9;_oB5!fp-Jn~iv$VOjxRCF7 zD86GwwP+;2-GedGO_M43+lDr6ekLv!tpj&SO(3bENq8LGDzgen6e#$NtH=+Pr950lk|N&}W~Tj3)ZmJ$?=WBdD)kQsnEllfRzVV^^Afm#xP55-zbW%V@xM z0s{GJ*%%$%E}Dq-BDvx4rxx+V=aZ8M#&3&uZUj5E3nr z_I{C6y-g+pMcZh`C7P@8p?m`e3&>u-xSZkT2Dp^K8l6xMX`0sH{i< zMbBmPTJzwj7uq&B4#ojV=|R?av=;LfYj9M&==9b&VU$BZXa1pu`pomup+i#Lo(1W# zxX2}5>|HCd8<5Edmi&id*rkO%F2@ij>=#BxHTR>KghLWK)=ua_i)-7573+ii49y%2 ztzU>VQ{OiRyLg?G)!f1YN}d^PMfxKr2dcKSmv+rhemj@&v_KX`V9Rkz1eU9zO*arb zx^Bd9L7J8|W+ZK^RQzdTot-`eIg+~E&I$OeQFiBe4%mRa`#EyakP(XYF~}sF&76j=YqNP zb zCGYsw?q>)tM*HEMqj~JEBs+1sI{7n!Go_CW)>J5u3L)D;kJreb$rO`r`L+`OoefqJg**3mf=o3oB7OTM< zTJSEVWJxj-5tyeTk!6ePZn35uoZ9Xek-RN+=4}j)pgsX4iyu(dx`5&5XI6~9IsMfp zAEK_atyaCHRX5~H(ZInAZC_r3jP%nI&_)k%iJ~rlynUuW+Sl4A3_1ha?i|$D%-EH6 z-KcHKJ3OZdTdb8LqaGlocYTw1nQ3N2KMXa@EGc)*FJ_gLg2A-Sl9WsO5))x(ZmYge z6yTzGfF))7VR<}7!lyb@*ZU?*m_O413#nEZ1b?K~2g^HWy7iJonGOGfa`KnSf)^_~ zLrF=*0DF0tJLY4m_fOw69m-q&+D2*yC8o`xPxj+O7cr1%+g-WY*p|%3Vuf4;1_M9o zUTd0%!?8O+;PGl-3|B6G{prDs`}a)U=?OktSCs)~`n4GG-bx+Xsu=I@>qpTzB!J z#!J6+V8@pxBtqeogG8juqQ=q!w0kix9vg!Uh9OzDEWi}MG)bG5k=c-0I(kokv277EWEcbb0#2*@+cO40V^LjU6CoUchuDc~M^`pf=+E5wsd%Bs0lF z)f7^q6tHq9=+*!iKAvU!=6Hzow%kp^+_ZHcd_^x5>Fnt0egpD|JVy(Ck2uo~ZxkJDJg>U@sy=a32*0)KYnB#X7>N!ErT9qUh!>hn-(u>2 zqwjlvMe_s#ync1E3hccg2?Qb+_Oh9zGClCmVC4tU4B@1Q2NV6;=X!jgIB%t+1G?<7 zIvI(C6gbg`#()p~G#^}qJiff`2}w2@2dDUR)}qxxcpu)7b?e*vc(nTGE8MHxp@@2` zhS-ruNRNYhKuuM68OW-4DEGZNIEKI{j}D`ttNV5K#z!(a>6f<7S{6mSxs%!-r3(jiNc z>Pa)nsd}Fo6l|m_0uN-R*`NeIhL5(|z|NE5>6Ni}6lu-znBU$>zh2k~jKSgy8lLB^ zTdDC^j1MO`9Yh*9yg7^p-vWf0voa!i5xR|&&-}F;U9Y=U+dmhY9$hp63HXoOx7~DY zcb~wB_OB?zGif04i91utEk!h{Ue*-}N)Tsu0=%Aq-)l-ivqT2$TA2+KBk1VWA;J<6 zSi@ej0d}yZ}^}FKeJG|bZPQN_?Gq5<=h2m z#J|C1Osc4P9>g;an$lLFfc*Ma@#r203Q%KNS2ws^7jXXwt^g39{8FE$w#z3QIzm*B zm>ZJ)mO*q)YGAmE^dfq2EK17H7GX%)t}fGk5+?n1c%QEb!7?N{f7XOZO&hiSU}8Q}17moi5Ol#_<8Gfc>meI91_4nHmfN%#DM$ zB_np==jA>&%$=)m6XIQ(kr3Mo8c&ZZCirH^XL;UYvkcG%z`BF16!!(31uGXnD+<3q zJ8cSL&-V2k@AQCHvcn|NhM?QL?y?JPEXp7L;~_k*(Qeo~RxRA}S)np3oFZAt$*l%Z zDeZrZ`jvf;NdIUz{pM8=?SrJ)L1~Cuk4?;(val;~fn@Bq75cGT6%(UfB3hAY7q?>= z#Q^29MH++CmvuAm({6wbM*wl8M#=)^HTcN5dR#zJ?Ys&I+V^~iCi_SvOSI=V_HV*kzof7GSHrU8%H z_`G(B&&+sb4@furBUL6rLpa`Kb3$q9&(aumDDK|)s6?BcGjC_nZUdXqEa zQK73)YT%<4<<9d0(Pq$Jc#$771yj3WoV$y_+yLq8SPTFJJvrm|ngVF2%Mb(ru|C)4 zAltHd=i-lO-ZsWRY=ZtJ!IY{$Jm4W$g3i>)^n}|L zk1o|5FwndzXRyHyg)KVf0eeh&H{RzYex|~hXemJrzir7p;D57i>2%@fK+`5u4O!`8 zP|jzj{1yD#3x_j)is!U3?Ry|U%7)o#bwioye${m#^r_PlvC0NN2$n12biqe z#q4+hJz$@2+gfals!Uh>5IVFbDhOG6(*uswaI&#|3Lg%hjl~bKu*^JEb{ly3<6~45 z^O94c(}?!MOzh~=Cu5ZcIO2i8j1Ruk9pRNw`Q$>w*lBdij1`kab!WNE?-I%`CdhG5 zA*R)%&C`r@h2!m1*wYV-Pu62hEbboxhs?8W9O3puo3Vpuq42{7BM!gl3@Tjqh#7Vb zfGN>F48lS<;Uo$BtAM)vAh%pNr(yTq5w;uA#RJA?J%GaelnpInBkaK0vxbvfaA7^TtGLH8^MT;*TY;4Ra*Z<(g89DT#W!Y zgs{fHE6h9a0Tkw5R7b%6&}pKVR)J>*;dG2-1d|UiCxsC0oq(?l>#*)PAcF?5YxyNL zf8XD86@ofRSU6J8g0`{9TclO1F)L|chv}vRB@u7eG z;H(tESbNf&<`4fRpf|a`V%6C{x#8dz~%2yL^p@N3?Jd3`5 z=Ko;&kQ<+bWHPXzryZanBgey(3kDsi4l<$1K(+!m-Al39E+jgPeh0D&m3jog+pM zN6MusdE+1rTs!$K6dn|#I8(%|+Q?M#Dyp`BPZsgI>+jd1ZE6&!z#Hh-VZsNXzM{#3 zspx>+l3h@)hVIS3JBR*RMbp&|oI8%`wSe44K^ex?`N@9dMhri-aoruE9-1wnQ27lm z6^u_Df=w1?`!~!4Y(c|5M2>|mYHDq=_zG}#FBUcVXf!nq`}0EY*}fRD%9zf4=V zBT`46?DPFFS;!1DD+*CTH~)c}OZNVMf+7e(x{vq^!MABkW2;=gNpst*;aJ4Vl^x6?~$lUj>L|yXtI8TP_!97eGhW zy#Eu4L>pv(QM@aGN(}^_hOjFGSR(48P|*EM8+>P2QfG$`I2)BayfzbdJs3ERW`n>F zZE=uM88b%^-u(>r7k(?xrAUrII0JR~6wq`^mUYCSwe3MoJ$&iJ3yA_TB3xSt{74B* zFyi%qsLO&L37c7N$}QZIT_dXaA%!Rup&1aoy*~P6&dap>+g}#X84NQW{1`(WzSBux zl-euxY9^DSa++=3*1#CeVIBt|{pK5{9`{RM_wQC`@GjdJt`@If93uCKeqf{f^@D4y z+Bk27vIg+1x?xzO(|>#X;O?}2J#vSZL}{I!4=AZTnmjXm+RwSm34HvN2fo|S_haqF z?7YBU=6e%AJe7S{cL*O(zs{38y{EinW8cI1!L{UQluUx}nCWS@=+-vXGNhS~-gI{T zws8XcvbNF5)M2=zS=eRZ@<@x7DknK0n*W5aZN^lGYnckW4i)9uj+ss6VFD*^%>4Ca zUMt&SI6|f z<3p2hFDMvShjloR^1JR*1$0-x%O0|KP<~XPt#E{o5;!^s;pHbG7u^rLWQPR1&P{|} zJZ`*;sGwQ!`oSe9+V08thZT!9tI3I`cX&O3lFz((eq>#&l2L7Z;lq+ z_cpVX5&xg3qV*eHOBwtFLg*Y!jlatuz9@$~|_$&OE6H)`7f#vEa1Kxc^S&!%^P{m@Y$m>b-t~C?%I4kTPX_Y^R#TO>tt(S{FXW0HHCW+Ep;Z#9H4Y+yn+FtbMKE?t*TD`;Cqe(q)+%5WMQfaOG9z8ro zHgm`|a31k!wzVmDnZHX&Nre}KQ6FcGb% zAUo2#dc;t&T-IYH&sJd*-1&5^JFKA6FPH?8Al!vzd>)Su8v5$QYAm63dL)IJf{|+I z6~xeFo1I;H5|5EG z$48vXHm$bbZ_H401!d4=kHOzQ-iG{OCRqL{*xTWItVAuILZbJ3&TutN41}T#wsLEg zB(E$4z4?x4{iD@UB33!PIzpqp8gghgl}yfxkIi`&EeiQ5Az}0YxlMbjaB;tEZ?9GV z*hlcej`d?7kc%OQf~wBkC3}IW0NIA=c)-6vu=cnc9-vum)B;n%r-U$vhK7>Gj}Jhg z=SjM2=Uo>^-o@v86mmmeM`XrUDe}bQ(S~^nK4JU73>|lJ!MSL@rt8{k(0p$mvIG16 zdC$MMyoJ|#;;T9(CWCQ%X89 zm?SU`!DKC7w^fjF=Lj=-t{L($*AP7IAz0h~%6~X0rq5N66H4mF3vj&A<4{};160Y9Eoz1}lJ2D1*b`2mUQzx_<(@Zg20K z#FZH4^?)qmvqr!(&=w)Qau$Hyy099-Dw=&jH)IToLYVz23aQ2NE}-fA>_ma^#9~(s z#D&0SqXt03ax}#s?`D57A`>#AQS(1Q)2MW+O%tURxi$)C<6i@ZZrKy2B>4cXVByO> zg!KaskKq&=iy}ByDCLp>xy8bm{)8!D+u>i(AK>o-G%;u%{~MnnDCTA&q+kIEqHqK9 z{dmNigtA3=zUk!OAf#9Q2OQ!PMF9Ux9oOqb_zq=S_=r%jNai^OvXVl4ffhDHhjQs> ze11E)zbJQfw=&F0S9i9OkL+%}cTjLK(PvQEgI4^_r1fu@NnC?wYtM;e5UQGZIx#W- zdwi}zKw-bOJ&A-W=8(hGd)(bRA%ppEfZH4cX#BK1&Afs^hgcyxUQq*#qD(_K06$s# z&ia1~IguVkUEJHsp6Fxk$HQp-!ue=2TK^3+u^9AQSdy1UQu;dYOdxzh8AWT7>3nq` z!XE^Vc7rZIr?3yEa5nv)0h)mjfXqC83s5yBfB?PF7NBdgy{?Y|S9h+h9r~AutX>On zOfVBDhZ!Sogk$Dd@d{h>W~@2zldWM!DC~(7*WJXRVxov0pS{Cd?OujT4Fd8XhAh1` zNx&Fz?-6z&$Qawzn*HWcSD82t^-~ca82ta2T@q<?osIVQWLi8~Ze?tf;x?W91!vdC4=-hkjeNbrh-yF!C#d?AcdDP9iMg33A(-mF@uw=Ux805N%Zy%=u|uECPWD5qLlZINlhgITR() zQX=pqgo!A*?aYN$C`ZP>?8K*F1LOzQcm%6JQPz&HLKgn;?YZy~QWZqtXG!ur2%349 zfiOHA1|Sta()gZtX^eKfeR*({rdxP+rZ`r3esozpyU?6W?ucD2r>!!z3xzg!$RTi1 zxI+P=y>55#TW#U4Q zRU3k}BK8#Swq(BaO=5A~Y6p1;*`7%Y@iV|U$shAcG2tHJi)-Z7@G^L1B29dOFeJng zZ%KAnEprzNFZRuP>n_IMU+@3}&vyB{1_2PzkRw;;C36#f{h2h)k;N#cN#FG$GU&$Y<17zoD9_F4mCu%-8HiR5(!xzORs>ZXGpfhA#Ii*1 zqQq?QtiKzn@ui2HF3jG9eUs(CW~#E$#F7f<7JPMhQ{$THEbKP> zv9LyWVL;iqSEB&%kR^Oh5%@w^CK*`LM|1>lIVSeBQ4EIF21D3lv*fm{cX`RJpt@;! z;s#o?+PrB#pi_lgZU7M3f-(Hz)wlGy%?q_FWbBo>d5CzO>v*=5*^aoq>yLY*-OF)l$lb_j-PiDhm#k}bC2M-m^Ti3}fxYzv5kT>MU7SM9W%G+X4WK_{{QR z?ef0JrMcRpB-uiy`N#?Iw$f7botN56oF?S_u-`26xpTTInt_oJizp9q8w_vaS8X%l zEwSLfKw6&5O$VfvZmWQA{lYY}f$)X*DLqWNh;m z{Ac^y7c7^iQ{2P^CDLnoo$u@NE+|4IOP^j_Hw{EYK_k<#qTF4O;zoPl`gNS3el4z@DCpFw2xlJ8d?!2>jE}7Ku zNqm}Y74o4DIV)cFTaG>QDm3SPJx;t4X_eWtW-4KCeq&W*3P+Ph7p;&+_EJ@4?OuoL zIo*5WYK@b}O|vwXL_VEK%Q@bzJr#7P z0&xc7BZ^>>H&NUEUSc73`PHyQ8_)sa#n9RZ^MiNsGp~HRAs6KK#Rae1TR;Xa8xy;n z=eHb_tSmU1#P$`|hdXSU3_UX*+*9FN)l+C(Xcxue!wblSnH)h)VpHlu`*>)bTLcQ7 zh9!2?L$J6_CPH8swcwHSuxlk*2Lr_h&c&A~?%6aTpz6jw@?z)O#ifka?`=xs^Bjzf zeW9yf^U2uKpVHqzY}msg;+pp4hll|av>I+-C(`q5#@uS)fm%z(`HmfK@0Z7vm*hZX z33`ir*~cI9N+2$i0!6qp&N~Q;nps$@k0_~qeb6jdQ!3}m$FOFekR*Y>z7)+)?@3FQ z$5WkbReE=I_9&$w&6f94`TFW3=4y^3k0v_k3)`8g^O$bA5F1$VSDmBJ@Ero1En3Bw zTxotS(ppA6wX;X8-FS~%=0oQP>tbgd#EI5`X4e*_kOqTaykCcX)(-@wj53rwHI}ZA zSM_c#mpN+z5HK>C9lTB;-{Q$2GVc)bfV<*cWEGl_;Mj5qkt*;^JkG%$5E0qSYF1t9E0*Vzh(cpn{aCz5MU~7tQ{5$cfh7vFDAZwuuJBGgO44E$v)#(~q}a%XMkth>7x7qbFkn4| zS+p&LrODY8^%38=k~?zK&ES^#QcMDP_Adt3Q{7~0Ip32IkDvNf{?;+E1kH*yUq3_cOP3;WD+`8S{>rI24*elG{R+Ylbs(pSpaCI_Q z&k|o;u)Mmt3eCt)I-B_V&i(#tr*^7%Z&VQcCjJEi@t0+Xhy(SI1?VXZ{ElqsV*?57>$7=aQ=%2=@mAuOnc+_72^T}X^T1($3Ho-s{|LozSCtEbsrep@UkJ0% zIkwj5{%`SE{Xm6`dcTAtN3P-@dI`h2VHR`q)JH+P{KdjCB|%oB!HJGvby5zlwe$7J zpts~mblG8o}c=#^>{%W`RWwo=s6(-s6r1PQR zN63=wt?e6Eb(G`=zjy=iwSzicayu`Y7SI7*2$dIG>#N+iw6{hv%@_&1`K3gf$zuux z{e7c@GH(xGH^38k8~F&SUjM(e)bTJML}b za?p}_d(8T`c`+%&dR(*XJJZadstDkCCzxR60zcq1FjWgFUnsOTCWx{KEaX_`Q8wUC z1;Df;0Jr41&Doiy^1q3_$->4A!W7xQl+|1PHh!G!e}yFG^QI7h!PS69f&I5kac%Jx zUH^TmD(K&^K>*V`(Q@V!1ZA7Rh8SN?9emwbhQS5z&~uQ%syM4dq$sh4SF9sgE7&2hGGS4x_$?Hf7)eLKQWShZzPo(m>}XJ22{jfm+U_3ywd|ZFY!sr4 zc=?OAcPK12nITxyETJR`aH>a)Wo8{nX=?K!ClCuo7jMH)NRX=ah=Vb45X{xo#`IM4 z;a5~+JUDd_;;850_xm3ey)vqQHYE=+UCuXI70;nyR=%kXgg%n=7SJGypKlYG1iyJ~ z5>Epll2hIWAB5Nj>PK#9^;{7^HQA5tTuFA+a7sD^3(4 z3ozv?%YcII&5!L@z{#lO6+`AP%zfa~$PE_8degv0aX$F%7_m0x@%#LI-%;-d7eUTW z1d(ae*ddkNU&9Q{Fi$sRxFN2S8u*b4`8@SC|NpxRVIYJ{XoXoUwK0WUUYU^2?ce%U zkDP0`?eCJD?RR5(IlJT_nx%is7Q!Y-7Q96bHme)Cfsmp=*Sq<2T5}*YoS&Anj<@HT z(kO5qpfC#Mft92OO3{AoxgeD8?vKFNAs?|B%OnV~KT!LEE~pMHK)q5vcdF*%bbz^O z{eXI+l^x(6ruD)v*mLF1y20POPQ)N{h2w-?R;qi$dAkX#;`JeyMZBW;sP#-~AMBR6 zs5t%zUX=}jW-aitWH^|sY5gehi1RCqpw_7vPANTK1Qd$k=kr{Nh^`)6z*5!oJq#s8 zq3AgEp1^zr!bw&d=qVf`4}8_C^`j`{i8!J1AN+I;MhrCFLG=)A1)wWq>U}y+K6FmFh-dcylArp{RT$CM% z=UXj$-%C+h3qBBtl4 zjsO9TKi6~OivJ0~{D-pcjzA9K?d+}>xR_Z4-GAO{1n~rKl%NCwP!g-jZ^vj5uF zi&Gu=1tqDX^&!V7h?Cy+Yc)-%?=;8h1TYY2SO5Iw#yb5A-p#zhWM&5NrP|I@ZtoOY4meoXBeLYjMBAxxCSj%)w#`f<++KCx%P zZmR+fWkv^}6H(-(Q0rkOyK^|TMqCD->v_zF05E{td5nlC%pkN#4|K?+vgt-8sxnY> zVDe`R@6z$fkpqQr_5WyZkjrS1UIN$t&p3W^o#MYBfI}|xj@|W6`w%=}gq=ujgsbZ> zYk20%M*#FDZ{is;cLHXTaNA-X4oLHXD~zvLu_k#T|edS?TuJnGO5;4-H4 zB@isSZaMmn&vC1vPTk&$9BX_R&5fncrZ^7=ilHXT3_uoFrr;JmX3ALhaSffD-5nRL zq7SZ3l#vGQ!rhyQ2C=v0N%Vq4NMMy&H>KlA8O)3fV7zT(f%&f45B~Q4XYhU=iR^sx&NsYZ z-UR^;?-e8vIO1SJ=@~46?7~Hq#*qYi^XL|+Je9aI07(yh|J}U>8V`n!LT!T;e8*o` zkNE@6foZRFz0P-4p_wD2Q)1rBwNrpiIFW#5X5i7u$2D>VpiUc9fJ@N~cGhQsKqNBY z{Ttyv9_Jxz@t!OJxH#EtXL9Q(RaHiPL@NeA>_R+G9>dfx_-bnp~Pih1tk*nwDFu`xQo0CgmF{^S+O*9wkbw)LareN;M}i71#Uz!N;vd?7fwiVd~*leU-u6M zMh)mGh_xUHk~?7&JQ(;~adCDZGwM+56I#EE^TahC9L>K1GzzXUXFQrkB~VuzoQ7uh zD+=Ic82qMy-*xTMFYpQ74$_l!4mDD2MyS9aI9Bu@Z4`x_qo*Fle>*rt{kaL~L8xDa z-V8!?rC&w2kTuD=@ABECe=D9K&!M}3`r>)9zXBrur+fvn-9Zh3Vv^$n5U=pt>J<_9 zW?J{}NfV@qPtvBK(1KA<;y#PTV8qG5XK+!CP)L9^WPu9RwAq zoPfSiIF*{7BSrmZ|AWTcfj0WE^eYz-qet}+?IuxLg3Zd!&Due^?fk*Z$GLeEI0R__XwAv#k!Qi*#tR3=dQu~ zpyZ;83QAzocpAuu5kmOE#<-kdUlJF2YZ^Ky&973f-I3{Ye=fJ9g6dAnyh}wq|N1oW zMigFpyVTof9GU*ER^u|gz*V?@+})4-%zT$caKyOlTs|xwH01+PyDwW72rta0oFCQr zdhl-I_EBFd;zndB;zR}r^6_~;U}xaOiq4Uri4!-1Xsp_F>7^YC+DX-VGkdfW)23&K zS7FWgVsda%`X|2u+*gr8TMV5Kp>YMnj=8f4Mg*!&>jYYf7xHQd^xJVLO|B-Gp&!m7 zK4dERF~t|Bp+gZ85woQEk-s%^J=#v|xXH5c>c`8lG*X`L`nmjw?#1KpX)zo;_?q!l z4tnB=cC&w@!FW#&`@BnsoIaEI!qbFgDzP5fiXz(K0$rX1vs6R|1fUABc#%i22$Yr# z;2uIh(3I_ohn&=|Sr#-YkIOw!t|ZY&RJvE{u=Gwqs?pe0^=?|W?nRK0D9kljc;g*}XKVgd|kjl?fprjI4A+T|EebW9c~KNu3+ zfqg+eE1da1e}=w9^356~odP(px2Ket6^Cl#p9(y*+LdwQX$)zR!?-p$Y0UQ@WrM_mDQ|RxdL;i?Dus-()JLEXpmw~bbViuArP1KWxBG5;$hz~JdZRv7L z(eW5xB7g!x?m92r0AUBnGqvUL|q_yn9s>Gj+0$feF zftqj;MOxlpIO;s`MNNjuXNucMdBO;UB|ncXR_PxtFB)s>bhe(lx8y&p)Htc<4FYRE zN0M#qyz8Dd3$I^bd`HnthR3s%PaPwZL#No0;850eSsjiE8~9BC1Rqj3#q}AC`xzX&YEi8 zRa~nsh+u(l*!d3J`bfWuY4g_OVe9Y8W1*FVO39oM)5wj2vab~?=DyMHw2$Cq*!TX+ zDvc_(o%T*P*JuZlGAkFK;>DDsIa!ydt}FJ^G+{)(c_Jdn#)%=35LwcKO`=mjudX(8 zes*xwah;zgsd|2iPBSn2UiAKHn`5GOGfpR7eXke{&KY{kcTAoC%*J=I&zx8=F~pXO zUbQg@8FZc0aQwm$9Nzqe!R~0BkW%e)5Bn7IgL8(cc+)=SkBYMK{7DkW98UuPj@t!A z1b*0lLC+}xfiUz{9hGk@W%1$_qY$_`ohkW<~clGiVrPrb|`Ws7f;Oo4!wv`fkz za$&4L6WL687ClKS-^OF~*h_ol#*PRcC&>fH)KgD4X2$B9>R^tjQQJIPu~DbJU{Oqi z%{KmJvkKWRZ@kdyB!VJ5>0;BDCnR`Bi#i=Phl;WEtD74=4Sfw5xB%+$7T+_%cA;atg;iJZo)1?S4!x+XyMJAN>}gw z+GMIZv+&ZGL2PACD?>eVY@dpBo(9fN1x2&_kK3fL>d%kiG`ecq=J5ZR`tm@i`tSd1 zOJ!>+AzO{2lqD6iE0PLrwq#FI*6hYGB}@tRs8se8vM*&{qo}b(+4p@JhU~`jJ9j+K z_w$>-o=5lI_xpX`XL+61Iq!SnFMzKQKfz*Bpa+kB_#T0Trx>OJ}-+FN&mOqn&FBB_PfagdiflLTj0MMPfyx8 z!Irh#IiOpnmy~_ds@s0s!uN5{y-P;JJ~wD95@@vII3V;DPO3uUNH|yUL`=10eq}1p z!PhA6r?#DKko;3>Y|rZbf44bq;dJeGn3b10jKT+_%;-fJT}<`!B4vt+0 zXfYao_Z&_0XBxxg{l~JI8+~B_7fr*wh^73zDXAqB7%EZW%g3s}An5RmRqQ&qq;(8( zqpI3yV3QD->)KAWPTU0pwH@kWE-zKgrznDk<~x|oby0it0ZLTP553+E!sZZ>P&T&P zvKWPCSG8xZ?F@aVA5#&JwD}E;li+V$Tk%LYds+A8OpaLJ7Nd)6Iijbfb6+kmPC0ND zwGBTZT~A@NMfoPAT&Zj40^Q8Mqh0O-DUQAJoOIl|+4dS)ib;9)CeF{OJuoZ}C<)d0 ziUi)?=+>gsUny-tCAZy{@3-1jZhwM3F68=a`Ue?HWDdU9qFQpb*xRVS?YpA75$FY!W zn3c734v04kS^Q~||C*am-l#g<`e&=ntPvM_t2#8Fze1h@)A1} zME8lVOKIs|zAifybPsVESbwm$)6XkjwkJ0~5S+oxwun7R3m9n1VI^-YOT~qK6Au3EUR{|`%+XsT-i}h>Xi^=nTUFmSKQ{k4xjm!Jk&aSASrK_ z#c2g(DJ)4|9kN>Md;IMljl1)?(`{ulCpY4S`TO7`@oLM|A#ABAPx&OPZC>OOX7-HY z`_#@!gKm+Cj#BrJpPqJR+c#hbB>o`Fqa}Z{v_DTSX+>$fJLGPFXBqRW6UWWX7hmRp zxi>u7Q0f>*hiEj_A72UVKHFj>MmOW8yyIY-nDy{EFK^B6wL2K6GxOR$TDrBQ!u7+9 zqYurCO_jVuyS#gUCyjVOt=~3P!bQxIB>KmpccWAn%YN!tXl4gI6QWdfw-pDWTXb?! z0bAdkcy@cnoD#OQN_5DbGez8|Ic{J4r>B||T_VWNq17JQr&Hia=k}NN7ETs^dg}WC z&PA1HDR{<_KsWk_tngp6m7Zj6#W&@g0;3w`R*B|w;3Mp1Iauc0$1T;ok54X2VZ|-~ zd~+ZMOV>By%BUJD)(UrT*?*)1&_fNiJ!rP4n4*PwD=97+X&&EU`_tkb2(gjlpc5o-dcS>JDiR zjBhI?MNSoaK54I%fWVYV+7rI8~*?!?cD>p_s!sPeqdIj26wG8O^4)vA&^TJnrIw`=HO z9Q6Yu`TBKEIdGCC!FDL!{_pii-7#4g1RI*?q!cZ>D-uCgV-FY*`~uAVXW^9HQfY#y zee+5!C4iTpxZ>Q&#Y9ECl2bdYA9=;ke+f-S<7T-~y3l|$RF9kldyM9bk8vO~Qj^p8 zGKlr#gDkN8ce#RYzH9{i8$0TIGeMPrT-zXCOxDIbJ6a0mQG4BZ(LN&C;0OkpxoFy~ zn3@wUPX9)&$~1t7p!mjtc2D3-S9w&)7W4`PZ=hr_K?8ib;{l_6eacGfw+2z^H0rD&^l5-}*Re z<<<3lU9SLO2l=@;u92l==hDY?yuJ@JT_(d^;zqogU}N5njUxi4ui(KjLqw;&#mWJb zf?^v){sT#XRl8SiNef&|<<4^6y6Dx=M|c(SJ!{p%i}CZPk6EC%Y^~}&NnnQ9ODZ&$ z);-a%?hl*U`h{cLu-cBcFp=IpOjLsS zb6UP`{Z{&?r#6OpVY}{a>vJ7ZrV4^UT0tNj!pj^Y>;FlFrUM`h{&^+r9p18_2hzdB zjDWoa{Wt4mbiblcR`lMAvVMeCC(Ez57%y(@nD`h9uB+fLLI(M(j3~W!#kJq~raqEk z33Eh>yIikxl490%V7{rE8?yL(AL$Bob$tbJcWEcP48GL6p2-G@)(BTLJ5UO0N%EZ4 zfP1pxqsl~`fIS2*j}}~vnc%!bc3JdL=%7-*_5H0if<(*dV8%0khK70ZU{}sQY!H+1 z?(Z4NZS!X~p;L6o7h}dhz?&F^=#8TamYIO+=PS^C;@teWtYYZb1suVy=bLDk?|G=O{MIWp^b_6xaaL^i1stxY_()#!jU>QgLT9bEnytNO%J8 z`)KFZ(0tAs$Q$%$cBJ&RtGr#Z#oO`O$qwf7hFc{c`e;0i$m~^2f!^iX(la_ z&?jcN^JDVHvo4s*v!sl|+gl_+N95~2-|sz+RoZ_R5%3K401m(Hl&RSj2B17J>LrC z0pNKFkMsDbnJTw5d`AEi!zws`uHz%dZMJ8|;t@Wx({yamfN51J358~jLi$;S@X?l- zNwm&K?gS+i;i*^LhpM2|HF`I*#dpfUPsl&d?S`n)kc{fzd}HyJ3Lwn$;@Enu#k?J|wP026^%VNdJm##R06m2}^1`52qrn1Cwc^D_^YtCHw-{KC#)alj{3!55* zC}Ug63vyKk4LoIAf+BMK%mjGge;4phNimq1m5d+`FLg6BK0Sqk4RT61&Qg$ku5kGj zhY1)sBOUs*=GhGQmnq3(PP#QQ{FCSBPmGb;>Z#l9BO-TmK)Pd zvkn6Orh7Y8JSkksR9ZLd2A0qb`4}?xq`6J?!T@2!+=+3%;=&G(N@{ro3>iSvN%vQ< zHUhi|m}GLD(|MS#jScc7!b6^8bdHQdhx<6w-Lo7GGdcdrwwDkZ2trf(@^~~%py?Fi z^StxDzyCo7?$jukH=JZYBKV*Em>4umCeSroar7YqF70T_>lLY1#SDM;n7=gvKIs;{ zbKZGYvrI;+nTCk(*5qT$wxW+XEcBLjhaX_bjL!FRIz^c;7lV8W9>gd=zmL@kl0PO%%oj4mO1IM>vs^9>Iy1XQ?! z&n5x;ydG&yPc}Bp^XZ-0J!ib>{|G<79!?%t+USSpW^#ddYH=4K2Ho8EPUr>9!jaa|5Qf^=pe?QQEjxq2vY7)k)1;7sZCOpIHNho*0nG=M3ND z|NW8mJ1B5K3dG)}SuU2vUoy=^kHmiu+<^t7>K#yW`oJD?yv)zSC}3<*_1^liLk1QN zq=L==KS&>9|1Q~JdQyUmEQEuVRS7g_{C5MwK|Y;vs7*ugGIpQ@qUgUrW(c&QFfBfe z>3^#rgsdbnKL7G!_sruWz^>G_ZJY7mZ%S|pH)vMb`sDo3imC+U&I5d5Z zFd4`z2T$-U>XFKeOdPcW=)yc#={c6qgp`Ngp>Aw@gujjQTxz$H06g5D62`uU^fp{+ zv;WS|gWwpKe|X>Ci-EAR{{0{sJf@?qd*=vf2(?F;O*W~Mk6p_69DQsVBef6H>^KOr zEhPUE#})Km)_hoLW&62ZhkxTcFUK4wtgYMgYPe$T(!RHRqcvCP=9ku71dDbkg2>z; zhz7nMg@+%Hn#y*+{Hd}Rixrm{5wjkj?FohRQRRAIMac8`@q?w%M8Dw#3%XwdSKj?( zGDpn6(7jfFt_H1&?E}IxPF|P3rU!PmYHe4qT4rb}>cs8gr8ec4?26t>EsNs<|0!HC zhSXLjM7M^L^AjHSwu784qtif|&)0H3K)}DVeh?`VurpgE=BuQTdkvI zCwvieyU{)?>+T;JshvRv{_FLX-wuww`u%b4klwLEjd9Z8y!U<#idVsx1Ui%QIU0`x zMWKr&ST|>J#KznST!oW#LqphGYugYrSzE*3mg9HY4q=5qom@G@xE9;o^r&({>n-5v zkJXxL-d7GIv6bNIRu6^u8bUTV-@JCE_d;gq@ee_xT;T3hIL5N8-QOj@IbU_7oFhcU zE{q>c7kMrMf>8Z2w)8FpkF0wOHf3=LG^T+u^TFjt;@d7;a?V7&VW_bGH_Zy8d445u z(mpOxzp@H*85)&+1^!0tSp4N#2$8;#u8`~`3C8=g5U>J?xSWd3?0zkdi!d6V08ix- z1x_U+r`EQ9=WS6jZvVhLfopeQl`4rKuaM!*iR|hVA0j+PL0^R|_UDdTslbvDuRdvP z`dRQ}_?qFRv6?HYi)-?CB32HTy)_ezN-zSiSbgZX2D8t$QOt>p{A;C2+ZEr8hC((? zn=Hk14Li+s1j#f47|%yqh@1-S67@l{g_FemV4{_m zt+om9TwV5O!XsqE{nqcR#ETUC*9(AV19oav6dH14EmsH|1VrV-eUy&(PW5uaBfQHi zdk7U&*F8p$ys~!Ab_>Ku$<93ZieCq>CX4sjj}aNqD&@&!zq|>{QTqZ@;(iD2=q=ww z+g*^))gC`a>R7Tf%+=$|f?hrtN3iZ)iGdf8MwLFM7J}Or{Du@pujE^pwHVbmGvIX?F6RHM!r zdJm2c9uV9Zlo1JZO;#KpVF{w*&EEzal4spMy@tL>)D0lzPPI~J>a*hLX9PaOfmoM| z6O#SHdyz&o)G`B6BJ~edd=H$Jl$P)u?&w2L$Uhl-9>Y9YgycV_DGr zkY&Ojq_GVQTnu0_c4LBcA7%~1ZL^E6RE0D``UX;RQgK8EqUlJR zi%D&7ly^s(1JVIK?!8IDl(TX{uDGsqL{blht>INFZ=vh_nu=FvBsx$op5Bo zUF7&K`&Ko(lyH zlrek;iK`f30KK;;1n_+08h5?vq>TkbW93quINxJ4LF3u0I}o#s^uY?Ze9Q@*2G9Z4 zO0cnyXqZ>oCd|V>S2Odk|67X%=_8FBe=!+p#^48yy zEL=bf=dW4kK7t)%`3|AAVKK&lX&HprcUoL%z}*V2MC8a)@s=f$w;GipDkOi6brpu( z$WoPg*?&9IkO%uI{+qe{K2RvZL|#}9+%O@U6Lq(qm1n-`$!^vbQ|*T`D8^9%R0GGmVb6RVBGs#K=e9K-n-k}US36WIwV!dy2H7dR z5qW0edh#&V0-*1p&#NIDwPIX_sV6O!B@(Stb5F%^e6DIXFh1lvn#hKDRCxY|cyeR+ zfo9K<%7WoL9t{-fv5>C9g(zMrLeE>*aWh7$taM5wB9qvuk`sx@jQLrBt%_fq=}8ey&)Yb8Yp= zYmxEEcb8O5gx{`jtlX}lxlw6!gOR^WVd6NES$ux_C8ZD5;q!9o7Jq)(x6D27Jq1FE z&DcVrPGzqeEw;1p5PE7)=GBS0w)<_Yp3750LKI`BJ0cA;LoIpHCP0_Y7lmYgQuX|D zNouDu)}o_Y3>T67CfpUbr%)fhGbmj|PHWJ4J?;eT@YyGX%Oh{VF+|L1&+X+-(7aQP zGp~tlB`ck|+?>u2%^lU!*Fe=|*^TzC{~jeSM;0z?d2!D~s88J3j_^UCQxP0_6Iv&x zF@7IZEp!D)e5>bw(~ihN)#lVom-# zhZ5HeQbY0f+KU+-2mX|O@VeSFQehOtnzz&-DDeRQXl!84j%0i!2{Z;4d=$r(XGM*= z^t{~HT)45VQ8`Ck04jggw{;#6DBV@-bp)$ad-hZYZ_+sz=8o*cgR7pm-|uWZ6Hi=D zW@TOy$NFe-IW^!MD}DB*hy~ISaIn@ANKu|YR0hdfyVdTg+}3z0%3B$lkqMPWA%EB& zS;?u6)oMN5D{w18$JgN1^Ruk+2FBYJ*p9i;ai{BGPDns$VJ?C?2Q;0TL3-1i*G5r6 zl6JV_0Ty_+q7&Cr(bb{9RClubaTVp$XmYF|sYh>yq+7W9nPF0R84WWgdUGF$r>*f< zPhbaRQ|Fn?WRBgS8a;?=Z<*BDWLTB6FHkK`e)(=q@?TbvT@`J7& z<`!*cl4O-L$9>%v%0bV}+@~#E=gcseIo8hVvWtah{x-1v^ErxQm?|zCV)@1DATs}_ zs7AI6qBc|&qujEUc<6)Jkm)10twAxzjib$t?(C&FlM<#u3|^etqzrHo9Y@TBoeDcK)q< zIk+J3c&%P&pzAg_L14w8WeO_3U=oU`coqDqX#EDBy{Zu&Nf|UFjr)~n^ zn#ordvJkD!6P)B#u(|&a0O2*4S%w4dP>G4Ma(m%r(*{OPP^5}=bJbkDcP&B+d#b*R>%oNQ|Dkrj8fuB4sF+oIa3k~Z{{&j`-t z)ilG1+bRok~@smB8NRV z5@;zD_gR9;GY#FpU*?wsKqn?)6~7(?4!S*FV-kpvob>`6%Y4mC#RTycnBP z@0>6B9F5vAgP(H0^J-@Mn(fcVunMVUtiL^{VTdlKPYx?CHSwlW2+{+9B0+x^159r` zJ_tB0+wJwQtew#EgCIrEU6Ul~Y<6q13(G1CT zruoaWbgflTZLFR#_0CVY8JWK&cov@seA|_;eNjhLDaJCu!1b#@v1u&A6gwd0>S~Dq zsJh%aXL7zugws3*qV~7N*d9#)5wQuGx%4qk(U-EL zyDtv<=(S9FLOHK6Zq@?O4kQivz3lGY_Qv6geP4PYGFbdVSKoNO731`py8iYvQ-*&h zQYl$Cj83AaTPu|w@BA^AR+E@>ky^Z}P6WA)J#HS`*jesxj!wX2OjIwfG?nXA$0IJY zE7K1qB#%LhM7?bhiK8jG+{rMH3%Hl3^AX@MgunlqH8X|aY1O^|DBRjt;B!BD0K3Em zURzVGmQ|$O?Dm4ZDeO3(adq;gn0hINb7X8cc|ZsQw}ETh&Hjoy$nO}ooHArbIHBp zDhJE*zA|N|7%f6uhA?;m*Z5@vL=!G*+DgT0O_y)vO9`VhG`_t{0TC*kC zj+MvW8eUX_x;;S3@xeOj+>xlj5J##D4@U46U7tK8r!YoAVUX^izoDtg6_mB_7_Tm& zCz$`3E+LzKXC<%~Jt1y#PFU(+tFFG9DyKqU9_O-wo&7F74tFB=ebuUxbmB^fq{xyC zl4|WGG2<|n{yI+zr&->`3h|FIpPIAnL1_%t(aVuOd6}$2jgyp47SK#=7cas+gfjvo z>SDhMf)roXxy~8>vs?*KD4=V!Ux)Ud6@*ws%qLH3Uj&o%$I+KJM2V_OSheHz;GT3X z?rNK&8?ui*R|{~7dugMvwh3ZR{K$&<$NxJ5z3EMKytQ2<2JpMW3F2l5*^OvZk))tq18OvTR@K zy?g25X0w6o0>7OCLReep!Gz;E=I!1DsBa+WWJn9;pu)1Riwx{asG6>Qo9_HoX_8Ors)*9i=j9~ zy>b0P)Eq7rmd)%t_)Is6qIXpGk*8Ym^=-&9@NP&f4m<*4V%{A^d62}m4~T{BaY}s) zU6;t=HucOBu=s;J7MyCItewIt0W+oXyi(mI4saQnPZtt-v+x%4Qp4+ zCzKKSp)l&l1r_ou>DYnGNufg8LuvI4eFm@jePj4|u}IrEE(K73`N3P&qN$P)bJF=X zyI7Wu4}B6|EuUJ?vBarW$M$I>oO(4 z#neN;m*&-+_ohTJ4d$0Q&9wYk=h$3p4W@8qb?o-UpD;T?SX|4={DwiQU85@em$J<1 zW2>DhiG^gKG*KQsWJnHcZ|Pd%vtC?_CzT6DQnZ8yaxNnBt5FY?4dZXHdgf)GsW+Dza5pHVOt#%fb$BH%B}f+;QfO#FYX$F$@+m!K zrQ(^FLyam*qM|vp&n0oRrR_O97OYI2p@9+RxYFgsW95ck&*F<@_O_UpWmt9hd`l*E zD`4*w&aQbas{7IR2IgA>8HFyvtmpEmzMJ$B%Fs7Z_R!Ln?7 z2du?ze#$_&@O-nQ&~}1-jk$VXnT4ewm56A=a(SIFTt4)>IdRTrCF(>ZvYSYt9h^RTd@7yu7hp|wNrfR5NF5Eo> zT_U^JC*EvV=>dH73NM%FbOMqOLMk}FxSi{-!k6A1CE+AviHMdoJ*uMc+LlD1Iv>mUvqfbTqQ3 zk|=z~gC!{!KV0oq1|J*mI{|bA_5#R4-c>k7^N7N&u|d-5>%Ldm5EHYWL@wwZEH_#M zu-CIK86esd-PneUnWHOw7;EU;IA1k@Trv8TiCUG^<5iOhmO&YV(E4_1{2KtK^82?ms?>Evo+V;Vu$gD&dBHb35*>TLDdpbR?!Q!V z35E=JJ_IBH+#h8=X^gn_HJl@hx?ceEF8&QzZ()k+PT!e5r6!hlo z7_{*Upu<$%C{Pg%CA`Q8ERdK(K@e_aU{@P;E`%EM7$>@`!57 z9Xw7Iol=#=8J9TE{tr&OF`H~@-5mXRwKb?hTJ0PyY3X7VB!mF8oa2+*pJ->N#Dg+G zeQ%mV=t+)I^n~vGX(PY)+l^-FXT0@++x0qSuJAjve7XK1P=a4ktgq0i>t({cu(5-p z=>F>g6lk|EZ3>8k4Nf;8nYd=9QuJMh(LzCK!zPk8Yk!`*eGlLJSpk=P8m>*mIDNW> zxYP>1bv>oT!c`BC!vfUK2<^h_#%#@B!i=Yeu2y}ucr`aI=di_kLfHc&M;05~{123^G|e=j)t(4}vm3W|=~vFs*F)>c6t386+5rp}Mh@ z61e{a*cIz{T~s$kUWtI4fOYk`+FN{?n*PiofhKyX;`y*0-B5Xl07azE^k7@n+f+81 zzW4_bWjU5ikg_4PgSXtOy4Nd99Mj$LWy8rR4eu)TKN6-Jy!_&kQZ33dH_noIPqfgCM9p6+P!?K zU@W$1{$$bRP*1hv0oiht7jyAIVg8K=#X>4yr;i6)at`I(q8I2x)0a<<)84)BD6jRJc>j%pclGIIac%n>hN zw!TBt4Bm<3vnEyucWnD}lT>Iul(cG1bFgGFA(Z~I3hf%tc8_$9Z{}`vLw7;)`O3x- z?D?#n(`hki=fVU+?l#zwEh*R(1eqLn0*TcRdwq}ofs;@x=w(`fD%sySl8J`h!$%O{!jH09o%FWP~>(ClXkdoJyd8IkT<=bNfc0*|I5P?$eJ~u2^A=yf_ zoAFH`t=YiErnHoO!Y*J5?Z-chLo!)>*{7ITK!Q4Y-K(}0EPQRiF+Pr}c_@xke4RV^ z)}MA8-#zh-8{xp-qkW*vCwV(q_Q71ENwp#FyX{RFilFj{&mj^wwFFtB7bB<8cSD*< zINL!vyBr%NMX66oTG+eg=TvsN8z4cofnf z$>U+QAxllqEBc@vg7qdSMdmtsW+rv?2N1abmS{W_D=796Y_sa<^s9BXcPv7qN~D5n zhH z^ZVY?>YNg2txttxBwxq1U7pQ&f{u{b4fPT30T#$IxC5X*lfa|(x8Yoocg?lyoYu+6 zOu}4jm_eGt?*eX!+I%CKD2}B{^GpqEtx ztX0X-az1mVdlexZghp&MXGJG1Hd zGE@f(CSgYB#35BtDI0!iQYLu|Q8E3f&f1)bM)g<;=VBtYuSZiYG9e=>;2YqFB1u6n zI`BKIlhE~f{1M(}ctGUbHe_B)uA#ss9qi+I9iRP6CH}$X?!Ks-s zDGuImp{gZe^9yKW)$^#gy8#c+>z(hMiS}nXhNz6tE?bmp-Ji%IlUHdRxTKW43sG^X zdj;Jfu^Ah+V+IYZT*&hjm#}dK+O;N9;rpQm2;fD#x|B9McW)4!iXQl8%~46KWPqx70n8%_IR=dBV9H zmI+!rk$(5>-!*qBTbEX(?Ct_2G!_n8U=MRdv2#0gL~qqJbx*^3M!}}w zjGjv?nrQN(6R_GUkM2ylNJprJy+Rvg>`S3X12uK%latneL;mqZB^dVrN}M4oiQ5-x zR|&e)gxGQ=rj8kGJv_h8DBL7Dk_{b)7ci=kn}W%NK#<57@!muTe@I$5D0JCA1d z(_HmP;R@ArE}{B@Zr=(Z+2d$e55OS6MbiM!=Yk6+Wff!2SIH04Aq4W}SA80&2v2|r zT_+i2GlSFo&-W)VlbbzL_ZhXNLvFA*c}{ID9U^NZuk+z$cqyNXFYGc}*=}PqV)>O5 z^Jmj889Vs|N23m-)vJ7i(Ow=qi`CZcLx0aFS_+n*9Lv@?ubeU& zLt1EO8u5@BIJ4-Nnme27P~M7vbAsT&v}{D@-Jw$KC;3TL_$iJ~ zuHRU7jPtS5O_hSvpH#O^-Bgw5y;8|u%WgIkva)SM{>V$s@@>a|G&qNZJWDyS_^Ld2 zzPV(Em|Vk1MbG*)azt?(hRZ>XCPW<9rr-N}v^dpT_eEV{u~;&;=m*J*F9<__wgjCD zGNbP+S}}<3t$E9fYR|jZ>Fl8T&EMk=O}ptpb2;TI-P@hxT0IRxmxk$xU>8P!4dh* zo;cBL&7He^Ka=Q@nVQkoVQSCtr~y|bNWRD-fiaXOy-SA?w2-Umh_XI;+rTRZ|NL1-kkpK@?K^09Il$NJ-&Ea!tM5;>H$bYx2$> zuY=k-UIt8)OwjQ(j9DBic!nKl5oSWS(@bN>q9Pp4g8wu=0XyBcAOcdm$ul55r;`c0j57eLxLnX~erQa()Td=Skx zG-=r+ep`M(dq5kfZvso-3R6WX|LgDtQ#kq(qb6{^>V>GPh|2(zgv8_vEheOxFj$-_ zk&Km}T;22ODOsUJ!^=7cS;~_v?o}_E(gK*titmbnC>)injhZ04wFX{5Muf-Lc=RUML;yh<}wEX`Ecmx#;VTa$~`0I4gK>{uMODiKYRxj1Rg zZN->rhw4!A`$1wp@tbU?cFI%Rf5I1lf9n8Eh2Q++5PZY$RWmdo#D5k@_-4>G#VZP5 z8v8_jb`};j{=Y?8kLP4I6w~f<>CQ{n>1q#1+eW>{{D=rGymeO#n5C~yvZ2imcV7g7 zVx(Y;$bZ9;8hnCNcK-`)#<7{Jy9-0?m)3FgIiL09M%3 zFtpHT!F0mI8}&h3b98xQ*1JENlZ=zxm&Zfft)sv&AVv_4xG*QC(fzgkCw>3=-G2qH z+6n@H)xT28O#Pc}g0_b*NCNq8=G=RBJ0Ie~D>#=Ot*b6gQw-Zkr5r&R=d+fj*QKh^ z>ad6<)O#0Q$}2rR1>T9)Jv-m1ZqgDC@?PvKh&*3qb^JUVLwUpnV@sjwb6y-Gg&xMJ z+WS}~Fiy4y5mOxhC{IG8hHZD|xlmUDv{2;m@6y0AkN-ud8y&tNi`}rxq0juJQAidO zDdY$ zBCKv_xg}azKnNo8S0CxiTz|A6=7*1YMNg2C)CXN==^3@c>wy;2e601+%zk=B1dIJX z?y5>_5R46Wnd~g@g_%7g-v5a7vDLyBw*4dFX}B~zLAt8e)$svQtAbP6EIz24FrWMHj1c44b9eMEHLcvcE!d z(@#cOHwEQROCjaCeCkynIB0%HZLM<4tHpj4zL@#8OkM4Ux^P={;jD4mU*b_glX zM&DW?=C~IVHdgV_KejZp&cJsUk5p z-_gT$lI5>IULF0fZ4eak!PgHP zH1z6qi5%R~s3>CWl{x-+?n@o|kfP$$2I`DjGB!f3s?7Epx@_d8N~VKW$|L+qE4s1B zFm|Oo88V1UCye0rJ8bm9K8(IJ>IYCy@I3sBWAA<__Kh{Ln74kP^(vu5ZmtM?^rNI~ zyoU`Ya%)tjZ7D?g>m7?}{Sp-#J{A|^BSOE)61XX}F#nd%hRi{8;?>qBMZ?-?7#H2CqD$Tk;5SYM5vC;B=OK6Z*}>l@k?@ex@*GIvd}<_GS(165QWocU)Vl!Scjv zBNc;mSb%YA>ZA+9Sq2hOHrtR29iHfOVu!yUY+Jgd!?w7?aOR};c9kMN*L=GvbuT)1 zi?>7~fCzD+(wN9-e@DU3zwC~mRej;3Bed^fm*;BH^wR56pKb5XbBI5<$fXZ%&eyJ` zo;zXbJRDa>Gg+|MR_o4(kApt_D7f+d2e zmL;m?Xz=?ysB5BXCWf4aAF#6bYAmX(;CDP@#i%n`@Q zknG=EzQNgd5mlL>ncw-tiNTK|3B58v!a&mViKuqPLS{AL!9dsBQ| z>Bqg(z?|y*WIAT|8+xU4QQ)q~!zHQhEAh;khR^!G@FxyV?$=fr(5xs0Q2t4tJ@sYy zLR?r?qg<4okr8M6afwOgbJcH*AMj%06H9GC72z)=$=tWy5BPoAChA~^+H(C2Zn3tm zq{st=0dyU?@tv>jGb&n$2u^B|M=S5)8kT*TjxWCr%U7;o{XEK)NwT}&fVJ4GElPQ0 z?Z5iEscmF?ztU>I(anbD2YZ&{A3!VT;=j_Y7xV^D1bFmhM#k1dA2#nI<9<6o!sh^? zGWL&l=wKQRAwaatI*PMPyJBjo{Psguao8^Uk5PKA?M2Vj9pOCGSU4mG4d5`{)}MT6 zZM~}I{n?NP9X-@FzRxO6p8-wZu8+9X8M?@J!T-=r*b_W>&M^V<=RnQG3vUF-q=O z@Xd97kjoi)iYdlv@n-+0y^Q?+K^Ql*sXxLSybmBF$bSx%a8MH=;e}tLVG2D?;sHB^ z>`J2S6XI1%JNoUD+|}!6l>ULUo=tyN^L%y~nkO+f-h==yprw6Z zDOh=&AAb0JeujIg;@b0qwZ8G6{ITD}|7MqxuVv;t?GkTVmGmj5y&4#~8>*|tF+!sD z4DemNH*(_s8udl}cyz+I0=ejk8#^}cIRsPQ283uL#?JfJ-)JgdbWmfeEgGdbw0}v$ zOc%|Re%vD{t8aWzn&NeUr_GZYb3${FAy;Wcp8vA^Ws>G#iEb4(-~DzNx-gYvaI)Sr z%G>*1cq*lvQPKJPiq6L#N|4 z&q|qxb=tN)%dVq-)#K7iW*^q^k>Rc$lx$95oQ|iTFCl(YP0^o)vvw3)pqC&8@V{e5 zkr;)XGkbE>S@5D3AM_c3rGfcqu!u`(SL@ouG#i|X6f(@S?4?{}Zam7IB^&4c%TLBP z90IGS*u>)$BDVvM(R}|P-@&dWy#;|!^yM5%BUXw=iOy+Tp01IH6u>-Za3U?q;bDpE z2g?s(-+!msg^Vj^k#hfWD&`=k%?6>qKMw%8N^7J#$0IyR27ff^a968|?|1BP_vU}_ zcOt_VYLytuU*Cf4tAMpg8M<1u0fz~m&Hp6C-|$>mKI-!)KfyF} zJ_-Zwz7N{Hz5MIKj@X3|2>Kb#VhJA|mLF3)CVc@@Wi}w??yx6X4@((_QK1mhik@=D zJ2tn{;~Wk|6-9i5-jC?QuV*@mRQ*=D4SRIl#CNqNt|aLXBlRDxe?8^<9@nW$4)ZSN zI9zMiSd)AEFZ>;z>4?XusgHQUEo;Z6d(ru_g{jA2IgK1Ryy5OV)LO6%Iz~R z{*e&1)-zU2d19RO2Td~W@=>&AOH*y57-Z-=)Wx$$k`@v+crc^Jy@3KQ z(>V=WBdm2KXXTUZaWcksJ1fqIUjV3M4^WMGfWM$Wg372239FLFw zUb^P6M)UVb^q`y`;{rDLr&jQ>*idxNgNLy7)1^KhEuJ;!^Bn{tWTs`aj>`3Wv{uiS z-pJHpJ_MZI9tX+T9EpHY-4{_y>rWEOuErOqR%daa^S(W|*(Y6+9y3+WX%YtK&I?zf zaom_ngIii2$yjs)8b#}}@_T^aP6SUqdcM+RU5 z5Mgpxh)T+}vFrw$LlkeWXj|ReVZTc#$Hj^^5;B(fSKs~3j#jI}l`X2UY$^pe)rHOX ztV&L2?Eh^CWG&$JNl|#a@<3^4k9WBI#ftqQLg<@c8txr<_28m4im#_11KhH+-4~=L zhIF5PLj0Ak(7xA9zJaugb(86Hf7QdN<$kb{YgY01s3OZui!Uy~sn^PZ2VU*66wr^Q z|MFu9Q0y9p7dsQ|!j zxiS4mUa5UAWxIuxkf@Gp8;s4W6R0CImM{n6dZ(XigluTkaOx-7%-s^mJr`MfOUcxAfn z1Y>D{QlClsM?TJUf(2I23!8UU$c*Y|-Q`jSSeHwZciFkHKCRDd&|HR+Wzbq)YnKY< zc-U<{k~xB^ZYJ^n`1%fbs@wPf)86SMqmUw$EwWc-l#!Llj*>0eThr#Ltn7%$>e%6+ zGM=(CGmB);aBz(ObszLR-{0^1|9xJsUay>UKKJJy*Y&>M*ZAD`$1`D;LOwpG5O@6f zyJaKH7wogRQtPS2oudtwM*LglZfUOL<55ox`Z8&fRx!i*1DdaU8XWLP&UHIsv4B}* z&3*5ibHz=*eZtGp-@A+Dv1RIfxS0ygtx|_wlPg!3?iks8``h5%ddJ!BU+#NYTg|F* z5$_z9qpjaUI9IU`+cs8UGj8zo2NUpdpG8B7?ZZ!iazen8U&U|AdhgIk;LkG*pbRSP z+dWuJook*2^nKmaTQhgj(fGh>=;qT(d5jjvs5x<^GznIg2M-{Hs!QVAHD#gLh>cq0kabqeGnozrPnq z7$ankT|NXV1u&X8JKuIKXrRaSN1VU`NE4I_`k;gWBmI}yIpY~-{NeiRM#USr#JWv; zU03I100}la?+T${WK>d~%npm&+#LW@5mYlq%GT6l7b*=13cJfzZSI4aw5?Z*t4v6X zIvlimA&73QlkoLJDHL^N({G!rvRUr(czetac-M=2OovMK6tc;|Uxj1Tk zrQYRNX?EZ0-ZLLiIhaHzUEwUsSOM7(MR0{@{CA&9<=NK5cNk_YsV%HvO?fK))lo?< zJj@+K%6U{I= z$qmOp(_pD^dp%a!3+xhdW91OB~K^*1X;9 z0B6Kul;&Oa+D>=NM!i<@QUH%d9vlI0=PTzQ;Ozc4n{NC+?f+jxSIfaMBm; z2=};H`lS982JiMPzz1?9j6cNl&pnATKHVbaNca(F|IJpJM0oQ-9t0BL1U`RUp@jv= zLsArM5IXCGi{7=;+H^vf$b7n^{jLaakmFRS$7IWa!;;qf2sm{Jcf(7Tq4AZ(lub^1 zjU?7nMmCK7*{s<#Fny5S2-fXze=YYe|F@GKYz3s(<|$J_q*!-OiH<4Yg>Le85Gp-# zZ66EWa@UK4VqG#gCic!ExFJg9m3!}a0h>g_g>k5ePnN~`J~b2$`ZS)U}d#Hyj~u~`I2N) zzXE@7Mu`95#C^(!u}*Zj~je%v{Vp`Yg^}naRC&IltC;1Ii%v zMj)lVF_^C3_t>qZD%fF7?=Zspa^Ki9AC`EZj^^p4&`AIX64VNDaTK@cqj2dsk%-QN z;Lkfqh$%WB6b{L$n^JBn`%Zq7kQw>Kt#cLCk6zUi(%jpDNq8>+w1}PrUb?*{|0TrZHJZH1lh@7>!q4}hyVtCUh>x9Vr zRd1XNZ6+If?Gj^990u<|@0tH<3Aowu2U;S=cZl+$wvud0@XQ?ruWkySE>m-ORmU`~ zRt8}|pvgMtI=<&s4EK0g_o);KLHQf%W;{n`|3zi4$>NDRh^?|=$IJp?FH;`a;hD;I zM}sXlFq>wePRR|6vEJme-d{Rs@buNhPUO`uOhmq@igJVe=e3^v`kn61nc%3Q5_h}% zU57SkyP~0J7PyC z2hORUwK(xn-?B$Mv1(7uEkSOQ?pVGfaW62%Ndvzv5_l*HKW4rUrs$|SdRZP98}iKb zvj_{%dpqBL6N1ifAm$2A$H%KKUb=R)Sa3j4{P^6SV6egL4E2`uHS)LP zU_7>xA46l#ZayPE)!t|2CNt^J$Cr;4UhVF>+pv=d}q1>(4lZ`A@=Pg_GJ zr2pz(0~WfCMU+*)J@n-w02FMd^yAcrv{uIutIVRes&!};zfWAK?)M-AgR666l^lB@)2f4n4T{KI&B*Fb&$6nnp(;c@%+o20ygi%oT$`duV&}3Sy#_Y;+x8N{e6NL5@YVA>?~IT2`+;K1usKY5n&<-MKBBHF8Q02y2(+R zG*5`voiJ9)M)+ z*GB6L+;*JVSjvexj*KBwQ;^woKLzg-ZEe*4T?a`iB$)HYL!5@gWvHEIloNyKPTx~D z9*kx~v5ynVNJ!~aF#H@cXkkO_obrKq&l2jLfh$0*$A*(iG7M0wb*pF<=G`ku$iMPR zZ+%zS$1+J?j=;QV-)`i@$4dm`K-P@0VtK7UOkm4df_pwo|#akXq zM{2^*bQs|{Y(qTPYN{XWV?fWP7-jiA!#%(!7|3mPf`4BN#apHDs_~#p5hPL7`-=Fo z^uMeW{+p6E~KoscJGiAC#JkPx+-Bw=MCN&IWd5sWzGZp%Grd2%AT$m z7rQ8DV1H_J7LgJy<@)aOV^bILc3qk}{QT78n@PK5L)a7SwO+tLPuJHn5%lVPZ`Jvq zRHiyp7Vqb9QTit`x(?39JU)eLM=-?@AR$0}0hu7hRReNh8dwQ9sSM@gbLG@;=ai&V z7z)f8(oXR|a@QZfj48o^fJcNGH%`H3w#5#umU?Z8g%Xl{`%jbf#i54e$v{yM>QV65 zI>cNf!JG&0!kA>$2M^G7_w-l}(gTX0)RH5#uDgCIgoy7{$bOSoX_~Z)#R@fb{A8Hq zX+4Nr7Kobg&7DBACfUGI-Cy7Qbv)k@y!pVRxJ=oqe$FYHrvq7-l783d;^K8W%N4DK zE_z6CIJf&d1MmL+zK=02+jdPUTtZ~ra;6VfGmKOIQtbfbjh6 z^a87Z#8PpGsL3%K&+mUbkw9d56a@vowhJhk(qe)ELtsnfL(Q-;-ad@WeCbh-K|Tg% zUH55#j%mB8lj+E=cs=>0*$oRa=ngb1RVEyd1}}p!2okaHk52CdTL5ulpez{z-_Y!1 zFc}UcIy$KoU;otwBJ?`Gn(css0j(FsniU}n-$E=&Co2{XaR!co;ng(onpc zLZlT?dB+G?)7c&i;8cnC6=k+z_<39>1;CE0=Et;r%XIHLyr6jbT~;vU-$_^gsJ7Pn z9pGF#4tYkqCK~^!DpnTCb4t!n-F0UDP=o6P&wJL;o3ry;v6;#70e_j9q)&Cly;y! z&u+&U^!a8_q}xd8*iBrV%KOekvg7C_Z>Tj(g(o^|F);iGj2F;`rhV9rX%r{`FE0J} z$z|mchc>~T#J2M}Q>5E4batEM?}oIoD787%j5tEg$Wv6JGgjI_Io_pP4c;+8r{l;) zYcbU2J9=&HSex6MUDh)Ec4rE7qG!|n-vsR6#;~PN&Lq($(aEvP)Gpn;PtV`uhj^!_ zixJvK46fXk4X@hwgLAvEU?b`zp8gZ*6<&UdtGo>MlQopv@)e6C`cJl(T{y{LbYop3sHR zT%uHZ8jvzLL0O2keV+m3_ZMwrtiRNBQtL5L>JsaVXAKBi3;u-OwT)Ps2r2IM$0@*V z88(dY-TYsKL!m*?(=N0-3A*CRB8_ayfcip#U|oohB41Vi;eoX?6SLxA^fAlkMZX9m z9dHDI3UDrfHHRM`^3Qb)T^1$XoZGiCGdv#Pl0&=!2{?Xm13Wu=8W_-05}l1+yPX;E z5ghxt!%`8UAGkRh;(yIQY$KIGV0vXK{Z~L8oVJ+<{-~>2KErT0B=|M> zQC*bdP<+5bB!NCg^z(i8Nix`>KMy>*pBKXsUurf)l}gqlQ9LCj@iunx=K4^bKnl>f z)2L>Xo;sfYCk_hQo-AcyNOA^0fr-8#J1DHN10xxw05S4svon$`RWp-$(>$PTiL0bO zd&O!6RmQww>K8A$`#-n~rcn{eJlwkW?C5McOf*W?bgi7)MMO0l^umiIF&vNBqAb8W zRRK@_%~?RH{O!wlxXgP}oNG`$&3+FM4Zb0&3xnkR4QP5Xbp!}z zltRF<@d2Jamh{!d?QQyBAl-?cYT*9g@C@t*>=uLZs*A}Y27=0ds^nYINvod87Xoj$ zlyqbHev-2crnu(q-&P?cXPzH++|MP|DnfO2)Z!34_V=Mu{Q_}ed~oi0r0=3!W9IZh zBq(+Gl3mlgwZ;&|@nlaCP$*D5x*fEqFc8YEnT+oIq&f__9Sv!I(}71_<~Bc)u`{37 zns2h$Nc5tF45q`f0J$$=8>vrk0s%!7RkGg_Ny z?C^0zF{H~jJabQK|9HKeE498Js#N;e2hDEdt;)oA#Z_ETWf1!8?j+ZXe6bXK7?maLvoIlo zZpLtdK>#gD>VhudJ{WicSXSv*_aENS5ii-5-;-nBf#Ttid0Tk@=%PIjARf74-i5D2o4Pjk zz#pm}lz<0?olz0G*<1|&1K8`D^(s07^v)VR*^AONsB-mWi*_$4YLpr56P0=Rn0gsbqGLYHS;)n#Rm}V=N1e2V>nP{CDchOM8OXE>Njd#dC{|`ohd@LxENTxb4&qU5NxGV7TyQyz$0X~F{RUa-P zMI_{*W=f5LzlqvkBmnj+I$z;<6uSr22EU`=Ix$*P1A9JAg@jVsfj4#)9EL8BQ@Z;R zi6OyqrxglahWYs1)S~gPA$i>ChetVNN&7Nl8uhq(Qn@Y_i0f4gGSug&93w9R` z*}yy#1y#SMbo1*}DmaQ!`xnD$lFdh75uwYH?RcjYC~N-hBdDsS_W=SdV!9jkdmkyn z(cRNu|7+++a3A1MGw{}} zgqO6s9lN3cPc#_XTB-eMNI_%L#Jv;bL?O)|7qS`22M0p~jcRm>MVmHB@h&ZC>B`dz zN!|>#e@zwGGnJzEP!E{d{sDW@M$eyyp$Jgp+w7&(fXN8mfpljnv^2 zXzd#H|G&gR6JA%s@Y~S%OZNS|;8BPzDS4F{&;+>GM1oz(Y8_H|w-YGKdFpWi z65v*?rgTHh2GEF&Na^2H{JVYe2Pt_cu+w^wos!YHfOLc-wB1bWPZazA;3ejrCCcOy zI$srE9p-E367KmW(OU^7O1$~Fw;c2gW7oX_nKS49H+2QK564Cxi!J zGsdi+CAdeV_*0kMo4@P-ST1V1rd=$rcCn)QxP}Z6pf+%?C-wK%t)+urn0@zVz`)TUsh+jq1?bVYFb8;C@xPfQK0m-yC{<|&awUj+=1pYcLUyc(%L`=KW`P8ernA^y>P!r17m;+kLFF52GO)c zJ6mLqex>NJpvcYlUUl}MrdpVw4!MGoW1~?|ERIaP3$-b6rQ_^?okupnO$#N?LCJ{I zvA}&u*^SZo-dm&|Val>gI_?Y6-J-;XTVF6H@B}KyO)lkDLdMP8+MQkPU2r=e)X)Qg z&-lNX2c>(0C^G89yWmq##?!QiGlYen`faQ4maS6P0;L#km1q-6*KijQgv&$S2~pgQyw z-ak{?NbP8x#v!lEt^tY*!vE9bDpNx|%^(UGiT6`IyP7CSU5#D*0Ci859?f!xj{qFK z^WVrGZA8_ijMyi+p|THUn|HyjS{$gZ3C@HGetU6GVDlPrbQ#$+efY{tARFxpEMKvT z+qdE6Nd!nMXMM8-!`$8i_7nrV^$z!36|BGLh>+bBC}3^PvM@u?xBz@v9=Qdu|EWQ| zB>p~(-;7W<+HCq?WeXCy?Jphz`F*j9d~Qvsmiuo+l+B^u^!G5BG88?NiuP6@TjdQB*t>9Oa&mHcw)%U$ zc(dF(gePgbfW3O%-GEfsDtH4@Az2m=9BczqFVkW6hr93`j;;REyQ$B{3+S9!CmSH^HSxWo zkQ;o$S2TWT0M0>^0|y;JycR1I*lF%u=Ib}4qJ#GsW+SQc2+W)GH_b;dzYl&?{z8Xj zkMsovvivMErP9q&A`?^{h=h?K`~XAu;-gzl<*t|GMJRcK_ru3hn4dVjAH=NuJ_HdM zQ^FzYi*g|lx`ks=ARVyrc$ZULV}m?#Dq6Gz*d!9%vKO$ibhRY?SAqk*@>q{7pK{>go6q+PdR5lX!w<5y!_7J`&1q_51ElkY6(}ZlcNgPa5 zJk$Tul{FXp`KyH(gg5a8s?~TE_MjaxkFU8-x9M5ZW|7{xO1J*MI0)ulBFYy_zu`VD z-jNAqAt>`vI!88X^v>GY6CP@C8Lc*zDRN8UK(->tP+i!KbkoZ|0Jd)F?B}Db8`ir% zg^V`56SR6)s-&O+zMd`zJP<&N{7)*>`-cG=e1(zhi!QAq>lrh}f&1G|$%s&*_ivJ^ z1l@q3Hk^Tm5{Y#UMO#RK>CoMi#S>JJ1#x~TG(}ICyOdMY%MP*JKOte;ZAsScAg@mhfTcB&u@#S8xtIKW~yKR3qdCIo-!49^{x+T^WgDaG-GI zH~udI0pHWO%-EDbYz+v$tS$Q_Brg6V;|M82Qv4Ram(&g%*i}8V@Q+Va?%4%(@8~T& zI=dxF)E;i-v(BF9TNT(L9Ed~QsYf5~ug~9|EbbAj( zG{IBN$wg5n(aoB}4TOe0@k=@cd-e8gy4bAIf5F|I1NZHZ$ofW4_d6&9Hfk@OAhAe@KznCQqtY!CK zfIZg`gms+LfW7yr2z2|Zq8(3aGL3%e=3B#Gid%VsX zf&ev_!Df;jdCMD#L`-=Dtu;hTS&-(y8%g=a@L1v>`wP|FDkRFinVcX+Jke81{tARZ z%!KkQ5}b!;2m*iciYYK-pS<&LP)Y9EIF@N~eZ0r|uNHzk%c7F3i==~9@cUE2FFNbK z4rkk(kH3>laXa^plxyHa21`D2yYvgCg}Xw__l4lz)f7I|Sih!P5vDACmTn)NAX7_b zT}P!~Op~-;T1D)h&v{=X)p^s81ZCY%NbSj}kdpg;KYhOZ?fX5=b$p52T#{Xli--gl zb^AjBMcyNXf)RSwUN;B?{pK{EvIZb7136t3bJasQ*2s+{_w*tPq>C+jQtr1597zHl5gu9B*-P`v4{t=p33 zR=;tmJ?7N8<;%D%=1;F6A}8r8qP6CPOVL=v!D;3kp`$6s=D*I&f`|Br z{hF~z;Na7J>M#(PkT(;7@X#R`85~C&qt%j@{v~fyc?^EknbBn# zf>_pezeLl$_Wqn}3sdN5p^gfd?pn9jMt}m78$!o}dtP9Cm3<-5B?eA>INoY*!zPVa zU7~#QAwWW2HQcnVUq_}z`;17V&<<3@HI)fi_xXk0%yTlvgq__xb8%#{#wo}?72 z7wf}`*Qskmpi4=rbR!X^DH=CJi&aSm6NB;16Ab5CpxVv*DNp=+=i}WMPWS}Bs1oerFc*I6V|4z{QySta!l~&gkF;+qf|Hlj|Rrq zrCJirIIM)3{ar$j>MKdHhi%{vM)B=0`w}#smbWmT>!s2PVTAO`B+k@+LKTp~Q<$q# z7q4HJ6;9?FRlhM9iMCaMOEPV&VbDJ&Z>7h~(BJ*ZhguU5UV3I13?|waBtu0nRGYds zz}M$nBs8kpA|Gyz#hNE=$cE%4_8{L>_dQt-)#l_UTkc7956qt@++Q**;*L0Xbvx#l z`n*=Rzcl{K5cESY^?J1(XxWmHFhiIeDV-172*2vkc+{jk9>p~h5xsLKre#V>;oNBD z&s_ZTOJegWTK+UVH(PQxMG7<8u2CbbM^0qWo7UQfiM%o&f`?U5T`~r(lur`Q9;ClP zHUCy)kaKHFYE#p$O~~6J!50dzp;CJ6%ZMpo5!71K+z?*f3H{sUq1XSX>|!Dx8R{Q8 zEK|{Jh{25BV@^Id8tQ4aq55zAUB1m$+bLvz(Pi7vN{q=l4c+Rr4uSXmhcO0kNAn7) z{9OjMkL~7NqrIs6wyi(eC_6=CDLM}_Ea+-1%@oYznyD;>#bgiXirts?`InZ`S(WXL zI@c;f67*X0zG&%;K9_@n{pAF`JL;2io5CcSFtN9?H0?x?53!Q_jj%MPTr@SkGBAa8 zv{K4;iwDyv#R`!8 z_CH`&6U=~KsQDMGD1>6T^`99(^NDH9iGnC@b$utsm(QNVYW~89|1P1J zGo4>`N+U83QmBqcC2T02EJK3Q35?|r1qHPh|Jk?QqpNe=YHDr$psK8Ke^lE`%hK!h4&1fj)F0<&>Y-`$mD)~*c@?vfy83JxFh5p;(jY)!<;nLZwd5hcj z+J-cw0^GgTx#PCk$IgqMkJU>w5@7Qx(hRVzcZY}}<<6D(`8y^GmnQ?4hZctk@MiHNU6An#P`A63<+;~M0%x9q6su-;f-w4$fe;)*g zU}}zHb3mT|Cw^ec)924E=<1d2J&~!lQ@H?y#OHGYm^?m()(|{^#vS#{Es(-AQimS? z`+bD*K!Rc4;2r74dtz7~_T7c)iE6#Cxts?$Hw02HNjRBpR6W!FACiK>q;&nmue55Y zRK|f2@AcXZ&=He=3mDY=l_X(KjTU+De;#%v^zfB)$=?b){(c36YW{oBUkr=WJX)@P zT_By!`YTmmp}D2zr$Ho`)wfl$RQqi+Hf7nXDrEx$rJes$0|?~r>-)>FZ*Ex{!nP| zI}$nsq&f9-pE^$3`FRQVrAyrCIACs*s)jHGNLNxt`*AGWrfJ1s4ylkhmYpQ$W!%(2 zHiMV*t9RAWVCGn-Mp~uuqw4Sd|NPcogd8EQgoFmN)h5Qrh~k`V+f)2Mp0v$0F<22(g!@~1D-5ua)DKAt=TVso8pK6@~DBtj>&_{Ju0!ZaQs zDHnrG4gCi49gxLMsouo?rL0B>cTG(G@xRR+k|0n(_0{0nI<0O>K;P8#y}v@PYX4Tc z6)Y5v#4{m9phv5_o_im~mPRLi-G#Hn)q#|gRp~1L*CEH=b^=PK?*` zhSP#5RwBd0D&=vt@hEFCp7&EFH=})g=mJX$U-KVMs>#ZTomDio<`=rA-|@%LU`}jM z%-hxAA4S~tbN6%qosr{P8vYxLgQatRjn!v|PD?N>*JPa|@6QYg{kUnPF}2|cG2eo- z6|z_levc8u!(T6k4fQ$o6}-2rsK)sCD9-CetI~M8Fc``z99yPj5xf3GY;&X$8nQL? zTpK2hN=xS}%fcP}&Z8rqS&nl0utLcZXXnnnm6l>{e{KVn_FbH?VP) z)5=@mKo}PuKX1DRhpF{8HJQ+$fscS7F zM;^hDgpCX@^{p~&t^oYzg(3ZfMSfDLg%s^Ua=K0GgYnum&AZQI(mkjw!!q_x>eMrz zMZL3IC&OYe2hKbrCxWiFH5KI5fxvutDH>nm;wZ?_<_967jZ5>&Ro%)c`?&+mV%7TV zl{Z6{VLJI3C`GoG0b}rr$)3WxEK#4^_I>|C<;%=IMN8UIvLx{JH?DZ!GnpO0_eB^D zlM<~(7<10fTl)EU(#ZXp4oUK>{S~F@M%E%M42I1LCzUzp@uxPnQiCSqznxuZ8m*U= z@&vn{*|z6jBdBBdtt|DZ?$sN*3G~4XpQ8#M?#9(PepG!N+-op}qa9Q$wAqK2RrSG6 z%9!JA%?6Y`|J8~jrztrxJE+8x76JncZ7xGCRj*=w1kdtswH5#E+(MIIef7Z`tZ(=a z+sjm#NU>AWZGGD~{`|)HnBz~&TVU~Qt#%XW5B+QK(r1#<;9W1hPooO}75S9cE0kwr zVl9<^jOI@Ztk3yyTw{e%GDGb2j^Ygbt)xDz`4sARZ~aD+O=aBZ^jz(%jfk1R{=lUel)e zfWpFSxM1UahbDk1K&p*l{_+0s;6An$2mEz`3QO#e{RtSlt4s(UTbdo3k zqZyVJ72=Uiy~n#9y*J%N2=_RA&95xgDeWM~`qSCe2&sV^)_%VlWTl=v6rwO2mkIBL zC@iIuHf+^0*+u^)YU>NhDAOUsxT{tfpHKXm!Bb70?>h?GX85y!rpNwjW?l)z-?i*)6E#OW6@n*x2FC(`^fgT7W~vDPr)rLkIwN#nV|}Nop?;f9{_9A8cR*^fEiW8K zr7HpoLw8p`@^eM$wSUc8W{jV^Ir{u6j%zCl1R&ItCyj(XvaLM_vP&{fM2Jpx^l z#pdB?MBnbaF!ZNvS#pS{Bz06@y2<`$y1atTmypPg2l#{rWitiVO|OYDY+4smj}!n$ z0yxIH4^H)+JHOF3>Cu-#q^SRl+Jwr_oju~C!7uE&t>0jD-X@Vm1QvnLs3unb#{NHF zg`3U$f(~=5R7w5$EVuXu7bxVdF;+mtyNiF>s{YfB7!)Sly!f7laiC?4_0b&PtKD|| zkDO!Nbl8-jw{9F6eE!t|et&?-#4$q$M5r{Zjq%^(9yILJs&4;kTq5JV(pa9-vGo8i zhxX@4t4t1A-;bgCGsMPvEqhqFCZ@IsR0lx1yd1#rrm1Wc;h|4DwQ7(Y8{U;lx3kMY z=Cro|77Dp-T$0-6m1y7@mUi|1Jc)+?jPP3?$D-I>I_>*`^e4_H@gI)y^-21QZt{Ap z*+L=j@uTRt*w060ZW8^Ua?ojh7_H}q^atF-5_6ooO~9=Ok@b4gh?Nh!@T*VD{oZnj z;I^X{pR*@@e1=zB^?iMOJQvA4#5487g5bYvG;x8wv6D~NT&kEiN}v9O8;&wg?&)~4p}4JcV<$t1on zbgU_l_B_DIMen=5GAZ@JaJ=I4qUZYLx__CVE%VxB+4>oAL3cQ}PLRcmvb1V$Z8S@V zeX>s4G>Z~1)^lOCD0sqyzgI-pZ+*FMjWuX}x*J z4)Uf^rI%}D?Q!fO;2PAESMh7B1^rz0(Y{~Tf9vZ!LQ^f&YF1gA&S=gy@=eqPWa2#_ zDMXLSPec4=E{uIF$a5vwgXc!p7b%Cj(d2W}tpjG#{sR&#w#}=UU(E@bnl_)_^tZcM z`6y+5sjYe3{^Y#Sg!QZz-|Xx&>a`q=0f|67IZNNtvjil~jmn@huU*<$$-I$tmrKis z*~?C4t;u!IzHDu#{NCAWC+$B(cCgZXeQo}1teb$`)SC0zOLWE;`A(B?3CrVEb%uTMp#_lNt`tF9epxm~ag1FRiJ+ zHsHNmW^9!K0%0an=@cvwl}eP>#Vt4EZHUVaOmF`dpg}8A`g^o2*hpeU#mz4N%n`5S zBR&*q=V#2t1S-Pwt*t({79AL@5up!elr5uY38uLG89H!QL|EM8G~4cY$_zeS1C6%p zD7+T`Qaq(32x#0S7UuG=W9@cHiBmZRQj-T9^D51HmS(?a5;?=@W%b05K9O)gCsRr& zdQM+X@jASZdbMn3Y-TQY&to3>)^F#QkUH`r3>!-wz`0(=!2?ZfzqkdeUNvUE>Lq~CybNn?HhD?BU~gU8 zxV{HoPQ10tLM$C9f|v1iy&NJ@|669QfKsdk_pyePPEBW+PCXDdobPNX{Kf9|EIhb^ zex07H>e>1jasMwE6YY(e?H7nIDVN0Ysd-sRgZ;lO#279CRO+Hph?EwwRe9bQ?xht= zH{c1L>^XmAYUO*eim3RBsCO8&p>H*Hj zNhScyU9-xtxkxDB_G+IGQ;mYo&d8bzx~6Q7U5lN(qUZZN5oGRr)ghZR44Vl%!S)nB zkQ6aFOo#jNTj)tCzr$461E+Po5pE!@n1RxM-%d@}_tz|rW_kS(_9G&*w4pxTc2IeRd@$9kIS!G z)~NFBg^$ph7k^@hEU#&Wa4)q4-#bQzYd%nm7a>81hS|SL2$JrL8LN0^5ISGNe0E!= zNNqS+1*f4seSxxZPG8NOP=6Tx-1%NWCC)@b0-{~nHJFF&FI95u%{@FC`2WV`(BA+EGyTVCOpVkq7e-D$l?Fz{$o4+E ziFBFPbzV7LGf#%PT%F@)8(rlx>v}Fs ztUqlnfdMvd2Td~$=371h;!W-E10LvUJt$)FqqGM_Yp4K-`TL>J%*Qn`@VZ9L?nCq{x0+@!TL0q^T8~A_uZvhh{AWHR@Ck6- zm8)Q3MKttF%v|)XrD!RjgzrpqGDp`ylJx}n&I2;<$({pR*um5Wgii4V0`U;AIi%IX zgj@)dqlzSECC0<^>QJ( zpyhg0JW0Mw(I~rnPi_>ba0O0-OxjwhfZIe4D45N7>*X(qs5b6|MP~vR#-`eB)e!Vl z4*u~=O9?aZ%T`=@@$()7GxPq~ndcy4E_Rxat~8^yw&={(J<=$1BVCIe*)=(LKD^v} zu1%>f-!2yz94t^L@S=vQnr`2PVN~ouIWACF^~ypaL^%iBlrrCRmm%T$+6*a)Eg}G` zl3q2Hma`((x{P;sKrqvkokCBYPVVfA4!AYX1mLqDXb0cGAyw`ev#rNQGjqoJtbc@>kuJ%bz5!;|=3x^>df3i%jhx zT#*tTzmn4A>+?4ys&Y^nuwDqf9K)kB-G#-n)x_NZ$KcehkYy7w#IxVd(+ni$Fx`^$ zR~b#zMG7hT>FmNbAPvmRddqZsc;B68kb#8ao3m!T07>0o-5$ZzyD%gOFz5yNjywRC zaYW8NHyMHSNI5T9jDsep;e!_-vpt$Pv%piZdE@o~0eqC- zvFN-XtV(Y=@E#w`c3qNOZ8Wh5F%yux_mluf<)S8GhH>g|Tg>l};7JXnNKCJzO!i1F za!(cqs_BpHRj^eI4Xwd4+tAfEw{cJH$= z?Dt55x!ld;PMILAS2REJ>L&ZBALyN5Z>-hLzs@3P0^_KOY&EwmXo`l?&}`+cH0N!Y zQ_gU+5e0+q^mNd~C9hrWSmN67z9jLZV}SCN$sC!o=pL%bR~_wB)DevCJh;eqa{z;* z{eTk37S>;#y7Cx6f{N`%26iWVJUm4Zc;czOM<<@Fy6ObO%?5{GS5;S2jZ;BEh8WhS zn}?fB1|rEQpI1p+@@zvv&OjlsvVT#+;xD#j=4WR?@}!dmU`LwA+kRU#hfN@~e(06` zuVpXHP8=AZ$~MH9;Tp+_B{zBWml+J9?m*m7j0-|>jA=)%B9ZHuUMk)RZ2+~9bLXx! z_tp;p+KOCZlOvVl&u`mEiPDmfIa914ax}g;8lHaX3{G#kOjU(KE zIF94QM3$YfSeQfEjcHERblVOLyGhXo_~38MwJpgQQov&m{LL!m(@|o7msWH-`jkPv zJrItReYoF0mv&s9X`fnGEO9J4wmx6B+FIGL-m1TDzcNUq*SX)PUubo8WraoDW@d=3 zNP`;X4zZ^z+8W&;`w4y zlDv^L;SB?!%u2a2`m#W`op!Y7!qZb=We1KCy&^eoerFjUAlLwjmsyTE%dvf8>43NoVQab`*%&Z1^FE6)9{Ira?98VAE+-&84ZBE6jR zt=9zXjeU=MQ;T798g>mW4%$^`zu3a;QNE2o!bs2DTr$$FsBzITynGh zDZ-&4d<|IVvgbfMB71^=3wPTS@W9>T*7AV#B{^MrL_Ubdo)LZUW}oRmTm>X_af zbQ7Wrpxrxpb~Mma`%$gWzj7KICM4dhacdp}h?O8OTMwORavT!gb8~DxadrHB8riD{ z4sQ10_uCI5$vo+_lA6rRGn zSV^qkdzXzk!$OtR=P4b=(s&eh_^ z@KG8*wB4IbUbtwKu2(D$4hXx?2}R1~UXxFE+p%L-`dQxvYTBhe`=}BI-hNpfdNE2go zRA50+X=LM0=KUV2ak`WcY-u}?u-i4x>8wHsuvf264k=ug{y03Y#jIz7CWMW10QKod za##PWEKd$`VQo1*41H`MUTGo-m`~kY>AB@e9V$@$UE6YQ?V6%M;*nYG(JJ*)lymRT zPdPJ`Y zjOPXVupphYA5&&4OS_(6atwA&4fcSP4^I&#EnZoll) zhennCowp*j><;jEW+tPa$VvirvY@yFYgk4h(}H-Oh=SbP*&p9J^5@q8?ccC}Db0mV zoDH5LQz|!3ktya~rh9MVeZm18A+;x&pj#O?-ot@9p7Oy>X}rdd7N$xIEdn#M;taqC znpo(~0V6G{e$d$dU*o$~q@=*+KosWe-jtiN$k0;jxQ^a%Ay~e+ofQu;L)@f8yBRcD z7`eo`Fz=6=OuLD9!24cR>vpN88bI@{AXiib3w8nkI_eYy15rtWV`mDeFX3#6l1+P0 zmyWCP*ryzv<=9k}uA}vfO1{{YN4i-5B9fWY;O?s|&0_$${4SRXfhlmncBweHjbGOR zJr$g#ds$oY*~t1V;fZ~TavIPb5+tY$K8>D0X<2)f^o(5;pY9T%sa8r3Q>g+Z4o5tIZ>(mVtmohxg9x!^-->JkI{Gz(| zh|G>G*>;cn&b0KlVp$6iVADy2roQk0WosCBp#-(sO;u41d2KVs6cxZ+z!gQ zAGnp!O#o4p#$v&*!c8vBKZHiT&izX3Xy-z5X8gJ&(+Z~4a{YR6aEzb&n1IYkPeBYZ zy68w*j*$jK+!B|5S?$cHV^O7xWoN{9B$YnFGm8O4zU7s-whVi_bO`@A%}O@a5j#92F*}P*DowVz_&#eK%o#+`oUcL`CBL~r8rKi@8S`>+x641a>aOoo z?I6)b*)Y`q`ZZaDaJRGL>HFGc&kOJ3Z{I9P^q!r10t`63W5^SfqdQMJHS1fZd{=&N zpToM>E&lYsVU4}6{#F?uqe5>62HKoHxxC!27ca&?SdD*IPgg>d28A)_^(T~`QAp}QrL(+{5y~4|8@+;qr zIbU`Hu3&8SVWPn`@_KK78X4BqH(j*!A{1SvbMvs=;?{Jl9v@?Eyf3rhJZyFOpEbD7 zo{(Y_a{68w7Aev{xw5}roX6CI>Zr+v3%^mE3Zk98HPAmVsi+(@ zXSr~OAh4}@gb^+|io8FPHzf84AFgSAnx6c(j^~dero+)va-&)eAitDJj(rQ;O@2tU zTlCFH8pf@^@O)R}ztLa~Xz2_nEcZHRMSeyZ4Pc4ohcfb{(l%um!bF9F)bf&&+s6kl zB(?JSgI0CXL;|NwX--jXL`@?X?oBM=1g1k zvCSOdG4NzC2S#A&4O^E3f0srQpk04}-+LI2pBYA#Qlbs9p=`ALzAq~5V-XZWj_k{i zg1`f~9|cp2KY6DhaL9hMZGs7!kz}ZAttjqWZiUlb)1sdJNE$S9I8b(cA5#KFwN8xDLLkmE7|giTL_kj2qK{gpOr=1C##4_&1vUFK4yGJm>5&Hzjs zG7^|8w4_NpI*^f=Rb}6v75Sp^xc^3#w)@n_UuiNO@+PAyW5~zdC(|?#78fyT|3F{^YG3#ijbzZsxmcTROua-`| z^)>BFUi^rbkk7jzEX8}SupBO}qg$%~K@C6bk0ng4S`!4_pxvW)Ihnz_LnWbC@&bu* zI2r*6+k2)WvzW;t=RWZr(t+6Rxq(58Ul;0pU8?kn;l)Vahsg~Ld+ujL^p*2#jkO)b zM=)o;=o}+v8v;{YOdz4Be} z-sjxVNyNrLQ5yr3ihDezL#_u~9qBkg%Ea!7v?v^=LH#=?tOxTQua~d!(ia4r=qzHV zR!a*dQM|0?FenT4ofdL|)Ro1Mu4rb{Rh+UL;Po-sONQs6P`MOfyjwNSjf=G-2y<&r zhoZXhgi3S2Dx)n}{D<(DiWdcaZww3>7mTH9Cqn}2#r7Ru>Mf9Hu~-2BY&C||CK>@7 zK)jG$zpdBmLrg)AT!W~>4ohiKb5Q@N(JENwyF#M#U;L!uYLgT_eZ1w_-L9mZjN=3B zv#nVb-KsFszKAM>sgMEc{MsA@z(aV3r#`6hwa|?JR6V)@=Zzu&-MQN2M^6I~;MSO7 zI+h-vU)k2#fmHPuZ1DyrAFvL2wX$vbnUzNS>?fzJF)Fp@igOGPyJvzj#?+E*bD6@4TDEdxQB1^{iFqzu#@9`IT^1;dFh=B>vn&eEVXSfi$-pyojR9xG10T;){mLU zdu?$=eqJg!ySddsi7%~nY-mlK`H?=tM_xQhxicwxIg(u2HgD5;_mbmOz;z$-Eon)v z)!yMZkO&o~;iDcjPivTEVl2>YHFXq*)KU^BJ6$qw1;colqDH|s@kqBy^`Jo2f_Z;x zHU7Je(_gis?zNo_sQ~gt#P)fetAo@v_$QRnSLyp5vd;)st)$2Qyin?ze^W&zEYM6! z%8e!Y-PblGRC>y(86~t-hkdnVnjd@i7p8hrreVxcXR*R`;>1;(?(q*d$_1P%Vz>^Y z5K_cP&q?2v-W%$$PgB={j|jWb;lS4f;bue9Y< zqS>+qE^-A^e`jiM%;!B<<2Wv7oN5kd?UMpB0*Hg}0|PyjlPhCWl?$9FA008UyLcxo z!-6u=>^Iu&Zbl)rd&h&&S}7K=aE9Az=cB($WMqz7t**}JKjdX$TeOWZva$nF0v<-; zGZv?})z)%`WnGNK`jvxIa>+y3uCI?yCOk6gdyQYeYuhnyRsLf$b;%}jmJ5-7iqp-`??&Gg7N~pT?R`1aMyg z(U`Y8n)H?xRzmF@%f9Y&(tv#`U2rk@4(~;_g-%dnly)sBaBt1z@F9?^FzY4F;;BLe zX;`nDRnfYJjSsJA-8@^uBe;6wE!)p#%Zx8zo<+UdmA=)5!72OQVGhptefcTdZ1&3Y zm>757y|J4`qFSNbrn4mPRk=<7$S>*ggs{`EjeeqmUm)fK6X`y&(w+RFb+}#{6!0}| zb=AH-^@7}TN>Y*#txt5%En_&Tx(6O5;`s28?pk3T{xVGOH^h2Bkjlg}SG$T;@}S!# zjn|>S1Sh=jShQ(Mm&7_KxpN$g?o;E3i(Sq0*}#3#`-;TfQae@QvaCL>bbW6fTgOhh zCJz_=70Y-Hi_4lzjw<)`WJ;%7;LJ#TI|%mDmT&3fG+e=El6$*~RrKSi<}0@gKd3L6 zG^q#BI8=SF^>&kYTAjGE2ndu}9(OWG3875!@&0U%WlTrxT9YI^&IYF**jwe$NZYKQ z`6bNyBCSRA+eq**k!+9b#tdz>yYPt8eh3}xBcnSU(!Xv1}FQGflv2YfEP8wMWo2N&af8WxdWr^b1%WPvk3)UaHyZWJMy zl6*xMt`XVSO-pyZuJc=AC0thRtF93|cVO0G^n$zI{g7Yo;3}?677wS*bCAk;MAe4W zSkAy@%-idglR-Z_uCSI14w^_Uc{t5B%e(89366KS-6(qv^GC0%Wc}pgj$BFe&|VdH zpysfzwl$NA^1Iz!_)ULN&B%nW3`JkQl_YaVd->O>W3bx=VWDG{sVD;fszP}O?dE3Q zuH3fpB{m?9qlO0R!%coy`LP`TsLo0wWT;~GFVr>i49ktj{cob3!me-d7x_h&PAxSy zWwO&ooOjBp%a`zN54ylR&MP!umPS{e33dtsMXnC1m!fIy6;*_3;rIFx)sqgd+nL!^ zsmAZBp#I=`=Uw}ed3vruGmF*YXZwV^V)Qg_S5aoR9wgHEwnbI0>oL>UuRXAO(0svl zqRMkc87`e}wRW*I6g10P?*;#G_N16R-+oRuODh?I9!`jyXb0Ox$pz- zFlcfpL%&$&mRrPy`7N(tN1sSNCC4iqO@4QhHtJ1HsCBOiXNd0W&@eY1xtZzab6qF6 zimKc#oIWGfeYHKtHN&+RJwEcXd}Z;~^Vrw#L3MdznyC-=9UtxDg?lVBGNtMlE5SXY zR5T2brF8SCIcE|Z>s9ydEnvsRQ&VcoJR3)+60O$;H8}0TzP>Kr3Aol!%nsDy|8!%& zn9$Nuccj3<=iP<*J9yycn5v>&9hyn|JYLP z9q-NsFSa5j#Nei4ZFZP#qm4R#J@)l1Gj?AZdbiIB~U}A3ju| zeDuiIQ>zC@{ibKAR~iN8_LgV(57UD@FYU8ZlFvCbR9#G@PSvuim(CmVqr=vt>3L-xmF>p)d1Vi?V4}y;r+R74z|j@>GHMpY zpHTPoo^UKixlaE?nOvLov2os&3KOR?6f0lvU8P%8zCXz6;_|xl(d5jEp;$`}(6B)&4rD9{{nivxFLsOH2G{_MlrBH?WHvaTj<3_23b^ygCamJ>gw#(|Kt`6owJPJ0zQBj4 zbSX&b*RQ^U&baLWND-EUp7v(`IFdW~;-*I4rT3F2jdKsFk#k}qSN?!Ky3RKPHm;m| zdUD_o$7_?rcNVV$LVBsm5#LbwB4%HZ@@ zhzs%!z8fi(=W;zV{JRpuHLndZEmh&q1O_YiJeShB+ZA0~(GF0FE2!Y-Wo9LB$DSER zll(g+)+0z?yt|a(Np-r4ntphmw@sziUGaE+Mvw`2sS6Mcq@D8WLfkWg)8cWwH!b>} zg7*?IGS#=~3kc08JQPhaDf&>c!;9dt>4|W@S}o(!U0mUWqi&^rML)0FDTI84T;)bj zJv0p$ZtJG4c<@jVZmT*tM6;;=IY=lb8Q$acH~nbHhlU^acB;uP@MXY#Nr#xEj=b6Y z@*`WZ;%mJ<#z)~}@_tK8sCulf1Afm5mui1O?)K4&JJ1XHer)JIQ`I*!Vq;{yN z-SpSKw0#Lrk33m-A@i~S*-{Sal`y9*s6E9hW>yf|aK6&j#@3+04CO2KjkIMxNmDm~=w! zr|`yxg?9>C*B;!l4WD_DY<&`4hbas^NHLMP(tE*yYvdmn#-ji3oUk#Q`+nr|u3IpR zW3p4*Dffv=?J3N6dVbW+_6buJq#MV0P$g+7veqh^k*@V1%m81z!9-xcDBi$0TI_S8 zzN-b#|E4&NiQ!%&@|b-(!~n`^x^U|$@IDy8H;Asw>Q;LSL-^nHPgHu&w`;!Iix`(k ze}(qf2Lo?um-d?A1UNccbECm#raY*WqIy40i)y$Z~;v(^d0?`*wOY=TBeG@LxZ$15jggm#Wku7 z;A0Y(dWyddaG#nExib^&EQ$D8c(cUM2Hyqvn>6mvC~zOA9PjHnRxbH}eP zF*{0G>A@LfVi~P}rTgb+Gut{j!BbHCj`Tr}G~aR-hLARr#rx6XTByyw3s2wFQtj%S zbeg+x6y3*kE8bTT%Mw7R+(Ra`g{sgC%iDcXxe`mw;KoskbjKfrV`jou^R9}V`Y#p5 zGU5DEp!#q0E&D-W2GdZm+h3T@kYZYr_)?!1T=G?~1_cnN9?;TQm3dBCg`2)eRn~t& zc4m6Vrqg7|R(@_)v5JDP#i3K75o|}rw*=1DJ%`KFk=sLwSoLEUHb)5&&ra;PTRa{i z%K*s{>)5Y?2v@8xidYZ3KtBIDu!$%c6v~ah3+N2SA&kc@v-wf)04FE5Te79-3RxP9_%OG{y8{|LN?p+LQqf4FsS4ccl0`Q|r$b97eeH0hCi7Ib-!$q*~+gd6QTDI^rUZ=S^#g{z3 ztj^2eh%lZVE!1FFZ`n?|Q52IB7k&Dk;R>hk0&(fEaI=rMgaud7_VHL%6;`LOG!DpN zMU*K(x5Aszs_nhdk=2pi^1F1DWHg5EHJ{!_loDB%M_SS^@Bf^6yDAY>yB+)lu;7=w-KqdQq1LbAf4tBJoj~ei?yTio5SS671Nixg zp?K)R&WN0@H_XI+x#PWRfT?u+)%Ue3m-FZF&+@@gIN$;ky_}}l{o2O_L*Ippw;VMQ zwNyTwljai~CJj!ONdP@1le5o^^IFbA#|-z;6=XyD5cyUfQoyX)*nZ08HcFTFA7#u^ zlT{c9u4`U^cNZQx?eoK)V6?E=SvA~Fm1rv)_EH<_`N`>!t3O68ql5xjGzBd=$9a{x zlG62yTYH?hfV`utKOa&MIj(<^Q$58F)b?DK=Z*Ij5m365sG|o1xFN6v-J6Yb(zUzx zt!XPC3M;Lb!rIgI;WnwEc>G0{Lk9)HMBCmdtTk(5fAXGTz35-@OT;*S$8 zf7SC{CqS=G%4@ z<#+tMVU|y$>2Q(Zx5*I&!j2Gw<8;k2Nryhu&*5r*3s7?>Uf-n=)+wngf^J|w?==Fy z98R-3l>sr!5-X|&Lt#xpCd3+G> z=~!SJBxq_QWS&AAqjuN2x>9Ez56HbIITBrb9P&PqIL*K!U?hvuQqCYAtGY7Z{i1SH zs{d+oxBIBv+<(}P$sNcf@ZRj~g})P38TT%KBHcF+=gvM;B7EDTD2(&HVR1{0lpdR7 z@gkp)E^hG=cfrTx4RnB-dmO8Zt5@gWa0mMoIt#e-IUP&K4 z^l)XRt$3JfQ)It_viLt5w>)P=zgah>FVu;L)}kWsLv88-0ciHkyhq#fENhcsw&J_+ zboMbSgfhmqi3rKJq)F5gA2b-cYU3qB_nd1$@V3zjsq?z@)BL^1q0c zmr>>uJHscPW3++LxVHNDGeBmS%Zf0Gh3tk#1N_CIo~qL-Fyyo?h3CvfxlGs zMwYf902GyPann-D2vXY-Nr#ux2JB;;YUUAlEPiV7sjCILUC9KATYmk zQEiLa?zBEmk9x77EgQDKdbP1KHoo41D|qLbj7x{vgl7;_gfi4gye_64&|ZbJ2x~N>^lcmG>!2kbG)WZ|ruXLz z5z^bFpxZthDpeF5Bdca{n7gm9=6D*=U({!wQ4IVV&&dISYuJCY+3r%~*ys36*=w5| zSg(gse^ckJu*uRXkGoOUG>liHeP8k9NZ7)aX9ED5DnRh=TLq@bo1cY>!8NH=J0-5^?nDdO|#j7yZp``Jfre z>`K8PKDv+{DfPPwIzR*e3O8t7KVeV(qO~iZuG;4SOMhy$^={2%-|C_Uu3Bxp@{s>3 zeZF{P?$-ZMk_Fs023jMqvg*aYsi@VdqFVdJJ!}h{I2o>hN4e`+N|f8xx1VsojSy>d z;QM@4YL7D4e0)vAZ1wZ%vY2JXJ7irzb&5QL`J;k&e}e3+ffS9sgvRcd{m)qFnAI6R zqhPz=l*@zAs>jVqt0TboquzUBhdXD;(d93~Sr^WweGrUCQ7V#3nZ)Lkr^DzA7W%zT za>*AnRQ%Rl#H$aFE18s(Z(dxjpIWL7-q!LVM-U>T`2td1G#=<(2@}OpluqYAffwu# z**!M7TBCT~gvTobJ^1CgT8ylcw)o({K*R?=^9_uZYk{d<2(J%nuUcgf2O@Y zM(7vIh0W8oCnGetPbtpN;q8&??6*r6#rr10C09M+d{&> zuX~qjD|1Mwd-Lm`|A{~|pAUl&Jcw~9oU$*Ki%k!ypB>9!N_zm7QNW*_#7>JFx7ai+ z06i?R|MOaU3VF9l+9lc1!EQiL(`JxK&0ex#s{}4E_Yv#1W~5~NabS$!1P}g8nFdcz zKK*wX2JGQ>EZ}&^J9@umKO%0!&KL+JnrLX`C9}b;#c6R9@l&Httm(ZlYEg;_dX=gS ziJs?oZVb4|wy<@lNdE-ARZ`00+1H^?0|$He+jPDzNU=hK!;V(?OEfmqUh~0_1E*3< zw+BKi(Ha*yvIXGH$^rX_*>jU70sLPFNXjXEd}OJ5)hEv8hh>J?sFy$I5u|Z^v7ICz zAmDWQkWji9^dG2Auxt$nI-Fw{u^QBlK+HgI+XOjpuh-xP@l5FMtxap5-Y8!xFR*Xy zL~1xp@wK;pb%veJ%ZZPF;||oDkt5?*2R_u6tG~}Y^QtYkY=UN_z@#Z4`}L32*-1LI z2s1#*yj0(S4QqF!Ag4PSwZ(uuj)iM6kbS>5e_->o5MF6L3~P`b8^r(q#^^5!rSwL5 zZd`PQ7BHL`vmXxmIu5PXCyLMh<8=2fRM8{E>KEaZ=J;fptqPDVAiP+{#pEBeKLlZf z*hoA^KYxX;=|!F=`}80GiBV~Z)zJ(lnVuGuR)GT(#I{?s=UGJ=_X0oz`1@r7Y2r9V z6ITF4&DF_yUcpwZVeVY@(n|-D~_gfnDP6-Js;m?>$9nu`H zo|4*>yK%cAx$d7nofus|6X!lh5e6 zi@N8P4*{V}iK`Ju-**Y%uOFd^kbLyjV zl02YF?WDe<46|;xW`3^~7JTX_t`LkeNEA}(*jqvH^HjBaI;DCI9UHa-x~_|vxqht$ zI;WeedBtgjqE?%R!ztOeHuw7E?6%XxRAg~|GT$-p%BRYw0|Loao8dQbV}0@I&q81} zpx3GVOt=ovr1q^!P;VgWq-o25&o0Am|q7s z)9>92_*;G?=rMv!0AsuclCS!jfE_vn@w^;)1!0c-u^Vy89|ZhScadW(k2tBVFZJE7 z#y}cigT%d==Q@}akvfqVpX99CN7Nu9s>6Yzf!yDSSDwi5jnZTc2K9?v7YJ?#a+W+H~u_^KWKYx9jiWGVV3kts) z7X!@OSrLr^Ohk;(vz*nI1{N5_^gJFO`wZ9mG%&>PI?P@xe3SJ`mdOM_c7Az&7Fa2# zIKWeU6%e|s;upmxMTkOTxbp9ODV{hJGkfv9$@hM9El8Mu@mvNN5mC#h53y!?3*oIL zHC%zLlK-xYSM`CrPaUKyg5~(z7<&T~tOamBy$tmf_p{SsY#wIHP|#jj3dhva?}Z%n zRSPxnq}%Fe2?XXX9iKE=>3c>zUFN-kN>0UBcIuxwMA$Pxz19IL@-Ia*B4@X#=FhS@ zV0heNb)*;;+1|q1^jxc!!(gJ5>qw{y3rlC6&X@4nFUexTzi58!Pluxat>bQ1lD0vv zHM#EZuD4JoP=??01hunYJTC&)z=C+3%e#Oip#gOb1q$$M)l5cAv^$*7p9;%o0POZ< zN;nTTAfRQ<@Y%0Y=ApVc{R3Rip1TI1ae#hr|FV6HB58$XMAa$iWZUetgsOq_-JKZe zEC5DP=@jbBF?v^o`+QFD!7|D2J0AaKSZ>u!>hvT!T{;?L_f^N;BuT2nTg_7Lt% zJ*Q@G3;DOan{rQ*5|o3yG!ChjhkNT?fd;`%K)Sd&kX@E>qU@_Is{Qfc$3UfoC!_;u zS<%(10Pf8&*Hg7U=L|}(D5fmWI&w_xpe;R71RH!TVk+6LvU6Q{sALAE#Fn{f zDHnzIJz5d?3$Vyklw>i8c$2#gD|kV>dJ}TNz%_nq=%vQ5{jkz*SM-$rwz>={w+qNO z?f!BOPMv+Z)i z7*Y1n6{pJ3HmZ};AAj9|^G)Hipr$lw!%Q_4EyH) zOi0o^0$Qg9MJu0u1faS24|ikQ!VA8y_7{P;A#HqxIo*i(ts3dG4>{w37H3z|IS|ez zMxH*%!0>XT>1}Rrck@}XLVF3gbtpp003REu6=aA|{YBYRVO0n}g(q?W z;}=&uy8&u)d@UjYBJku+_Vx48+5=pFG3=nADc-Y2CWue6OPJ=PrM?6p`|4Zf9yUzK zGOJ9ykOdS3c~ovle@VHU_C!I)E1-X71;^e4g|nMY;DrdZ=s4XjL8Kp93(OY@iw;)6L?)!O_}Z{lfXVMDZFmp|E!Gj(3&u9G zqaUVlQ!TGri=QD1+CTGD035krlyb=~7w}Te9s|y_G!P^9kI7F>f3!IT1zh>n0t<_z zlp9b8%2L51TFrklX&h*H_M*O@W+_zP&>aCg>B`DZ1M>(N<5E>Uok@N@tUyRMC~+zc zAg*V!yHKd(lNKvlQy}g_`w;-xyD&ekf_4k7dOs#gFEw!eP*l$R`n)1(Syk(xrFLIo zAOPIlcUo=q_s~)hleLhc>^K4xH|%?x0rZzlRMem~MY{s?3}&>V2BZHwf#|UCDJwfw z@qNF&u{<;P(hDY;N&{V>30Qj%TT~^}iw6Ii+#~l=VDuIfwQ)1E3lDPiUXzU7ua++A z45)L3Fv9LZ57-XKXqBMaQ`^DQm=^ze14e{x3uG5)E5RrTh<7|jwJ8xGL)J;+#;Djv ze=sJ@-z&f-_^)&0VKK;qZg3^-FJeFo#t!Xvr!VGsUK{n)3d{U7Ftv1YuC+8g!CJXx zjH+SrU|}CXjsW0%{&S0skWLD_WYqkQ6Zb{NTAQ_R(sBpvspq8ry)PbRAm(CKsEVQX zy-i{2m$FAZNf&qkLc>{?m zDo2g)YgW9v(hR)!Pwt)4;Q)Lk5!Fo)1u|HD&b<(EJHauJ9yuN*vr3k_nyeLuqpw$m z=acDWTk4{&T`T-Ha4sdy%!j#SeML&tDHWhYq#Hcjy?5~(qNK5xH)|$o)Zi()o44M7 zf5Fz66g>>F%(Bfo43dVu!Bq!JB5tI-*orx&S5qzU*Ss=poIEb~7zz;3AA2|BYnEL= z^?=`iL*gU>jLdg>?#Z=E73g`OA>p+BG%Ys&I0)XRz=Ha_^_5Excvch%vTqQ&G@z0z z9kR>9**?Oyk(=_9cP_uY2PHKeEk2;358+)BY%GM_4>aaNWySj;iRxA}0&J2!wM_x7 zapG$ta4rKIo_aA>g?=TKXzhx#!IJ!bc~BJ+;$mqw$5unaQakU2-VlHhUf_rh6OTj- z3{iI*fqoEj1>RO=(tt5Qj1rt$?1d*j%=LlI?aTM{$`|K$?F`ce7GLbDqC2yA zdXh9e1~WmuSx9S_d&Pv4zi>at?*|#r7FIoSvvHyJcJF zM<;ZAieuJGJVwd^cHiO4sWj-BR5*xbCuhAlDPC}aA}?0#YtB>xD{JtzkJ$QY?6Y32 z_=+jfoMH&fV`q<0sv^ER0%r#3QWS%AiDr2YAw5XN<*y9_cmd8JT~mnE9{2^+lCV3h zqJ|T{74R9tD#x_~)Kw9^zo!So94UJNWN4rOVVJ~JagfRON9=c0YGzzq5QV@XeSrdo zKEqlVoT2yxU*iKM16_WF_^qifT@d`>TG6^QIIU7A?|j4_4;TrN-jJkE?>ccEBKY^J1-k#s zb;~X3d(u<|RHG8>9mib=Id9)qnm9yyC#miK;%O@en1FnPLiCAfpL5Dl+9qwbY&NPg z@&Y7vd%T^pWLFOvj|N}tUwf+?tMcNbK4%eS5b(kd_hhSYtXn9uIC7n;G!r3gQ#J zJw7cv+O;V}D9WU?_xVp>fajJy60l4qdx;4aflmJkTITOs{^W>~*2_O&yFuH- zXx%&zT3bR%spZ`-LhV_p8L*^%j7=vu^&Y`22#j%_)X zv)95zV0h+_YncN!N(F_Oi-rSGqM3E<8No@HVPksnPw9ZFKXndvwI#O6SeQO*xUFQi1qodT+x6?wY&UUY>nTFMtW-wbhs zXS;o3AGve#3cfeAn*GTPN;#Crf{98}0{DjAIJph!@4+2)6N!nFb9d;S!9e1>vdq?)HNhK zL%=Lx`3UelR1|=CyYiYD{)>ttTJb}H11lu3_eVjS_{OPVKglawpGXwhL3S>XKK*U_ z3?PWwty>qIF&};K9$A-zk6=BZ&|7$EcDy6{55<{TYrwP-%l*owosUr$QP-E`Nvm~} z4%(|NXP!c1EC!UfXZ;63H+#^b_NGnC^b#8w*kQ)^HBZp@=&^L(Ltq+y`-PCTe^Hc! z4;tbFupj<>5*N2Sv>Y*IqtYp!Dbd|lKV|*rn?oH=qm>}olQP%v=+TOM5$55m%|tlQ z?eh;XKL~^|?MCVFnbqZ7pNP|cLMN>ryvR6SBBxHr1S{d`?P3koPLYu%nL>R^VL3v^ zb590iZoGYX>K+B~$i9XkV)*t5#^1q%`>RKJX?J)F8%wz4K2R>U9hL&!?rQCYP40&Q zY~g!IUmzk6Jz?PZ^1`9kXIk>FAazv$f64$1EM=}M{w{MnVX}Y_#E?wqCR67glnmXR znBU@B@F4@9AGidYnCC9{nl6ns4$AgG#E9w)l0{ZSv~kB{2=d1}O$_s5v~lK*n2O_w zfbFW8owH7ShRLHwAic`U$d{_t$!{GG8@{lFx4Xexj=8+? z^=p?nwj)6*UO^{7-?t*_tNHMbefMW3H`uVz1tm3Ps#*(RJ=%`oWs@auGsfRiqyu!-$w<#%!DL4jTyVYtIh*mlGeo$CoHg_c`rqnhj&vxi$?xeexD8hJx zSD;{>Xzqg%;HMk@aR%6}y~={i1)|OI?Ety$)(mXP?dxuy_a~AWjtKYFf3vw`qb zlMb(u@I~;?fNi8IG|%cEfW+{F#5?7NF#y>~9PJ&rq-u6>48q-$*^>qAY^k)Qwo_@V-?A=XlQLV_i?A4qm%?R?^Qu-A13OcWlN zB;OQZMo9=AE-o(q*Rfz~kRoB)jq(|Wv3#2S{&V&2sN)q@L23cd)wYvVA9Kv)w(Tkw zk~X+%s_ZRa`E^3y`On!7iCri3oA+M)x>2U`GV}hIw{|}L<79l`^P^N;f3xjLR%L3@ zsh_!GT0Q*7QO(lK=JQA0TFcL%WjLS z?0Y51+LZkHYF%w|*fWPSL!0bRuIZ6f)#!~iQhydAHrnDI4+4wqgZ~ZNwTLlEu8B`P zyYzJTkd%_7{04@Rj|z1;61~3bU%m3HzHtg${8=nS+`m+`Zk{w_#f`**U5h07Uw9nA z*<=q3_TBGHo;r}I+14&5*gFbP&6K~R9{Y*!J%f**R+{vY^Od6Z(~^ENomR>V(v@BJ z6Fqr$nW&BLw2Yx6DAGEzK1Tfc^nvHTH62Z>jak5_C@cRS$i|4*hkTi6AMse)j+#>msG4oYCV++kX~2iIjH^nl$zEBGngz(k!IZ%oU2>-<)P^Nggyi?476 zBaG7j+m5~y-iHY{kR5r}gfk_;oNrI;=O%=Hj*jzWwYk2owdn7aud0W>QN~DNuqQR) zKf(*wk=WCWVC!BGNFy8Cg>Oj((Aqr5b%^02_+RjEcO=|_NxY3m3hfej5NFF)!gGA> zz5yHUqRxuxVo%GTJCHNyrPfBlqMh5xkGu$=kHmlUfm~#}-1x>WVe9``C7q(a9iYD5 zPYQ0X4gF^LJS!$z^p2W;*KZflzu@1D9qVG(BrZ|ODKSY*P@ZsuE7BV&)AV=@s!CzB ze`j`lT{lMWZ^I5Y@7qkKH`OK311fNcsLhu%GO&X%&n)JwUm!9c4${oTE^dMXlEb+V zu~F#IXRjRFcg5{8YcS$>Vv9^`jDgkN=uPgkqB7A}~qhm_OPjiVo?xbK6N~<~mG- z1JC4@th{q0*MpVjmo$hW~IPLv0(-&xuP zWcu6zBTej%j%$-JmtMce?y4w-z!$s7w@pD{SLO9lI$kD9V29}VW;Xa(5tOFASd-WD zDEVmiTVFk~tsMk33;w9HITEMQPoJZMe6)!$uxYmsczSF-E9En+<7EO2bpl+#$4*4) zKVc{8FKKY`4EC%9G{`!*9*yLHL`m$>d30}dffuWQL~rfdV8mTB-VY=VETgd9K45>> zb8~Ofqt|DtlWJT`CA|?{=pe52kgepOOtO-Wk6?5cSchMy~hS>TIA-Z^(ynf1vu#>hkn5xpVX8`Z5lD9K?!5|cjjS?G=5 zR;LR;e@mL=_hW(N3Q?P`snJb)GC$wW?dGQp9<_UVq1yTSt-=| zIlm{R9+k9Ngb^G{fAw%$q-8xnOPCWC0#y@dhBPxpdLl_U*5c&o4Hcw%o>BDH>EoNxF>f(Dh^zr&s^or4F= zo9AF^>5z|9|A<|dBDKvi35-8y;| zHW5N^hS6Z78~WCjMN&=kkL1nVwe`(=^iASNs`tOMg`Q{wxXe~G)ask~fkf7f^%aO& zJaw2ms>ypp03F1Q-WB$8S?`_e#*hwynUd4Zz?K43novt`L~W+PCg`0oL^3iD$4hvSKdj z$vb3kNptCSEx7(p6g$yyxgV(t?yS%CM13mc3MoLU-n)_v+x}dOG-Bs{-|B=?tZW}- z*IY~HnXvBGe|gZgMyWGel4-}b5Tsy40wMFmZ@5BotvWZbNzaRM5z}-c{AW_n?xp$a z$!{gnLHy^g5EBMuy%Vjy*D80%JL|{v0R~`TYw+aHN$Z+;R!oyimbTDgBEt`@$xW=u zcWA5J*hb#Uchnt{RFQ1(j!XO~E~m-G#`klRX>HbrB@SKsxN{F^ICuGSzrcLl&D_O-_#vi;1V78sLSFs z<;+Fb9E0?>`DB!;_l6EFn3wwSqb4VBD~=MLbCdzGr`p^ScgMUBVw+%YnUbO1TPR;J zWFLyX&5ld5SUWtP~7* z?z0f-$)Rx2h6HyB*S)n-bEBjrdZkcRv^E6s`AHwCDtcJ${`nfsAzr7E%2XukteS-K zdNgN-f7x1)xY3mMQqfLA!lw6e4c@_&-+hLDlns1~vjj7p2CsYi@QpGQ;yl)jzt@cT zlC?=T_1AVyk|7LBD7*ST4$zEuS?t=^Wtn+XVh+eiqQb{FkjH$hhgemW*W7}cL(~CV zMAzv?ogI{@;8?%t-Oi}9hG(!LPcW?LL-N1flI+oRI_kCm2I4A+gT4cC)FfW~zMo4T zYluRi20J!WshEo$J2Uqt`|MoD4vK;ZJL#S;V7n_o>3^ZL{afi}B#S5Q;v4vxL9Ou9 zc&bw7nrrStbkks1I=_Rw2Q?yCu~~=m^eykS^>n7FhsOx%Clm~ZhDU03V%}5UE#Yga zn{fPt4<|GOk{bw@o;qM%mmVy3<%h6ZtlNVt!++&(6R91fp9}2UvEsX9DyQ6^P-m_g z(@3wDiogQb>71V<=7g_R&hOfN9t)W07l@@j5c9`v))Cwr=L%}a$<4%TaSCobuxAgq zsr*||F0&M0J=LwGDsW)_p(mMf4L-s0Yi0;ArQ~vtP*C^oc5`o|H7_M?{}7@pv6VCq zrI*ZlsQCYQ8;u^fM2xSV$_~m2n;Gme%_H{AYm*Py59I>1U0e#v^*)k(^rDJn+UZT?p8#hAz;_LK zM%Frm-Cwdkn!LgeK?hITey0Vk7Qk_6BRKkY$h?G)9&1&c#FMQL3OxXBbE2i=$>f%` zoJ!i8eN!@xa}!zjZ`5$5|0E~x@C-~Zj47Yo{oW2iC z`FBn7NrLgDS)SM`nWg+ z7dH3Wv&*P#C0QafYy>krxoh(r>6aMbF%RurziE=Mp3GL#4ElZ_MW#ayhljh%Vsj?Q zVk0H5bL4h{;OQZ7&z+EerM*68n(&p}^1g5#M(G$}m;_BKe*2sHO%&KETAIDwR;kWi z!WK6-iDRJUfg#dCl-B$k9`GfC(Tq0)*nNo&-(|sP6#w?sE6qf!1Z}_G^RyqM4l5m> zXWRlqMk90WM^Y&~G1FpOhKHWr;50%IuCQE_mAqo0aLJsFvZ?oLslGd+!4iD+W>bR} zasLU}yUf$x?<_D`>*I+Ys4H_Do-!Hu;kWV4GLjSgY0+M(&QPM_6wHo%BYQ>PSlH%L zM!V&w01zkOI=xQQkn@339h27G_CBdNzr4#ga4uP zmqW)@IRTb!Bwhr?m%RZ*5*OF!lfagB9j%L;c#afGrZr+yJr&jDwUKCx&iY#+FeEMx zq(5;X9=sWQmS|CvsG8fQd&Fi={Y53b3KOnjG-6dfjW8228(s76Bh^aJ$C_L@cBG5U z1IVQ6?cf#yP<>D^G<2{W|WyRA)gA!900 zY6C$4lq>G-TRjyQ7b@oj&+M|m*SkD%Nriq(`T?AGOy>#r=1C=`o7b3Ej zyT|Q+Jz@H4vb2!g4^o&8pFW|AqdVdZx&{h4hmz8)cS2E3E?lFY_%UE~XnD5xE!AiZ zq!*&oOf}O~BBZGtki%LLYE&rtMSzZBb*pqA#Zdt-yH`TGD27Z;e@MK7#xfEMFap<6 z_liLn$C~$ln1OJJ-ur=I-cAwV>c~nAm&$WOSB4$%aRV+3TYY}6YQ4IMf(d(S!o94v zP#=YLoI_*!DFkXN)rGKvlbr;;5tc9VwFVXm$o6_YtL&Ludj1%xrd`kbc*fL*F02Nn`BuQ={2Z5h;1o~Ac><;bKfCdc=DiT!p ze@!B4!n+(}Wfci89tBl2`hTQu_!7)MQ|m@pNfHA$Py?7)viq|}|xW`tb| zO`B~GdUhmN4x)fGZVo3k6rz)IhGz16SmW_?$-0DI&^G^lwkXlwZi3)qkx$vqO;>Z()++P>1&wg4l9Cri0PV)lY(Pj zcILe!HApLmlB6U6Q-LNCKZ`NA;+mY4Q1-s`7Tv)VC2n`C;Iisu`|l`TiRS9!tNj|F zNKVhsOEC*V_12HF4=n(*1Sc`$ltY!9GJrNp6H9zT0?IO~zal{FcO5!!#N4 zPyWVy40*u`EF&>uBN9FSBYhCe)xX*)v|$*f{064-@=*soB18m+qJ)2``EMl2Bb)vS z1FI;tN~{{RiP3@_dKLeFKG%Qdjx+;!k?0G<^PhdfeTm~qpG|}JA*9KGdnhYnMi1FR z23wfmZkXVq?2q(sWR>b#S>=!)O8X4Hur%+j)v)O}Hrrj+8iUfUei&%CwVH~|4+(+5 zBWaKgks0M=*Z!CVQGs|$kajNrOP-}=eJ{XNSZk~IMv@ut&?aIyjuI2%Y>!I-mwXB? zVSKP=qJQOd{p38>R)s(%c8s4B6+3u-NAvPT=TIY}-1|0E6Q7^TD%nJ2_*y%^fKI>{M9@P3` zzgAtbn!YOwa-$;E_1`_)VFN1tE1axc#5}V>^6Yl`EI9Oq&(U zET_X)+;7j{KY=o_*G7^AFo+_Cf8?8TDJ$jqu8=E{w~&8i!xeXBTm7hn%;hRt9Bv{1 zZF=Vq{%fd!ecuXdOxMI~Zpc(vuLH`Y9n+2@PZ`t3R%UUll|?_FGU`j?dg1d%$YBe6F|;9&u$o^b0yMahu}{SyGKo;%7O*d{1L*-_M_ z56DQTfQX>Vm`yyPiq42u3JEe1@T%Eq)f>ykG4@{g3KE?m6$B0Gf~=PHa-}8*QWxPl(#C}++}0faf|Yje;N+&(|0i#aDSxPOvdm!Hg4IBq zNP4Zb<}k+IeykR8Fq$=r3P7AC$oM2fvwTP^n}Ah7C#y)-9KT3t^`}01W z{`hPYV74UIC)|(Sm6W)ngvTsU20wH&q(Y`ZAD7y3IBIohByc}gb`X@ANkL^Htnn1M z(-2oto)Pl(U+9SJXcXxr)t&?wu)qbt5YQL)l!o>RM(==)j?ROgy}h&fUvQysXZo(Z zNrow=!4$D1;+S)aqS8aY5*jy{-<>4kz#no)Dw`HZ%db+m#UOD1+4QJH1D6BjLn_Q9 z-ZxrJY1($7a`H6fB68Uo6u`u@A8HDspsm7wfrpUd33Du2z}-rE8+%^>FAbp0;I=2M zjtgH3=Cul=LmqXzS!(rZJ|vP3wq@VV(CKc~;_UOe4=pY^VeUJXFcED+BEK^_@tSX7 z6NwK1H`V}96M7%^l4m~Z3Y6BYBX0QkyeWIRHhcMtL)cg^7?>CaWv8YfZ}c&G#0CzN z!7JVs9ei|H2NwVk@&<6RSJeru7yNY95NZKg_%eOFZvYTyFHeF&X3!wpfGh$UL82nY z$@vm~7FIH^5D2suIv5XC{Bg-wcdc~z!7jeNWz$5$#Ns6ehdu2kP0wPA+U(G zuM+_QIEWvHj@tmhg{Dw!H`WLs5@Ya!s>>R}N?(Vcf$5P&y=CzbG9{o}TmgnZ>TIcm z?D4EfaBesV&ZqGS11$-%nwp}saBc)djfW}#hqTvDL`XpC#am<&&w-Y<1{w29B_E&= zz#-yp#CAbbGOhC!2q1){NCRA|5IE23dAv!HqE~${U|XaNV3-fx7^w<5>s82|fh&`_ zjQ8+SFs^s6A%#KHPfQ1eb?kvW51a)E*V2Z32IPp&V`VxWg#fVECQKBVDC~p?Bsy=P zCfCNG>DC6*WbDF-(n#shvHl;^bnMZPG>`Mu%Yv47H@yD?qzxbd6@;YiLrM!c5;oV} zH!(`@bZ)g@c$J<9K6(I>UyM2{2)<>y1YI5BHKiCHS6#zeip@|)a%pLlt@4EgK71Kt<#dUW#}sJWhl)-&sj^slnNNR8>#XYgZ*30f0aaR_cJuM zVuu0(h*BFcAD|krThYGJDoWG#ka_T`PdLJ;WqmPhWvDN0+%LJe&ff~&qyDD+bmZz( zlG*}j59+?i&Oh??t+?09AuMx4z{3(~2w*o*2Qd|$;_e5$!0Y6HDm_Lu=_==VnqGJ^ zXWr*-sLV?L9S}NTtDS_hltH!vCL)01W)8!UDmPiFAMK_tn7g9`-W^?~=iLK~ zChXW7L8Lv&UHLD$|5XGrlb`h|0HPHe%_Jt2`xzg7sG zj*AoM7cO7?8)?#^(m3y>oKx>CLKOj90BTMTOK!l10l;C3`eWA}dH@~bC88|+ZiePp z6Q?D`{^fDrCYzN?PzEVKpB??|LHaG8u6L@25;g)lfMMIR8KNPJDGg8uByv3jv?8D7Y@}FTdeakVB_W zSgC*hk`mI8Ufp_eBsd@q6$4V#w6tqKfI!9h`9d~ffA_HY)}<2O$`h+osmvf$9A5R| zeY?@HriY>Cv6WQ{sztQ$m;g%ZgjmPP3`aJnxgu^x=r2T8U*&@h9)g)sOGw_u5!J7x zBp9|*lk15(WNEiALJKLE^5&;6%|16dVE{TJb+17wtOiA=UP}iP_79dav$Gs@wqM{a zxQhysNjgH@$cZe$8!!oP#I8g0XXTT?`Wi=4QUAjVB)*GUk~MxCFg;}BF&YR&|JJq) z)bS9cky;0x#;zm%SQ`eRZVo^y)_hSds4mviacGst zbC06e9jSa+!%^h>P?fpJm@)io;A&e8yT6gMmko)ebIg z`ZRH;a`Ffg-Ywg(Z?EWWSUKD7*sqX3<(J%38Rj4~U)7FwH#Zn_OJw-!Deb^I5|Ma|u(*0l2`ETl zulIv_`^VAMOb-2qHq&(~lOdyyqhD4>cS6_o=`h=5-smcGrPCnyWMaX*?8N8Moxnhu zm>ffC@Wp<>tZJOGEA6BK?CHm}_43+SE;{ph%(s>0v`<&$E^3UH zafeCHIL>)CIgU7ATCKL4;N~u1Wre5DBJ-fh(D2`gW!^#)Tx*b|){s5P@|Tg2Pol6B zPfm{A{4*8H+39wjk;B41IV1e9;m>@RS9?YK3bS2%lf*P)KhI$;Pi&4-EYadn{O_8bt*`0-rfK7fq8gN% zNltjKT!kcaD}+0${~I7T*u?`64*?>8ZV1mB#e+4g%d?ZMtIHWWOp_WVJ;w?P76$z% zhIVovM3TsyM}SETO!o#!;swrF43;mIP{xS^hFH0!jLKfWR;FHf7mnXj0n@U+_Ui1C zb6COAg0V?H)_%{WmCoeV69P^T*})wasrO=}53rEN6{YI85o4eO4=(UzC&lk+ZBrP5hYu!K6DX zARw{Qw3>pAtv2QOGn9`mv`vNy|3TNe!Rp7+txaw@7u7wuKi08!Z2Nz0T?trI#}>XW zm9{R}+6q*JRwJk=ASjCox!L)r-#9xF1!XIsahtX_aNKH_E2xLU-8>zcO5CL#9iO9}6 zss3Zzoy`36SCU%)S`Jv9GjX$T!mYQ-YC&)DF(q?G8FjqpxaaT)C(fKf5M3AF&C>2$ z3DvOcTjXboP3}K4GY1o(S}_mals;GJkt`NID7_W2-E;f-ZGDM>Rc-6Um$vIE4||2R zcZ3a|uA)%CfxBL`axdMzP%<0Ptr%f0i}mVM)Np2JmAkIQBpoUY=PhTVK7yY=A&gkv z*7UPdq_ku>L$mjB@;Q`DKE`?a%6%(oFbf4Vi&mT5tC^h{Zj#mFmwy1hFY6u~8XF$3 zQ|##)EJ=zmiEujaIFOgG%5Q4+rSM%^2m8IpY7T|@=^Ia^8$pl49%Zkv$z2Jv83Ub; zU|o5oz&SB9vAx(4V5hvw_1wBBLFwqtRl?7Mer_FHzz<9uzh>GqWY{y5Y^99mbGd3( zW?#k@n2#Zv&z0HKza9lRW+k<%L6KGVKeujRquF47M09&%sJ2!3sL3(bUkfrL{0`q9 zuNpqvB94GjGp?1!C7JeKf%(*S9;J7}u}#*OIF)R28TI|u8pd(0F~Ck(>v(jy&^|$J#$LEg61qbN}mvnmW1qdCDJzIRwfq}Yy3#Bq5#)m`g%fpJU z%-qZnO6xem|30Ze32iQnot4<^5BC-*&%_wBfbn~WGZ^L_7h3Yv|B0Kq+7D68c!yR- zp?TDo_EU4-S5>u2b6$fhPWI1AeCfym(9=YN-B)JB#J;=Jyq?WqABXWIzG|Ue@ctn0 z32o}glXGW>8@|$ENg0cWt7|9z+^jZXt`^bv1#;QgjRdzF-2SWRrXhspN4SlzB_YCn zY}6M^irOo}YSs-pB#sOOPXD?7h0j==Us=C*wYO@-#LUH|-s{F*N?T(!;b>|@c$$hs zM-!Y0RklMD+V~wKJ63$BIc!Ev?;Yrkbg$al*1V~7cC1Nr>R;|^Ht zCv?J%7n}>*u1qi!@)Pd<A7bqevb9_Tb^3^?)VmZQ-5)VxMnb)ao)Xja7@}X+2P?crL;}~ z76e3&&5USnW|EI5iKpXhGS>X0{DtB8z1hY-q8}N(^}^^lZ$=t4 zF3GNI_jnyteX zZr(HhV!(*DVvuNf_0ZUqT?= z>8^BnmcQgPf_DawbL^Eu3aTLMpqS};{TB?7#&+GWf80IL4jdG85Tb&J{(0!`!IaLB zG0GsQTNXF%)Qu$fJ~(;l|8ugk;x*2SJ5Ln|$wQQOnLpAy6|)9cY8a<{PUxO43F=N8 zu80`PoXeVyR(m5i5sL1bWx!kvkbAXOOXscu`<$SRQ55J?fG$Oh)l3*?m2{812x%>U z!Dw1(9Mr#Hc~Ky=6Opm!q#}=*#I+v6sKsfi80PC+9TLF}%n;YZciv=}GaSA~<~Z#Km=>514!9kL98l;s^vdJaG1&OA`;3VBr9G*t z#j~bFwN-??<$uv&R|`&?v))En|7Xjq7T zIr5^ty}l|DvJ8 zSA!Uo3>)M=|*pqt9t3`~5qHQ5>${(@M*L zP!z?hw-s8MO7A@oi_X@!FWfw*9oY4Swk3Tb#YH89cU}Z^Hu=5IH~St~8DF$j2v|q~ zNE$~1h4K-)S88X7mWpXrXg<&+YUTgN!#`*ec1PuDp*$OfgR9HXPhRr05bcu=ZCYGv z=NuS*c%857;nH^(Rf|Su&zo?M_%s^Igz%6+=`A@g*4>NzTK+&Xt?3Z*>wLDV&1ZyY z-{NgtcO2%tKs_1ra&el6|Jm)wjC{8?481tVBZ(m%2sv~SxFyEss4c#dx)mtr{ zpu!>&9KaiPhkQ@0YEKL@N~&DYlajC2Tua)+?ic;zKMDVUMYO=33ZN3(d_sCnI!+CD z&r>Yb?J)^z=?|`mDhsYDJP_DddbPguO@DFyn>>4A;=I!SDbJ@6w;kN|fTgHN+JkE}3ZUU(CJdAvqV@+>uY*4snQfx8`gW^(3I{H22(I#ULWhWWmb+`f zqOe0mv|x*_pG|#H72xRo1C7c@9Y#ReIp@_qq5b~#?RAR{+Xk8r^Y5k!B{wHh|BLDA zfeEj|sX5!+5;Pc+0$uLWbN_kOU-Az{6A-XrJGI&>F<7s&#x%CyFDK1P?TC)LLf6lT_2 z;f5vp-(2vI^BuIW$1Fa2hugm&q+eW;c4cz=3o`=^_|GY*9t3@sRjgeaQt>40U${|H zeY{Kv2UnQIfEr}OXMwt5VyD1>{YVzyYLI0vBA&l~@L-i8+S1Kd&*Su^HU16eu0?^w zRIe0p)Fc8;wh3^G>hAmGR3pd0L0a}h}uJ-P5aI%)REC2nLPYhJaO1e zda4v{Stfg!0IjP5g@jj$qC<2OixX9Habonja)32Qe zd|wZZ_A01L6XJ*7DT46KGirDwdj9fTC@!~^5hOX>c%{IPMO5PjoS@0BWpqDSX*`hV zyb7p=i)sQK*WC(u8Vx7+fokm%j3APBx4*;{T1&fqZFSDoFG9r+lBDk)jn{^r0TRuM z6Ue$+<~9_qyhyIc0@_E#koQl={eF_Y|(s(Q_j1Ojh|YFCWBrEXaZ-M2QHNU!eUA>zhh8z}XcOd4sO^`) z9gYE<5u=%(u(9Op(XsZzpAibL-dhbQ4EsQ&7Dt%hla&3-mo*)%lM`o4@q&=4gMEKuFxJ>YtH(!I3#sgx!NCV+`;d7OBzM-JU^b*Hb_s^ozHEwrN>$My0f=$LPOkM-$d(9_vod2ZGa)n zQRhmyUgfS_5(_7$@GTSCwXqcaGVkq>$-XEnl}*Yz!)Kyt+D(T6m}hRqwg%DduY1^| zWar|q*wei-xK$d)33qG38%UV3w9Ad<<{{T7!|`xvjqC&?Kobk`fmwpOe+@tCl_3R2 zM=B9v0Zpv6ppE_F+j_Vn{B79cwRAxnxACMZfwdTrYYqhZd>%+y+h4#p95Mv6G-Jt??onLJJRJOSh-##kJnTrw8VVE!fXr z8U6rQ^Tczw1x1m;PNvzS?Ij|{sFN0HoBNp^JPHNf#Rk`enq&);jNf__8hlV*8k#J9 zx!fw-+%?AV9SZ)=1#Vsppi3p5B`X7GI_MHiTAv35MT`N`3d8FA+c+yUjFApocyL%> zv6V9zu~yMcy2U_k_|o@;&oH<--2;_PT|TmJ%wCdO(txjnLc~nylg4-t_c}lDt2qRS zW!G&1@&}yZfyGq&AqLZEPVm~d%7B&(Qk zt1F5DiV8zH@!cIKDt|qe)_hiVkKMoKD|8<7FFD$Mxpi|5T*ySGoAPcU;APJIR5&gA zbC>$?FR+n?FEE&{0ZphUS_3+pLx`@~kn)a6EZ7IB1?SP%)pn1Kno2Jya900BxCBnN zyfFumH6?o7M(FWY?)NDc{|1!0_RZzo&Am$Mqm}7l?;XHcAyA}T>Q`z)W0nVvnM)(m z26$S^j4g@4>K$f~tllD1>D+LM#^*%W*(!v*U?^e+p3|aFNgl^l?u<0&agXs~{^rl7 zFpK>WU3ct23q~o$+w>j7rCTm(vaW%6SeZ1jJ~8wFG-wT>ov1Ry&Nm?qMN9BGeNsK% zz3_wnpDb>+3R^xnCU9=oI=AjH;LNDI34b5G6V3(@I*6bV+PmoXs!n2i3*Yt7R6Xeh zC2Cu{+Ezv%>w6-*)K(7gMR3<3B=poW#V1I)su2Y{q3juWo_a29wPN~sxZ1e-IoLkt z{nAkF@;D#Z0^y*Fe$p@nhZEp9*{Otfo>(QcQ?qzFeG2o*5jpoF98B?-e<)LYHc7q; zTmH)f5U#o*26C8pKzcFJ@N=1B9dI6*ikN`F)V1X(dlSkfQ4jW!cB;o%W@o~7UjshY zpI-L3t3A*ZPaM5Soj74S_~;~z+h~h=e&`wD<{f0q>@(a(b2b3{N=k<&YWjIv(B3m| zga7C6KZ2Lu9@{bG0h$s3?9-_)HrwyPLQnyYKzXU zg8qjpDl=SHDk(;E0~JRLP=tvXWjUoH0;2K7lmAP=)9qH<8@f8;{f*K`50z^6w?t)q zF_mcXo(z)EG881{Kho{H$P`CPD=Y3zjp_NT6C*;D5P9_QHaa;>xcoModZp&5Y#)bN+@n6;67f(d z&7VMdQ7aD_m(@7$l&|BEsUjsy=n~#8R1}bUAMFwWpCOX5jmkID zo3`kEB*10f-{5(!jT6zIgfMWemu%aGaOuNWhyjUBrW^Y#`#(;oJ!s6oCz;p?=+A;% zo1k)RpnGY3jOP;Hi`3p9&4MSc^@_^Q0fXZmZK?(~xdh6h%Pk!F%4r_kpda9i4mKA; zrAY*#`6Dck=ZiXCB7MiD4}Uvm0pq;$ZBcM@6MYJ^|(x$L$fe?`X~IVWfDQc{NF_&j;rKq z40{kbkcNd>+cxg(J`CP`yw+W?RzTxFAtj;V!!rLz)_34eMi7UOvMlAX zq-+BA_U5zuI7my}^37Vv2Kv`9r@rsT&oG};p#1Z?Lx-MJzzti> z%G^tCb=T2gsC_0Z3NY8PM z`~Vm;<##lMSiWlB3);yC>3dq>wyCRlT1O<79kNsZQ~lmwH}>eH4fh) zLR*f~<5E4a>2TLbIN8!W-9Z}RqKjmw*>Y4>#^L!u_5?XEO zacLe4eBtYuIQm3EeWvKsx_2Q08*ty34V-T&)ES>2P_&5thFukIfFA!nCGHRS0&o9w z3*RDcm0j*iAWY0893Bogxp{0i1OCA^@C^|=o~CCa^#UR)VWW6vR_YZsLmR)E&xQI= zNdBnfsAhP~%z1u!ilcFH-h|d%9<6Qy+ZetkRqy@T8pc$Sf`~H5EVjgSrgX-Sh6N&$;>bE5lJ=yTG9#wW}+h`U}0|KR(jla z-@RxS8qYeo2D=2dKwF3a+=ygra`#gCQIs^q9d&;IcPt!7_s2A>LLtFRO!a`BW^KMB zEe{b?7YjJ*i8=BmAhv++jgCfrBlC?w8~cc7i-^<9c=r%>Wzg6z&F~ zTf~uPjcEewEH`hb-~c<`7KOLg(Y5?Tbkx9s>VXa302GC?nVrr>9$&I|yYDS-KSC11 z`~q^P?nPOC$O2C~3l>Vxh3rOwr;GQCm^VQC;5>p`bkQZEZ^VO+bOx}CXn{lJaG_AT zR~olU(>RfYf|CZE7kg08g4!P5ZG>-xhB?`^U?kWjwt&MWXwQ)-M@QrdUF(zeqW}ck zF%a;c?ZNJVqZTN^j-VzIZsb61%K?t8ZQmJ)^2iPyJK@-Yru(#CP zC8!30hOj{UPw*f~n@@0nm4M+YjD)M0jo8{YTn{a}mj;Og<>eg|=yGAZ2Oe>W>L9Tz zgWJ!6WupF(_h7Hpq%%@}#cSyQ6a^N$n($M(2KItFlz(K4gLY^w^f+z^1eoElks|X& zZ8`FVXe#N80)2i8f|}677z9d45U@b!zQKdA`Ne*uVVsO+k!Z|uJ1`VC3+Cv7=UBvo z4)TONH?lnetFk<1(!I7pr%kpdgml(qr_9*_SLuqcrF-RZ(asE^i_Hy~x|a(3ban#x z`1ZauTI8$&IX4Q z7zJDuW@QbM{($=P<42&3cO3DSV;xH2T_jkgJPu&*!VBf2rF5ViB?5k;+dl$kvmcP3 zxeRNpI5!;7!FAYZ1eq0sG6_}|+3zTUwkW-RfS}}Ez_8n}pYFBncxSl#GZ;_fF%m9> z@LQsbz(cItAxD8agaR781MC*M*JZ93nnkuBp2Yw}MXE;*&C*?B^DPW)v=-8X+lWXi zVS?K+7j@`!<@v#i5>PguDm@6FHY`DbON?IOdfDU_Py+wyhfBNM`WTjpLL}eAeGBy5 z9LSFq=omliuSr;D7GogNohlP)OmXP(K5zIKmb(_>wS2YngF~{6HJLE zGYrcvFTfd4N@UK^K*!2~rf@$vqx@bt4Gg&lO;dxM<~L~`Al&^Rqi4J=jfkBkz%~RT zcosMdVXwoM+h~E=0B?(Nf}0$x(8+k%H~5L(scFo1LsM+9!-81}oCN|3h3;~Iy$=~@ zAq7lcV&g}G8F}^{G>_B|0%q6gH%OpCV1-Y*1LM2-iGb;1M+Ti833%9@B6qw@cmM;$ zT);B~0ugNhTTHCT!I6`XQQ6LI9sfNy4}bv`2GM$)!VYX%iL4g!;ZT(5De?tbeh8q(|UD3!qzHPH3~H}6lGu*o~KLNj(1dak@^=WSGcdDY{O zyI>ax^lv2a?mE;v;VE{CY}%T)gn8g>&5u1y$&VG&?oI31``ANqqoTIy+;xAM{$)z6 zL;uX3v8LI3M_2uwF~OHxwqfA=5y7wZ03)4A+yk(loEy;X)hN1wki%rASd1WrRZv9aq_(<^jr+OgRs zk1{!r@Ds&Vr(&O|R!qy=?pGe%ybTTgTerULhyh;Oj@@`^OKtkM)15U6w%+6bN>L9+ zyU_*i*fw*{V%tQDS2d+<0^8W50j70>ZSwE{bMaHJeTvRC8WeBy<+NUa#ShIWWUUuw zEQPrlxmmsk^ZVRVD?RT>DL~Jrop`;AO&YF(ho9Vi?LE({R+$wfUNGrT7j6Jk1uy5 zkE_FxUP1xI%(=16moA7VN6;rn7%0o%o~2(m+PoFE|E`2v_LOiVu-Pjtv0rPjs1`E2rdwNjR`HS9Rc{r7 zX-KpBIM8Nn3W2d0j#d1qcwS zzl1c(KnOuh$R__Aw zT{)W&F&#DckgtAdMuzyAo_FC-Pm-s+EgNwpX%xiiy>QE$;9$vg zIh6VYkz=ni`?qPedwhHGpYUnIB$P7C-0*XnBX`h+HvRi$;U#p5Zsl@oFyQz!kOSPH zb~oL6uv;9e1*Y?!tYE|`^3C3sZ=!@LfwI^?7oc*Y1eX!sdmr?mcEa+0i_(A}+Y_Se z+=S+C((Lca=(#o|@~+i$Ef$|$O^CWo-QU&EpLUq-07z(A=g3y1hc8A*XT%`QeqUzxHFaBpQ+DIp)g`zlqYOr5&1ObCYrOS{ zjC0AMNyb26M-vk`nd9A-%qD{17R8bsh>H;nR~#op2QnrL7xkSs{}i_buSv27uZd@v z_O=O_P>&}&VIv_r^^vtDcI5C>K!1O-B=ZbM<8M68{}$z#BoM#4fSL3ZrbZH>@j8fb zF$P#(=@A@8L(Ayl32r!jhqlQPRAi5Ff=IORtc?e7hU`5*Dlf-O@y~eTL3(8JVwe$G zyqhdqg!FTA>N&r7?R85Zblf_PsqY)z8cr8tYY$mt{N&|$c!fk;OG3dcmJQm#9&ycL zCcVL7Ac3&-VsAnL?(?_V5)xMktADVkvJEpJZTm~0Eci@S)2r^z#K>;CguHMwVrb43 zsKw01`CIk05W6C3?vhSkv^Q?PN@sZVQ$qCnizUN51h^CvGV&+dWP>qWTGKHu1(mnpA;~5m4LCeVCJ#Hf~qyri~G&=D)QR5{C zOVL%*S#z8`YZpPzLs2k2UPuwAjgXH1VF#jiM5MWAZ6WKJQ0pLI*@t4K`ZYXH4pKAO zTHwuD!48Aar*_DTmCx^Fgl$fRgoR4@!)&6YY?2``H|)m-G1`iVnG($wR=gmCO%hJt zWz1Y4|Lf#DU!*fh^9j{yq^F*weZ=$CFh3v@-bjO7H0Nm}0Qh!x{!_xpbCOFF73Son zX=KJaZJ8!Y@6!7+oV0c11x(3!w2&1?AJHjWTXtpYv-%T-EIGMASr!hi`(r+28WWS&k{5gYX{Q*W~Y>%0SoN5n5DSN$9!KcUr??R;g5&o>|Vz0X53gmM6-08B!En9V%i zci#G6dmIKv3M34GC8sp5caEciZ0CX**Dos5kc@W5;VckX8o#6mOksnAskw_9RrqWJ9Jv}@MN|NaF zbXm$0H8mI^c~d5F+ekMMaYGzN#6X$ssu$t+83vph| zdYENoLE=Sm-{#Zi)68hohGrzm;DnfyL@sLHV_4K~F*Jt~1r$W}h|&;7bI3@r{E_Z# z*T0DkBWF#TyMnA`yweBeWwN@?QQiO%6&0klPp6XgKZ!Ljo;Mt{r6-A7VuQ2R$VoQ1 zgJ*37Cu~d4*6)072GGnjhIb1}e@B=vx=p@|D*o4s-lB=^J!e*nTEn*XIM2l4b&Y&0 zxQKPjph_jpDf%fhIWSs|HlkbP%eUe$*Fkr9Ea{lKYSJi0{hJZAEX!zeZYrKo!EcD5 zE*J$Vs>}>GBp2;PniFVAIQdJp6G-}D>L=sghBvWGa{Tz;j}apJq+rM+hBy_+grlGa zF^dbWdaN%aIw}eyXD`V|p*)lEB|{?Z)|*d?G4MWe@+#7_x|B`eG^K+)&gh>v9_Qm6 zA!IMA5x%-18Z_gdqGVB~QV&G~=7OyBExIz{ybISw(WzSo#WhQZilb(P<&3iYOR#Jp zXHUe?G6*>s-Z6dXuJiLH1!w&V(T~FxW49BD8$D|~S-wf%QkA>)tKT)-_UpVxpNs5e zb8l6%lQvTs=|e{>1AtP$*ximDvsw0W`rf$a{VRsY7R|P7XlLn>VhJ&{hg@6NKX%tb zgiC_8zOv-CQ}T~^AmY!|Od-wKylnW${ce3rbkz*F0U4OW9P)QXOP5e1nfsB^i2>Og zqmIAd-DBT2__t6iRWda|WmAd&pTqb!Q^?<_rlUeV%DO3Ba9YCZ?hTFdUI|-FNLIqm zCN^J&(&SSt zL9x&*j^eyRg1*K}B4^B-H|)_N&VTK!7E!{G78yT@7zrZDgUz!ugIt`Otz29nEW zt{deNF;ed@Bw37!ciuIQUrO)955`rgj}P>VzYIl-kXVc>TJSSpr|WecM*mOSWVtbO Iz00xx0Prj7umAu6 literal 0 HcmV?d00001 From 29e3fc3dd20d2a782f3b781f0cc51ac5af5df213 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 7 Nov 2022 10:25:58 +0000 Subject: [PATCH 03/55] Fixed link --- toolbox/fdc3-conformance/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/README.md b/toolbox/fdc3-conformance/README.md index aa5109dde..4f1671077 100644 --- a/toolbox/fdc3-conformance/README.md +++ b/toolbox/fdc3-conformance/README.md @@ -2,7 +2,7 @@ This folder contains test packs (test definitions) for conformance with FDC3 1.2 and 2.0. -You can find the implementation of these tests in the [FDC3 Conformance Testing](https://github.com/finos/FDC3-Conformance-Testing) project. +You can find the implementation of these tests in the [FDC3 Conformance Testing](https://github.com/finos/FDC3-conformance-framework) project. - [FDC3 1.2 Conformance Pack](FDC3-1.2-Conformance-Test-Cases.md) - FDC3 2.0 Conformance Pack (tbd) From dd876fcfdc3653030b2e8e2fbc96058049b54d94 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 7 Nov 2022 10:27:53 +0000 Subject: [PATCH 04/55] Update README.md --- toolbox/fdc3-conformance/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/README.md b/toolbox/fdc3-conformance/README.md index 4f1671077..163223878 100644 --- a/toolbox/fdc3-conformance/README.md +++ b/toolbox/fdc3-conformance/README.md @@ -2,7 +2,7 @@ This folder contains test packs (test definitions) for conformance with FDC3 1.2 and 2.0. -You can find the implementation of these tests in the [FDC3 Conformance Testing](https://github.com/finos/FDC3-conformance-framework) project. +You can find the implementation of these tests in the [FDC3 Conformance Framework](https://github.com/finos/FDC3-conformance-framework) project. - [FDC3 1.2 Conformance Pack](FDC3-1.2-Conformance-Test-Cases.md) - FDC3 2.0 Conformance Pack (tbd) From 8d4f08be78662a40e1b19fe145f1cad835946bcc Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:09:59 +0000 Subject: [PATCH 05/55] Update FDC3-1.2-Conformance-Test-Cases.md Removed 2.0 test --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 04da65e31..4d52d12dc 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -101,11 +101,10 @@ - `AOpensB1`: **A** calls `fdc3.open(‘app B Name’)`, check app **B** opens - `AOpensB2`: **A** calls `fdc3.open({name: “”})`, check app **B** opens - `AOpensB3`: **A** calls `fdc3.open({name: “”, appId: “”}, check app **B** opens. (`FDC3 2.0`) ### A Fails To Open B -- `AFailsToOpenB`: Run the above 4 tests again with a non-existent app name/app id. Should return “App Not Found” Error from https://fdc3.finos.org/docs/api/ref/Errors#openerror +- `AFailsToOpenB1-3`: Run the above 4 tests again with a non-existent app name/app id. Should return “App Not Found” Error from https://fdc3.finos.org/docs/api/ref/Errors#openerror ### A Opens B With Context From 515cd04765e619a00b2842176f7290e7f5bb6e45 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:16:45 +0000 Subject: [PATCH 06/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 4d52d12dc..3239609f7 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -110,10 +110,10 @@ | App | Step | Description | |-----|-----------------|----------------------------------------------------------| -| A | Opening App | various open methods as in `AOpensB1` except with a `` argument
check app opens | +| A | Opening App | various open methods as in `AOpensB1-3` except with a `` argument
check app opens | | B | Context present | `fdc3.addContextListener()`
- receives `` from **A** | -- `AOpensBWithContext`: Perform above tests +- `AOpensBWithContext1-3`: Perform above tests - `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.instrument`)` From eb572a27d01a5a12c1456d042e9eda37c8a0cbb4 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:22:16 +0000 Subject: [PATCH 07/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 3239609f7..f77c00be3 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -110,11 +110,11 @@ | App | Step | Description | |-----|-----------------|----------------------------------------------------------| -| A | Opening App | various open methods as in `AOpensB1-3` except with a `` argument
check app opens | +| A | Opening App | various open methods as in `AOpensB1-3` except with a `` argument of type `fdc3.testReceiver`
check app opens | | B | Context present | `fdc3.addContextListener()`
- receives `` from **A** | - `AOpensBWithContext1-3`: Perform above tests -- `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.instrument`)` +- `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.testReceiver`)` ### Specific Context @@ -123,7 +123,7 @@ | App | Step | Description | |-----|-----------------|-------------------------------------------------------------------------------------------------------------------------------| | A | Opening App | `fdc3.open(‘app Name’, )`
check app opens | -| B | Context present | fdc3.addContextListener()
- receives from a | +| B | Context present | fdc3.addContextListener()
- receives from A | | A | Promise | - receives a rejection from the open promise with “App Timeout’ from
https://fdc3.finos.org/docs/api/ref/Errors#openerror | - `AOpensBWithWrongContext`: As above From 356d65a4c9a107d57c12bdc29a90a02cba477001 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:29:44 +0000 Subject: [PATCH 08/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index f77c00be3..4145d7aff 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -155,7 +155,7 @@ Also we assume a fourth app **D** that is going to discover the intents in the o - `IntentAppDWrongContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextY’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror - `IntentAppDMultiple1`: Calls `fdc3.findIntent(‘sharedTestingIntent1’)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. - `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextX`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. -- `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. +- `IntentAppDMultiple3`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. ### Find Intents By Context From 5b9c085feed303f35e5672a5345825bfacaea483 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:33:49 +0000 Subject: [PATCH 09/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 4145d7aff..f7dcd2a77 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -159,7 +159,7 @@ Also we assume a fourth app **D** that is going to discover the intents in the o ### Find Intents By Context -- `SingleContext`: Call `fdc3.findIntentsByContext(‘fdc3.testContextX’)`. Should return `aTestingIntent` (app **A**), `sharedTestingIntent` (**A**, **B**) and `cTestingIntent` (**C**) AND nothing else. +- `SingleContext`: Call `fdc3.findIntentsByContext(‘fdc3.testContextX’)`. Should return `aTestingIntent` (app **A**), `sharedTestingIntent1` (**A**, **B**) and `cTestingIntent` (**C**) AND nothing else. - `NoContext`: Call `fdc3.findIntentsByContext()`. Throws error of some kind? ### Raise Intent From 5320a8c50150fa9ce777982be2b2f626fe5a1001 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:35:15 +0000 Subject: [PATCH 10/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index f7dcd2a77..9779b81c9 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -160,7 +160,7 @@ Also we assume a fourth app **D** that is going to discover the intents in the o ### Find Intents By Context - `SingleContext`: Call `fdc3.findIntentsByContext(‘fdc3.testContextX’)`. Should return `aTestingIntent` (app **A**), `sharedTestingIntent1` (**A**, **B**) and `cTestingIntent` (**C**) AND nothing else. -- `NoContext`: Call `fdc3.findIntentsByContext()`. Throws error of some kind? +- `NoContext`: Call `fdc3.findIntentsByContext()`. Throws error of `NoAppsFound` ### Raise Intent From 90837b2dac08f721c75363a91e2adf474aed4ce5 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:38:59 +0000 Subject: [PATCH 11/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 9779b81c9..87e7421e3 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -131,8 +131,6 @@ - `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise completes successfully - `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. - - ## 4. Intents ### Setup @@ -171,6 +169,6 @@ Also we assume a fourth app **D** that is going to discover the intents in the o - `SingleResolve1`: Perform above test - `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above -- `TargetedResolve2,3,4` Use the other ways of addressing apps (via ID, metadata) as described at the start of #18 +- `TargetedResolve2,3,4` Use the other ways of addressing apps (via ID, metadata) as described in `AOpensB1-3` - `FailedResolve1-4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive No Apps Available Resolve Error - `FailedResolve5-8` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` and variations. You will receive No Apps Available Resolve Error From ec11322148d3d312be2f94ae5b4029ca3724c4aa Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:40:47 +0000 Subject: [PATCH 12/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 87e7421e3..a3a7d9cd0 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -169,6 +169,6 @@ Also we assume a fourth app **D** that is going to discover the intents in the o - `SingleResolve1`: Perform above test - `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above -- `TargetedResolve2,3,4` Use the other ways of addressing apps (via ID, metadata) as described in `AOpensB1-3` +- `TargetedResolve2-3` Use the other ways of addressing apps (via ID, metadata) as described in `AOpensB2-3` - `FailedResolve1-4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive No Apps Available Resolve Error - `FailedResolve5-8` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` and variations. You will receive No Apps Available Resolve Error From ea18d8b3eebc73671e7216e7875da3dd34aacdcb Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 13:43:42 +0000 Subject: [PATCH 13/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index a3a7d9cd0..250084f3a 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -170,5 +170,5 @@ Also we assume a fourth app **D** that is going to discover the intents in the o - `SingleResolve1`: Perform above test - `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above - `TargetedResolve2-3` Use the other ways of addressing apps (via ID, metadata) as described in `AOpensB2-3` -- `FailedResolve1-4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive No Apps Available Resolve Error -- `FailedResolve5-8` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` and variations. You will receive No Apps Available Resolve Error +- `FailedResolve1-3` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive `NoAppsFound` Error +- `FailedResolve4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )`. You will receive `NoAppsFound` Error From bacdea804273c55ea813c906d2626bc634930869 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:01:47 +0000 Subject: [PATCH 14/55] Update FDC3-1.2-Conformance-Test-Cases.md --- .../FDC3-1.2-Conformance-Test-Cases.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 250084f3a..c126c48e4 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -12,10 +12,10 @@ | B | Broadcast | `fdc3.broadcast()` | | A | Receive Context | Instrument object matches the one broadcast in 2 above. | -- `UC Basic Usage 1` Perform above test -- `UC Basic Usage 2` Perform above test, but join channel first and then `fdc3.addContextListener()` -- `UC Basic Usage 3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining -- `UC Basic Usage 4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining +- `UCBasicUsage1` Perform above test +- `UCBasicUsage2` Perform above test, but join channel first and then `fdc3.addContextListener()` +- `UCBasicUsage3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining +- `UCBasicUsag4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### User Channels Broadcast (Filtered Context) @@ -27,7 +27,7 @@ | B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | -- `UC Filtered Context 1`: Perform above test +- `UCFilteredContext1`: Perform above test | App | Step | Details | |-----|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -37,14 +37,14 @@ | B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Contact object matches the one broadcast in 2 above. | -- `UC Filtered Context 2`: Perform above test -- `UC Filtered Context 3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. -- `UC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. -- `UC Filtered Context 4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `UC Filtered Context 5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. -- `UC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. -- `UC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. -- `UC Current Channel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. +- `UCFilteredContext2`: Perform above test +- `UCFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. +- `UCUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- `UCFilteredContext5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `UCInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. +- `UCInvalidBroadcast2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. +- `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. ## 2. App Channels From a4708667519dcfaa3264239fd3b55fa2d452dc17 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:06:12 +0000 Subject: [PATCH 15/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index c126c48e4..80aab7221 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -41,7 +41,7 @@ - `UCFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. - `UCUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. - `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `UCFilteredContext5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `UCFilteredContext5`: Perform above test, except that after joining, **A** calls `fdc3.leaveCurrentChannel()` and doesn't receive anything. - `UCInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. - `UCInvalidBroadcast2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. - `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. From 3f32c718427ac4547a0c7872c2a451f468927d2d Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:07:07 +0000 Subject: [PATCH 16/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 - 1 file changed, 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 80aab7221..67fdbee33 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -43,7 +43,6 @@ - `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. - `UCFilteredContext5`: Perform above test, except that after joining, **A** calls `fdc3.leaveCurrentChannel()` and doesn't receive anything. - `UCInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. -- `UCInvalidBroadcast2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. - `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. ## 2. App Channels From 83dfa4e63602ca61024136a483ab8a6bab74b469 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:08:50 +0000 Subject: [PATCH 17/55] Update FDC3-1.2-Conformance-Test-Cases.md --- .../FDC3-1.2-Conformance-Test-Cases.md | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 67fdbee33..21c862f09 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -57,9 +57,9 @@ | B | Broadcast | `testChannel.broadcast()` | | A | Receive Context | Instrument object matches the one broadcast in 2 above. | -- `AC Basic Usage 1` Perform above test -- `AC Basic Usage 2` Perform above test, but join channel first and then `testChannel.addContextListener()` -- `AC Basic Usage 3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining +- `ACBasicUsage1` Perform above test +- `ACBasicUsage2` Perform above test, but join channel first and then `testChannel.addContextListener()` +- `ACBasicUsage3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### App Channels Broadcast (Filtered Context) @@ -71,14 +71,13 @@ | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | -- `AC Filtered Context 1`: Perform above test +- `ACFilteredContext1`: Perform above test -- `AC Filtered Context 2`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. -- `AC Unsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. -- `AC Filtered Context 3`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `AC Filtered Context 4`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. -- `AC Invalid Broadcast 1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. -- `AC Invalid Broadcast 2` (2.0 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, promise is rejected. +- `ACFilteredContext2`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. +- `ACUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- `ACFilteredContext3`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- `ACFilteredContext4`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `ACInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. ### App Channel History @@ -89,9 +88,9 @@ | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | `testChannel.getCurrentContext('fdc.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc.contact')` returns the last broadcast contact | -- `AC Context History Typed`: Perform above test. -- `AC Context History Multiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. -- `AC Context History Last`: **A** calls `testChannel.getCurrentContext()` retrieves the last broadcast context item +- `ACContextHistoryTyped`: Perform above test. +- `ACContextHistoryMultiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. +- `ACContextHistoryLast`: **A** calls `testChannel.getCurrentContext()` retrieves the last broadcast context item ## 3. Open API From 7a0b19efb2744d8be72fa5e1d40ef577fad8c790 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:10:48 +0000 Subject: [PATCH 18/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 21c862f09..c4a1b4a1e 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -15,7 +15,7 @@ - `UCBasicUsage1` Perform above test - `UCBasicUsage2` Perform above test, but join channel first and then `fdc3.addContextListener()` - `UCBasicUsage3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining -- `UCBasicUsag4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining +- `UCBasicUsage4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### User Channels Broadcast (Filtered Context) From dc7f8ceafb4d580bc65e916e28e2955b143f5df2 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:25:09 +0000 Subject: [PATCH 19/55] Update FDC3-1.2-Conformance-Test-Cases.md --- .../fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index c4a1b4a1e..ad4a89f39 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -72,11 +72,11 @@ | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | - `ACFilteredContext1`: Perform above test - -- `ACFilteredContext2`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. +- `ACFilteredContext2`: Perform above test, but add listeners for both `fdc3.instrument` and `fdc3.contact` in `addContextListener` step. Both should be received. +- `ACFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. - `ACUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. -- `ACFilteredContext3`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `ACFilteredContext4`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `ACFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- `ACFilteredContext5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. - `ACInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. ### App Channel History From e7c24cf9c77f7ef7939281b82f88415ef222d2fd Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:38:27 +0000 Subject: [PATCH 20/55] Update FDC3-1.2-Conformance-Test-Cases.md --- .../FDC3-1.2-Conformance-Test-Cases.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index ad4a89f39..c03c78a4e 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -51,40 +51,40 @@ | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | joinChannel |`fdc3.getOrCreateChannel("test-channel")` | +| A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | | A | addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | joinChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` | | A | Receive Context | Instrument object matches the one broadcast in 2 above. | - `ACBasicUsage1` Perform above test - `ACBasicUsage2` Perform above test, but join channel first and then `testChannel.addContextListener()` -- `ACBasicUsage3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining +- `ACBasicUsage3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after creating ### App Channels Broadcast (Filtered Context) | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | joinChannel |`fdc3.getOrCreateChannel("test-channel")` | +| A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | | A | addContextListener | Call `testChannel.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | joinChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | - `ACFilteredContext1`: Perform above test - `ACFilteredContext2`: Perform above test, but add listeners for both `fdc3.instrument` and `fdc3.contact` in `addContextListener` step. Both should be received. -- `ACFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. -- `ACUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. -- `ACFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `ACFilteredContext5`: Perform above test, except that after joining, **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `ACFilteredContext3`: Perform above test, except creating a _different_ channel. Check that you _don't_ receive anything. +- `ACUnsubscribe`: Perform above test, except that after creating the channel **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- `ACFilteredContext4`: Perform above test, except that after creating the channel **A** creates another channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. +- `ACFilteredContext5`: Perform above test, except that after creating the channel **A** calls `fdc3.leaveChannel()` and doesn't receive anything. - `ACInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. ### App Channel History | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | joinChannel |`fdc3.getOrCreateChannel("test-channel")` | -| B | joinChannel | `fdc3. getOrCreateChannel("test-channel")` | +| A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | +| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | `testChannel.getCurrentContext('fdc.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc.contact')` returns the last broadcast contact | From 3f01e44ccf53620dbfb79e82a886c0f711583d42 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 14:58:54 +0000 Subject: [PATCH 21/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 - 1 file changed, 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index c03c78a4e..2dbfd8638 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -41,7 +41,6 @@ - `UCFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. - `UCUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. - `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `UCFilteredContext5`: Perform above test, except that after joining, **A** calls `fdc3.leaveCurrentChannel()` and doesn't receive anything. - `UCInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. - `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. From ab59c4888a6814740610aca007be1877f926b299 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 15:20:31 +0000 Subject: [PATCH 22/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 - 1 file changed, 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 2dbfd8638..7276ef694 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -15,7 +15,6 @@ - `UCBasicUsage1` Perform above test - `UCBasicUsage2` Perform above test, but join channel first and then `fdc3.addContextListener()` - `UCBasicUsage3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining -- `UCBasicUsage4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### User Channels Broadcast (Filtered Context) From f14485d727ca9fabf163248567c37ec5e602b533 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 15:21:44 +0000 Subject: [PATCH 23/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 - 1 file changed, 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 7276ef694..e3363704e 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -40,7 +40,6 @@ - `UCFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. - `UCUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. - `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `UCInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. - `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. ## 2. App Channels From 14c093cce381b35d062e91cc76717a1e77472b39 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 8 Nov 2022 15:24:18 +0000 Subject: [PATCH 24/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 - 1 file changed, 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index e3363704e..e1db6496a 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -74,7 +74,6 @@ - `ACUnsubscribe`: Perform above test, except that after creating the channel **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. - `ACFilteredContext4`: Perform above test, except that after creating the channel **A** creates another channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. - `ACFilteredContext5`: Perform above test, except that after creating the channel **A** calls `fdc3.leaveChannel()` and doesn't receive anything. -- `ACInvalidBroadcast1` (1.2 ONLY): Broadcast is sent either without type field / invalid object structure. NOT DELIVERED, no other errors. ### App Channel History From 8f268791c16a1461f4d327437970e67566275b83 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 9 Nov 2022 12:33:11 +0000 Subject: [PATCH 25/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index e1db6496a..14cdbbf49 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -158,7 +158,7 @@ Also we assume a fourth app **D** that is going to discover the intents in the o | App | Step | Details | |-----|----------------|---------------------------------------------------------------------------------------------------| -| D | Raise | `fdc3.raiseIntent(‘sharedTestingIntent1’, {testContextY})`
starts app B. | +| A | Raise | `fdc3.raiseIntent(‘sharedTestingIntent1’, {testContextY})`
starts app B. | | B | Gather Context | `fdc.addIntentListener(‘sharedTestingIntent1’)`
Receives testContextY, matching that sent by D | - `SingleResolve1`: Perform above test From dd130718a316108415ec36e236b5545d18a1747e Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 9 Nov 2022 13:36:10 +0000 Subject: [PATCH 26/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 14cdbbf49..9c6aed323 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -13,7 +13,7 @@ | A | Receive Context | Instrument object matches the one broadcast in 2 above. | - `UCBasicUsage1` Perform above test -- `UCBasicUsage2` Perform above test, but join channel first and then `fdc3.addContextListener()` +- `UCBasicUsage2` Perform above test, but A joins channel first and then `fdc3.addContextListener()` - `UCBasicUsage3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining ### User Channels Broadcast (Filtered Context) From fe242fdca8cc7ba1c76193ff19032285ec211dd2 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 9 Nov 2022 13:41:52 +0000 Subject: [PATCH 27/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 9c6aed323..bd2aafc60 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -38,7 +38,7 @@ - `UCFilteredContext2`: Perform above test - `UCFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. -- `UCUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. +- `UCUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the context listener. Check that **A** _doesn't_ receive anything. - `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. - `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. From cbd426ba96409b15cd04a2fc1e1a61dfc0e105b5 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Fri, 11 Nov 2022 09:33:19 +0000 Subject: [PATCH 28/55] Update FDC3-1.2-Conformance-Test-Cases.md --- .../FDC3-1.2-Conformance-Test-Cases.md | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index bd2aafc60..72e57f7c3 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -1,6 +1,18 @@ # FDC3 1.2 Conformance Test Cases -## 1. System / User Channels +## 1. Basic Tests + +### Context Listener + +- `BasicCL1`: You can call the `addContextListener` on the `DesktopAgent` for the `fdc3.contact` context type without exceptions. +- `BasicCL2`: The returned listener object has an `ubsubscribe` function. + + + + + + +## 2. System / User Channels ### User Channels Broadcast (Basic) @@ -42,7 +54,7 @@ - `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. - `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. -## 2. App Channels +## 3. App Channels ### App Channels Broadcast (Basic) @@ -88,7 +100,7 @@ - `ACContextHistoryMultiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. - `ACContextHistoryLast`: **A** calls `testChannel.getCurrentContext()` retrieves the last broadcast context item -## 3. Open API +## 4. Open API ### A Opens B @@ -125,7 +137,7 @@ - `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise completes successfully - `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. -## 4. Intents +## 5. Intents ### Setup From 6fe8d360becfff0c707d8a9c30220c7947bf1255 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Fri, 11 Nov 2022 10:06:42 +0000 Subject: [PATCH 29/55] Catalogued basic tests in the conformance suite --- .../FDC3-1.2-Conformance-Test-Cases.md | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 72e57f7c3..067452455 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -2,15 +2,19 @@ ## 1. Basic Tests -### Context Listener - -- `BasicCL1`: You can call the `addContextListener` on the `DesktopAgent` for the `fdc3.contact` context type without exceptions. -- `BasicCL2`: The returned listener object has an `ubsubscribe` function. - - - - - +_These are some basic sanity tests implemented in the FDC3 Conformance Framework. It is expected that Desktop Agent testers will run these first before commencing the much more thorough tests in section 2 onwards._ + +- `BasicCL1`: You can call the `fdc3.addContextListener` with the `fdc3.contact` context type. The returned listener object has an `ubsubscribe` function. +- `BasicCL2`: You can call the `fdc3addContextListener` with no context type. The returned listener object has an `ubsubscribe` function. +- `BasicIL1`: You can call the `fdc3.addIntentListener` on the `DesktopAgent` for an intent, and get back a `Listener` object with `unsubscribe` method. +- `BasicCH1`: A call to `fdc3.getCurrentChannel` on the `DesktopAgent` always returns a promise. +- `BasicCH2`: A call to `fdc3.getCurrentChannel()` returns a promise resolving to _null_ if called prior to any `joinChannel`. +- `BasicGI1`: A call to `fdc3.getInfo()` returns an object with `fdc3Version` and `provider` properties. +- `BasicAC1`: A call to `fdc3.getOrCreateChannel()` will return an object matching the `Channel` interface, with properties of `id`, `type`, `broadcast`, `getCurrentContext` and `addContextListener`. +- `BasicUC1`: You can call the `fdc3.getSystemChannels()` function and receive a promise containing an array of more than 1 `Channel` objects, each with type and id set. +- `BasicJC1`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. `fdc3.getCurrentChannel` should then return that joined channel. +- `BasicLC1`: You can call `fdc3.leaveCurrentChannel` at any time without exception. +- `BasicRI1`: You can call `fdc3.raiseIntentForContext`, passing in a context object with some `type` field. ## 2. System / User Channels @@ -52,7 +56,6 @@ - `UCFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. - `UCUnsubscribe`: Perform above test, except that after joining, **A** then `unsubscribe()`s the context listener. Check that **A** _doesn't_ receive anything. - `UCFilteredContext4`: Perform above test, except that after joining, **A** changes channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `UCCurrentChannel`: A call to `fdc3.getCurrentChannel()` returns _null_ if called prior to any `joinChannel`. ## 3. App Channels From e8cd4c07eb8d45cfe96adb6abc32f0f896f37b7c Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 11:14:15 +0000 Subject: [PATCH 30/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Kris West --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 067452455..ad70f0946 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -95,7 +95,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| | A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | -| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | createChannel | `fdc3.getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | `testChannel.getCurrentContext('fdc.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc.contact')` returns the last broadcast contact | From a8fdaa5176abc80bbdb34f84de5ff3d24783527d Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 11:14:27 +0000 Subject: [PATCH 31/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Kris West --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index ad70f0946..91dfd74e2 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -97,7 +97,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | | B | createChannel | `fdc3.getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | -| A | Receive Context | `testChannel.getCurrentContext('fdc.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc.contact')` returns the last broadcast contact | +| A | Receive Context | `testChannel.getCurrentContext('fdc3.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc3.contact')` returns the last broadcast contact | - `ACContextHistoryTyped`: Perform above test. - `ACContextHistoryMultiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. From cd95bbcc58c2e5d60358a15b433850ef1b51f5ac Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 12:55:23 +0000 Subject: [PATCH 32/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Kris West --- .../fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 91dfd74e2..0647fe8da 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -77,18 +77,17 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | +| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | | A | addContextListener | Call `testChannel.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | createChannel | `const testChannel = await fdc3. getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | | A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | - `ACFilteredContext1`: Perform above test - `ACFilteredContext2`: Perform above test, but add listeners for both `fdc3.instrument` and `fdc3.contact` in `addContextListener` step. Both should be received. - `ACFilteredContext3`: Perform above test, except creating a _different_ channel. Check that you _don't_ receive anything. -- `ACUnsubscribe`: Perform above test, except that after creating the channel **A** then `unsubscribe()`s the channel. Check that **A** _doesn't_ receive anything. -- `ACFilteredContext4`: Perform above test, except that after creating the channel **A** creates another channel with a further _different_ channel. Check that **A** _doesn't_ receive anything. -- `ACFilteredContext5`: Perform above test, except that after creating the channel **A** calls `fdc3.leaveChannel()` and doesn't receive anything. +- `ACUnsubscribe`: Perform above test, except that after creating the channel **A** then `unsubscribe()`s the listener it added to the channel. Check that **A** _doesn't_ receive anything. +- `ACFilteredContext4`: Perform above test, except that after creating the channel **A** creates another channel with a further _different_ channel id. Check that **A** _doesn't_ receive anything. ### App Channel History From 2148848fd852df00d85cc6e84a3571e3ddf2f69b Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 13:45:37 +0000 Subject: [PATCH 33/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 - 1 file changed, 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 0647fe8da..9bbee589f 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -71,7 +71,6 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `ACBasicUsage1` Perform above test - `ACBasicUsage2` Perform above test, but join channel first and then `testChannel.addContextListener()` -- `ACBasicUsage3` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after creating ### App Channels Broadcast (Filtered Context) From 3c72a9cc387641725b37d2e5e0fe6c7ec4f936e9 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 13:48:00 +0000 Subject: [PATCH 34/55] Update FDC3-1.2-Conformance-Test-Cases.md --- .../FDC3-1.2-Conformance-Test-Cases.md | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 9bbee589f..ce8dc622d 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -22,15 +22,22 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | addContextListener |Call `fdc3.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| A | joinChannel |`fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | -| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | -| B | Broadcast | `fdc3.broadcast()` | -| A | Receive Context | Instrument object matches the one broadcast in 2 above. | - -- `UCBasicUsage1` Perform above test -- `UCBasicUsage2` Perform above test, but A joins channel first and then `fdc3.addContextListener()` -- `UCBasicUsage3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining +| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| A | addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| B | createChannel | `const testChannel = fdc3. getOrCreateChannel("test-channel")` | +| B | Broadcast | `testChannel.broadcast()` | +| A | Receive Context | Instrument object matches the one broadcast in 2 above. | + +- `ACBasicUsage1` Perform above test + +| App | Step | Details | +|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | Broadcast | `testChannel.broadcast()` | +| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| A | getCurrentContext |Call `testChannel.getCurrentContext()`
Check that the Context object returned is of the expected type. | + +- `ACBasicUsage2` Perform above test. ### User Channels Broadcast (Filtered Context) From 7f38212ea35eafbd0390b5df4deab4167a9bc121 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 13:48:33 +0000 Subject: [PATCH 35/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index ce8dc622d..5786ab15a 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -32,7 +32,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | createChannel | `const testChannel = await fdc3.getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` | | A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | | A | getCurrentContext |Call `testChannel.getCurrentContext()`
Check that the Context object returned is of the expected type. | From d13d5469588586614ef01de87476f53d5e43ec30 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 14:43:40 +0000 Subject: [PATCH 36/55] Update FDC3-1.2-Conformance-Test-Cases.md cut and paste error with basic usage tests --- .../FDC3-1.2-Conformance-Test-Cases.md | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 5786ab15a..b0d70484a 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -22,22 +22,16 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | -| A | addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | createChannel | `const testChannel = fdc3. getOrCreateChannel("test-channel")` | -| B | Broadcast | `testChannel.broadcast()` | -| A | Receive Context | Instrument object matches the one broadcast in 2 above. | - -- `ACBasicUsage1` Perform above test - -| App | Step | Details | -|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| B | createChannel | `const testChannel = await fdc3.getOrCreateChannel("test-channel")` | -| B | Broadcast | `testChannel.broadcast()` | -| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | -| A | getCurrentContext |Call `testChannel.getCurrentContext()`
Check that the Context object returned is of the expected type. | +| A | addContextListener |Call `fdc3.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| A | joinChannel |`fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | Broadcast | `fdc3.broadcast()` | +| A | Receive Context | Instrument object matches the one broadcast in 2 above. | -- `ACBasicUsage2` Perform above test. +- `UC Basic Usage 1` Perform above test +- `UC Basic Usage 2` Perform above test, but join channel first and then `fdc3.addContextListener()` +- `UC Basic Usage 3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining +- `UC Basic Usage 4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### User Channels Broadcast (Filtered Context) @@ -68,16 +62,25 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework ### App Channels Broadcast (Basic) + | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | +| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | | A | addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | createChannel | `fdc3. getOrCreateChannel("test-channel")` | +| B | createChannel | `const testChannel = fdc3. getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` | | A | Receive Context | Instrument object matches the one broadcast in 2 above. | - `ACBasicUsage1` Perform above test -- `ACBasicUsage2` Perform above test, but join channel first and then `testChannel.addContextListener()` + +| App | Step | Details | +|-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| B | createChannel | `const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| B | Broadcast | `testChannel.broadcast()` | +| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| A | getCurrentContext |Call `testChannel.getCurrentContext()`
Check that the Context object returned is of the expected type. | + +- `ACBasicUsage2` Perform above test. ### App Channels Broadcast (Filtered Context) From 2ed7c2e85c8f0facd8bd563a9a6d91f528176708 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Tue, 15 Nov 2022 14:45:15 +0000 Subject: [PATCH 37/55] Update FDC3-1.2-Conformance-Test-Cases.md --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 - 1 file changed, 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index b0d70484a..dda9a611b 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -31,7 +31,6 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `UC Basic Usage 1` Perform above test - `UC Basic Usage 2` Perform above test, but join channel first and then `fdc3.addContextListener()` - `UC Basic Usage 3` Do the app B steps first to populate the channel with context, check that A will receive the context after joining -- `UC Basic Usage 4` Do the app B steps first but in reverse order to populate the channel with context, check that A will receive the context after joining ### User Channels Broadcast (Filtered Context) From 629c9d0eafac59051b7a90d7fbb44cffeba38cc3 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:20:59 +0000 Subject: [PATCH 38/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index dda9a611b..25c058b84 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -4,7 +4,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework. It is expected that Desktop Agent testers will run these first before commencing the much more thorough tests in section 2 onwards._ -- `BasicCL1`: You can call the `fdc3.addContextListener` with the `fdc3.contact` context type. The returned listener object has an `ubsubscribe` function. +- `BasicCL1`: You can call the `fdc3.addContextListener` with the `fdc3.contact` context type. The returned listener object has an `unsubscribe` function. - `BasicCL2`: You can call the `fdc3addContextListener` with no context type. The returned listener object has an `ubsubscribe` function. - `BasicIL1`: You can call the `fdc3.addIntentListener` on the `DesktopAgent` for an intent, and get back a `Listener` object with `unsubscribe` method. - `BasicCH1`: A call to `fdc3.getCurrentChannel` on the `DesktopAgent` always returns a promise. From e75f101844800dc9dd93a7461d29376c2ab7e0cd Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:21:18 +0000 Subject: [PATCH 39/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 25c058b84..5b7d3f3db 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -143,7 +143,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | A | Promise | - receives a rejection from the open promise with “App Timeout’ from
https://fdc3.finos.org/docs/api/ref/Errors#openerror | - `AOpensBWithWrongContext`: As above -- `AOpensBNoListen`: Skip `fdc3.addContextListener() above. +- `AOpensBNoListen`: Skip `fdc3.addContextListener()` above. - `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise completes successfully - `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. From 9f33b4d6c6e33e190776a5d8d069da5d546ec165 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:21:30 +0000 Subject: [PATCH 40/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 5b7d3f3db..ee54068db 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -11,7 +11,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `BasicCH2`: A call to `fdc3.getCurrentChannel()` returns a promise resolving to _null_ if called prior to any `joinChannel`. - `BasicGI1`: A call to `fdc3.getInfo()` returns an object with `fdc3Version` and `provider` properties. - `BasicAC1`: A call to `fdc3.getOrCreateChannel()` will return an object matching the `Channel` interface, with properties of `id`, `type`, `broadcast`, `getCurrentContext` and `addContextListener`. -- `BasicUC1`: You can call the `fdc3.getSystemChannels()` function and receive a promise containing an array of more than 1 `Channel` objects, each with type and id set. +- `BasicUC1`: You can call the `fdc3.getSystemChannels()` function and receive a promise containing an array of more than 1 `Channel` objects, each with `type` and `id` set. - `BasicJC1`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. `fdc3.getCurrentChannel` should then return that joined channel. - `BasicLC1`: You can call `fdc3.leaveCurrentChannel` at any time without exception. - `BasicRI1`: You can call `fdc3.raiseIntentForContext`, passing in a context object with some `type` field. From b7240fa04374fa24338d597031505d384200d873 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:21:40 +0000 Subject: [PATCH 41/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index ee54068db..fcccd89dd 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -5,7 +5,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework. It is expected that Desktop Agent testers will run these first before commencing the much more thorough tests in section 2 onwards._ - `BasicCL1`: You can call the `fdc3.addContextListener` with the `fdc3.contact` context type. The returned listener object has an `unsubscribe` function. -- `BasicCL2`: You can call the `fdc3addContextListener` with no context type. The returned listener object has an `ubsubscribe` function. +- `BasicCL2`: You can call the `fdc3addContextListener` with no context type. The returned listener object has an `unsubscribe` function. - `BasicIL1`: You can call the `fdc3.addIntentListener` on the `DesktopAgent` for an intent, and get back a `Listener` object with `unsubscribe` method. - `BasicCH1`: A call to `fdc3.getCurrentChannel` on the `DesktopAgent` always returns a promise. - `BasicCH2`: A call to `fdc3.getCurrentChannel()` returns a promise resolving to _null_ if called prior to any `joinChannel`. From bc91396751700d1991567eca7a1a9e7ed23be310 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:22:25 +0000 Subject: [PATCH 42/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index fcccd89dd..ca7711f3d 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -104,7 +104,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | | B | createChannel | `fdc3.getOrCreateChannel("test-channel")` | | B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | -| A | Receive Context | `testChannel.getCurrentContext('fdc3.instrument')` returns the last instrument
testChannel.getCurrentContext('fdc3.contact')` returns the last broadcast contact | +| A | Receive Context | `testChannel.getCurrentContext('fdc3.instrument')` returns the last broadcast instrument
`testChannel.getCurrentContext('fdc3.contact')` returns the last broadcast contact | - `ACContextHistoryTyped`: Perform above test. - `ACContextHistoryMultiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. From ba6b4546f17b86cc1c6193514aed6138e837767f Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:28:21 +0000 Subject: [PATCH 43/55] Fixed step numbering and references --- .../FDC3-1.2-Conformance-Test-Cases.md | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index ca7711f3d..f48963f60 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -22,11 +22,11 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | addContextListener |Call `fdc3.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| A | joinChannel |`fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | -| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | -| B | Broadcast | `fdc3.broadcast()` | -| A | Receive Context | Instrument object matches the one broadcast in 2 above. | +| A | 1. addContextListener |Call `fdc3.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| A | 2. joinChannel |`fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | 3. joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | 4. Broadcast | `fdc3.broadcast()` | +| A | 5. Receive Context | Instrument object matches the one broadcast in 4 above. | - `UC Basic Usage 1` Perform above test - `UC Basic Usage 2` Perform above test, but join channel first and then `fdc3.addContextListener()` @@ -36,21 +36,21 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | addContextListener | Call `fdc3.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| A | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | -| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | -| B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | -| A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | +| A | 1. addContextListener | Call `fdc3.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| A | 2. joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | 3. joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | 4. Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | +| A | 5. Receive Context | Instrument object matches the one broadcast in 4 above.
Check that the contact is not received. | - `UCFilteredContext1`: Perform above test | App | Step | Details | |-----|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | addContextListener | Call `addContextListener (“fdc3.instrument”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object
Call `addContextListener (“fdc3.contact”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object | -| A | joinChannel | Check that there is an unsubscribe function on the returned object | -| B | joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | -| B | Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | -| A | Receive Context | Instrument object matches the one broadcast in 2 above.
Contact object matches the one broadcast in 2 above. | +| A | 1. addContextListener | Call `addContextListener (“fdc3.instrument”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object
Call `addContextListener (“fdc3.contact”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object | +| A | 2. joinChannel | Check that there is an unsubscribe function on the returned object | +| B | 3. joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | +| B | 4. Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | +| A | 5. Receive Context | Instrument object matches the one broadcast in 4 above.
Contact object matches the one broadcast in 4 above. | - `UCFilteredContext2`: Perform above test - `UCFilteredContext3`: Perform above test, except joining a _different_ channel. Check that you _don't_ receive anything. @@ -64,20 +64,20 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | -| A | addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | createChannel | `const testChannel = fdc3. getOrCreateChannel("test-channel")` | -| B | Broadcast | `testChannel.broadcast()` | -| A | Receive Context | Instrument object matches the one broadcast in 2 above. | +| A | 1. createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| A | 2. addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| B | 3. createChannel | `const testChannel = fdc3. getOrCreateChannel("test-channel")` | +| B | 4. Broadcast | `testChannel.broadcast()` | +| A | 5. Receive Context | Instrument object matches the one broadcast in 4 above. | - `ACBasicUsage1` Perform above test | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| B | createChannel | `const testChannel = await fdc3.getOrCreateChannel("test-channel")` | -| B | Broadcast | `testChannel.broadcast()` | -| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | -| A | getCurrentContext |Call `testChannel.getCurrentContext()`
Check that the Context object returned is of the expected type. | +| B | 1. createChannel | `const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| B | 2. Broadcast | `testChannel.broadcast()` | +| A | 3. createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| A | 4. getCurrentContext |Call `testChannel.getCurrentContext()`
Check that the Context object returned is of the expected type. | - `ACBasicUsage2` Perform above test. @@ -85,11 +85,11 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | -| A | addContextListener | Call `testChannel.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | createChannel | `const testChannel = await fdc3. getOrCreateChannel("test-channel")` | -| B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | -| A | Receive Context | Instrument object matches the one broadcast in 2 above.
Check that the contact is not received. | +| A | 1. createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | +| A | 2. addContextListener | Call `testChannel.addContextListener("fdc3.instrument", handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | +| B | 3. createChannel | `const testChannel = await fdc3. getOrCreateChannel("test-channel")` | +| B | 4. Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | +| A | 5. Receive Context | Instrument object matches the one broadcast in 4 above.
Check that the contact is not received. | - `ACFilteredContext1`: Perform above test - `ACFilteredContext2`: Perform above test, but add listeners for both `fdc3.instrument` and `fdc3.contact` in `addContextListener` step. Both should be received. @@ -101,10 +101,10 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| A | createChannel |`fdc3.getOrCreateChannel("test-channel")` | -| B | createChannel | `fdc3.getOrCreateChannel("test-channel")` | -| B | Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | -| A | Receive Context | `testChannel.getCurrentContext('fdc3.instrument')` returns the last broadcast instrument
`testChannel.getCurrentContext('fdc3.contact')` returns the last broadcast contact | +| A | 1. createChannel |`fdc3.getOrCreateChannel("test-channel")` | +| B | 2. createChannel | `fdc3.getOrCreateChannel("test-channel")` | +| B | 3. Broadcast | `testChannel.broadcast()` the instrument context.
`testChannel.broadcast()` a contact context. | +| A | 4. Receive Context | `testChannel.getCurrentContext('fdc3.instrument')` returns the last broadcast instrument
`testChannel.getCurrentContext('fdc3.contact')` returns the last broadcast contact | - `ACContextHistoryTyped`: Perform above test. - `ACContextHistoryMultiple`: **B** Broadcasts multiple history items of both types. Only the last version of each type is received by **A**. @@ -126,8 +126,8 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Description | |-----|-----------------|----------------------------------------------------------| -| A | Opening App | various open methods as in `AOpensB1-3` except with a `` argument of type `fdc3.testReceiver`
check app opens | -| B | Context present | `fdc3.addContextListener()`
- receives `` from **A** | +| A | 1. Opening App | various open methods as in `AOpensB1-3` except with a `` argument of type `fdc3.testReceiver`
check app opens | +| B | 2. Context present | `fdc3.addContextListener()`
- receives `` from **A** | - `AOpensBWithContext1-3`: Perform above tests - `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.testReceiver`)` @@ -138,9 +138,9 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Description | |-----|-----------------|-------------------------------------------------------------------------------------------------------------------------------| -| A | Opening App | `fdc3.open(‘app Name’, )`
check app opens | -| B | Context present | fdc3.addContextListener()
- receives from A | -| A | Promise | - receives a rejection from the open promise with “App Timeout’ from
https://fdc3.finos.org/docs/api/ref/Errors#openerror | +| A | 1. Opening App | `fdc3.open(‘app Name’, )`
check app opens | +| B | 2. Context present | fdc3.addContextListener()
- receives from A | +| A | 3. Promise | - receives a rejection from the open promise with “App Timeout’ from
https://fdc3.finos.org/docs/api/ref/Errors#openerror | - `AOpensBWithWrongContext`: As above - `AOpensBNoListen`: Skip `fdc3.addContextListener()` above. @@ -180,8 +180,8 @@ Also we assume a fourth app **D** that is going to discover the intents in the o | App | Step | Details | |-----|----------------|---------------------------------------------------------------------------------------------------| -| A | Raise | `fdc3.raiseIntent(‘sharedTestingIntent1’, {testContextY})`
starts app B. | -| B | Gather Context | `fdc.addIntentListener(‘sharedTestingIntent1’)`
Receives testContextY, matching that sent by D | +| A | 1. Raise | `fdc3.raiseIntent(‘sharedTestingIntent1’, {testContextY})`
starts app B. | +| B | 2. Gather Context | `fdc.addIntentListener(‘sharedTestingIntent1’)`
Receives testContextY, matching that sent by D | - `SingleResolve1`: Perform above test - `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above From 7fc58c8218fb421129b0ffb1732ec4fb777c37d7 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:29:28 +0000 Subject: [PATCH 44/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index f48963f60..b46f1cefb 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -144,7 +144,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `AOpensBWithWrongContext`: As above - `AOpensBNoListen`: Skip `fdc3.addContextListener()` above. -- `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise completes successfully +- `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise resolves successfully - `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. ## 5. Intents From 450bed08623c6083ab8bf35f5c450cbc48bb962f Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:29:52 +0000 Subject: [PATCH 45/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index b46f1cefb..5783bb4d9 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -168,7 +168,7 @@ Also we assume a fourth app **D** that is going to discover the intents in the o - `IntentAppDRightContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextX’)`. Receives promise containing an appIntent with metadata containing `aTestingIntent` and only **A** app metadata. - `IntentAppDWrongContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextY’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror - `IntentAppDMultiple1`: Calls `fdc3.findIntent(‘sharedTestingIntent1’)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. -- `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextX`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. +- `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextX')`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. - `IntentAppDMultiple3`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. ### Find Intents By Context From 5b7a9de6a35a3034ec7a31b56802dbc7186e2692 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:30:02 +0000 Subject: [PATCH 46/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Hugh Troeger --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 5783bb4d9..d2b06cc37 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -169,7 +169,7 @@ Also we assume a fourth app **D** that is going to discover the intents in the o - `IntentAppDWrongContext`: Calls `fdc3.findIntent(‘aTestingIntent’, ‘fdc3.testContextY’)`. Rejects with no apps found error https://fdc3.finos.org/docs/api/ref/Errors#resolveerror - `IntentAppDMultiple1`: Calls `fdc3.findIntent(‘sharedTestingIntent1’)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. - `IntentAppDMultiple2`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextX')`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **A** and **B** app metadata. -- `IntentAppDMultiple3`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY`)`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. +- `IntentAppDMultiple3`: Calls `fdc3.findIntent(‘sharedTestingIntent1’, 'testContextY')`. Receives promise containing an appIntent with metadata containing `sharedTestingIntent` and only **B** app metadata. ### Find Intents By Context From f77a9eefe7a1cbaa3ed4590b8a2a17b921c9f63d Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 11:34:44 +0000 Subject: [PATCH 47/55] fixed exception query --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index d2b06cc37..ec06adea8 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -13,7 +13,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `BasicAC1`: A call to `fdc3.getOrCreateChannel()` will return an object matching the `Channel` interface, with properties of `id`, `type`, `broadcast`, `getCurrentContext` and `addContextListener`. - `BasicUC1`: You can call the `fdc3.getSystemChannels()` function and receive a promise containing an array of more than 1 `Channel` objects, each with `type` and `id` set. - `BasicJC1`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. `fdc3.getCurrentChannel` should then return that joined channel. -- `BasicLC1`: You can call `fdc3.leaveCurrentChannel` at any time without exception. +- `BasicLC1`: You can call `fdc3.leaveCurrentChannel` at any time without it throwing an exception. - `BasicRI1`: You can call `fdc3.raiseIntentForContext`, passing in a context object with some `type` field. ## 2. System / User Channels From ac7308ca0581be26a8d93a868525b6b497410b87 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 12:09:27 +0000 Subject: [PATCH 48/55] Incorporated Kris' comment on the 2.0 spec --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index ec06adea8..06e88e8a7 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -10,7 +10,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `BasicCH1`: A call to `fdc3.getCurrentChannel` on the `DesktopAgent` always returns a promise. - `BasicCH2`: A call to `fdc3.getCurrentChannel()` returns a promise resolving to _null_ if called prior to any `joinChannel`. - `BasicGI1`: A call to `fdc3.getInfo()` returns an object with `fdc3Version` and `provider` properties. -- `BasicAC1`: A call to `fdc3.getOrCreateChannel()` will return an object matching the `Channel` interface, with properties of `id`, `type`, `broadcast`, `getCurrentContext` and `addContextListener`. +- `BasicAC1`: A call to `fdc3.getOrCreateChannel()` will return an promise resolving to an object matching the `Channel` interface, with properties of `id`, `type`, `broadcast`, `getCurrentContext` and `addContextListener`. - `BasicUC1`: You can call the `fdc3.getSystemChannels()` function and receive a promise containing an array of more than 1 `Channel` objects, each with `type` and `id` set. - `BasicJC1`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. `fdc3.getCurrentChannel` should then return that joined channel. - `BasicLC1`: You can call `fdc3.leaveCurrentChannel` at any time without it throwing an exception. From b7826c7e9a97ff4475816b5c083f2d17d2f51eb8 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Mon, 21 Nov 2022 12:10:38 +0000 Subject: [PATCH 49/55] incorporated kris' change from 2.0 review --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 06e88e8a7..0c77518ae 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -12,7 +12,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `BasicGI1`: A call to `fdc3.getInfo()` returns an object with `fdc3Version` and `provider` properties. - `BasicAC1`: A call to `fdc3.getOrCreateChannel()` will return an promise resolving to an object matching the `Channel` interface, with properties of `id`, `type`, `broadcast`, `getCurrentContext` and `addContextListener`. - `BasicUC1`: You can call the `fdc3.getSystemChannels()` function and receive a promise containing an array of more than 1 `Channel` objects, each with `type` and `id` set. -- `BasicJC1`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. `fdc3.getCurrentChannel` should then return that joined channel. +- `BasicJC1`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. After the returned promise is resolved, `fdc3.getCurrentChannel` should then return that joined channel. - `BasicLC1`: You can call `fdc3.leaveCurrentChannel` at any time without it throwing an exception. - `BasicRI1`: You can call `fdc3.raiseIntentForContext`, passing in a context object with some `type` field. From febfc32db672c17ee7bc678909ceb74fb5651d7a Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 23 Nov 2022 15:21:04 +0000 Subject: [PATCH 50/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Kris West --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 0c77518ae..6d017af6d 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -47,7 +47,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Details | |-----|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | A | 1. addContextListener | Call `addContextListener (“fdc3.instrument”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object
Call `addContextListener (“fdc3.contact”, handler)`
Check listener object returned
Check that there is an unsubscribe function on the returned object | -| A | 2. joinChannel | Check that there is an unsubscribe function on the returned object | +| A | 2. joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel. Check that there is an unsubscribe function on the returned object | | B | 3. joinChannel | `fdc3.getSystemChannels()`
Check channels are returned.
Call `fdc3.joinChannel()` on first non-global channel | | B | 4. Broadcast | `fdc3.broadcast()` the instrument context.
`fdc3.broadcast()` a contact context. | | A | 5. Receive Context | Instrument object matches the one broadcast in 4 above.
Contact object matches the one broadcast in 4 above. | From 2a01225da4d6edb9eaa7a1ee65b52ed0fc374eff Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 23 Nov 2022 15:21:47 +0000 Subject: [PATCH 51/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Kris West --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 6d017af6d..f20eda553 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -93,7 +93,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `ACFilteredContext1`: Perform above test - `ACFilteredContext2`: Perform above test, but add listeners for both `fdc3.instrument` and `fdc3.contact` in `addContextListener` step. Both should be received. -- `ACFilteredContext3`: Perform above test, except creating a _different_ channel. Check that you _don't_ receive anything. +- `ACFilteredContext3`: Perform above test, except creating a _different_ channel in app B. Check that you _don't_ receive anything (as the channels don't match). - `ACUnsubscribe`: Perform above test, except that after creating the channel **A** then `unsubscribe()`s the listener it added to the channel. Check that **A** _doesn't_ receive anything. - `ACFilteredContext4`: Perform above test, except that after creating the channel **A** creates another channel with a further _different_ channel id. Check that **A** _doesn't_ receive anything. From 39f9a077dc30fe820e50792437d5bcf41eb2531c Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 23 Nov 2022 15:24:30 +0000 Subject: [PATCH 52/55] Update toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md Co-authored-by: Kris West --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index f20eda553..5ed76eca3 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -95,7 +95,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `ACFilteredContext2`: Perform above test, but add listeners for both `fdc3.instrument` and `fdc3.contact` in `addContextListener` step. Both should be received. - `ACFilteredContext3`: Perform above test, except creating a _different_ channel in app B. Check that you _don't_ receive anything (as the channels don't match). - `ACUnsubscribe`: Perform above test, except that after creating the channel **A** then `unsubscribe()`s the listener it added to the channel. Check that **A** _doesn't_ receive anything. -- `ACFilteredContext4`: Perform above test, except that after creating the channel **A** creates another channel with a further _different_ channel id. Check that **A** _doesn't_ receive anything. +- `ACFilteredContext4`: Perform above test, except that after creating the channel **A** creates another channel with a further _different_ channel id and adds a further context listener to it. Check that **A** is still able to receive context on the first channel (i.e. it is unaffected by the additional channel) and does *NOT* receive anything on the second channel. ### App Channel History From 3352c918ea42402693b26bd5f44f401a9219e5a7 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Wed, 23 Nov 2022 15:42:18 +0000 Subject: [PATCH 53/55] tidied up kris' remaining issues, removed 2 tests discussed in maintainers meeting --- .../FDC3-1.2-Conformance-Test-Cases.md | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 5ed76eca3..e09d2fb9c 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -116,7 +116,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `AOpensB1`: **A** calls `fdc3.open(‘app B Name’)`, check app **B** opens - `AOpensB2`: **A** calls `fdc3.open({name: “”})`, check app **B** opens -- `AOpensB3`: **A** calls `fdc3.open({name: “”, appId: “”, appId: “”})`, check app **B** opens ### A Fails To Open B @@ -129,8 +129,10 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | A | 1. Opening App | various open methods as in `AOpensB1-3` except with a `` argument of type `fdc3.testReceiver`
check app opens | | B | 2. Context present | `fdc3.addContextListener()`
- receives `` from **A** | -- `AOpensBWithContext1-3`: Perform above tests -- `AOpensBWithSpecificContext`: Perform above but replace **B**s call with `fdc3.addContextListener('fdc3.testReceiver`)` +- `AOpensB1WithContext1`: **A** calls `fdc3.open(‘app B Name', ctx)`, check app **B** opens +- `AOpensB2WithContext2`: **A** calls `fdc3.open({name: “”}, ctx)`, check app **B** opens +- `AOpensB3WithContext3`: **A** calls `fdc3.open({name: “”, appId: “”}, ctx)`, check app **B** opens +- `AOpensBWithSpecificContext1`: Perform `AOpensB1WithContext1` above but replace **B**s call with `fdc3.addContextListener('fdc3.testReceiver`)` ### Specific Context @@ -139,13 +141,11 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework | App | Step | Description | |-----|-----------------|-------------------------------------------------------------------------------------------------------------------------------| | A | 1. Opening App | `fdc3.open(‘app Name’, )`
check app opens | -| B | 2. Context present | fdc3.addContextListener()
- receives from A | +| B | 2. Context present | `fdc3.addContextListener()`
`fdc3.addContextListener('fdc3.instrument')`
- receives from A | | A | 3. Promise | - receives a rejection from the open promise with “App Timeout’ from
https://fdc3.finos.org/docs/api/ref/Errors#openerror | -- `AOpensBWithWrongContext`: As above -- `AOpensBNoListen`: Skip `fdc3.addContextListener()` above. -- `AOpensBMultipleListen`: **B** performs `fdc3.addContextListener('fdc3.instrument') prior to the existing `addContextListener`. The correct context listener should receive the context, and the promise resolves successfully -- `AOpensBMalformedContext`: **A** tries to pass malformed context to **B**. Context listener receives nothing, promise completes successfully. +- `AOpensBMultipleListen`: The correct (first) context listener should receive the context, and the promise resolves successfully in **A**. +- `AOpensBMalformedContext`: **A** tries to pass malformed context to **B** (i.e. no `type` field on the context object). Context listeners receive nothing, promise completes successfully. ## 5. Intents @@ -185,6 +185,7 @@ Also we assume a fourth app **D** that is going to discover the intents in the o - `SingleResolve1`: Perform above test - `TargetedResolve1`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )` to start app A, otherwise, as above -- `TargetedResolve2-3` Use the other ways of addressing apps (via ID, metadata) as described in `AOpensB2-3` -- `FailedResolve1-3` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive `NoAppsFound` Error +- `TargetedResolve2`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, {name: ""})` to start app A, otherwise, as above +- `TargetedResolve3`: Use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, {name: “”, appId: “”})` to start app A, otherwise, as above +- `FailedResolve1-3` As with `TargetedResolve1-3`, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextY}, )` and variations. You will receive `NoAppsFound` Error - `FailedResolve4` As above, but use `fdc3.raiseIntent(‘aTestingIntent’, {testContextX}, )`. You will receive `NoAppsFound` Error From 1b08e94fe750316c53becc6c40e85b17a08b8d13 Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Thu, 24 Nov 2022 16:33:55 +0000 Subject: [PATCH 54/55] removed errant space --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index e09d2fb9c..486046c32 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -66,7 +66,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework |-----|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| | A | 1. createChannel |`const testChannel = await fdc3.getOrCreateChannel("test-channel")` | | A | 2. addContextListener |Call `testChannel.addContextListener(null, handler)`
Check listener object returned
Check that there is an `unsubscribe` function on the returned object | -| B | 3. createChannel | `const testChannel = fdc3. getOrCreateChannel("test-channel")` | +| B | 3. createChannel | `const testChannel = fdc3.getOrCreateChannel("test-channel")` | | B | 4. Broadcast | `testChannel.broadcast()` | | A | 5. Receive Context | Instrument object matches the one broadcast in 4 above. | From 03bd0de988045860313c9670dae026be49bae21f Mon Sep 17 00:00:00 2001 From: Rob Moffat Date: Thu, 24 Nov 2022 16:36:01 +0000 Subject: [PATCH 55/55] added BasicJC2 --- toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md | 1 + 1 file changed, 1 insertion(+) diff --git a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md index 486046c32..de8561864 100644 --- a/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md +++ b/toolbox/fdc3-conformance/FDC3-1.2-Conformance-Test-Cases.md @@ -13,6 +13,7 @@ _These are some basic sanity tests implemented in the FDC3 Conformance Framework - `BasicAC1`: A call to `fdc3.getOrCreateChannel()` will return an promise resolving to an object matching the `Channel` interface, with properties of `id`, `type`, `broadcast`, `getCurrentContext` and `addContextListener`. - `BasicUC1`: You can call the `fdc3.getSystemChannels()` function and receive a promise containing an array of more than 1 `Channel` objects, each with `type` and `id` set. - `BasicJC1`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. After the returned promise is resolved, `fdc3.getCurrentChannel` should then return that joined channel. +- `BasicJC2`: You can call `fdc3.joinChannel`, passing in the `id` of one of the system channels. `fdc3.getCurrentChannel()` will return the same channel back. - `BasicLC1`: You can call `fdc3.leaveCurrentChannel` at any time without it throwing an exception. - `BasicRI1`: You can call `fdc3.raiseIntentForContext`, passing in a context object with some `type` field.