From 5edd90c0159e0153cb7e38559d438af4b2e3ff61 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Thu, 2 May 2024 16:02:58 +0200 Subject: [PATCH 01/32] chore: Wrap settings, trade and wallet screen into shell route This will allow us to have root context, which can manage dialogs. --- mobile/lib/common/routes.dart | 301 +++++++++++++++--------------- mobile/lib/common/xxi_screen.dart | 24 +++ 2 files changed, 179 insertions(+), 146 deletions(-) create mode 100644 mobile/lib/common/xxi_screen.dart diff --git a/mobile/lib/common/routes.dart b/mobile/lib/common/routes.dart index 2ea0f22e9..176aa4c34 100644 --- a/mobile/lib/common/routes.dart +++ b/mobile/lib/common/routes.dart @@ -5,6 +5,7 @@ import 'package:get_10101/common/settings/emergency_kit_screen.dart'; import 'package:get_10101/common/settings/user_screen.dart'; import 'package:get_10101/common/settings/wallet_settings.dart'; import 'package:get_10101/common/status_screen.dart'; +import 'package:get_10101/common/xxi_screen.dart'; import 'package:get_10101/features/wallet/domain/destination.dart'; import 'package:get_10101/features/wallet/send/send_onchain_screen.dart'; import 'package:get_10101/features/welcome/error_screen.dart'; @@ -64,158 +65,166 @@ GoRouter createRoutes() { pageBuilder: (context, state) => const NoTransitionPage( child: ErrorScreen(), )), - GoRoute( - path: SettingsScreen.route, - pageBuilder: (BuildContext context, GoRouterState state) { - return CustomTransitionPage( - transitionsBuilder: (BuildContext context, Animation animation, - Animation secondaryAnimation, Widget child) { - const begin = Offset(-1.0, 0.0); - const end = Offset.zero; - const curve = Curves.ease; + ShellRoute( + builder: (BuildContext context, GoRouterState state, Widget child) { + return XXIScreen( + child: child, + ); + }, + routes: [ + GoRoute( + path: SettingsScreen.route, + pageBuilder: (BuildContext context, GoRouterState state) { + return CustomTransitionPage( + transitionsBuilder: (BuildContext context, Animation animation, + Animation secondaryAnimation, Widget child) { + const begin = Offset(-1.0, 0.0); + const end = Offset.zero; + const curve = Curves.ease; - var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); - return SlideTransition( - position: animation.drive(tween), + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + child: SettingsScreen(location: state.extra! as String), + ); + }, + routes: [ + GoRoute( + path: AppInfoScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const AppInfoScreen(); + }, + ), + GoRoute( + path: ShareLogsScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const ShareLogsScreen(); + }, + ), + GoRoute( + path: SeedScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const SeedScreen(); + }, + ), + GoRoute( + path: WalletSettings.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const WalletSettings(); + }, + ), + GoRoute( + path: UserSettings.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const UserSettings(); + }, + ), + GoRoute( + path: ChannelScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const ChannelScreen(); + }, + ), + GoRoute( + path: StatusScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const StatusScreen(); + }, + ), + GoRoute( + path: EmergencyKitScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const EmergencyKitScreen(); + }, + ), + GoRoute( + path: CollabCloseScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const CollabCloseScreen(); + }, + ), + GoRoute( + path: ForceCloseScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const ForceCloseScreen(); + }, + ) + ]), + ShellRoute( + navigatorKey: shellNavigatorKey, + builder: (BuildContext context, GoRouterState state, Widget child) { + return ScaffoldWithNavBar( child: child, ); }, - child: SettingsScreen(location: state.extra! as String), - ); - }, - routes: [ - GoRoute( - path: AppInfoScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const AppInfoScreen(); - }, - ), - GoRoute( - path: ShareLogsScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const ShareLogsScreen(); - }, - ), - GoRoute( - path: SeedScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const SeedScreen(); - }, - ), - GoRoute( - path: WalletSettings.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const WalletSettings(); - }, - ), - GoRoute( - path: UserSettings.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const UserSettings(); - }, - ), - GoRoute( - path: ChannelScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const ChannelScreen(); - }, - ), - GoRoute( - path: StatusScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const StatusScreen(); - }, - ), - GoRoute( - path: EmergencyKitScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const EmergencyKitScreen(); - }, + routes: [ + GoRoute( + path: WalletScreen.route, + builder: (BuildContext context, GoRouterState state) { + return const WalletScreen(); + }, + routes: [ + GoRoute( + path: SendOnChainScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return SendOnChainScreen(destination: state.extra as OnChainAddress); + }, + ), + GoRoute( + path: ReceiveScreen.subRouteName, + // Use root navigator so the screen overlays the application shell + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + if (state.extra != null) { + return ReceiveScreen(walletType: state.extra as WalletType); + } + return const ReceiveScreen(); + }, + ), + GoRoute( + path: ScannerScreen.subRouteName, + parentNavigatorKey: rootNavigatorKey, + builder: (BuildContext context, GoRouterState state) { + return const ScannerScreen(); + }, + ), + ], + ), + GoRoute( + path: TradeScreen.route, + builder: (BuildContext context, GoRouterState state) { + return const TradeScreen(); + }, + routes: const [], + ), + ], ), - GoRoute( - path: CollabCloseScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const CollabCloseScreen(); - }, - ), - GoRoute( - path: ForceCloseScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const ForceCloseScreen(); - }, - ) ]), - ShellRoute( - navigatorKey: shellNavigatorKey, - builder: (BuildContext context, GoRouterState state, Widget child) { - return ScaffoldWithNavBar( - child: child, - ); - }, - routes: [ - GoRoute( - path: WalletScreen.route, - builder: (BuildContext context, GoRouterState state) { - return const WalletScreen(); - }, - routes: [ - GoRoute( - path: SendOnChainScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return SendOnChainScreen(destination: state.extra as OnChainAddress); - }, - ), - GoRoute( - path: ReceiveScreen.subRouteName, - // Use root navigator so the screen overlays the application shell - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - if (state.extra != null) { - return ReceiveScreen(walletType: state.extra as WalletType); - } - return const ReceiveScreen(); - }, - ), - GoRoute( - path: ScannerScreen.subRouteName, - parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) { - return const ScannerScreen(); - }, - ), - ], - ), - GoRoute( - path: TradeScreen.route, - builder: (BuildContext context, GoRouterState state) { - return const TradeScreen(); - }, - routes: const [], - ), - ], - ), ]); } diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart new file mode 100644 index 000000000..ddcd5c87e --- /dev/null +++ b/mobile/lib/common/xxi_screen.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class XXIScreen extends StatefulWidget { + final Widget child; + + const XXIScreen({super.key, required this.child}); + + @override + State createState() => _XXIScreenState(); +} + +class _XXIScreenState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return AnnotatedRegion( + value: SystemUiOverlayStyle.dark, child: Scaffold(body: widget.child)); + } +} From db8e1054988268776e067d2cfe5ceb2182af614f Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Thu, 2 May 2024 16:45:34 +0200 Subject: [PATCH 02/32] chore: Move compare coordinator version check to xxi screen First step towards aggregating all dialogs to a single root context (xxi screen) --- mobile/lib/common/xxi_screen.dart | 70 +++++++++++++++++++ mobile/lib/main.dart | 8 --- .../lib/util/compare_coordinator_version.dart | 70 ------------------- 3 files changed, 70 insertions(+), 78 deletions(-) delete mode 100644 mobile/lib/util/compare_coordinator_version.dart diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index ddcd5c87e..55feb33ca 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -1,5 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:get_10101/logger/logger.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'dart:convert'; +import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; +import 'package:get_10101/util/coordinator_version.dart'; +import 'package:http/http.dart' as http; +import 'package:provider/provider.dart'; +import 'package:version/version.dart'; class XXIScreen extends StatefulWidget { final Widget child; @@ -13,6 +21,11 @@ class XXIScreen extends StatefulWidget { class _XXIScreenState extends State { @override void initState() { + final config = context.read(); + WidgetsBinding.instance.addPostFrameCallback((_) { + compareCoordinatorVersion(config); + }); + super.initState(); } @@ -21,4 +34,61 @@ class _XXIScreenState extends State { return AnnotatedRegion( value: SystemUiOverlayStyle.dark, child: Scaffold(body: widget.child)); } + + /// Compare the version of the coordinator with the version of the app + /// + /// - If the coordinator is newer, suggest to update the app. + /// - If the app is newer, log it. + /// - If the coordinator cannot be reached, show a warning that the app may not function properly. + void compareCoordinatorVersion(bridge.Config config) { + Future.wait([ + PackageInfo.fromPlatform(), + http.get(Uri.parse('http://${config.host}:${config.httpPort}/api/version')) + ]).then((value) { + final packageInfo = value[0]; + final response = value[1]; + + final clientVersion = Version.parse(packageInfo.version); + final coordinatorVersion = CoordinatorVersion.fromJson(jsonDecode(response.body)); + logger.i("Coordinator version: ${coordinatorVersion.version.toString()}"); + + if (coordinatorVersion.version > clientVersion) { + logger.w("Client out of date. Current version: ${clientVersion.toString()}"); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text("Update available"), + content: Text("A new version of 10101 is available: " + "${coordinatorVersion.version.toString()}.\n\n" + "Please note that if you do not update 10101, the app" + " may not function properly."), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, 'OK'), + child: const Text('OK'), + ), + ])); + } else if (coordinatorVersion.version < clientVersion) { + logger.w("10101 is newer than coordinator: ${coordinatorVersion.version.toString()}"); + } else { + logger.i("Client is up to date: ${clientVersion.toString()}"); + } + }).catchError((e) { + logger.e("Error getting coordinator version: ${e.toString()}"); + + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text("Cannot reach coordinator"), + content: const Text("Please check your Internet connection.\n" + "Please note that without Internet access, the app " + "functionality is severely limited."), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, 'OK'), + child: const Text('OK'), + ), + ])); + }); + } } diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 54ef7461e..4d9c74534 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:get_10101/backend.dart'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; import 'package:get_10101/common/color.dart'; -import 'package:get_10101/util/compare_coordinator_version.dart'; import 'package:get_10101/common/init_service.dart'; import 'package:get_10101/common/routes.dart'; import 'package:get_10101/features/trade/trade_theme.dart'; @@ -43,15 +41,9 @@ class _TenTenOneAppState extends State with WidgetsBindingObserver WidgetsBinding.instance.addObserver(this); - final config = context.read(); _router = createRoutes(); subscribeToNotifiers(context); - - // TODO(holzeis): check if we can do this without the addPostFrameCallback - WidgetsBinding.instance.addPostFrameCallback((_) async { - await compareCoordinatorVersion(config); - }); } @override diff --git a/mobile/lib/util/compare_coordinator_version.dart b/mobile/lib/util/compare_coordinator_version.dart deleted file mode 100644 index 2e7324f19..000000000 --- a/mobile/lib/util/compare_coordinator_version.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'dart:convert'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:flutter/material.dart'; -import 'package:get_10101/common/global_keys.dart'; -import 'package:get_10101/logger/logger.dart'; -import 'package:get_10101/util/coordinator_version.dart'; -import 'package:http/http.dart' as http; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:version/version.dart'; - -/// Compare the version of the coordinator with the version of the app -/// -/// - If the coordinator is newer, suggest to update the app. -/// - If the app is newer, log it. -/// - If the coordinator cannot be reached, show a warning that the app may not function properly. -Future compareCoordinatorVersion(bridge.Config config) async { - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - try { - final response = await http.get( - Uri.parse('http://${config.host}:${config.httpPort}/api/version'), - ); - - final clientVersion = Version.parse(packageInfo.version); - final coordinatorVersion = CoordinatorVersion.fromJson(jsonDecode(response.body)); - logger.i("Coordinator version: ${coordinatorVersion.version.toString()}"); - - if (coordinatorVersion.version > clientVersion) { - logger.w("Client out of date. Current version: ${clientVersion.toString()}"); - while (shellNavigatorKey.currentContext == null) { - await Future.delayed(const Duration(milliseconds: 100)); // Adjust delay as needed - } - showDialog( - context: shellNavigatorKey.currentContext!, - builder: (context) => AlertDialog( - title: const Text("Update available"), - content: Text("A new version of 10101 is available: " - "${coordinatorVersion.version.toString()}.\n\n" - "Please note that if you do not update 10101, the app" - " may not function properly."), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, 'OK'), - child: const Text('OK'), - ), - ])); - } else if (coordinatorVersion.version < clientVersion) { - logger.w("10101 is newer than coordinator: ${coordinatorVersion.version.toString()}"); - } else { - logger.i("Client is up to date: ${clientVersion.toString()}"); - } - } catch (e) { - logger.e("Error getting coordinator version: ${e.toString()}"); - while (shellNavigatorKey.currentContext == null) { - await Future.delayed(const Duration(milliseconds: 100)); // Adjust delay as needed - } - showDialog( - context: shellNavigatorKey.currentContext!, - builder: (context) => AlertDialog( - title: const Text("Cannot reach coordinator"), - content: const Text("Please check your Internet connection.\n" - "Please note that without Internet access, the app " - "functionality is severely limited."), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, 'OK'), - child: const Text('OK'), - ), - ])); - } -} From 75dc01f932673fa5e5ad78784ccb6c04071c3237 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Thu, 2 May 2024 17:06:17 +0200 Subject: [PATCH 03/32] chore: Move recover dialog to xxi screen --- .../common/recover_dlc_change_notifier.dart | 23 ++----------------- mobile/lib/common/xxi_screen.dart | 19 +++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/mobile/lib/common/recover_dlc_change_notifier.dart b/mobile/lib/common/recover_dlc_change_notifier.dart index 471f88c0d..2ca3fe4a3 100644 --- a/mobile/lib/common/recover_dlc_change_notifier.dart +++ b/mobile/lib/common/recover_dlc_change_notifier.dart @@ -2,13 +2,10 @@ import 'package:flutter/material.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/global_keys.dart'; -import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/logger/logger.dart'; -import 'package:provider/provider.dart'; class RecoverDlcChangeNotifier extends ChangeNotifier implements Subscriber { - late TaskStatus taskStatus; + TaskStatus taskStatus = TaskStatus.success; @override void notify(bridge.Event event) async { @@ -22,23 +19,7 @@ class RecoverDlcChangeNotifier extends ChangeNotifier implements Subscriber { taskStatus = recoverDlc.taskStatus; - if (taskStatus == TaskStatus.pending) { - while (shellNavigatorKey.currentContext == null) { - await Future.delayed(const Duration(milliseconds: 100)); // Adjust delay as needed - } - // initialize dialog for the pending task - showDialog( - context: shellNavigatorKey.currentContext!, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - late Widget content = const Text("Recovering your dlc channel"); - return TaskStatusDialog(title: "Catching up!", status: status, content: content); - }, - ); - } else { - // notify dialog about changed task status - notifyListeners(); - } + notifyListeners(); } } } diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index 55feb33ca..fdb823780 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:get_10101/common/domain/background_task.dart'; +import 'package:get_10101/common/recover_dlc_change_notifier.dart'; +import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'dart:convert'; @@ -31,6 +34,22 @@ class _XXIScreenState extends State { @override Widget build(BuildContext context) { + final taskStatus = context.watch().taskStatus; + + WidgetsBinding.instance.addPostFrameCallback((_) { + if (taskStatus == TaskStatus.pending) { + // initialize dialog for the pending task + showDialog( + context: context, + builder: (context) { + TaskStatus status = context.watch().taskStatus; + late Widget content = const Text("Recovering your dlc channel"); + return TaskStatusDialog(title: "Catching up!", status: status, content: content); + }, + ); + } + }); + return AnnotatedRegion( value: SystemUiOverlayStyle.dark, child: Scaffold(body: widget.child)); } From 58e75f45d3bf2d976300d8c2c1d0f065490e4975 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Thu, 2 May 2024 17:10:15 +0200 Subject: [PATCH 04/32] chore: Move rollover dialog to xxi screen --- mobile/lib/common/xxi_screen.dart | 17 ++++++++++--- .../trade/rollover_change_notifier.dart | 24 ++----------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index fdb823780..397e1c13f 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:get_10101/common/domain/background_task.dart'; import 'package:get_10101/common/recover_dlc_change_notifier.dart'; import 'package:get_10101/common/task_status_dialog.dart'; +import 'package:get_10101/features/trade/rollover_change_notifier.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'dart:convert'; @@ -34,11 +35,11 @@ class _XXIScreenState extends State { @override Widget build(BuildContext context) { - final taskStatus = context.watch().taskStatus; + final recoverTaskStatus = context.watch().taskStatus; + final rolloverTaskStatus = context.watch().taskStatus; WidgetsBinding.instance.addPostFrameCallback((_) { - if (taskStatus == TaskStatus.pending) { - // initialize dialog for the pending task + if (recoverTaskStatus == TaskStatus.pending) { showDialog( context: context, builder: (context) { @@ -48,6 +49,16 @@ class _XXIScreenState extends State { }, ); } + if (rolloverTaskStatus == TaskStatus.pending) { + showDialog( + context: context, + builder: (context) { + TaskStatus status = context.watch().taskStatus; + late Widget content = const Text("Rolling over your position"); + return TaskStatusDialog(title: "Catching up!", status: status, content: content); + }, + ); + } }); return AnnotatedRegion( diff --git a/mobile/lib/features/trade/rollover_change_notifier.dart b/mobile/lib/features/trade/rollover_change_notifier.dart index 7e97b3f0a..ef02ca863 100644 --- a/mobile/lib/features/trade/rollover_change_notifier.dart +++ b/mobile/lib/features/trade/rollover_change_notifier.dart @@ -3,12 +3,9 @@ import 'package:flutter/material.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/global_keys.dart'; -import 'package:get_10101/common/task_status_dialog.dart'; -import 'package:provider/provider.dart'; class RolloverChangeNotifier extends ChangeNotifier implements Subscriber { - late TaskStatus taskStatus; + TaskStatus taskStatus = TaskStatus.success; @override void notify(bridge.Event event) async { @@ -23,24 +20,7 @@ class RolloverChangeNotifier extends ChangeNotifier implements Subscriber { taskStatus = rollover.taskStatus; - if (taskStatus == TaskStatus.pending) { - while (shellNavigatorKey.currentContext == null) { - await Future.delayed(const Duration(milliseconds: 100)); // Adjust delay as needed - } - - // initialize dialog for the pending task - showDialog( - context: shellNavigatorKey.currentContext!, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - late Widget content = const Text("Rolling over your position"); - return TaskStatusDialog(title: "Catching up!", status: status, content: content); - }, - ); - } else { - // notify dialog about changed task status - notifyListeners(); - } + notifyListeners(); } else { logger.w("Received unexpected event: ${event.toString()}"); } From 5a1351690b640aba96fe58b3d4535a2812470586 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Thu, 2 May 2024 17:25:32 +0200 Subject: [PATCH 05/32] chore: Move async order dialog to xxi screen --- mobile/lib/common/xxi_screen.dart | 41 ++++++++++++++++ .../trade/async_order_change_notifier.dart | 49 +++---------------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index 397e1c13f..0f704ce0a 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -3,6 +3,8 @@ import 'package:flutter/services.dart'; import 'package:get_10101/common/domain/background_task.dart'; import 'package:get_10101/common/recover_dlc_change_notifier.dart'; import 'package:get_10101/common/task_status_dialog.dart'; +import 'package:get_10101/features/trade/async_order_change_notifier.dart'; +import 'package:get_10101/features/trade/domain/order.dart'; import 'package:get_10101/features/trade/rollover_change_notifier.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -37,6 +39,7 @@ class _XXIScreenState extends State { Widget build(BuildContext context) { final recoverTaskStatus = context.watch().taskStatus; final rolloverTaskStatus = context.watch().taskStatus; + final asyncTrade = context.watch().asyncTrade; WidgetsBinding.instance.addPostFrameCallback((_) { if (recoverTaskStatus == TaskStatus.pending) { @@ -59,6 +62,44 @@ class _XXIScreenState extends State { }, ); } + if (asyncTrade != null) { + showDialog( + context: context, + builder: (context) { + Order? asyncOrder = context.watch().asyncOrder; + + TaskStatus status = TaskStatus.pending; + switch (asyncOrder?.state) { + case OrderState.open: + case OrderState.filling: + status = TaskStatus.pending; + case OrderState.failed: + case OrderState.rejected: + status = TaskStatus.failed; + case OrderState.filled: + status = TaskStatus.success; + case null: + status = TaskStatus.pending; + } + + late Widget content; + switch (asyncTrade.orderReason) { + case OrderReason.expired: + content = const Text("Your position has been closed due to expiry."); + case OrderReason.liquidated: + content = const Text("Your position has been closed due to liquidation."); + case OrderReason.manual: + logger.e("A manual order should not appear as an async trade!"); + content = Container(); + } + + return TaskStatusDialog(title: "Catching up!", status: status, content: content); + }, + ); + + // remove the async trade from the change notifier state, marking that the dialog has been created. + context.read().removeAsyncTrade(); + } }); return AnnotatedRegion( diff --git a/mobile/lib/features/trade/async_order_change_notifier.dart b/mobile/lib/features/trade/async_order_change_notifier.dart index df5ee2d85..9fc3964c3 100644 --- a/mobile/lib/features/trade/async_order_change_notifier.dart +++ b/mobile/lib/features/trade/async_order_change_notifier.dart @@ -3,15 +3,13 @@ import 'package:flutter/material.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/global_keys.dart'; -import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/features/trade/application/order_service.dart'; import 'package:get_10101/features/trade/domain/order.dart'; -import 'package:provider/provider.dart'; class AsyncOrderChangeNotifier extends ChangeNotifier implements Subscriber { late OrderService _orderService; Order? asyncOrder; + AsyncTrade? asyncTrade; Future initialize() async { Order? order = await _orderService.fetchAsyncOrder(); @@ -25,6 +23,11 @@ class AsyncOrderChangeNotifier extends ChangeNotifier implements Subscriber { _orderService = orderService; } + // call this function to mark that the async trade has been processed. + void removeAsyncTrade() { + asyncTrade = null; + } + @override void notify(bridge.Event event) async { if (event is bridge.Event_BackgroundNotification) { @@ -34,44 +37,8 @@ class AsyncOrderChangeNotifier extends ChangeNotifier implements Subscriber { } AsyncTrade asyncTrade = AsyncTrade.fromApi(event.field0 as bridge.BackgroundTask_AsyncTrade); logger.d("Received a async trade event. Reason: ${asyncTrade.orderReason}"); - - while (shellNavigatorKey.currentContext == null) { - await Future.delayed(const Duration(milliseconds: 100)); // Adjust delay as needed - } - - showDialog( - context: shellNavigatorKey.currentContext!, - builder: (context) { - Order? asyncOrder = context.watch().asyncOrder; - - TaskStatus status = TaskStatus.pending; - switch (asyncOrder?.state) { - case OrderState.open: - case OrderState.filling: - status = TaskStatus.pending; - case OrderState.failed: - case OrderState.rejected: - status = TaskStatus.failed; - case OrderState.filled: - status = TaskStatus.success; - case null: - status = TaskStatus.pending; - } - - late Widget content; - switch (asyncTrade.orderReason) { - case OrderReason.expired: - content = const Text("Your position has been closed due to expiry."); - case OrderReason.liquidated: - content = const Text("Your position has been closed due to liquidation."); - case OrderReason.manual: - logger.e("A manual order should not appear as an async trade!"); - content = Container(); - } - - return TaskStatusDialog(title: "Catching up!", status: status, content: content); - }, - ); + this.asyncTrade = asyncTrade; + notifyListeners(); } else if (event is bridge.Event_OrderUpdateNotification) { Order order = Order.fromApi(event.field0); if (order.reason != OrderReason.manual) { From e52851b1241eae90547960a2730485d847f680a1 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 08:28:13 +0200 Subject: [PATCH 06/32] chore: Move full sync dialog to xxi screen --- .../lib/common/full_sync_change_notifier.dart | 36 ++----------------- mobile/lib/common/xxi_screen.dart | 24 +++++++++++++ 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/mobile/lib/common/full_sync_change_notifier.dart b/mobile/lib/common/full_sync_change_notifier.dart index 61872e04c..223213687 100644 --- a/mobile/lib/common/full_sync_change_notifier.dart +++ b/mobile/lib/common/full_sync_change_notifier.dart @@ -2,13 +2,10 @@ import 'package:flutter/material.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/global_keys.dart'; -import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/logger/logger.dart'; -import 'package:provider/provider.dart'; class FullSyncChangeNotifier extends ChangeNotifier implements Subscriber { - late TaskStatus taskStatus; + TaskStatus taskStatus = TaskStatus.success; @override void notify(bridge.Event event) async { @@ -22,36 +19,7 @@ class FullSyncChangeNotifier extends ChangeNotifier implements Subscriber { taskStatus = fullSync.taskStatus; - if (taskStatus == TaskStatus.pending) { - while (shellNavigatorKey.currentContext == null) { - await Future.delayed(const Duration(milliseconds: 100)); // Adjust delay as needed - } - - // initialize dialog for the pending task - showDialog( - context: shellNavigatorKey.currentContext!, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - - Widget content; - switch (status) { - case TaskStatus.pending: - content = const Text("Waiting for on-chain sync to complete"); - case TaskStatus.success: - content = const Text( - "Full on-chain sync completed. If your balance is still incomplete, go to Wallet Settings to trigger further syncs."); - case TaskStatus.failed: - content = const Text( - "Full on-chain sync failed. You can keep trying by shutting down the app and restarting."); - } - - return TaskStatusDialog(title: "Full wallet sync", status: status, content: content); - }, - ); - } else { - // notify dialog about changed task status - notifyListeners(); - } + notifyListeners(); } } } diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index 0f704ce0a..b5d17e650 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get_10101/common/domain/background_task.dart'; +import 'package:get_10101/common/full_sync_change_notifier.dart'; import 'package:get_10101/common/recover_dlc_change_notifier.dart'; import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/features/trade/async_order_change_notifier.dart'; @@ -40,6 +41,7 @@ class _XXIScreenState extends State { final recoverTaskStatus = context.watch().taskStatus; final rolloverTaskStatus = context.watch().taskStatus; final asyncTrade = context.watch().asyncTrade; + final fullSyncTaskStatus = context.watch().taskStatus; WidgetsBinding.instance.addPostFrameCallback((_) { if (recoverTaskStatus == TaskStatus.pending) { @@ -100,6 +102,28 @@ class _XXIScreenState extends State { // remove the async trade from the change notifier state, marking that the dialog has been created. context.read().removeAsyncTrade(); } + if (fullSyncTaskStatus == TaskStatus.pending) { + showDialog( + context: context, + builder: (context) { + TaskStatus status = context.watch().taskStatus; + + Widget content; + switch (status) { + case TaskStatus.pending: + content = const Text("Waiting for on-chain sync to complete"); + case TaskStatus.success: + content = const Text( + "Full on-chain sync completed. If your balance is still incomplete, go to Wallet Settings to trigger further syncs."); + case TaskStatus.failed: + content = const Text( + "Full on-chain sync failed. You can keep trying by shutting down the app and restarting."); + } + + return TaskStatusDialog(title: "Full wallet sync", status: status, content: content); + }, + ); + } }); return AnnotatedRegion( From ee11bb1b17d48f3201fa2d1563e0ab965f23faad Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 08:31:32 +0200 Subject: [PATCH 07/32] chore: Move collab revert dialog to xxi screen --- .../common/collab_revert_change_notifier.dart | 21 ++----------------- mobile/lib/common/xxi_screen.dart | 13 ++++++++++++ 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/mobile/lib/common/collab_revert_change_notifier.dart b/mobile/lib/common/collab_revert_change_notifier.dart index 8db24daf5..4db692fe6 100644 --- a/mobile/lib/common/collab_revert_change_notifier.dart +++ b/mobile/lib/common/collab_revert_change_notifier.dart @@ -2,13 +2,10 @@ import 'package:flutter/material.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/global_keys.dart'; -import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/logger/logger.dart'; -import 'package:provider/provider.dart'; class CollabRevertChangeNotifier extends ChangeNotifier implements Subscriber { - late TaskStatus taskStatus; + TaskStatus taskStatus = TaskStatus.success; @override void notify(bridge.Event event) { @@ -23,21 +20,7 @@ class CollabRevertChangeNotifier extends ChangeNotifier implements Subscriber { taskStatus = collabRevert.taskStatus; - if (taskStatus == TaskStatus.pending) { - // initialize dialog for the pending task - showDialog( - context: shellNavigatorKey.currentContext!, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - late Widget content = const Text("Your channel has been closed collaboratively!"); - return TaskStatusDialog( - title: "Collaborative Channel Close!", status: status, content: content); - }, - ); - } else { - // notify dialog about changed task status - notifyListeners(); - } + notifyListeners(); } } } diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index b5d17e650..a7e76289d 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:get_10101/common/collab_revert_change_notifier.dart'; import 'package:get_10101/common/domain/background_task.dart'; import 'package:get_10101/common/full_sync_change_notifier.dart'; import 'package:get_10101/common/recover_dlc_change_notifier.dart'; @@ -42,6 +43,7 @@ class _XXIScreenState extends State { final rolloverTaskStatus = context.watch().taskStatus; final asyncTrade = context.watch().asyncTrade; final fullSyncTaskStatus = context.watch().taskStatus; + final collabRevertTaskStatus = context.watch().taskStatus; WidgetsBinding.instance.addPostFrameCallback((_) { if (recoverTaskStatus == TaskStatus.pending) { @@ -124,6 +126,17 @@ class _XXIScreenState extends State { }, ); } + if (collabRevertTaskStatus == TaskStatus.pending) { + showDialog( + context: context, + builder: (context) { + TaskStatus status = context.watch().taskStatus; + late Widget content = const Text("Your channel has been closed collaboratively!"); + return TaskStatusDialog( + title: "Collaborative Channel Close!", status: status, content: content); + }, + ); + } }); return AnnotatedRegion( From 16e5f2b031d7a6eb710b9849204de3895b18e4f5 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 09:14:50 +0200 Subject: [PATCH 08/32] chore: Remove unnecessary fetch async order during async order change notifier initialization I don't know anymore why this was added in the first place, but it doesn't make much sense anymore. --- mobile/lib/common/init_service.dart | 2 +- .../features/trade/application/order_service.dart | 10 ---------- .../trade/async_order_change_notifier.dart | 14 -------------- mobile/native/src/api.rs | 7 ------- mobile/native/src/db/mod.rs | 15 --------------- mobile/native/src/db/models.rs | 13 ------------- mobile/native/src/trade/order/handler.rs | 4 ---- 7 files changed, 1 insertion(+), 64 deletions(-) diff --git a/mobile/lib/common/init_service.dart b/mobile/lib/common/init_service.dart index 681b0de5b..159b04877 100644 --- a/mobile/lib/common/init_service.dart +++ b/mobile/lib/common/init_service.dart @@ -61,7 +61,7 @@ List createProviders() { create: (context) => CandlestickChangeNotifier(const CandlestickService()).initialize()), ChangeNotifierProvider(create: (context) => ServiceStatusNotifier()), ChangeNotifierProvider(create: (context) => DlcChannelChangeNotifier(dlcChannelService)), - ChangeNotifierProvider(create: (context) => AsyncOrderChangeNotifier(OrderService())), + ChangeNotifierProvider(create: (context) => AsyncOrderChangeNotifier()), ChangeNotifierProvider(create: (context) => RolloverChangeNotifier()), ChangeNotifierProvider(create: (context) => RecoverDlcChangeNotifier()), ChangeNotifierProvider(create: (context) => CollabRevertChangeNotifier()), diff --git a/mobile/lib/features/trade/application/order_service.dart b/mobile/lib/features/trade/application/order_service.dart index 90ee90570..ca3b73a0a 100644 --- a/mobile/lib/features/trade/application/order_service.dart +++ b/mobile/lib/features/trade/application/order_service.dart @@ -47,14 +47,4 @@ class OrderService { return orders; } - - Future fetchAsyncOrder() async { - rust.Order? order = await rust.api.getAsyncOrder(); - - if (order == null) { - return null; - } - - return Order.fromApi(order); - } } diff --git a/mobile/lib/features/trade/async_order_change_notifier.dart b/mobile/lib/features/trade/async_order_change_notifier.dart index 9fc3964c3..f6b2b3519 100644 --- a/mobile/lib/features/trade/async_order_change_notifier.dart +++ b/mobile/lib/features/trade/async_order_change_notifier.dart @@ -3,26 +3,12 @@ import 'package:flutter/material.dart'; import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/features/trade/application/order_service.dart'; import 'package:get_10101/features/trade/domain/order.dart'; class AsyncOrderChangeNotifier extends ChangeNotifier implements Subscriber { - late OrderService _orderService; Order? asyncOrder; AsyncTrade? asyncTrade; - Future initialize() async { - Order? order = await _orderService.fetchAsyncOrder(); - - if (order != null) { - notifyListeners(); - } - } - - AsyncOrderChangeNotifier(OrderService orderService) { - _orderService = orderService; - } - // call this function to mark that the async trade has been processed. void removeAsyncTrade() { asyncTrade = null; diff --git a/mobile/native/src/api.rs b/mobile/native/src/api.rs index 151986a16..8a64e8268 100644 --- a/mobile/native/src/api.rs +++ b/mobile/native/src/api.rs @@ -363,13 +363,6 @@ pub async fn get_orders() -> Result> { Ok(orders) } -#[tokio::main(flavor = "current_thread")] -pub async fn get_async_order() -> Result> { - let order = order::handler::get_async_order()?; - let order = order.map(|order| order.into()); - Ok(order) -} - #[tokio::main(flavor = "current_thread")] pub async fn get_positions() -> Result> { let positions = position::handler::get_positions()? diff --git a/mobile/native/src/db/mod.rs b/mobile/native/src/db/mod.rs index 109535c2b..c51b8c99d 100644 --- a/mobile/native/src/db/mod.rs +++ b/mobile/native/src/db/mod.rs @@ -210,21 +210,6 @@ pub fn get_orders_for_ui() -> Result> { .collect::>()?) } -pub fn get_async_order() -> Result> { - let mut db = connection()?; - let order = Order::get_async_order(&mut db)?; - - let order: Option = match order { - Some(order) => { - let order = order.try_into()?; - Some(order) - } - None => None, - }; - - Ok(order) -} - pub fn get_filled_orders() -> Result> { let mut db = connection()?; diff --git a/mobile/native/src/db/models.rs b/mobile/native/src/db/models.rs index d1196293e..493a3aae5 100644 --- a/mobile/native/src/db/models.rs +++ b/mobile/native/src/db/models.rs @@ -239,19 +239,6 @@ impl Order { .load(conn) } - /// Gets any async order in the database. An async order is defined by any order which has been - /// generated by the orderbook. e.g. if the position expired. - pub fn get_async_order(conn: &mut SqliteConnection) -> QueryResult> { - orders::table - .filter( - orders::state - .eq(OrderState::Filling) - .and(orders::reason.eq(OrderReason::Expired)), - ) - .first(conn) - .optional() - } - pub fn get_by_state( order_state: OrderState, conn: &mut SqliteConnection, diff --git a/mobile/native/src/trade/order/handler.rs b/mobile/native/src/trade/order/handler.rs index 729b6c7a4..fcc0147fa 100644 --- a/mobile/native/src/trade/order/handler.rs +++ b/mobile/native/src/trade/order/handler.rs @@ -334,10 +334,6 @@ pub async fn get_orders_for_ui() -> Result> { db::get_orders_for_ui() } -pub fn get_async_order() -> Result> { - db::get_async_order() -} - pub fn check_open_orders() -> Result<()> { let open_orders = match maybe_get_open_orders() { Ok(orders_being_filled) => orders_being_filled, From 81da5c8555cbd343a9d15e91ac1cb5ca338cba22 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 09:51:26 +0200 Subject: [PATCH 09/32] chore: Move trade dialog to xxi screen Before we showed the trade dialog optimistically assuming we will get a dlc offer instantly, even though this is coming asynchronously. Although there was no issue with this yet, I think moving this to the xxi screen as well makes sense, because we might end up with orders not getting immediately matched. Also gets rid of a redundant show dialog. --- mobile/lib/common/xxi_screen.dart | 77 +++++++++++-------- .../trade/trade_bottom_sheet_tab.dart | 16 +--- mobile/lib/features/trade/trade_screen.dart | 16 +--- mobile/native/src/event/api.rs | 3 +- mobile/native/src/trade/order/handler.rs | 6 ++ 5 files changed, 55 insertions(+), 63 deletions(-) diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index a7e76289d..4228beac5 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -8,6 +8,7 @@ import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/features/trade/async_order_change_notifier.dart'; import 'package:get_10101/features/trade/domain/order.dart'; import 'package:get_10101/features/trade/rollover_change_notifier.dart'; +import 'package:get_10101/features/trade/trade_dialog.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'dart:convert'; @@ -67,39 +68,49 @@ class _XXIScreenState extends State { ); } if (asyncTrade != null) { - showDialog( - context: context, - builder: (context) { - Order? asyncOrder = context.watch().asyncOrder; - - TaskStatus status = TaskStatus.pending; - switch (asyncOrder?.state) { - case OrderState.open: - case OrderState.filling: - status = TaskStatus.pending; - case OrderState.failed: - case OrderState.rejected: - status = TaskStatus.failed; - case OrderState.filled: - status = TaskStatus.success; - case null: - status = TaskStatus.pending; - } - - late Widget content; - switch (asyncTrade.orderReason) { - case OrderReason.expired: - content = const Text("Your position has been closed due to expiry."); - case OrderReason.liquidated: - content = const Text("Your position has been closed due to liquidation."); - case OrderReason.manual: - logger.e("A manual order should not appear as an async trade!"); - content = Container(); - } - - return TaskStatusDialog(title: "Catching up!", status: status, content: content); - }, - ); + if (asyncTrade.orderReason == OrderReason.manual) { + showDialog( + context: context, + useRootNavigator: true, + barrierDismissible: false, + builder: (BuildContext context) { + return const TradeDialog(); + }); + } else { + showDialog( + context: context, + builder: (context) { + Order? asyncOrder = context.watch().asyncOrder; + + TaskStatus status = TaskStatus.pending; + switch (asyncOrder?.state) { + case OrderState.open: + case OrderState.filling: + status = TaskStatus.pending; + case OrderState.failed: + case OrderState.rejected: + status = TaskStatus.failed; + case OrderState.filled: + status = TaskStatus.success; + case null: + status = TaskStatus.pending; + } + + late Widget content; + switch (asyncTrade.orderReason) { + case OrderReason.expired: + content = const Text("Your position has been closed due to expiry."); + case OrderReason.liquidated: + content = const Text("Your position has been closed due to liquidation."); + case OrderReason.manual: + logger.e("A manual order should not appear as an async trade!"); + content = Container(); + } + + return TaskStatusDialog(title: "Catching up!", status: status, content: content); + }, + ); + } // remove the async trade from the change notifier state, marking that the dialog has been created. context.read().removeAsyncTrade(); diff --git a/mobile/lib/features/trade/trade_bottom_sheet_tab.dart b/mobile/lib/features/trade/trade_bottom_sheet_tab.dart index 24b1456de..4af1c0707 100644 --- a/mobile/lib/features/trade/trade_bottom_sheet_tab.dart +++ b/mobile/lib/features/trade/trade_bottom_sheet_tab.dart @@ -20,7 +20,6 @@ import 'package:get_10101/features/trade/leverage_slider.dart'; import 'package:get_10101/features/trade/position_change_notifier.dart'; import 'package:get_10101/features/trade/submit_order_change_notifier.dart'; import 'package:get_10101/features/trade/trade_bottom_sheet_confirmation.dart'; -import 'package:get_10101/features/trade/trade_dialog.dart'; import 'package:get_10101/features/trade/trade_theme.dart'; import 'package:get_10101/features/trade/trade_value_change_notifier.dart'; import 'package:go_router/go_router.dart'; @@ -202,22 +201,11 @@ class _TradeBottomSheetTabState extends State void onConfirmation(SubmitOrderChangeNotifier submitOrderChangeNotifier, TradeValues tradeValues, ChannelOpeningParams? channelOpeningParams) { - submitOrderChangeNotifier.submitPendingOrder(tradeValues, PositionAction.open, - channelOpeningParams: channelOpeningParams); - - // Return to the trade screen before submitting the pending order so that the dialog is displayed under the correct context GoRouter.of(context).pop(); GoRouter.of(context).pop(); - // Show immediately the pending dialog, when submitting a market order. - // TODO(holzeis): We should only show the dialog once we've received a match. - showDialog( - context: context, - useRootNavigator: true, - barrierDismissible: false, // Prevent user from leaving - builder: (BuildContext context) { - return const TradeDialog(); - }); + submitOrderChangeNotifier.submitPendingOrder(tradeValues, PositionAction.open, + channelOpeningParams: channelOpeningParams); } Wrap buildChildren(Direction direction, rust.TradeConstraints channelTradeConstraints, diff --git a/mobile/lib/features/trade/trade_screen.dart b/mobile/lib/features/trade/trade_screen.dart index fb92bac5f..ebe913a89 100644 --- a/mobile/lib/features/trade/trade_screen.dart +++ b/mobile/lib/features/trade/trade_screen.dart @@ -12,7 +12,6 @@ import 'package:get_10101/features/trade/position_list_item.dart'; import 'package:get_10101/features/trade/submit_order_change_notifier.dart'; import 'package:get_10101/features/trade/trade_bottom_sheet.dart'; import 'package:get_10101/features/trade/trade_bottom_sheet_confirmation.dart'; -import 'package:get_10101/features/trade/trade_dialog.dart'; import 'package:get_10101/features/trade/trade_tabs.dart'; import 'package:get_10101/features/trade/trade_theme.dart'; import 'package:get_10101/features/trade/trade_value_change_notifier.dart'; @@ -170,21 +169,10 @@ class TradeScreen extends StatelessWidget { direction: direction, channelOpeningParams: null, onConfirmation: () { - submitOrderChangeNotifier.closePosition( - position, tradeValues.price, tradeValues.fee); - - // Return to the trade screen before submitting the pending order so that the dialog is displayed correctly GoRouter.of(context).pop(); - // Show immediately the pending dialog, when submitting a market order. - // TODO(holzeis): We should only show the dialog once we've received a match. - showDialog( - context: context, - useRootNavigator: true, - barrierDismissible: false, // Prevent user from leaving - builder: (BuildContext context) { - return const TradeDialog(); - }); + submitOrderChangeNotifier.closePosition( + position, tradeValues.price, tradeValues.fee); }, tradeAction: TradeAction.closePosition); }, diff --git a/mobile/native/src/event/api.rs b/mobile/native/src/event/api.rs index c18535d0b..3b44d4620 100644 --- a/mobile/native/src/event/api.rs +++ b/mobile/native/src/event/api.rs @@ -36,8 +36,7 @@ pub enum Event { #[frb] #[derive(Clone)] pub enum BackgroundTask { - /// The order book submitted an trade which was matched asynchronously while the app was - /// offline. + /// The order book submitted an trade which was matched asynchronously AsyncTrade(OrderReason), /// The order book submitted its intention to rollover the about to expire position. Rollover(TaskStatus), diff --git a/mobile/native/src/trade/order/handler.rs b/mobile/native/src/trade/order/handler.rs index fcc0147fa..39eca64dd 100644 --- a/mobile/native/src/trade/order/handler.rs +++ b/mobile/native/src/trade/order/handler.rs @@ -5,11 +5,13 @@ use crate::db::maybe_get_open_orders; use crate::dlc; use crate::dlc::is_dlc_channel_confirmed; use crate::event; +use crate::event::BackgroundTask; use crate::event::EventInternal; use crate::report_error_to_coordinator; use crate::trade::order::orderbook_client::OrderbookClient; use crate::trade::order::FailureReason; use crate::trade::order::Order; +use crate::trade::order::OrderReason; use crate::trade::order::OrderState; use crate::trade::order::OrderType; use crate::trade::position; @@ -121,6 +123,10 @@ pub async fn submit_order_internal( set_order_to_open_and_update_ui(order.id).map_err(SubmitOrderError::Storage)?; update_position_after_order_submitted(&order).map_err(SubmitOrderError::Storage)?; + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::AsyncTrade(OrderReason::Manual), + )); + Ok(order.id) } From 3afd6a9846b93b65aa347e9ba6cd1e409125e724 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 10:05:21 +0200 Subject: [PATCH 10/32] chore: Remove unused event --- crates/tests-e2e/src/test_subscriber.rs | 13 ------------- mobile/native/src/event/api.rs | 3 --- mobile/native/src/event/mod.rs | 5 ----- 3 files changed, 21 deletions(-) diff --git a/crates/tests-e2e/src/test_subscriber.rs b/crates/tests-e2e/src/test_subscriber.rs index efd0eca3f..5f62abf3c 100644 --- a/crates/tests-e2e/src/test_subscriber.rs +++ b/crates/tests-e2e/src/test_subscriber.rs @@ -12,12 +12,10 @@ use rust_decimal::Decimal; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::watch; -use xxi_node::commons::TradeParams; pub struct Senders { wallet_info: watch::Sender>, order: watch::Sender>, - order_filled: watch::Sender>>, position: watch::Sender>, /// Init messages are simple strings init_msg: watch::Sender>, @@ -32,7 +30,6 @@ pub struct Senders { pub struct TestSubscriber { wallet_info: watch::Receiver>, order: watch::Receiver>, - order_filled: watch::Receiver>>, position: watch::Receiver>, init_msg: watch::Receiver>, ask_price: watch::Receiver>, @@ -46,7 +43,6 @@ impl TestSubscriber { pub async fn new() -> (Self, ThreadSafeSenders) { let (wallet_info_tx, wallet_info_rx) = watch::channel(None); let (order_tx, order_rx) = watch::channel(None); - let (order_filled_tx, order_filled_rx) = watch::channel(None); let (position_tx, position_rx) = watch::channel(None); let (init_msg_tx, init_msg_rx) = watch::channel(None); let (ask_prices_tx, ask_prices_rx) = watch::channel(None); @@ -57,7 +53,6 @@ impl TestSubscriber { let senders = Senders { wallet_info: wallet_info_tx, order: order_tx, - order_filled: order_filled_tx, position: position_tx, init_msg: init_msg_tx, ask_price: ask_prices_tx, @@ -83,7 +78,6 @@ impl TestSubscriber { let subscriber = Self { wallet_info: wallet_info_rx, - order_filled: order_filled_rx, order: order_rx, position: position_rx, init_msg: init_msg_rx, @@ -104,10 +98,6 @@ impl TestSubscriber { self.order.borrow().as_ref().cloned() } - pub fn order_filled(&self) -> Option> { - self.order_filled.borrow().as_ref().cloned() - } - pub fn position(&self) -> Option { self.position.borrow().as_ref().cloned() } @@ -174,9 +164,6 @@ impl Senders { native::event::EventInternal::WalletInfoUpdateNotification(wallet_info) => { self.wallet_info.send(Some(wallet_info.clone()))?; } - native::event::EventInternal::OrderFilledWith(order_filled) => { - self.order_filled.send(Some(order_filled.clone()))?; - } native::event::EventInternal::PositionUpdateNotification(position) => { self.position.send(Some(position.clone()))?; } diff --git a/mobile/native/src/event/api.rs b/mobile/native/src/event/api.rs index 3b44d4620..072d6f590 100644 --- a/mobile/native/src/event/api.rs +++ b/mobile/native/src/event/api.rs @@ -60,9 +60,6 @@ impl From for Event { EventInternal::WalletInfoUpdateNotification(value) => { Event::WalletInfoUpdateNotification(value) } - EventInternal::OrderFilledWith(_) => { - unreachable!("This internal event is not exposed to the UI") - } EventInternal::PositionUpdateNotification(position) => { Event::PositionUpdateNotification(position.into()) } diff --git a/mobile/native/src/event/mod.rs b/mobile/native/src/event/mod.rs index 37268bc50..0fba3d0cd 100644 --- a/mobile/native/src/event/mod.rs +++ b/mobile/native/src/event/mod.rs @@ -11,7 +11,6 @@ use std::fmt; use std::hash::Hash; use xxi_node::commons::ContractSymbol; use xxi_node::commons::TenTenOneConfig; -use xxi_node::commons::TradeParams; mod event_hub; @@ -32,8 +31,6 @@ pub enum EventInternal { Log(String), OrderUpdateNotification(Order), WalletInfoUpdateNotification(WalletInfo), - // TODO: this doesn't seem to be used anymore - OrderFilledWith(Box), PositionUpdateNotification(Position), PositionCloseNotification(ContractSymbol), AskPriceUpdateNotification(Decimal), @@ -68,7 +65,6 @@ impl fmt::Display for EventInternal { EventInternal::Log(_) => "Log", EventInternal::OrderUpdateNotification(_) => "OrderUpdateNotification", EventInternal::WalletInfoUpdateNotification(_) => "WalletInfoUpdateNotification", - EventInternal::OrderFilledWith(_) => "OrderFilledWith", EventInternal::PositionUpdateNotification(_) => "PositionUpdateNotification", EventInternal::PositionCloseNotification(_) => "PositionCloseNotification", EventInternal::ServiceHealthUpdate(_) => "ServiceHealthUpdate", @@ -92,7 +88,6 @@ impl From for EventType { EventInternal::WalletInfoUpdateNotification(_) => { EventType::WalletInfoUpdateNotification } - EventInternal::OrderFilledWith(_) => EventType::OrderFilledWith, EventInternal::PositionUpdateNotification(_) => EventType::PositionUpdateNotification, EventInternal::PositionCloseNotification(_) => EventType::PositionClosedNotification, EventInternal::ServiceHealthUpdate(_) => EventType::ServiceHealthUpdate, From 1293dc443dcfef8f4804ba67055339b33c66118f Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 11:12:15 +0200 Subject: [PATCH 11/32] feat: Add error message to failed task --- mobile/lib/common/domain/background_task.dart | 48 ++++++++++++------- mobile/native/src/dlc/mod.rs | 2 +- mobile/native/src/event/api.rs | 4 +- mobile/native/src/event/mod.rs | 2 +- mobile/native/src/orderbook.rs | 2 +- 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/mobile/lib/common/domain/background_task.dart b/mobile/lib/common/domain/background_task.dart index 802a7f47b..2916fb0e7 100644 --- a/mobile/lib/common/domain/background_task.dart +++ b/mobile/lib/common/domain/background_task.dart @@ -20,29 +20,37 @@ enum TaskStatus { failed, success; - static TaskStatus fromApi(bridge.TaskStatus taskStatus) { - switch (taskStatus) { - case bridge.TaskStatus.Pending: - return TaskStatus.pending; - case bridge.TaskStatus.Failed: - return TaskStatus.failed; - case bridge.TaskStatus.Success: - return TaskStatus.success; + static (TaskStatus, String?) fromApi(bridge.TaskStatus taskStatus) { + if (taskStatus is bridge.TaskStatus_Pending) { + return (TaskStatus.pending, null); } + + if (taskStatus is bridge.TaskStatus_Success) { + return (TaskStatus.success, null); + } + + if (taskStatus is bridge.TaskStatus_Failed) { + final error = taskStatus.field0; + return (TaskStatus.failed, error); + } + + return (TaskStatus.pending, null); } static bridge.TaskStatus apiDummy() { - return bridge.TaskStatus.Pending; + return const bridge.TaskStatus_Pending(); } } class Rollover { final TaskStatus taskStatus; + String? error; - Rollover({required this.taskStatus}); + Rollover({required this.taskStatus, this.error}); static Rollover fromApi(bridge.BackgroundTask_Rollover rollover) { - return Rollover(taskStatus: TaskStatus.fromApi(rollover.field0)); + final (taskStatus, error) = TaskStatus.fromApi(rollover.field0); + return Rollover(taskStatus: taskStatus, error: error); } static bridge.BackgroundTask apiDummy() { @@ -52,11 +60,13 @@ class Rollover { class RecoverDlc { final TaskStatus taskStatus; + String? error; - RecoverDlc({required this.taskStatus}); + RecoverDlc({required this.taskStatus, this.error}); static RecoverDlc fromApi(bridge.BackgroundTask_RecoverDlc recoverDlc) { - return RecoverDlc(taskStatus: TaskStatus.fromApi(recoverDlc.field0)); + final (taskStatus, error) = TaskStatus.fromApi(recoverDlc.field0); + return RecoverDlc(taskStatus: taskStatus, error: error); } static bridge.BackgroundTask apiDummy() { @@ -66,11 +76,13 @@ class RecoverDlc { class CollabRevert { final TaskStatus taskStatus; + String? error; - CollabRevert({required this.taskStatus}); + CollabRevert({required this.taskStatus, this.error}); static CollabRevert fromApi(bridge.BackgroundTask_CollabRevert collabRevert) { - return CollabRevert(taskStatus: TaskStatus.fromApi(collabRevert.field0)); + final (taskStatus, error) = TaskStatus.fromApi(collabRevert.field0); + return CollabRevert(taskStatus: taskStatus, error: error); } static bridge.BackgroundTask apiDummy() { @@ -80,11 +92,13 @@ class CollabRevert { class FullSync { final TaskStatus taskStatus; + String? error; - FullSync({required this.taskStatus}); + FullSync({required this.taskStatus, this.error}); static FullSync fromApi(bridge.BackgroundTask_FullSync fullSync) { - return FullSync(taskStatus: TaskStatus.fromApi(fullSync.field0)); + final (taskStatus, error) = TaskStatus.fromApi(fullSync.field0); + return FullSync(taskStatus: taskStatus, error: error); } static bridge.BackgroundTask apiDummy() { diff --git a/mobile/native/src/dlc/mod.rs b/mobile/native/src/dlc/mod.rs index 37961f99a..75ab1254a 100644 --- a/mobile/native/src/dlc/mod.rs +++ b/mobile/native/src/dlc/mod.rs @@ -464,7 +464,7 @@ pub async fn full_sync_on_wallet_db_migration() { tracing::error!("Full sync failed: {e:#}"); event::publish(&EventInternal::BackgroundNotification( - event::BackgroundTask::FullSync(event::TaskStatus::Failed), + event::BackgroundTask::FullSync(event::TaskStatus::Failed(format!("{e:#}"))), )); } }; diff --git a/mobile/native/src/event/api.rs b/mobile/native/src/event/api.rs index 072d6f590..236fd5a44 100644 --- a/mobile/native/src/event/api.rs +++ b/mobile/native/src/event/api.rs @@ -155,7 +155,7 @@ impl From for BackgroundTask { #[derive(Clone)] pub enum TaskStatus { Pending, - Failed, + Failed(String), Success, } @@ -163,7 +163,7 @@ impl From for TaskStatus { fn from(value: event::TaskStatus) -> Self { match value { event::TaskStatus::Pending => TaskStatus::Pending, - event::TaskStatus::Failed => TaskStatus::Failed, + event::TaskStatus::Failed(error) => TaskStatus::Failed(error), event::TaskStatus::Success => TaskStatus::Success, } } diff --git a/mobile/native/src/event/mod.rs b/mobile/native/src/event/mod.rs index 0fba3d0cd..4e04bd5da 100644 --- a/mobile/native/src/event/mod.rs +++ b/mobile/native/src/event/mod.rs @@ -54,7 +54,7 @@ pub enum BackgroundTask { #[derive(Clone, Debug)] pub enum TaskStatus { Pending, - Failed, + Failed(String), Success, } diff --git a/mobile/native/src/orderbook.rs b/mobile/native/src/orderbook.rs index 09358deb6..8a9a8085d 100644 --- a/mobile/native/src/orderbook.rs +++ b/mobile/native/src/orderbook.rs @@ -256,7 +256,7 @@ async fn handle_orderbook_message( execution_price, ) { event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::CollabRevert(TaskStatus::Failed), + BackgroundTask::CollabRevert(TaskStatus::Failed(format!("{err:#}"))), )); tracing::error!("Could not collaboratively revert channel: {err:#}"); } else { From 52515db7238a6ff2f866115c6a1ef064e714b13b Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 14:42:37 +0200 Subject: [PATCH 12/32] chore: Combine background task change notifier This simplifies the handling of background tasks. Next we will adapt the async order change notifier to fit into the background task pattern. This will eventually allow us to prevent multiple dialogs to be shown at once. --- .../background_task_change_notifier.dart | 52 ++++++++ .../common/collab_revert_change_notifier.dart | 26 ---- mobile/lib/common/domain/background_task.dart | 77 ++++-------- .../lib/common/full_sync_change_notifier.dart | 25 ---- mobile/lib/common/init_service.dart | 26 +--- .../common/recover_dlc_change_notifier.dart | 25 ---- mobile/lib/common/task_status_dialog.dart | 25 ++-- mobile/lib/common/xxi_screen.dart | 116 +++++++++--------- .../trade/rollover_change_notifier.dart | 28 ----- 9 files changed, 150 insertions(+), 250 deletions(-) create mode 100644 mobile/lib/common/background_task_change_notifier.dart delete mode 100644 mobile/lib/common/collab_revert_change_notifier.dart delete mode 100644 mobile/lib/common/full_sync_change_notifier.dart delete mode 100644 mobile/lib/common/recover_dlc_change_notifier.dart delete mode 100644 mobile/lib/features/trade/rollover_change_notifier.dart diff --git a/mobile/lib/common/background_task_change_notifier.dart b/mobile/lib/common/background_task_change_notifier.dart new file mode 100644 index 000000000..11531b6e3 --- /dev/null +++ b/mobile/lib/common/background_task_change_notifier.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:get_10101/common/application/event_service.dart'; +import 'package:get_10101/common/domain/background_task.dart'; +import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; +import 'package:get_10101/logger/logger.dart'; + +class Stack { + final _list = []; + + void push(E value) => _list.add(value); + + E pop() => _list.removeLast(); + + E get peek => _list.last; + + bool get isEmpty => _list.isEmpty; + + bool get isNotEmpty => _list.isNotEmpty; + + @override + String toString() => _list.toString(); +} + +class BackgroundTaskChangeNotifier extends ChangeNotifier implements Subscriber { + Stack events = Stack(); + + @override + void notify(bridge.Event event) async { + if (event is bridge.Event_BackgroundNotification) { + logger.d("Received a background task notification. ${event.field0}"); + final (taskStatus, error) = TaskStatus.fromApi(event.field0.field0); + if (event.field0 is bridge.BackgroundTask_RecoverDlc) { + events.push(BackgroundTask(type: TaskType.recover, status: taskStatus, error: error)); + } + + if (event.field0 is bridge.BackgroundTask_FullSync) { + events.push(BackgroundTask(type: TaskType.fullSync, status: taskStatus, error: error)); + } + + if (event.field0 is bridge.BackgroundTask_Rollover) { + events.push(BackgroundTask(type: TaskType.rollover, status: taskStatus, error: error)); + } + + if (event.field0 is bridge.BackgroundTask_CollabRevert) { + events.push( + BackgroundTask(type: TaskType.collaborativeRevert, status: taskStatus, error: error)); + } + + notifyListeners(); + } + } +} diff --git a/mobile/lib/common/collab_revert_change_notifier.dart b/mobile/lib/common/collab_revert_change_notifier.dart deleted file mode 100644 index 4db692fe6..000000000 --- a/mobile/lib/common/collab_revert_change_notifier.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:get_10101/common/application/event_service.dart'; -import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/logger/logger.dart'; - -class CollabRevertChangeNotifier extends ChangeNotifier implements Subscriber { - TaskStatus taskStatus = TaskStatus.success; - - @override - void notify(bridge.Event event) { - if (event is bridge.Event_BackgroundNotification) { - if (event.field0 is! bridge.BackgroundTask_CollabRevert) { - // ignoring other kinds of background tasks - return; - } - CollabRevert collabRevert = - CollabRevert.fromApi(event.field0 as bridge.BackgroundTask_CollabRevert); - logger.d("Received a collab revert channel event. Status: ${collabRevert.taskStatus}"); - - taskStatus = collabRevert.taskStatus; - - notifyListeners(); - } - } -} diff --git a/mobile/lib/common/domain/background_task.dart b/mobile/lib/common/domain/background_task.dart index 2916fb0e7..173679fb4 100644 --- a/mobile/lib/common/domain/background_task.dart +++ b/mobile/lib/common/domain/background_task.dart @@ -15,12 +15,14 @@ class AsyncTrade { } } +enum TaskType { rollover, asyncTrade, collaborativeRevert, fullSync, recover, unknown } + enum TaskStatus { pending, failed, success; - static (TaskStatus, String?) fromApi(bridge.TaskStatus taskStatus) { + static (TaskStatus, String?) fromApi(dynamic taskStatus) { if (taskStatus is bridge.TaskStatus_Pending) { return (TaskStatus.pending, null); } @@ -42,66 +44,39 @@ enum TaskStatus { } } -class Rollover { - final TaskStatus taskStatus; - String? error; +class BackgroundTask { + final TaskType type; + final TaskStatus status; - Rollover({required this.taskStatus, this.error}); + String? error; - static Rollover fromApi(bridge.BackgroundTask_Rollover rollover) { - final (taskStatus, error) = TaskStatus.fromApi(rollover.field0); - return Rollover(taskStatus: taskStatus, error: error); - } + BackgroundTask({required this.type, required this.status, this.error}); static bridge.BackgroundTask apiDummy() { return bridge.BackgroundTask_Rollover(TaskStatus.apiDummy()); } -} - -class RecoverDlc { - final TaskStatus taskStatus; - String? error; - RecoverDlc({required this.taskStatus, this.error}); + static BackgroundTask fromApi(bridge.BackgroundTask task) { + final taskType = getTaskType(task); - static RecoverDlc fromApi(bridge.BackgroundTask_RecoverDlc recoverDlc) { - final (taskStatus, error) = TaskStatus.fromApi(recoverDlc.field0); - return RecoverDlc(taskStatus: taskStatus, error: error); + final (taskStatus, error) = TaskStatus.fromApi(task.field0); + return BackgroundTask(type: taskType, status: taskStatus, error: error); } - static bridge.BackgroundTask apiDummy() { - return bridge.BackgroundTask_RecoverDlc(TaskStatus.apiDummy()); - } -} - -class CollabRevert { - final TaskStatus taskStatus; - String? error; - - CollabRevert({required this.taskStatus, this.error}); - - static CollabRevert fromApi(bridge.BackgroundTask_CollabRevert collabRevert) { - final (taskStatus, error) = TaskStatus.fromApi(collabRevert.field0); - return CollabRevert(taskStatus: taskStatus, error: error); - } - - static bridge.BackgroundTask apiDummy() { - return bridge.BackgroundTask_CollabRevert(TaskStatus.apiDummy()); - } -} - -class FullSync { - final TaskStatus taskStatus; - String? error; - - FullSync({required this.taskStatus, this.error}); - - static FullSync fromApi(bridge.BackgroundTask_FullSync fullSync) { - final (taskStatus, error) = TaskStatus.fromApi(fullSync.field0); - return FullSync(taskStatus: taskStatus, error: error); - } + static TaskType getTaskType(bridge.BackgroundTask task) { + if (task is bridge.BackgroundTask_RecoverDlc) { + return TaskType.recover; + } + if (task is bridge.BackgroundTask_Rollover) { + return TaskType.rollover; + } + if (task is bridge.BackgroundTask_CollabRevert) { + return TaskType.collaborativeRevert; + } + if (task is bridge.BackgroundTask_FullSync) { + return TaskType.fullSync; + } - static bridge.BackgroundTask apiDummy() { - return bridge.BackgroundTask_FullSync(TaskStatus.apiDummy()); + return TaskType.unknown; } } diff --git a/mobile/lib/common/full_sync_change_notifier.dart b/mobile/lib/common/full_sync_change_notifier.dart deleted file mode 100644 index 223213687..000000000 --- a/mobile/lib/common/full_sync_change_notifier.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:get_10101/common/application/event_service.dart'; -import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/logger/logger.dart'; - -class FullSyncChangeNotifier extends ChangeNotifier implements Subscriber { - TaskStatus taskStatus = TaskStatus.success; - - @override - void notify(bridge.Event event) async { - if (event is bridge.Event_BackgroundNotification) { - if (event.field0 is! bridge.BackgroundTask_FullSync) { - // ignoring other kinds of background tasks - return; - } - FullSync fullSync = FullSync.fromApi(event.field0 as bridge.BackgroundTask_FullSync); - logger.d("Received a full sync event. Status: ${fullSync.taskStatus}"); - - taskStatus = fullSync.taskStatus; - - notifyListeners(); - } - } -} diff --git a/mobile/lib/common/init_service.dart b/mobile/lib/common/init_service.dart index 159b04877..cd5f234e0 100644 --- a/mobile/lib/common/init_service.dart +++ b/mobile/lib/common/init_service.dart @@ -1,20 +1,17 @@ import 'package:flutter/material.dart'; import 'package:get_10101/common/application/tentenone_config_change_notifier.dart'; +import 'package:get_10101/common/background_task_change_notifier.dart'; import 'package:get_10101/common/dlc_channel_change_notifier.dart'; import 'package:get_10101/common/dlc_channel_service.dart'; import 'package:get_10101/common/domain/dlc_channel.dart'; import 'package:get_10101/common/domain/tentenone_config.dart'; -import 'package:get_10101/common/full_sync_change_notifier.dart'; import 'package:get_10101/features/brag/meme_service.dart'; import 'package:get_10101/features/trade/candlestick_change_notifier.dart'; import 'package:get_10101/features/trade/order_change_notifier.dart'; import 'package:get_10101/features/trade/position_change_notifier.dart'; import 'package:get_10101/common/amount_denomination_change_notifier.dart'; -import 'package:get_10101/common/collab_revert_change_notifier.dart'; import 'package:get_10101/common/service_status_notifier.dart'; -import 'package:get_10101/common/recover_dlc_change_notifier.dart'; import 'package:get_10101/features/wallet/application/faucet_service.dart'; -import 'package:get_10101/features/trade/rollover_change_notifier.dart'; import 'package:get_10101/features/trade/trade_value_change_notifier.dart'; import 'package:get_10101/features/wallet/application/wallet_service.dart'; import 'package:get_10101/features/wallet/wallet_change_notifier.dart'; @@ -62,12 +59,9 @@ List createProviders() { ChangeNotifierProvider(create: (context) => ServiceStatusNotifier()), ChangeNotifierProvider(create: (context) => DlcChannelChangeNotifier(dlcChannelService)), ChangeNotifierProvider(create: (context) => AsyncOrderChangeNotifier()), - ChangeNotifierProvider(create: (context) => RolloverChangeNotifier()), - ChangeNotifierProvider(create: (context) => RecoverDlcChangeNotifier()), - ChangeNotifierProvider(create: (context) => CollabRevertChangeNotifier()), + ChangeNotifierProvider(create: (context) => BackgroundTaskChangeNotifier()), ChangeNotifierProvider(create: (context) => TenTenOneConfigChangeNotifier(channelInfoService)), ChangeNotifierProvider(create: (context) => PollChangeNotifier(pollService)), - ChangeNotifierProvider(create: (context) => FullSyncChangeNotifier()), Provider(create: (context) => config), Provider(create: (context) => channelInfoService), Provider(create: (context) => pollService), @@ -91,11 +85,8 @@ void subscribeToNotifiers(BuildContext context) { final submitOrderChangeNotifier = context.read(); final serviceStatusNotifier = context.read(); final asyncOrderChangeNotifier = context.read(); - final rolloverChangeNotifier = context.read(); - final recoverDlcChangeNotifier = context.read(); - final collabRevertChangeNotifier = context.read(); + final backgroundTaskChangeNotifier = context.read(); final tentenoneConfigChangeNotifier = context.read(); - final fullSyncChangeNotifier = context.read(); final dlcChannelChangeNotifier = context.read(); eventService.subscribe( @@ -134,20 +125,11 @@ void subscribeToNotifiers(BuildContext context) { asyncOrderChangeNotifier, bridge.Event.backgroundNotification(AsyncTrade.apiDummy())); eventService.subscribe( - rolloverChangeNotifier, bridge.Event.backgroundNotification(Rollover.apiDummy())); - - eventService.subscribe( - recoverDlcChangeNotifier, bridge.Event.backgroundNotification(RecoverDlc.apiDummy())); - - eventService.subscribe( - collabRevertChangeNotifier, bridge.Event.backgroundNotification(CollabRevert.apiDummy())); + backgroundTaskChangeNotifier, bridge.Event.backgroundNotification(BackgroundTask.apiDummy())); eventService.subscribe( tentenoneConfigChangeNotifier, bridge.Event.authenticated(TenTenOneConfig.apiDummy())); - eventService.subscribe( - fullSyncChangeNotifier, bridge.Event.backgroundNotification(FullSync.apiDummy())); - eventService.subscribe( dlcChannelChangeNotifier, bridge.Event.dlcChannelEvent(DlcChannel.apiDummy())); diff --git a/mobile/lib/common/recover_dlc_change_notifier.dart b/mobile/lib/common/recover_dlc_change_notifier.dart deleted file mode 100644 index 2ca3fe4a3..000000000 --- a/mobile/lib/common/recover_dlc_change_notifier.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:get_10101/common/application/event_service.dart'; -import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/logger/logger.dart'; - -class RecoverDlcChangeNotifier extends ChangeNotifier implements Subscriber { - TaskStatus taskStatus = TaskStatus.success; - - @override - void notify(bridge.Event event) async { - if (event is bridge.Event_BackgroundNotification) { - if (event.field0 is! bridge.BackgroundTask_RecoverDlc) { - // ignoring other kinds of background tasks - return; - } - RecoverDlc recoverDlc = RecoverDlc.fromApi(event.field0 as bridge.BackgroundTask_RecoverDlc); - logger.d("Received a recover dlc event. Status: ${recoverDlc.taskStatus}"); - - taskStatus = recoverDlc.taskStatus; - - notifyListeners(); - } - } -} diff --git a/mobile/lib/common/task_status_dialog.dart b/mobile/lib/common/task_status_dialog.dart index 566b0c611..fafc15639 100644 --- a/mobile/lib/common/task_status_dialog.dart +++ b/mobile/lib/common/task_status_dialog.dart @@ -11,16 +11,17 @@ class TaskStatusDialog extends StatefulWidget { final Widget content; final String buttonText; final EdgeInsets insetPadding; - final String navigateToRoute; - - const TaskStatusDialog( - {super.key, - required this.title, - required this.status, - required this.content, - this.buttonText = "Close", - this.insetPadding = const EdgeInsets.all(50), - this.navigateToRoute = ""}); + final VoidCallback? onClose; + + const TaskStatusDialog({ + super.key, + required this.title, + required this.status, + required this.content, + this.onClose, + this.buttonText = "Close", + this.insetPadding = const EdgeInsets.all(50), + }); @override State createState() => _TaskStatusDialog(); @@ -71,8 +72,8 @@ class _TaskStatusDialog extends State { onPressed: () { GoRouter.of(context).pop(); - if (widget.navigateToRoute.isNotEmpty) { - GoRouter.of(context).go(widget.navigateToRoute); + if (widget.onClose != null) { + widget.onClose!(); } }, child: Text(widget.buttonText)); diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index 4228beac5..d9d17918f 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:get_10101/common/collab_revert_change_notifier.dart'; +import 'package:get_10101/common/background_task_change_notifier.dart'; import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/full_sync_change_notifier.dart'; -import 'package:get_10101/common/recover_dlc_change_notifier.dart'; import 'package:get_10101/common/task_status_dialog.dart'; import 'package:get_10101/features/trade/async_order_change_notifier.dart'; import 'package:get_10101/features/trade/domain/order.dart'; -import 'package:get_10101/features/trade/rollover_change_notifier.dart'; import 'package:get_10101/features/trade/trade_dialog.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -28,6 +25,8 @@ class XXIScreen extends StatefulWidget { } class _XXIScreenState extends State { + BackgroundTask? activeTask; + @override void initState() { final config = context.read(); @@ -40,34 +39,30 @@ class _XXIScreenState extends State { @override Widget build(BuildContext context) { - final recoverTaskStatus = context.watch().taskStatus; - final rolloverTaskStatus = context.watch().taskStatus; + final events = context.watch().events; final asyncTrade = context.watch().asyncTrade; - final fullSyncTaskStatus = context.watch().taskStatus; - final collabRevertTaskStatus = context.watch().taskStatus; + + final task = events.isEmpty ? null : events.peek; WidgetsBinding.instance.addPostFrameCallback((_) { - if (recoverTaskStatus == TaskStatus.pending) { - showDialog( - context: context, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - late Widget content = const Text("Recovering your dlc channel"); - return TaskStatusDialog(title: "Catching up!", status: status, content: content); - }, - ); - } - if (rolloverTaskStatus == TaskStatus.pending) { + final taskStatusDialog = getTaskStatusDialog(task); + + if (taskStatusDialog != null && activeTask == null) { + // only create a new dialog if there isn't an active task already. showDialog( - context: context, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - late Widget content = const Text("Rolling over your position"); - return TaskStatusDialog(title: "Catching up!", status: status, content: content); - }, - ); - } - if (asyncTrade != null) { + context: context, + builder: (context) { + // watch task updates from within the dialog. + final task = context.watch().events.pop(); + if (activeTask != null && task.type != activeTask!.type) { + logger.w("Ignoring task event $task while $activeTask is still active!"); + } else { + // update the active task to the last event received on the stack. + activeTask = task; + } + return getTaskStatusDialog(task)!; + }); + } else if (asyncTrade != null) { if (asyncTrade.orderReason == OrderReason.manual) { showDialog( context: context, @@ -115,45 +110,44 @@ class _XXIScreenState extends State { // remove the async trade from the change notifier state, marking that the dialog has been created. context.read().removeAsyncTrade(); } - if (fullSyncTaskStatus == TaskStatus.pending) { - showDialog( - context: context, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - - Widget content; - switch (status) { - case TaskStatus.pending: - content = const Text("Waiting for on-chain sync to complete"); - case TaskStatus.success: - content = const Text( - "Full on-chain sync completed. If your balance is still incomplete, go to Wallet Settings to trigger further syncs."); - case TaskStatus.failed: - content = const Text( - "Full on-chain sync failed. You can keep trying by shutting down the app and restarting."); - } - - return TaskStatusDialog(title: "Full wallet sync", status: status, content: content); - }, - ); - } - if (collabRevertTaskStatus == TaskStatus.pending) { - showDialog( - context: context, - builder: (context) { - TaskStatus status = context.watch().taskStatus; - late Widget content = const Text("Your channel has been closed collaboratively!"); - return TaskStatusDialog( - title: "Collaborative Channel Close!", status: status, content: content); - }, - ); - } }); return AnnotatedRegion( value: SystemUiOverlayStyle.dark, child: Scaffold(body: widget.child)); } + TaskStatusDialog? getTaskStatusDialog(BackgroundTask? task) { + return switch (task?.type) { + TaskType.rollover => TaskStatusDialog( + title: "Rollover", + status: task!.status, + content: const Text("Rolling over your position"), + onClose: () => activeTask = null), + TaskType.collaborativeRevert => TaskStatusDialog( + title: "Collaborative Channel Close!", + status: task!.status, + content: const Text("Your channel has been closed collaboratively!"), + onClose: () => activeTask = null), + TaskType.fullSync => TaskStatusDialog( + title: "Full wallet sync", + status: task!.status, + content: switch (task.status) { + TaskStatus.pending => const Text("Waiting for on-chain sync to complete"), + TaskStatus.success => const Text( + "Full on-chain sync completed. If your balance is still incomplete, go to Wallet Settings to trigger further syncs."), + TaskStatus.failed => const Text( + "Full on-chain sync failed. You can keep trying by shutting down the app and restarting.") + }, + onClose: () => activeTask = null), + TaskType.recover => TaskStatusDialog( + title: "Catching up!", + status: task!.status, + content: const Text("Recovering your dlc channel"), + onClose: () => activeTask = null), + TaskType.asyncTrade || TaskType.unknown || null => null + }; + } + /// Compare the version of the coordinator with the version of the app /// /// - If the coordinator is newer, suggest to update the app. diff --git a/mobile/lib/features/trade/rollover_change_notifier.dart b/mobile/lib/features/trade/rollover_change_notifier.dart deleted file mode 100644 index ef02ca863..000000000 --- a/mobile/lib/features/trade/rollover_change_notifier.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:get_10101/logger/logger.dart'; -import 'package:flutter/material.dart'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:get_10101/common/application/event_service.dart'; -import 'package:get_10101/common/domain/background_task.dart'; - -class RolloverChangeNotifier extends ChangeNotifier implements Subscriber { - TaskStatus taskStatus = TaskStatus.success; - - @override - void notify(bridge.Event event) async { - if (event is bridge.Event_BackgroundNotification) { - if (event.field0 is! bridge.BackgroundTask_Rollover) { - // ignoring other kinds of background tasks - return; - } - - Rollover rollover = Rollover.fromApi(event.field0 as bridge.BackgroundTask_Rollover); - logger.d("Received a rollover event. Status: ${rollover.taskStatus}"); - - taskStatus = rollover.taskStatus; - - notifyListeners(); - } else { - logger.w("Received unexpected event: ${event.toString()}"); - } - } -} From b5b95d9321210260ef271449039a90a422cd4124 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 14:43:15 +0200 Subject: [PATCH 13/32] chore: Report failed rollover to the ui --- mobile/native/src/dlc/node.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mobile/native/src/dlc/node.rs b/mobile/native/src/dlc/node.rs index 659770264..c8d632e54 100644 --- a/mobile/native/src/dlc/node.rs +++ b/mobile/native/src/dlc/node.rs @@ -659,6 +659,9 @@ impl Node { } Err(e) => { tracing::error!("Failed to accept dlc channel rollover offer. {e:#}"); + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::Rollover(TaskStatus::Failed(format!("{e:#}"))), + )); self.reject_renew_offer(&channel_id)?; } From 30438499209c55b10f6c76f4eca1623353df7ba8 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 15:59:22 +0200 Subject: [PATCH 14/32] chore: Remove unused receive usdp components --- .../wallet/receive/receive_usdp_dialog.dart | 141 ------------------ .../receive/receive_usdp_status_dialog.dart | 129 ---------------- 2 files changed, 270 deletions(-) delete mode 100644 mobile/lib/features/wallet/receive/receive_usdp_dialog.dart delete mode 100644 mobile/lib/features/wallet/receive/receive_usdp_status_dialog.dart diff --git a/mobile/lib/features/wallet/receive/receive_usdp_dialog.dart b/mobile/lib/features/wallet/receive/receive_usdp_dialog.dart deleted file mode 100644 index 0fcafca15..000000000 --- a/mobile/lib/features/wallet/receive/receive_usdp_dialog.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/domain/model.dart'; -import 'package:get_10101/common/value_data_row.dart'; -import 'package:get_10101/features/trade/domain/trade_values.dart'; -import 'package:get_10101/features/trade/submit_order_change_notifier.dart'; -import 'package:get_10101/features/wallet/receive/receive_usdp_status_dialog.dart'; -import 'package:get_10101/features/wallet/wallet_screen.dart'; -import 'package:provider/provider.dart'; -import 'package:share_plus/share_plus.dart'; -import 'package:social_share/social_share.dart'; - -class ReceiveUsdpDialog extends StatelessWidget { - const ReceiveUsdpDialog({super.key}); - - @override - Widget build(BuildContext context) { - final submitOrderChangeNotifier = context.watch(); - final pendingOrder = submitOrderChangeNotifier.pendingOrder!; - final pendingOrderValues = submitOrderChangeNotifier.pendingOrderValues; - - Widget body = createSubmitWidget(pendingOrder, pendingOrderValues, context); - - switch (pendingOrder.state) { - case PendingOrderState.submitting: - case PendingOrderState.submittedSuccessfully: - return ReceiveUsdpTaskStatusDialog( - title: "Converting your received sats to USDP", - status: TaskStatus.pending, - content: body); - case PendingOrderState.submissionFailed: - return ReceiveUsdpTaskStatusDialog( - title: "Submit Order", status: TaskStatus.failed, content: body); - case PendingOrderState.orderFilled: - return ReceiveUsdpTaskStatusDialog( - title: "You received USDP", - status: TaskStatus.success, - content: body, - buttonText: "Awesome 🥳", - navigateToRoute: WalletScreen.route, - ); - case PendingOrderState.orderFailed: - return ReceiveUsdpTaskStatusDialog( - title: "Couldn't convert to USDP", - status: TaskStatus.failed, - content: body, - buttonText: "Oh snap 😕", - ); - } - } -} - -Widget createSubmitWidget( - PendingOrder pendingOrder, TradeValues? pendingOrderValues, BuildContext context) { - String bottomText; - - switch (pendingOrder.state) { - case PendingOrderState.submittedSuccessfully: - case PendingOrderState.submitting: - bottomText = "Please wait while your sats are converted to USDP."; - break; - case PendingOrderState.orderFailed: - case PendingOrderState.submissionFailed: - bottomText = "Sorry, we couldn't match your order. Please try again later."; - break; - case PendingOrderState.orderFilled: - var amount = pendingOrder.tradeValues?.quantity.toInt ?? "0"; - bottomText = "Congratulations! You received $amount USDP."; - break; - } - - Column body = Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 200, - child: Wrap( - runSpacing: 10, - children: [ - ValueDataRow( - type: ValueType.fiat, value: pendingOrderValues?.quantity.toInt, label: "USDP"), - ValueDataRow( - type: ValueType.amount, value: pendingOrderValues?.margin, label: "Margin"), - ValueDataRow( - type: ValueType.amount, value: pendingOrderValues?.fee ?? Amount(0), label: "Fee") - ], - ), - ), - Padding( - padding: const EdgeInsets.only(top: 20, left: 10, right: 10, bottom: 5), - child: Center( - child: Text( - bottomText, - style: const TextStyle( - fontSize: 15, - ), - textAlign: TextAlign.center, - )), - ), - ], - ); - - // Add "Do not close the app" while order is pending - if (pendingOrder.state == PendingOrderState.submitting || - pendingOrder.state == PendingOrderState.submittedSuccessfully) { - body.children.add( - const Padding( - padding: EdgeInsets.only(left: 10, right: 10, bottom: 5), - child: Text("Do not close the app!", - style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)), - ), - ); - } - - // Only display "share on twitter" when order is filled - if (pendingOrder.state == PendingOrderState.orderFilled) { - body.children.add(Padding( - padding: const EdgeInsets.only(top: 20, left: 10, right: 10, bottom: 5), - child: ElevatedButton( - onPressed: () async { - await shareTweet(pendingOrder.positionAction); - }, - child: const Text("Share on Twitter")), - )); - } - - return body; -} - -Future shareTweet(PositionAction action) async { - String shareText = - "I just witnessed the future and received USD-P via lightning using #DLC with @get10101 🚀. The future of decentralised finance starts now! #Bitcoin"; - - if (Platform.isAndroid || Platform.isIOS) { - await SocialShare.shareTwitter(shareText); - } else { - await Share.share(shareText); - } -} diff --git a/mobile/lib/features/wallet/receive/receive_usdp_status_dialog.dart b/mobile/lib/features/wallet/receive/receive_usdp_status_dialog.dart deleted file mode 100644 index 7fda69bc6..000000000 --- a/mobile/lib/features/wallet/receive/receive_usdp_status_dialog.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'dart:async'; - -import 'package:confetti/confetti.dart'; -import 'package:flutter/material.dart'; -import 'package:get_10101/common/domain/background_task.dart'; -import 'package:go_router/go_router.dart'; - -class ReceiveUsdpTaskStatusDialog extends StatefulWidget { - final String title; - final TaskStatus status; - final Widget content; - final String buttonText; - final EdgeInsets insetPadding; - final String navigateToRoute; - - const ReceiveUsdpTaskStatusDialog( - {super.key, - required this.title, - required this.status, - required this.content, - this.buttonText = "Close", - this.insetPadding = const EdgeInsets.all(50), - this.navigateToRoute = ""}); - - @override - State createState() => _TaskStatusDialog(); -} - -class _TaskStatusDialog extends State { - late final ConfettiController _confettiController; - Timer? _timeout; - - bool timeout = false; - - @override - void initState() { - super.initState(); - _confettiController = ConfettiController(duration: const Duration(seconds: 3)); - } - - @override - void dispose() { - _confettiController.dispose(); - _timeout?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - bool isPending = widget.status == TaskStatus.pending; - - if (_timeout != null) { - // cancel already running timeout timer if we receive a new update. - _timeout!.cancel(); - } - - if (isPending) { - // Start timeout showing the close button after 30 seconds. - _timeout = Timer(const Duration(seconds: 30), () { - setState(() { - timeout = true; - }); - }); - } - - WidgetsBinding.instance.addPostFrameCallback((_) { - _confettiController.play(); - }); - - Widget closeButton = ElevatedButton( - onPressed: () { - GoRouter.of(context).pop(); - - if (widget.navigateToRoute.isNotEmpty) { - GoRouter.of(context).go(widget.navigateToRoute); - } - }, - child: Text(widget.buttonText)); - - AlertDialog dialog = AlertDialog( - icon: (() { - switch (widget.status) { - case TaskStatus.pending: - return const Center( - child: SizedBox(width: 20, height: 20, child: CircularProgressIndicator())); - case TaskStatus.failed: - return const Icon( - Icons.cancel, - color: Colors.red, - ); - case TaskStatus.success: - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - Icons.check_circle, - color: Colors.green, - ), - ConfettiWidget( - confettiController: _confettiController, - blastDirectionality: BlastDirectionality.explosive, - maxBlastForce: 10, - // set a lower max blast force - minBlastForce: 9, - // set a lower min blast force - emissionFrequency: 0.00001, - numberOfParticles: 20, - // a lot of particles at once - gravity: 0.2, - shouldLoop: false, - ), - ]); - } - })(), - title: Text(widget.title), - content: widget.content, - actions: isPending && !timeout ? null : [closeButton], - insetPadding: widget.insetPadding, - ); - - // If pending, prevent use of back button - if (isPending) { - return PopScope(canPop: false, child: dialog); - } else { - return dialog; - } - } -} From 617db2f4e83072db997343b0504372c5126af8e1 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Fri, 3 May 2024 16:49:13 +0200 Subject: [PATCH 15/32] chore: Align trade dialog with task dialog This patch simplifies a lot of the logic that has grown historically. The key changes are the following: - The AsyncTrade does not differentiate between manual or other order reasons. - The TaskStatus.failed enum transports any error that happens during the trade. Replacing the `submitOrderError` and `failureReason`. - The `PendingOrder` has been removed in favor of the `TaskStatus`. This gives us a little bit less information for the dialog, but this is in alignment with simplifying the task dialog in general. - If the protocol fails at any point during the trade, the error will be reported to the task dialog. Before we had only a few scenarios where an error was actually reported back to the UI, depending on the dialog to time out. Note, if the protocol fails on the coordinator side the dialog would still have to time out since we do not yet send a `TradeError` message in that case. --- crates/xxi-node/src/message_handler.rs | 25 +++ .../background_task_change_notifier.dart | 4 + mobile/lib/common/domain/background_task.dart | 25 +-- mobile/lib/common/init_service.dart | 12 -- mobile/lib/common/xxi_screen.dart | 85 +++----- .../trade/async_order_change_notifier.dart | 38 ---- mobile/lib/features/trade/error_details.dart | 87 ++++++++ .../trade/submit_order_change_notifier.dart | 94 +------- .../trade/trade_bottom_sheet_tab.dart | 3 +- mobile/lib/features/trade/trade_dialog.dart | 203 ------------------ mobile/native/src/dlc/node.rs | 29 +-- mobile/native/src/event/api.rs | 7 +- mobile/native/src/event/mod.rs | 3 +- mobile/native/src/trade/order/handler.rs | 12 +- 14 files changed, 189 insertions(+), 438 deletions(-) delete mode 100644 mobile/lib/features/trade/async_order_change_notifier.dart create mode 100644 mobile/lib/features/trade/error_details.dart delete mode 100644 mobile/lib/features/trade/trade_dialog.dart diff --git a/crates/xxi-node/src/message_handler.rs b/crates/xxi-node/src/message_handler.rs index d67a2d985..00e386e95 100644 --- a/crates/xxi-node/src/message_handler.rs +++ b/crates/xxi-node/src/message_handler.rs @@ -140,6 +140,31 @@ pub enum TenTenOneMessage { CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer), } +impl TenTenOneMessage { + /// Returns true if the message is a trade message. e.g. Reject, Rollover or Collaborative Close + /// Offer are not trade messages. + /// + /// FIXME(holzeis): This will also return true for any message past the offe rin case of a + /// rollover. We proobably need to add some hint on the message that this is due to a rollover. + pub fn is_trade(&self) -> bool { + matches!( + self, + TenTenOneMessage::Offer(_) + | TenTenOneMessage::Accept(_) + | TenTenOneMessage::Sign(_) + | TenTenOneMessage::RenewOffer(_) + | TenTenOneMessage::RenewAccept(_) + | TenTenOneMessage::RenewConfirm(_) + | TenTenOneMessage::RenewFinalize(_) + | TenTenOneMessage::RenewRevoke(_) + | TenTenOneMessage::SettleOffer(_) + | TenTenOneMessage::SettleAccept(_) + | TenTenOneMessage::SettleConfirm(_) + | TenTenOneMessage::SettleFinalize(_) + ) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneReject { pub reject: Reject, diff --git a/mobile/lib/common/background_task_change_notifier.dart b/mobile/lib/common/background_task_change_notifier.dart index 11531b6e3..f2555ae5d 100644 --- a/mobile/lib/common/background_task_change_notifier.dart +++ b/mobile/lib/common/background_task_change_notifier.dart @@ -46,6 +46,10 @@ class BackgroundTaskChangeNotifier extends ChangeNotifier implements Subscriber BackgroundTask(type: TaskType.collaborativeRevert, status: taskStatus, error: error)); } + if (event.field0 is bridge.BackgroundTask_AsyncTrade) { + events.push(BackgroundTask(type: TaskType.asyncTrade, status: taskStatus, error: error)); + } + notifyListeners(); } } diff --git a/mobile/lib/common/domain/background_task.dart b/mobile/lib/common/domain/background_task.dart index 173679fb4..5453da04b 100644 --- a/mobile/lib/common/domain/background_task.dart +++ b/mobile/lib/common/domain/background_task.dart @@ -1,19 +1,4 @@ import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:get_10101/features/trade/domain/order.dart'; - -class AsyncTrade { - final OrderReason orderReason; - - AsyncTrade({required this.orderReason}); - - static AsyncTrade fromApi(bridge.BackgroundTask_AsyncTrade asyncTrade) { - return AsyncTrade(orderReason: OrderReason.fromApi(asyncTrade.field0)); - } - - static bridge.BackgroundTask apiDummy() { - return bridge.BackgroundTask_AsyncTrade(OrderReason.apiDummy()); - } -} enum TaskType { rollover, asyncTrade, collaborativeRevert, fullSync, recover, unknown } @@ -46,7 +31,7 @@ enum TaskStatus { class BackgroundTask { final TaskType type; - final TaskStatus status; + TaskStatus status; String? error; @@ -76,7 +61,15 @@ class BackgroundTask { if (task is bridge.BackgroundTask_FullSync) { return TaskType.fullSync; } + if (task is bridge.BackgroundTask_AsyncTrade) { + return TaskType.asyncTrade; + } return TaskType.unknown; } + + @override + String toString() { + return "$type ($status)"; + } } diff --git a/mobile/lib/common/init_service.dart b/mobile/lib/common/init_service.dart index cd5f234e0..e25c438a6 100644 --- a/mobile/lib/common/init_service.dart +++ b/mobile/lib/common/init_service.dart @@ -20,7 +20,6 @@ import 'package:get_10101/features/trade/application/candlestick_service.dart'; import 'package:get_10101/features/trade/application/order_service.dart'; import 'package:get_10101/features/trade/application/position_service.dart'; import 'package:get_10101/features/trade/application/trade_values_service.dart'; -import 'package:get_10101/features/trade/async_order_change_notifier.dart'; import 'package:get_10101/common/application/channel_info_service.dart'; import 'package:get_10101/common/domain/background_task.dart'; import 'package:get_10101/common/domain/service_status.dart'; @@ -58,7 +57,6 @@ List createProviders() { create: (context) => CandlestickChangeNotifier(const CandlestickService()).initialize()), ChangeNotifierProvider(create: (context) => ServiceStatusNotifier()), ChangeNotifierProvider(create: (context) => DlcChannelChangeNotifier(dlcChannelService)), - ChangeNotifierProvider(create: (context) => AsyncOrderChangeNotifier()), ChangeNotifierProvider(create: (context) => BackgroundTaskChangeNotifier()), ChangeNotifierProvider(create: (context) => TenTenOneConfigChangeNotifier(channelInfoService)), ChangeNotifierProvider(create: (context) => PollChangeNotifier(pollService)), @@ -82,9 +80,7 @@ void subscribeToNotifiers(BuildContext context) { final positionChangeNotifier = context.read(); final walletChangeNotifier = context.read(); final tradeValuesChangeNotifier = context.read(); - final submitOrderChangeNotifier = context.read(); final serviceStatusNotifier = context.read(); - final asyncOrderChangeNotifier = context.read(); final backgroundTaskChangeNotifier = context.read(); final tentenoneConfigChangeNotifier = context.read(); final dlcChannelChangeNotifier = context.read(); @@ -92,9 +88,6 @@ void subscribeToNotifiers(BuildContext context) { eventService.subscribe( orderChangeNotifier, bridge.Event.orderUpdateNotification(Order.apiDummy())); - eventService.subscribe( - submitOrderChangeNotifier, bridge.Event.orderUpdateNotification(Order.apiDummy())); - eventService.subscribe( positionChangeNotifier, bridge.Event.positionUpdateNotification(Position.apiDummy())); @@ -119,11 +112,6 @@ void subscribeToNotifiers(BuildContext context) { eventService.subscribe( serviceStatusNotifier, bridge.Event.serviceHealthUpdate(serviceUpdateApiDummy())); - eventService.subscribe( - asyncOrderChangeNotifier, bridge.Event.orderUpdateNotification(Order.apiDummy())); - eventService.subscribe( - asyncOrderChangeNotifier, bridge.Event.backgroundNotification(AsyncTrade.apiDummy())); - eventService.subscribe( backgroundTaskChangeNotifier, bridge.Event.backgroundNotification(BackgroundTask.apiDummy())); diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index d9d17918f..273967e39 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -3,9 +3,7 @@ import 'package:flutter/services.dart'; import 'package:get_10101/common/background_task_change_notifier.dart'; import 'package:get_10101/common/domain/background_task.dart'; import 'package:get_10101/common/task_status_dialog.dart'; -import 'package:get_10101/features/trade/async_order_change_notifier.dart'; -import 'package:get_10101/features/trade/domain/order.dart'; -import 'package:get_10101/features/trade/trade_dialog.dart'; +import 'package:get_10101/features/trade/error_details.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'dart:convert'; @@ -40,7 +38,6 @@ class _XXIScreenState extends State { @override Widget build(BuildContext context) { final events = context.watch().events; - final asyncTrade = context.watch().asyncTrade; final task = events.isEmpty ? null : events.peek; @@ -51,64 +48,27 @@ class _XXIScreenState extends State { // only create a new dialog if there isn't an active task already. showDialog( context: context, + useRootNavigator: true, + barrierDismissible: false, builder: (context) { // watch task updates from within the dialog. final task = context.watch().events.pop(); if (activeTask != null && task.type != activeTask!.type) { - logger.w("Ignoring task event $task while $activeTask is still active!"); + if (activeTask!.type == TaskType.recover && task.type == TaskType.asyncTrade) { + // in case a trade protocol finishes we get an async trade task status update, but + // there might have been a restart in between as why the recover task dialog is + // shown. Since these two tasks are different we have to handle this case here + // and only update the task status of the active task. + activeTask!.status = task.status; + } else { + logger.w("Ignoring task event $task while $activeTask is still active!"); + } } else { // update the active task to the last event received on the stack. activeTask = task; } - return getTaskStatusDialog(task)!; + return getTaskStatusDialog(activeTask)!; }); - } else if (asyncTrade != null) { - if (asyncTrade.orderReason == OrderReason.manual) { - showDialog( - context: context, - useRootNavigator: true, - barrierDismissible: false, - builder: (BuildContext context) { - return const TradeDialog(); - }); - } else { - showDialog( - context: context, - builder: (context) { - Order? asyncOrder = context.watch().asyncOrder; - - TaskStatus status = TaskStatus.pending; - switch (asyncOrder?.state) { - case OrderState.open: - case OrderState.filling: - status = TaskStatus.pending; - case OrderState.failed: - case OrderState.rejected: - status = TaskStatus.failed; - case OrderState.filled: - status = TaskStatus.success; - case null: - status = TaskStatus.pending; - } - - late Widget content; - switch (asyncTrade.orderReason) { - case OrderReason.expired: - content = const Text("Your position has been closed due to expiry."); - case OrderReason.liquidated: - content = const Text("Your position has been closed due to liquidation."); - case OrderReason.manual: - logger.e("A manual order should not appear as an async trade!"); - content = Container(); - } - - return TaskStatusDialog(title: "Catching up!", status: status, content: content); - }, - ); - } - - // remove the async trade from the change notifier state, marking that the dialog has been created. - context.read().removeAsyncTrade(); } }); @@ -144,7 +104,24 @@ class _XXIScreenState extends State { status: task!.status, content: const Text("Recovering your dlc channel"), onClose: () => activeTask = null), - TaskType.asyncTrade || TaskType.unknown || null => null + TaskType.asyncTrade => TaskStatusDialog( + title: "Executing Order!", + status: task!.status, + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + switch (task.status) { + TaskStatus.pending => + const Text("Please do not close the app while the trade is executed."), + TaskStatus.success => const Text("The order has been successfully executed!"), + TaskStatus.failed => const Text("Something went wrong!") + }, + if (task.status == TaskStatus.failed && task.error != null) + ErrorDetails(details: task.error!) + ], + ), + onClose: () => activeTask = null), + TaskType.unknown || null => null }; } diff --git a/mobile/lib/features/trade/async_order_change_notifier.dart b/mobile/lib/features/trade/async_order_change_notifier.dart deleted file mode 100644 index f6b2b3519..000000000 --- a/mobile/lib/features/trade/async_order_change_notifier.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:get_10101/logger/logger.dart'; -import 'package:flutter/material.dart'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:get_10101/common/application/event_service.dart'; -import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/features/trade/domain/order.dart'; - -class AsyncOrderChangeNotifier extends ChangeNotifier implements Subscriber { - Order? asyncOrder; - AsyncTrade? asyncTrade; - - // call this function to mark that the async trade has been processed. - void removeAsyncTrade() { - asyncTrade = null; - } - - @override - void notify(bridge.Event event) async { - if (event is bridge.Event_BackgroundNotification) { - if (event.field0 is! bridge.BackgroundTask_AsyncTrade) { - // ignoring other kinds of background tasks - return; - } - AsyncTrade asyncTrade = AsyncTrade.fromApi(event.field0 as bridge.BackgroundTask_AsyncTrade); - logger.d("Received a async trade event. Reason: ${asyncTrade.orderReason}"); - this.asyncTrade = asyncTrade; - notifyListeners(); - } else if (event is bridge.Event_OrderUpdateNotification) { - Order order = Order.fromApi(event.field0); - if (order.reason != OrderReason.manual) { - asyncOrder = order; - notifyListeners(); - } - } else { - logger.w("Received unexpected event: ${event.toString()}"); - } - } -} diff --git a/mobile/lib/features/trade/error_details.dart b/mobile/lib/features/trade/error_details.dart new file mode 100644 index 000000000..f439cba56 --- /dev/null +++ b/mobile/lib/features/trade/error_details.dart @@ -0,0 +1,87 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get_10101/common/application/clickable_help_text.dart'; +import 'package:share_plus/share_plus.dart'; + +class ErrorDetails extends StatelessWidget { + final String details; + + const ErrorDetails({super.key, required this.details}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(top: 20, left: 10, right: 10, bottom: 5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Error details:", + style: TextStyle(fontSize: 15), + ), + Padding( + padding: const EdgeInsets.all(5.0), + child: SizedBox.square( + child: Container( + padding: const EdgeInsets.fromLTRB(5, 25, 5, 10.0), + color: Colors.grey.shade300, + child: Column( + children: [ + Text( + getPrettyJSONString(details), + style: const TextStyle(fontSize: 15), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + GestureDetector( + child: const Icon(Icons.content_copy, size: 16), + onTap: () { + Clipboard.setData(ClipboardData(text: details)).then((_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Copied to clipboard"), + ), + ); + }); + }, + ), + Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + ), + child: GestureDetector( + child: const Icon(Icons.share, size: 16), + onTap: () => Share.share(details), + ), + ) + ], + ), + ], + ), + ), + ), + ), + ClickableHelpText( + text: "Please help us fix this issue and join our telegram group: ", + style: DefaultTextStyle.of(context).style), + ], + ), + ); + } +} + +// Returns a formatted json string if the provided argument is json, else, returns the argument +String getPrettyJSONString(String jsonObjectString) { + try { + var jsonObject = json.decode(jsonObjectString); + var encoder = const JsonEncoder.withIndent(" "); + return encoder.convert(jsonObject); + } catch (error) { + return jsonObjectString; + } +} diff --git a/mobile/lib/features/trade/submit_order_change_notifier.dart b/mobile/lib/features/trade/submit_order_change_notifier.dart index 22d429d08..111b5671b 100644 --- a/mobile/lib/features/trade/submit_order_change_notifier.dart +++ b/mobile/lib/features/trade/submit_order_change_notifier.dart @@ -5,57 +5,19 @@ import 'package:get_10101/features/trade/domain/channel_opening_params.dart'; import 'package:get_10101/features/trade/domain/leverage.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:flutter/material.dart'; -import 'package:get_10101/bridge_generated/bridge_definitions.dart' as bridge; -import 'package:get_10101/common/application/event_service.dart'; import 'package:get_10101/common/domain/model.dart'; import 'package:get_10101/features/trade/application/order_service.dart'; import 'package:get_10101/features/trade/application/trade_values_service.dart'; import 'package:get_10101/features/trade/domain/contract_symbol.dart'; import 'package:get_10101/features/trade/domain/position.dart'; -import 'package:get_10101/features/trade/domain/order.dart'; import 'package:get_10101/features/trade/domain/trade_values.dart'; -enum PendingOrderState { - submitting, - submittedSuccessfully, - submissionFailed, - orderFilled, - orderFailed, -} - -enum PositionAction { - close, - open, -} - -class PendingOrder { - final TradeValues _tradeValues; - PendingOrderState state = PendingOrderState.submitting; - String? pendingOrderError; - final PositionAction positionAction; - String? id; - Amount? pnl; - FailureReason? failureReason; - String? submitOrderError; - - PendingOrder(this._tradeValues, this.positionAction, this.pnl); - - TradeValues? get tradeValues => _tradeValues; -} - -class SubmitOrderChangeNotifier extends ChangeNotifier implements Subscriber { +class SubmitOrderChangeNotifier extends ChangeNotifier { final OrderService orderService; - PendingOrder? _pendingOrder; SubmitOrderChangeNotifier(this.orderService); - submitPendingOrder(TradeValues tradeValues, PositionAction positionAction, - {ChannelOpeningParams? channelOpeningParams, Amount? pnl, bool stable = false}) async { - _pendingOrder = PendingOrder(tradeValues, positionAction, pnl); - - // notify listeners about pending order in state "pending" - notifyListeners(); - + submitOrder(TradeValues tradeValues, {ChannelOpeningParams? channelOpeningParams}) async { try { if (channelOpeningParams != null) { // TODO(holzeis): The coordinator leverage should not be hard coded here. @@ -66,59 +28,24 @@ class SubmitOrderChangeNotifier extends ChangeNotifier implements Subscriber { final traderReserve = max(0, channelOpeningParams.traderCollateral.sub(tradeValues.margin!).sats); - _pendingOrder!.id = await orderService.submitChannelOpeningMarketOrder( + await orderService.submitChannelOpeningMarketOrder( tradeValues.leverage, tradeValues.contracts, ContractSymbol.btcusd, tradeValues.direction, - stable, + false, Amount(coordinatorReserve), Amount(traderReserve)); } else { - _pendingOrder!.id = await orderService.submitMarketOrder(tradeValues.leverage, - tradeValues.contracts, ContractSymbol.btcusd, tradeValues.direction, stable); + await orderService.submitMarketOrder(tradeValues.leverage, tradeValues.contracts, + ContractSymbol.btcusd, tradeValues.direction, false); } - - _pendingOrder!.state = PendingOrderState.submittedSuccessfully; } on FfiException catch (exception) { logger.e("Failed to submit order: $exception"); - _pendingOrder!.state = PendingOrderState.submissionFailed; - _pendingOrder!.submitOrderError = exception.message; - } - - // notify listeners about the status change of the pending order after submission - notifyListeners(); - } - - @override - void notify(bridge.Event event) { - if (event is bridge.Event_OrderUpdateNotification) { - Order order = Order.fromApi(event.field0); - - if (pendingOrder != null) { - switch (order.state) { - case OrderState.open: - case OrderState.filling: - return; - case OrderState.filled: - _pendingOrder!.state = PendingOrderState.orderFilled; - break; - case OrderState.failed: - case OrderState.rejected: - _pendingOrder!.state = PendingOrderState.orderFailed; - break; - } - _pendingOrder!.failureReason = order.failureReason; - - notifyListeners(); - } - } else { - logger.w("Received unexpected event: ${event.toString()}"); } } - Future closePosition(Position position, double? closingPrice, Amount? fee, - {bool stable = false}) async { + Future closePosition(Position position, double? closingPrice, Amount? fee) async { final tradeValues = TradeValues( direction: position.direction.opposite(), margin: position.collateral, @@ -130,11 +57,6 @@ class SubmitOrderChangeNotifier extends ChangeNotifier implements Subscriber { expiry: position.expiry, tradeValuesService: const TradeValuesService()); tradeValues.contracts = position.quantity; - await submitPendingOrder(tradeValues, PositionAction.close, - pnl: position.unrealizedPnl, stable: stable); + await submitOrder(tradeValues); } - - PendingOrder? get pendingOrder => _pendingOrder; - - TradeValues? get pendingOrderValues => _pendingOrder?._tradeValues; } diff --git a/mobile/lib/features/trade/trade_bottom_sheet_tab.dart b/mobile/lib/features/trade/trade_bottom_sheet_tab.dart index 4af1c0707..711c19bc5 100644 --- a/mobile/lib/features/trade/trade_bottom_sheet_tab.dart +++ b/mobile/lib/features/trade/trade_bottom_sheet_tab.dart @@ -204,8 +204,7 @@ class _TradeBottomSheetTabState extends State GoRouter.of(context).pop(); GoRouter.of(context).pop(); - submitOrderChangeNotifier.submitPendingOrder(tradeValues, PositionAction.open, - channelOpeningParams: channelOpeningParams); + submitOrderChangeNotifier.submitOrder(tradeValues, channelOpeningParams: channelOpeningParams); } Wrap buildChildren(Direction direction, rust.TradeConstraints channelTradeConstraints, diff --git a/mobile/lib/features/trade/trade_dialog.dart b/mobile/lib/features/trade/trade_dialog.dart deleted file mode 100644 index 61a487900..000000000 --- a/mobile/lib/features/trade/trade_dialog.dart +++ /dev/null @@ -1,203 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:get_10101/common/application/clickable_help_text.dart'; -import 'package:get_10101/common/application/tentenone_config_change_notifier.dart'; -import 'package:get_10101/common/domain/background_task.dart'; -import 'package:get_10101/common/domain/model.dart'; -import 'package:get_10101/common/task_status_dialog.dart'; -import 'package:get_10101/common/value_data_row.dart'; -import 'package:get_10101/features/trade/domain/trade_values.dart'; -import 'package:get_10101/features/trade/submit_order_change_notifier.dart'; -import 'package:provider/provider.dart'; -import 'package:share_plus/share_plus.dart'; - -class TradeDialog extends StatelessWidget { - const TradeDialog({super.key}); - - @override - Widget build(BuildContext context) { - final submitOrderChangeNotifier = context.watch(); - final pendingOrder = submitOrderChangeNotifier.pendingOrder!; - final pendingOrderValues = submitOrderChangeNotifier.pendingOrderValues; - - Widget body = createSubmitWidget(pendingOrder, pendingOrderValues, context); - - switch (pendingOrder.state) { - case PendingOrderState.submitting: - return TaskStatusDialog(title: "Submit Order", status: TaskStatus.pending, content: body); - case PendingOrderState.submittedSuccessfully: - return TaskStatusDialog(title: "Fill Order", status: TaskStatus.pending, content: body); - case PendingOrderState.submissionFailed: - return TaskStatusDialog(title: "Submit Order", status: TaskStatus.failed, content: body); - case PendingOrderState.orderFilled: - return TaskStatusDialog(title: "Fill Order", status: TaskStatus.success, content: body); - case PendingOrderState.orderFailed: - return TaskStatusDialog(title: "Order", status: TaskStatus.failed, content: body); - } - } -} - -Widget createSubmitWidget( - PendingOrder pendingOrder, TradeValues? pendingOrderValues, BuildContext context) { - String bottomText; - String pnlText = "P/L"; - - switch (pendingOrder.state) { - case PendingOrderState.submittedSuccessfully: - case PendingOrderState.submitting: - bottomText = "Please wait while the order is being processed."; - break; - case PendingOrderState.orderFailed: - case PendingOrderState.submissionFailed: - bottomText = "Submission failed: ${pendingOrder.submitOrderError}."; - break; - case PendingOrderState.orderFilled: - if (pendingOrder.positionAction == PositionAction.close) { - bottomText = "Your position has been closed."; - // At this point, the position is closed so P/L has been realized - // TODO - calculate based on subchannel finalized event - pnlText = "P/L"; - } else { - bottomText = "Congratulations! Your position will be shown in the Positions tab."; - } - break; - } - - List children = []; - if (pendingOrder.failureReason != null) { - children.add( - ErrorDetails( - details: pendingOrder.failureReason!.details ?? "unknown error", - ), - ); - } else { - Amount fee = pendingOrderValues?.fee ?? Amount.zero(); - final referralStatus = context.read().referralStatus; - if (referralStatus != null) { - final feeRebate = fee.sats * referralStatus.referralFeeBonus; - fee -= Amount(feeRebate.floor()); - } - - children.addAll( - [ - SizedBox( - width: 200, - child: Wrap( - runSpacing: 5, - children: [ - pendingOrder.positionAction == PositionAction.close - ? ValueDataRow(type: ValueType.amount, value: pendingOrder.pnl, label: pnlText) - : ValueDataRow( - type: ValueType.amount, value: pendingOrderValues?.margin, label: "Margin"), - ValueDataRow(type: ValueType.amount, value: fee, label: "Fee") - ], - ), - ), - Padding( - padding: const EdgeInsets.only(top: 20, left: 10, right: 10, bottom: 5), - child: Text(bottomText, style: const TextStyle(fontSize: 15)), - ), - ], - ); - - // Add "Do not close the app" while order is pending - if (pendingOrder.state == PendingOrderState.submitting || - pendingOrder.state == PendingOrderState.submittedSuccessfully) { - children.add( - const Padding( - padding: EdgeInsets.only(left: 10, right: 10, bottom: 5), - child: Text("Do not close the app!", - style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)), - ), - ); - } - } - - return Column( - mainAxisSize: MainAxisSize.min, - children: children, - ); -} - -// Returns a formatted json string if the provided argument is json, else, returns the argument -String getPrettyJSONString(String jsonObjectString) { - try { - var jsonObject = json.decode(jsonObjectString); - var encoder = const JsonEncoder.withIndent(" "); - return encoder.convert(jsonObject); - } catch (error) { - return jsonObjectString; - } -} - -class ErrorDetails extends StatelessWidget { - final String details; - - const ErrorDetails({super.key, required this.details}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(top: 20, left: 10, right: 10, bottom: 5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Error details:", - style: TextStyle(fontSize: 15), - ), - Padding( - padding: const EdgeInsets.all(5.0), - child: SizedBox.square( - child: Container( - padding: const EdgeInsets.fromLTRB(5, 25, 5, 10.0), - color: Colors.grey.shade300, - child: Column( - children: [ - Text( - getPrettyJSONString(details), - style: const TextStyle(fontSize: 15), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - GestureDetector( - child: const Icon(Icons.content_copy, size: 16), - onTap: () { - Clipboard.setData(ClipboardData(text: details)).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text("Copied to clipboard"), - ), - ); - }); - }, - ), - Padding( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - ), - child: GestureDetector( - child: const Icon(Icons.share, size: 16), - onTap: () => Share.share(details), - ), - ) - ], - ), - ], - ), - ), - ), - ), - ClickableHelpText( - text: "Please help us fix this issue and join our telegram group: ", - style: DefaultTextStyle.of(context).style), - ], - ), - ); - } -} diff --git a/mobile/native/src/dlc/node.rs b/mobile/native/src/dlc/node.rs index c8d632e54..fd043c4a7 100644 --- a/mobile/native/src/dlc/node.rs +++ b/mobile/native/src/dlc/node.rs @@ -151,12 +151,18 @@ impl Node { for (node_id, msg) in messages { let msg_name = tentenone_message_name(&msg); - if let Err(e) = self.process_dlc_message(to_secp_pk_30(node_id), msg) { + if let Err(e) = self.process_dlc_message(to_secp_pk_30(node_id), msg.clone()) { tracing::error!( from = %node_id, kind = %msg_name, "Failed to process incoming DLC message: {e:#}" ); + + if msg.is_trade() { + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::AsyncTrade(TaskStatus::Failed(format!("{e:#}"))), + )); + } } } } @@ -322,9 +328,8 @@ impl Node { ) .context("Failed to update position after DLC creation")?; - // In case of a restart. event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::RecoverDlc(TaskStatus::Success), + BackgroundTask::AsyncTrade(TaskStatus::Success), )); } // If there is no order in `Filling` we must be rolling over. @@ -356,19 +361,8 @@ impl Node { ) .context("Failed to update position after DLC creation")?; - // Sending always a recover dlc background notification success message here - // as we do not know if we might have reached this state after a restart. - // This event is only received by the UI at the moment indicating that the - // dialog can be closed. If the dialog is not open, this event would be - // simply ignored by the UI. - // - // FIXME(holzeis): We should not require that event and align the UI - // handling with waiting for an order execution in the happy case with - // waiting for an order execution after an in between restart. For now it - // was the easiest to go parallel to that implementation so that we don't - // have to touch it. event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::RecoverDlc(TaskStatus::Success), + BackgroundTask::AsyncTrade(TaskStatus::Success), )); } TenTenOneMessage::SettleConfirm(_) => { @@ -379,9 +373,8 @@ impl Node { update_position_after_dlc_closure(Some(filled_order)) .context("Failed to update position after DLC closure")?; - // In case of a restart. event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::RecoverDlc(TaskStatus::Success), + BackgroundTask::AsyncTrade(TaskStatus::Success), )); } TenTenOneMessage::CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer { @@ -547,7 +540,7 @@ impl Node { ); event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::AsyncTrade(order_reason.into()), + BackgroundTask::AsyncTrade(TaskStatus::Pending), )); order::handler::async_order_filling(&offer.order, &offer.filled_with) diff --git a/mobile/native/src/event/api.rs b/mobile/native/src/event/api.rs index 236fd5a44..791d8c82f 100644 --- a/mobile/native/src/event/api.rs +++ b/mobile/native/src/event/api.rs @@ -8,7 +8,6 @@ use crate::event::EventInternal; use crate::event::EventType; use crate::health::ServiceUpdate; use crate::trade::order::api::Order; -use crate::trade::order::api::OrderReason; use crate::trade::position::api::Position; use core::convert::From; use flutter_rust_bridge::frb; @@ -37,7 +36,7 @@ pub enum Event { #[derive(Clone)] pub enum BackgroundTask { /// The order book submitted an trade which was matched asynchronously - AsyncTrade(OrderReason), + AsyncTrade(TaskStatus), /// The order book submitted its intention to rollover the about to expire position. Rollover(TaskStatus), /// The app was started with a dlc channel in an intermediate state. This task is in pending @@ -138,9 +137,7 @@ impl FlutterSubscriber { impl From for BackgroundTask { fn from(value: event::BackgroundTask) -> Self { match value { - event::BackgroundTask::AsyncTrade(order_reason) => { - BackgroundTask::AsyncTrade(order_reason.into()) - } + event::BackgroundTask::AsyncTrade(status) => BackgroundTask::AsyncTrade(status.into()), event::BackgroundTask::Rollover(status) => BackgroundTask::Rollover(status.into()), event::BackgroundTask::RecoverDlc(status) => BackgroundTask::RecoverDlc(status.into()), event::BackgroundTask::CollabRevert(status) => { diff --git a/mobile/native/src/event/mod.rs b/mobile/native/src/event/mod.rs index 4e04bd5da..01f4ef3f2 100644 --- a/mobile/native/src/event/mod.rs +++ b/mobile/native/src/event/mod.rs @@ -4,7 +4,6 @@ use crate::event::event_hub::get; use crate::event::subscriber::Subscriber; use crate::health::ServiceUpdate; use crate::trade::order::Order; -use crate::trade::order::OrderReason; use crate::trade::position::Position; use rust_decimal::Decimal; use std::fmt; @@ -44,7 +43,7 @@ pub enum EventInternal { #[derive(Clone, Debug)] pub enum BackgroundTask { - AsyncTrade(OrderReason), + AsyncTrade(TaskStatus), Rollover(TaskStatus), CollabRevert(TaskStatus), RecoverDlc(TaskStatus), diff --git a/mobile/native/src/trade/order/handler.rs b/mobile/native/src/trade/order/handler.rs index 39eca64dd..ec08820f7 100644 --- a/mobile/native/src/trade/order/handler.rs +++ b/mobile/native/src/trade/order/handler.rs @@ -7,11 +7,11 @@ use crate::dlc::is_dlc_channel_confirmed; use crate::event; use crate::event::BackgroundTask; use crate::event::EventInternal; +use crate::event::TaskStatus; use crate::report_error_to_coordinator; use crate::trade::order::orderbook_client::OrderbookClient; use crate::trade::order::FailureReason; use crate::trade::order::Order; -use crate::trade::order::OrderReason; use crate::trade::order::OrderState; use crate::trade::order::OrderType; use crate::trade::position; @@ -72,6 +72,11 @@ pub async fn submit_order( submit_order_internal(order, channel_opening_params) .await .inspect_err(report_error_to_coordinator) + .inspect_err(|e| { + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::AsyncTrade(TaskStatus::Failed(format!("{e:#}"))), + )) + }) } pub async fn submit_order_internal( @@ -124,7 +129,7 @@ pub async fn submit_order_internal( update_position_after_order_submitted(&order).map_err(SubmitOrderError::Storage)?; event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::AsyncTrade(OrderReason::Manual), + BackgroundTask::AsyncTrade(TaskStatus::Pending), )); Ok(order.id) @@ -312,6 +317,9 @@ pub(crate) fn order_failed( error: anyhow::Error, ) -> Result<()> { tracing::error!(?order_id, ?reason, "Failed to execute trade: {error:#}"); + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::AsyncTrade(TaskStatus::Failed(format!("{error:#}"))), + )); let order_id = match order_id { None => get_order_in_filling()?.map(|order| order.id), From 3f41d1ecd4167cf25aeb89dd48c85d50cbc35d3c Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Sat, 4 May 2024 10:41:36 +0200 Subject: [PATCH 16/32] feat: Redesign task status dialog --- mobile/assets/error.gif | Bin 0 -> 373913 bytes mobile/assets/loading.gif | Bin 0 -> 126439 bytes mobile/assets/success.gif | Bin 0 -> 41673 bytes .../background_task_change_notifier.dart | 7 +- mobile/lib/common/domain/background_task.dart | 12 ++ mobile/lib/common/task_status_dialog.dart | 164 ++++++++++-------- mobile/lib/common/xxi_screen.dart | 14 +- mobile/pubspec.lock | 8 - mobile/pubspec.yaml | 1 - 9 files changed, 124 insertions(+), 82 deletions(-) create mode 100644 mobile/assets/error.gif create mode 100644 mobile/assets/loading.gif create mode 100644 mobile/assets/success.gif diff --git a/mobile/assets/error.gif b/mobile/assets/error.gif new file mode 100644 index 0000000000000000000000000000000000000000..77a282eba99bce25434bbcf05ebf33c43fe0c223 GIT binary patch literal 373913 zcmeFa2{_gLzW2W-mStRqA|yg&4w~(6gP~W)?0Fq-Jh5nW!D~MzPu9t zeygr~m`q_cE^q#>-<0D0rKi!eH#{cgEJ)kC%f3mwLlX;*;cLmo2TQA~i3K|y{o5^H z_XyMT_W~E}L)J4tt;Xam`y>s+x!UW$R{H^ZwlO z>^0Z*?CRZq!odP@y`XL-Dtqp>&nSx~0jV-VqqH|XN!r`r=^i*(-53`zoL08o$i+`x zwB8*U8-~biw|(26T9~(fF)44k-QG7LY((1LUc-IdpIKad9I>8JF{9}?qx)n%uV&Hd z)!N(Az2T|dZzD5$E-R6lGdfSk`3;CKQYJ)A4v6bBXr~!1$HT)z0)yJJ_nS#+^H~G; zaUrA4lEz7yJ9D?ZcE1rws~da$V`Ch;OK#DGV;cK2OA8NPt|k?2pvNb$jh?$-%-hiF80Vj|J*#TY_&I@2nY2JWSX?en8}= zq|Jw+a)$>8W1JY$<~C_-=Wzdkba)8->4*FKhX?zktmt8=JZWotgyQ0a@w0ci%r4J)t!MktNWpZWPteSp{r2 z_3VEAF^sr4Z|P6k-zOa$Oq{?Yu5u++DA_fHmKP3dbgO2{2fG9|y0|dK99FSvIWM`+AIYtmppl=_5X2&J zf2cV>wJDTSIgtHw!P}My{;MBMS_P{U~hYEex$3q z`tT4$&QHL?j$0EvDb8dNyr`vS2;N9F{!t$$ed|$Q7R!uLKlUdxqyC(J{9^$;QPyKG z_|r1R0)>ia#)8Be`NxALzgdrm$V_F7zf{8nF;@PQqhsLwh36H+rn@)6@ zdO!WfeRFm?2}>?8gY!9leW|wjeaVd{Mc`qxmY~(WPY)P;3v3LIuT{FR5p{Axm3PTJik;yY!qCs zT>oaX{AqhCbGd4NbAGuR1Q#OWVa&F~8VbHFVlB1w0A1>3`Tclz4t;MYoEL>!p;KOXcJsQB5vpp6py|g_ZrY^EG5out*GZ|x* zvon?8ytFfo^B38jc^hrNJDZW|1aQaQ1B ze#W;odrH;tOYST5yrK##_tszb&_)Ju1#XyIh*I*(i%lRl2K+_Ix0={g4mQ50S9@%I z=_*pD=ua1YPO-qZ{%o_bIqBj7)sNi6{SBKDtq)t(M7!K$lw4-u9`zT#7>EZIdlKmO zD?f@kQCEuhIIhMp4l5Bvl&eKF3>7}j&w)nkDJ&fs zYSOKrU%IZRa?-rlP}ltODsKHPzxI1ggVrxmUGwV)qm2)S9Ut^dTEFJFZe*I#WEwVU zek+LE$gpR$RW3?GTb_GOgKHKCqGF(vfMp)!J9JyOE2f$ufg$_1Cg)<^^bH znKQTbH_C11hlONW@M(Q-HQFqQ>BzE_Zu{Qpx><;$$+lM48u${oS(KrjeczyM;9L3T z$Gi~rY+Ea>!GVFz;?j<6d*`;n;oZ#=JWY;+zt+$g>sD#Ac8+6o+t8HUR#|sQ&ZBg# zA9F@q<^3HwPfFT;EV*t~5NL8;Dp-*q;GiLcf{=ecReS&>0L~!bmuVUok=~b=S!qT;8sH z*0sEMi1qaH_VM-e4|ow66ddw0G%Wm8MC9wJ=$P2J_=LnaNx0;c)VJ@_(lg$F$jr*l z$<50zC@lI|TvA$AUQzj}sv2KYTUX!E*woz8+ScCD+135|OHc3DZ+-pW2L^|J437{- z$Hpfnr>19S=jIm{mzIeut842Un_JsEyL(4O0)kThCr)9~|F&cJKX(d~{6;HJ)6bC&pO7!g$7707CI57B?5sJapsgwrDQIZF1(2sDZPpe zLsd?l5qm(nIcA(wCAdDH3kCJCkyS$Fv3N=fy2?CCn!UZe8Xcyvyt0uuW-AR7mbSHx z>~83M266{<4)|=Ot#~VcM*F!oZqa0H3oU-i}-L`V5pIz`5?bXdkaN<_Irz^(>Z%fm0L@D%XqlxKCzzp z!Tw4!U+(^DyY%w@TDQ9B!FsR3gM*EJtK5UlA?M|TErP!&X?r620cmF@J(sk*P_j(g zBQ}X1?yvVfI6T;%&OIdUZ!H6lC~6!Cu7QWJ60sC$9E7S>BMno@` zb{x5Ma}BL4(VLSxnL=HomLZPl!;em;G-$3pUQYBC3r?oC(x_t{Ao|I)C(}AN*KzC; z{ZZ5@NPms`)2u528t4>;=;rz}aw{(|!6{7X8Vv$QD}jdXDaT8i8$?`Jg3PGHQdycb z8pY#Qg00c1tbNUmQspZl4#BDH(;7{311m3G+EY2Unwu`}u7qN#-*Un)H!HEOh6SMC zo@Q=oR+C!|4-0UaF=ms|DXRwFae?*t55TJ_6U zU*`qC6SBJ8W;C!GRoebe#JQ!-bayoxPn{;_f4SY9buFfa0{rXw|LghxkG>51_5A;j zUWNU7{{MRZ|9bxa{tDq2|Nk$G;eI{;e?9+y@&7OW{~HsaU(f$v&;S2T*D$~GpI`aU zul(n4eE0*O_Urlo>-qod`Tr~b|CRs$_sRdS{Q3UZ@3;G38Q=;SP^5m|0t1p2;9LQI z7hqTcdKh5k0qPVW-2vJgpk@Ik9-xE)?it|h0n!wpegWDQAfy2f9^k(LQWGGs0e%;t z$pK~*U|1a)cQ!$QbO+dIfc6H+W=E2hTQs2a0YVxeZXF3%N8b_w9}lq00Ot+x#{dNm zF!TU(50I&-`OnnHCO$#Dsa0v%7$lD7df$Fr3u_1%^>>w;`d&Nw#7Ts^7G-6QOyYWYijH z4D^H#ex-%~0lN}8O~6nW_?S!BYP;l}1uz*Uj8Jfa$^xU*f$DKrBBxpq3Wc!5AlJVr z-9hGmUc5$>=(*N~hLB-0dr)wpx0sE-v(DX)-zE*Qkbdj*U@tPVu#+z#Ch5Y`t?UYm zQqnXg3R}bMp#=PoK^2_jh>wlC5)6BXyXL#E^viRU3_PYZWTx`=vQ&mz93il1=T4=G zIC&^|{Ehre$XK#y4<7N(`C0AAd+t>1aQ3Z>UO(~~8J!msow}ba)fwX5=8uC!(a^Va z&t)m^ur0SOwK@-bu2o@>9*ayfXb%y}Fb9u$5)YxuLzu<=mOT0RNC9YmD*Bny=h>cD zihI*dm)gKrdzN<)V}o6R#9i(;hh|)bpr}qL^pPr*+EBiq7jtawj@hg@5q~`f?e&IA zk?d*>h`LzBf=x&j44SFwJSOV%mLE&5Ia5Z16Z0*)lRU0Qti8gI@_RFXi$;0{l=c-w zaT#075PKg!SqoeU!Hv&Iob_Rt9bhYuEmT(i+Y?PI?Nka zgNK_lrP7%pCE4Ge3sw$O>=rL+&`}Aql%N=6t1I=6t3gq?QKusNH40C{9A9Y0fV;a5 znslNJqdgHOgYYy)!Kqj1|uQ;L>wWiae_v!te!7rfy}j@ zhxUFW_=;l+R)QNMm~7@9xndUWp%P2;S5AXid%0!W4t@cZY6uquk(?SQmn+CDUqZX z1=i+{aeSFmBDt{zwgWv3r9M+4ZZ8UM6^O_1v7HfoVb<<#g`!L0!IqEivG%c$ir6tLArBK$^>{zmz57alE3%u@hsLPzizUA}MP@|( zRzp?L{NX)h|9u|&fV#F>Oip0H?VCGl%9ToxcW#sMR0q2h4CGH9@bTDk%efd=hUTEf@=TYdV1X zq*B}q$ObI!G6Oay^{t8Hi>Dp-j3dwKl?Kh2KGZ#aaY9PzV_O5u$;1kZ8Q~IWb?VaT zFy@=bad^*xn?B!D+&qaFYs)h?5}%&T2Yq_B`DETh1xju((AU7sK(AqXN7s2oLj&g+ zL3Z;w7x>2~9cO%~p@|unzZprBA}8kz>ZUhexb%saoJEXLup!NU&k9QxhVk<_gwft@ zEn8u%x!^fIe!{2a*Eop4ChUv3u{@)Ua3gN!21(8Uk}~ST1kVHALrjCIdN-TWIAbk7 z7mHJK?=UeH8h%wEFW_r~m_fK>YLIDSezMf&`m}{HP3S4{_?>oZox-@j_9>}~oeqbW zg$dK>X}Q6jPM6NYH(Tw~7x#9$u(U-uxb}<^+irJ&PEiVT$Bdf%?&q+VMQ{1EXElv? zzr=JFrAc?p>bULp;AlT)sB6#Z#qaiJ=zRQO&@rc9vHLae<;N^5?RlfY-EXCxA9I{L z=1uo@`|z~IdH&i9=6JTf{$`!xg6NI~OZmO;-7kxa(zO@w8}AMDcNQ0ybS&Dt?F|xW zOG=xxmmK5whGuk1%KJK&o>c7pAigZAoYr1;9o!qR5iZw>JW!E5*Zgh+b^_ z1Pa~KTINoopZxwPGPJawPiH02cz=wgtF%$NbLFMm{x~OHS+ly%>Z|zu34YzOR)fyf zsEYkbvCy)1E1k8t!Tl+juCh+&&b2pt`_m}8@@{{f^%S;)84ca?FVUUrY4ShDJpo(& zH<|F}|0hfyktD^%pBM==CIIapC>H=Nh9jP2MFWmK(7XVu6GuELYy^}Y0ICE^96*QS zh$k;U1o|LA1p_EM0OgJ&s=VcO1eO-QK-U217yJR1K-c4UwseUEItxH40O*7KBuqf& z2O1LqTLJ|Wpf&pG@KqCNf9f8Wj?_k+G43r~|*z)@*P~`yd z5~!j8-3P$)2Pz>)U516_BgiDK0lg1E?+2<1KV7J-H z{)l>0hCabzb5JY^Su;Rj3Ih+h)Fmi_A2~T;;ZNbF1#o>T&L<;ZCB?i5!J!HeXn^q= z_FIU7eLjLtg(IXt!g%Rv1D^sCKN=^>h?-7H=a3tDC)xv=e4k1CbiRc>&t;)B6eF|P zzyy+6!av8$E!Pdv?5~_aUP8l~q(^FpS`S}=7CM{ky#_w7={?zKatga3N@8$W-tQY3 zcLZ&W8CSdQ6tN^-TwUlZKv6DBC)IvgX-ZK%=(GuYE<}xGJ;bI%_76gjEwOPDUpb@n zSx{D#3LKR8zu~VLa(Z!=v6?(+7t6laUp{!1%4vAd^&kcFJhuR;|AZqRQxH(%Yn0#{!{2@0>&#(YMFm#m+r zHMR7%SiKU$TL%{Rc+oC!ErMJvVpQy`A|!PZA8X29+vX0^5m_hPRg#&M^k~r%nZR4~ z^q=9?G?V0syhB=nCGV{yTZU^57mlRl^;SF&rNoF{ ztg+@7%iuw>O87=GhVi7OWn z@6fOEb}{oved0wJllI&TIRRbK3Lv8p!;1=XdeS7DkYLeSWmFvX`|KtKd#e3NP?|#n zx%;SMf^HqNM9r?8Pyo@h)O>>bAy+ZneEEH8`3x0t!_=K(>K==$WTTj`Y{IzGBQgBb z#T72wl3PD$bepF`RvfkSOnFY#f;FpzrxGeDdWB_6uIa!ca}y@j_&ZCuHBQWyCj`LW zzV`QFtdD64rl{b0_`vq1%Ags4iHxq7Ef0E->zl2WiiNhP>HHdRf?DWEOAF`?zX={g%9j1T4vyUM?nbZ+Fh9n722RrELMY!<{H zELiJS4D@ww7FQfBI)qjXP3vrx4<0PJbX5#*b#7Jd$s88hNP?%L^eBdy`+KFz4>?)tzWzcZ}S|BYdf(omQ@P%{3V zVSfumj{ufl6#!VEVhaSK0K)=}TObn!+Pc4E?4KAGX#M_E=< zQ_nxc>|MW~St(FX1;7^QvmW(ItzR7BEfAVIy#m$h<)cyAN113@^HC-W zkSu_)e=sZ%i~gk7e!>yJ4ov_h9v~V0Nv}ufdepl;s@?(&dsOZ@;#L4!kBYDWw*vLl zqoDNvcXa)Od4DnNFNXbB_H6$P0?}M$av>rL#-M>wB->FV;vwYi@$_I?Oqe2^I|B#Q zY$X(w;3qHy5Ew$b)Qcr!59=m2vOh3^z>iB}&MDEFA(fi=(}(gXSOOHpQSfU-MJnD5 zpl5sPnghOVk3USYLmGba5#odpzVHI2HK?c?J!0ZTPRV|<3(V3xq|{?5A5zn)S16%a zd&B?aItAmS#7@Y`fb1ttLbgMmpDiOKYQEU?B|0MRHqpEUv-K}-b+EA`vBN_`4yz*p z>Fl)-CdQXEFjhX1r%gO4!uEMabk5TzUJVD?^T%yPL?>g3?oS zg6A^(fR=Hah5g`kn)V3J$ zlA#a^OVGLnzL^Y$dFev)jX4FFP}1;K9Zv?dD!EX`C*W)IPM1NE$(B|yY}5IqWPlJg z24JSBF{ohgFx*5Ykh~u0PK&$E4{@oRy@~S2g_+X5hpXuJI|TGN-Jn0OD9^LH^jND` zWiO#wep{8Ek(`C=n7RRE@8&}W+WwSP$L$793@W%b6?H-|Ur};t$=fEfp6SO-e)UHj z8Arf4&pNYY+>a|{lHFhiT$t~fZ9MsnOfX#(N`r@pBR3TEq;bW;_!YniIh^N!8VT2= z!2+^zw)LcX6y~cJR}hK9dUl%yt@s8IqE(U?=@@%{V?~di4s;jci0rsZJ8GG|V0qTVp^z)#RoIN= zU0T$4h`6Z}J$-W=b^X&;wu~(DbxB^Ht52X;({7g12w){*+efeipm=FSmyeO~$=6O^B1>0iA>1zS! zBh-3h_=EUSSC4z^75AneKmU&5G(t6&!z)d@@SgI+f&8Q|5$PoAIa!1(=~}#R!Q6}A@S?%UUy}W z>pa{wD`I1;HQkBxeJqk?cXI8{JO}=U(l&!l4U^Tm!x(Xkz=+rkyMBqAXE91Tg`oyE ziRTe}Em<#KMYf`OjiG~sU&Flepch*FLrMF1XA24+|>2V^V)W*bL)7Um??n<$(saOGpsrZTtyL9%pBO z%q5*Z{G)5BK6QqpTdUtfmSAGw3^%im$5(2-kPa^xqsKtZo2YkTIcI2Vii-85Ch zHg60nI$qx^!}BSUhTW-K(!o**gXyrjDH8LXdio`ztOL?~D^Xs`3q~kIt_`l$u5MZ> zWt4UbixhFT^I0D=!+iFkkW4_(+*7j1?HtN1;z}`?Mur*m_?oT1j^(q$P;t84JoD!L zg@MVMoB^b0PJZw$j{w7Hmv2Qm=YwjCPlnS}1!x zFs4o@ z+q~fC;P$b9G!XsA85aL{G3=Lk(t3vOr#XYJ-ES47jl9rL3s$;&1B0Z^(ymWS&Ru)M zd!#KqT@}$^cYloSaJyNzYBjoRe@gyvr#rN2Jze);&iHV*zpHAqr0ZbG?QoAkSH0b& zOInRT+@H~{-tFrmZB`r}5JRi?r*#i^2M>dkDo7QMkLh@kg@z-&P{{1D^ltgI_HDi>3cJu{4JOFy4ph8Ws%TF0lr_ z6@B)1dPdDUi+!51Y7b#T22;r{3aW z?C!wK8l;mLxP})x0U{Ubvz4ghG9#ec_fg$79jK8ZFic@&+^JiGO8e306&a$_7tG*L zO((iA71VLX%1(k@%)sL%jMG~9Ne8C};jyeiX!es1lcbX`p;WoTC9S70fLy@n0LTR# z{$e#h1~@U`5g%s-FN$OANE8TrH3CcSt3JF!j$rRDm84P--kG9t&cjc3TXgQs_y-YW zXF38d?#@vsy>t~vSaR?Ldjug1V^ z^=}RpC<1qVG0rTU$^6H0C5+^vu%xS_e8JO769?LUZ!~Vugf@ZMpQM20-8ov^GZ3ug z=Uk+DP6J_W{kR?KMGOi>72jNrG^7rE4dOcHy#*4|2U1094zfxO#FY z%!g>Zzw0q#H;`&-_P~aO8{&t%`PF3xvR?WGadEKaS4)crhu-k!<~(dJp{Et6pXnK( zv>OKZ-!=VLZiHO2fjp! za)P_jV&2BXj^w-`R)iTr%lHc(7C=3~a;uDjz-0&H>sLJY;3@Rxw=9@!Oq%dRWP4mV zfqY(!-7P~03*t-SPF^LA!MsXlL*5o zFYGf%G9hJ8#TR%li-9cveH9;aJAEzhDyO@mhWylqQ(nGb@X6=r%~Yt)eU2l$oh)w_ z%SST@jk?=|LlL>VRph=XmabUx81mC&@#2XLo_G0f@*^zn7s`JtLP~$Up~KwT^LmFV zL++zxcd#p|S1~g3E(&$F%{{N1qcrk8CUy2oZh1i<`Fe@~cbeiY{Ab@U68Frr-_v@l zL9nckaDv7)O6q0ezO0dC7;o$AWZ|9hUpaBM**6phcfJ+37LxC>FK{NjkYv=5NRSDe zYt_VhKbgWN48yEsnr`T{P@azJVh0OA>+SEQ|8i;a2@2~yl=pR7Y~Ycndp=% z1l8i6-?aV8Qun&imzW*$;E5u;yhD>-oybeFwS!SVZf zM1dO(YW5E!5y_w*da<`x2Mf4P@7(n((`!E~QbIaPTvm4IYA8LwQRa!#%3g`YRiXLCKIPeGIz}WCo2if>@CF&0g%8u(;RB}k4 z6;JbgpezhyWr;1nPv*{tBGIM}wLEeQ^HW&HY`f_#>14&C@+nE7;ISH2qW9 z<-U5PS^O4J|Djp@ly`waioonbU;rX8HW3)z_>-@Xu=(GT1G65E&vvZ$~F!ydh{ij8OXBoyHQI2Yni zqLGCc5g5Ws2dZzs28LKbcY&EQ*w?=ZK1X?eUO^GSJ=X>o6k9O4sd)11&US0$JC+`u zFikhR%_hznp-mZtgU9Be-~-J1z=#ZJ>xZB>5%lB7HSE?1mjS*+iWOwP-NZ`0)CvNL zExC+`T@sO<2sc>ToPZ~*^H!|^4YA2D%n{+yvW{sQPZ#| z1T=ARXDLcLXPf8Knn)!PM1hkB#XcvM&2lB+pRRRW>MC1H(iQbs|9Xe+!p7jO-2E*Q z!T-<$j+o%s-w8bwL98rXt=gNQ#NsN~3gbIv*K!6$W*ScL>Q&R(D(C9n1`)Sx8&mN0tr}2ZC$=r~<_65Lnn8pJ zqFp!%JuXfdudSP zc?T~E_j(v#vwZ7A>~nC!NxBim_7tJ-3*$$E1)L^nD{u;End1yT&eu5K)KOMLdont&fcRjX| zR`bj2M6KHl^6Hl)8z07gbmD*s_^TQVm`5ylpW+EWdvS$EJUCd$g6|%r0)W6s1UhG@Gm{C0#i6qzLP6 z%e@6ESK_>%8%>osuISmS==erFW?~36ZoYd>N#%MK}Ax0+LDVal+k*{nk9 z%E5YAns&urrI5+X_RX8w<8%h3%vX6%cD#Z&S{fhwiM`8{w7AS&fx$JtO6I`c7N(aE zxG;=~hL_?&u`L7U1y2gzP0S+i%(jJm5c4U0weLpM@%DF&H$DSRiyQHYt!DO2Qh(ei+Aj_a+@D>ujRROb0rWZDfPw2 zU*+xNoy!of3n3LjEcO@Z!W0*-J3nem$bNcf{`zq1w{oS*;k)yAh?;@?x+VB2kiAnEk?|S-U+=51*cC7f6<-Kpj@r{%&JwX*;MV z-2O==K6q_*cwa+>_G59O;CPCi;JL+OmhRoe1mDb7&9j-^@z}^5L*C5lC0=AJigx3D zjr6%Juu-&^Y34YoxjXY>QKG-?1DOz6)bnD!8u@SYxr!_c5R#72!(6H1SYa34D{(#QGhW8iQz^lLF6v_FQI2F z%J~E*q6ghyQu<9r8nc<%J%8H8Kvh$9GkCSp&b9nbyMXek;r36B(g~pTq{3r?nETV) znQ~`NHYgG1cnnNFf)wlndhAR?)CZl07-yaiephd`_?gOIZ zgWj-OS^0~7DaAz^FV38z`c36~*)$gkp|S4M$1l7YyE1#bSxS^#UPFl~PRxfjgV25P z{7v#(4&J9_Y7nZ;o>Zt8y-j{7vhyGaV+znOs7K-a5`Hv=1>ftD`dZ2*Tz>shGlWxR zbhrQ30d)pkKS$s?nQZg3O{Xxg9NLH~R6-50;S|}aJXB(W$bLPFc;8iO2UJRHbJIfz ze_Y7(;JY)FsBZf`0&)?A?VpBDO6v>5FH2!PbdhBA+c5eJm@uabk?b*})4gj}&p|lQ zpt38^#)Y#O7)6YSc$i+TkJ6~KS6?*L=^aLm!~;e0drAd(sA8V&`0*H$Dro}e3`7hRY5MMaB(}n+gBcgkep%@kDarNAP*?~ z3Ea1Muzor*{%aD(UE_Yv*8VrFy#+xU@OPdJh0^` z7vC#pK@WX`PWAYk8QR}zetx|{uj@_#=>dzs(k3RMEqo7jYH@Ie2$t%>^RS z4Z9)ZsSAQFGizu?qOF}=+BQitFJHgn*>HAohGe9>qPtxMK$rn?y%A-%Vt+SjvmjS# zD^a+6t-5=ofj+1a-DdFIJXU_kC+3`tX=p$g!??;x=Lg(VXeVY(C*GTP_{>gD#__7h zh&5V#P{mlfJj=X(fl1j_?Ye&0w3)_J=ZlSZ`tA5Xg-R&QXYey+b? zv2D^IL+WX_&)v-PPva%-BF;vd)EmO_peIo=H!U^G0!-d9C9%D;E{aVm3DC(|KX-B4 z`&_S#*frJtNh8~+7^lY)lKwbBD{D$hV^V0&ac-uMm_mYDD^Zu?Gp ztyC!6H|rJyQ`n4csKEPdDf{cwGTY87H@Cvh@}_mDrd7h7JWA{-&U`3&_u@3pY5WO- z#X%-#_XD}NZRULhc{eD}HPbKkT_Gz%(mS)tRjR!tGnx}zZIpF0RjO7q^U|HH_WKg2 z!m?sf;10QLA*Wm2AF@cjaoLP(V0+i>aNw@>Lw3*o>|rAWd0y6-W;O>VCl(nntC`J- z3R#dt*stZZ52UQ!N6=t%HUl#`k+>Zr1Y>t@Ltqxz4Y8q_mm8Q1w?QCqc_nhvG(m_b z(0u96|c{p0rnLemq9zB$adlWkHM?h#U{*c9UW^D@Y6jeJU@wrhHMvt-uFV zDBdPXb*=DC7-&DPP_VF2VGu!%Ekw16OUf4|g~_V3iL-O&YwjUV4;C?8Ex1BO$*%Pg zx|VMsPf3H3lFgL9X+vq(Q{*U7oPm-OmzT88q@)SUqpSdz4-}_@z?TGbPT^lX8l+@& zDCuY|cB3Luk$0DTpOeI}mF97R&+TQNM1li?sQ979SSW;5tRz&B3fX-QDT2|f- zItD61-#N!JUe<`oL?X*U5z-W?Vo^5b4Pl@aanTJ&QGcq6()fzY0 zd}Y0HWuseVb9`lMMP>V7W#?XHH`}K#@}GK*KYeri)F1z8pyJce;HTlePXxBAG5M+q z%#qZbkL}U^Qv48pMu=DBxixcyf0< zMFO6(5>GvZr`^XR*=raSYM4xFj=R^eB-F50*02xNaO~G`ve%wgsO2%KJ>y=>pHM4M zTv;nLR4cMyE5=?Yu23gwQYYnJCzDVoS6QbpRCjT|4#i%tq)@M7Qm^J-uaQu%Sy_)B zs@K`C$FMi(DKuO&Y0!6XFidDLs%$VBYB1ezFk^2tS7@{_X|!~2v`%QeU)g9o)M&ro z=)m6OsL=Gtr0I!!lS@LAYh{!BP}8&hCMTCZN3mqwmZQuSVYad;#j?Mg(4u5aW0PSp`HM6@1toiuOJN)}+jQ?eF^DqAx zh>pO&3f=$0Jt4n3IRC5;&SM4?1(fw z8D9bK?Xn%M388)nqb9Xy5|t^$h}e2|=k{|AWG2BF@PR9^CxlTHSRlZY!BJ&Lq*E;&@hbvB(@`QzLN zWu(h|6_I9d3fn^)JXKQHiC-umsdZbiV=!s1x7cE@8V>B`}s+UA8cv>sYnd06kUBzu2Q&wzZWcUQPON_12+M z_$82>2n5R0a7Zm97sQKX0`6SL)3)%sZ*{y%ByN()=A)<`X&aoCm=lRHvK#~m`4fX zuf_g@HqkHus&eHq9B0n$?$S_2b|ol~)0|m)OG)gsQm|?rmcj_*%`rqEGDFJvfE1Vn+4qZnQZHG@7Y zk-F71mT++KZER0mfQE_;4NR_dg7

AvGTLI?TuO%w07v4)@jYr1nWTT3)9x96|Ph(($d1rkMdEBO!GAi6kP~!~G9b_S`HRCHcpYK%cv0BD) z643(I156)Xv}5mbz8-nR12>EEa*-1!6C1}$w6%1doI$-*G3GlqctQf%-xJP@y}`XG z3ypb=kDU(A5LP|WeV<{>=Nwy&q8k$sDu z-_@&6=tU-)!Oxt3&#jIrdaWOU6O))xWDG3uZ7fXYce7S;n$rkeMdNf}0$4_2z66l2p9~7~TaI*fuhf|4^`&xgw>LCMS`2`y)S>mu&k3Rtd}I-YM}r z-_VXC8xc}5mY*jyDJIDtr+u(^Cx0szePbyr%KmGO$c{$8BEOz_u+KZ5v$1_zmW~mU zoP0WVCt9!Q>m#js;#j}WG&0A4aH^@PCs#7m)9>M7B6*5*uvoqHldtlq#1>c<_0`H8 zAC}tfoxYtNVA6DVr3hx7GhVN$I;y#4^H#wQr04dd_!x8PkHtYqksw8ZU*G-SuPKka z2DMgcy($(qvfapPhPGW7%hqn@dbmlAD8ihpR~H`ui$u)QM@y>dx*vFQ>noGMj4n0u z@_E=})VDnmrAXUMVoRgjs3MPU9mkr1|2b;&(1$MdQNsE4?k~m^c~A}X5e`A3ZNuax zrIljG4P9H}M;Vf~8+~#4kDTBZHXpX#RL?y0y(|vDJnmxYwz)-$_5xAy$A0Bc z6TdU)1*{)-(1r zZ2np;L|pobxkqZ@39X-Y;n4-C)NP=e1Negg(H_kkip)H!g#+`3eo|~|39tzd*v|)S z<^$He0bA~Vui8|$0*!H?CH|9Zf0o06O>ajH8^ZKaMI0DH^jpv7cfkFPZUK4lC*b~j ztr~I?9{c~oBAkD3a1iN#>OQ)E4rh}72kxUg&p@~jCgVg3W)-v=VKZTQ12o{G(}bgS zbZiS*Wpe^FxwS{@=&FYA3rXaQ1MBFjYmF8P>((_Fiw8}EghiVj1#?O}pT)P8l4jCu za)dvp&5M+fWwB{hEPt!8t6VKm%Kfyj8T6nkePM7J-%g@(;2&kk%BvpcXn%pHQctk0 zqrC&kuV;bUI5b3=B&;+QIJzU6c|--pd3nyBXi*T^ko_kTxBh<-{UDuYA*T15zLYj`2(mg(TTl9j| z$-C+vPuTU-g*OHslx9l}*R)@4>SvPTpOMX}MCX(+!`=_?i} z`*g^b4Cgs~Cn~EK+?Yz>Bch9Sa7^XO{+VUin&g9}O8V{|g#!k>!7cICa;s2#7;}bL z9j&mfnCB-3YdlaO%ENiWHdw`K$mhFoUS#ydHjl+&rwS0cJO#k)+hF+HAn-{R0!SW@ zeI!eOQdZW`+G9P*dTpNP8V^G>a451gJa)_+i;$B+F-l@gXf2mR{!=F83KIcd`p#2~90MKFBpfq#X#nXHZmKINt&r5L)lN7Bky#FbsY;J|pEnN= zk>>|9k850T{=^w7Z;dZ*v}!zIn+euuGG}{0gvcRo6C~_oe!*S7Y_&-}Sg< zXzzX0<64lsbK&l+F8A@?INIxmGKr&CoS3gY6ZvR*IWhT466^JM7r&ZnU!S_Z5qmw| z{<;a@<6(oZU$1kaAE#gEoiMaA($CI$ZDiLmX&igZ;B>;rxA(NCOtke4DweJr-u^Uk zGq%rwd*)H5@9Xhf%2EAFo#%74f7qC*yY?sQM5W#FwY||aV8}-uGn}tx9vJk+WY`@^cX|@c0IpNexO17*zt<(2C+V)6KCXiS}-pQBGb{60>(S7hMfgbCGC?UZaZye{{@4C zjQ`%rLH|+LTOIx#{`aL?nqTC*ZiSf;tA&xs^_8Cy*};C1G0&mX1EB z_?bEri)Ex0>&UCt=EQlmpOdF9q+#UI_Cx5kbvrSh(6Cb`*Fkm^QS-V8H$p52^E?^l zv_iZX?>;!W_D!O?5<6(7fRv`tnYmd+t>fOEH_Ckpw9V`lukFGZyd3Pp7-&UPG#=^< zF8R*dZMXTuqB`sRi0k2xr_5$r7o-^PYK1%@G2WN>u{n2BsAHW{SDOA~?=^|rAE*4< zhR!dUOti1hYwuGRb?atyIDZp672?j!1r70R;a{$FWD;36S=%t>R}iOWV&U|yKWiME z-`EgDIJa}Fv_h$J?VEAKr=6w2S<36qP87XQq8+vZlfmvQ^qtDop#d4@E^W zC5rYv%J_Xo9-i|(zwbHcI_Es+e9!aca=HA0zg(a9{l4G#{kltsFNPd~zBd5fFIk6U z(8@+ta!0YBC*yOTkYL2zhp@LH5#`8RSZI}i(m3hSw7E-Ojo>Ob7+9cehc8w(D0H-r zhh8)WtyfI}cq|830nwax(B)`MhvwDTq~2q-m@D`A zK{bs|lG-&$r2A!Rx~xF_2CRcVcIVW>3Q3Gp59(Qoyc#5^@T5E+6B}P1j8VCjp#9{`^3%|2r2Qh~J>=kM7?^i< zw?p2*#WCu51-i_yly&D8{tyU~rD+VyzLaB8cIE31(!ht0f}|>&Hw&dBrf$ndieI_M zhYEBYD>IuoQNG6P|MpPrPTufFI1i;bc8tLeS3?Rs%O2J|ncPXQ?jE zXU_kAvEk!Dmm1?hu;IV9nGPIIzivC%$l;h@x1AW}i{5>)YMHnD;)q3qeetAPwYLd+ zFTCF-8oj^$_O#jT;M+4~#L9k#rNsXJBwLlg22OtIw!@Mh2O(FKFv5@`%J>?HWCSw| zqu`cH7DJPP&$N0>E)W~f4T**>J$)I5xkN8$|3rg#sz+|H0u4R_g1vjhp0Fdw|!WJ*T(`T#q+MxPi8HWrycTK^t{iu?E z@w4Mfd4~O0))IpU_l62Q;C0$EvJ1Oxm{*MYPsKAx!(Pg(_1c^)G>!^y+R=Qh@5&K@ za%n@MM+G9Q2XNC}5Y))rs9-z|G}wAcJD^2XD=DBwLl=CcZhLAj8N`itMpUi1Mer9D zyAND`U_px$W0Sh!W!x27C%Ukh`Dc<(7U8+5V48<=Ck=|D(&pj+L-Xi=@6h4>JgIIo`3`3U7Gk5BuH0 zllgh3E!}|lXBt2zT)G4SFzjz{+3L(zfbmq^O%Iw zp8KzQ-_7wEdhADR4fK5zoHG_W_Lar_XK>zlfA5L%pW}s+_usv3@(+F%leJIAVruEI~Wmx{D2xX!U z0=+xcUkVwTkONisVC6R;(`2n-8XfoYn+?vT9cmF`T)D0zd`G_VRDO-q1=%dJAAV8>-LHIYL%*-%Z{uTRdvy>3#iII z(k8_onUw%LJNUg3`r3T>iGfymvBVfA;c&&VTV?ZQMnmQEy?bp;eM@={#6LuLohmba z$74ooejdDW>Cop7w{PWq{+Lxf`gtg~PIFEqQox zf~|Ugak9y9Y;lTXqxI$g_6;cL?;S>e=2>K|1p6M~UjDbAdHy#ZxUK+qm8B~Ra6cKP zUHP_^b>%w(HtEjN%>=lR{DfBluPficu6%OUAMYW5`0D>Mx_%j5|71qj17R8nCK*Vr zfQj=w85FpPE2jdEmnDM==(02lvj5`2(TCD*exQ<5M8DCp@v~*1vJff!*rNd%vX(s5 zmNxcCI*>tuL5C08fWNAAQ^1Ihr?kqiIvkRm5P9(stKWn)AuGNk)E_BxShlW8zG_t- z+mGO;^H6FZi_~yph!}2a+3dvxf8^)axacz7)}bS^NK34L>5!mCbOFb173D$4 z8V$eVH|oAK&t3Or&+s!SGab}ujoD7mOTM#R-nX)6U-}e}%)aug)0pcH?C_oI2_DFv zdmTDAGWUjt)STx=NFJK+jZw{+?@KTooqx-)(frhZe(Rx6?~?cBe0rZ2H2P`apZqf~ z@;9IPMEvjO5$@*~IQ(a%5N-xoMZgyr`1}H{5ReH324H}v>c81^f$>P}b@v__4KN-H^xcgZQP%xH`P54j(t zmHEix4;LaiWl@jj6jSd%-p_h9mNx}Sh$@9@adIm5F+#>3;;ujSebQ?kTKiz=z(H-9 z7B7d9+Wlhj+4+Rxr$hHEE&>2QV(~CA=u$_VYSQZfVAw_jSyL@$bHh`uWTeJ4$5PUF z`l+pI_VhCc!;$GW7aNV4_Dx&=gl}v2&yVY0OG0x5gn$1yO8@*g{tFj^Z>Wn{^J{|N z_Pc=1E?~2OzrGc62}la@$xu}sV5t?z0)4l}fk^bX8P_!+VZ0A|CfKIxOISV4x9t@iiU7qq?UlRYYzCJJx^0UY;$tsmc*Semn0T4mfD4X9*bi4k~5ok}m_ z7s2n8@#kq+E&PTIu+a@HD1Mvi{vQ7PHa+w0H27OR{o^e7Pygmuspi-7DIrR&?=Ss) z>L|k`L-Do*Fib#=3VQIEfTzRd6M)PPZ}0?_0z=UbV!?PSZM1y)YCISQE5X`>Mg3gH zp3DT0DB#cel`I5E)ol!c6HAB#OQ;e3A4!A`jjLe@W)ro8hZwAybRq~+r+jUp0zwGs zqoGz50|;xu8|C#7Vp(@SO06+87P7q4M;C<|bc+ScEDTQ~B(QSps;w7%=+BZ!oWM2# ziym9BmGeoxiY;1-^cRlyoCk`qd2CUuY`^KO0zR!r4|Z_5;{8`^Jn%sZC{9mcSrAsF zqFs8E3k9LSAWL}@MjFvUi7Cs`z+wqLQ*ANO4LOanu#*uGxz1tAyWgb73*Or*6OK2Y z4!;@=G1y3|hR7Ud9N~e)Ivq+s9@nE5)L=QO1%sM~v;}$J;C}jA&VcE-v!^ghFhx6g&*2L#f(5hjfXTdwkTQk^Q7oX6G%sPOyf7}H+w-+ z6#>YdmTbWAt^=vcglemth@)J{@H1t_tVj)C|Hd5|4mZ`e);DY^oxG5naFe)iUE_A3 zn_bd$Q!}W(ao6X`ODtR_DSBO#yUbMb|58}=Uq7GbH9WgmI(?Irc*kL%U0ce_=}e>M zJ5E6jZC5`}-y#d#b&0lX&ybn9ZR>bAE{S(H-LiXrcl*p;*XFxhiW{Ei zoS3;s6}abGXZIpMWhTqp@!s~1h8IPpGueKL_uK~TI!a&801E37kDrJo@N3TF_zH1zmLZ)C7S?x?^2`ndz}?{Q2>%nEyomwuhUf4%cJOB+u?$j4A2m{nP{FtlPY@FsvG*f&8$L%Css+^AKfB_@TS zN*E98-H3&VGRVMNLX>?a40Zb;7AnWak3F7f;82QYEAwec{qci-<@&*lL#%tUj0zmm zMs^Gb3=Wgj@izz)wG)}3ikh3ARA`;@lYaQ-f8qR=Oe{=2F1aZ9A>Z)NXgZh1Y$4IyYgagW%U=i`acB z8`|Km3aMawdH7bh-sf*8~| z+g?qM7S*p<1WDz5YE|w(R0pxWM$#9>rO~GQYpZ%cw<=``T0xXRi6PSgq2p8N7dCX- zlwox9Nm-k+#mdR`r18pTjWpoMTI)fBBi0sZt(6h(&Z->SY(yLJk)VHhKsl^guv=n$ zU%_K(l0eLnZ33P_k+9tCz40MT8B1zGpYNU^4N*GcxeFxKpN5sqy^OX_j!Jnr3~@*X z33%tOUg5^_Qll!!Y@zC+Npu7^11zdcEf60Z$C(9Q7PaLRg|uum6^_kaOvzd#H>41+>;WU>}| zn&`)e&Aa{kmT z*y+@s6NXBZ`7|1B_)At)W;bM#mT9J@H+DR48nVn+1^Px?A$Sa$B6H*+d=o_ASh_4^ z1QDa>Dx!-`ivSvn_>DE=(?~1jKAza^LVh62FU4( zp^}?vS*}g+SsY_ZPq}CKVV)R>bZwjKvbBb@2DB6DSD`(UYXnl@_g4h&e(&KenKjEf zy<%g=Hoxsw^(*uf!YaI%30!(+CKGiva+9~RIJ8-vmr`*4^q#%w$jkPP1fAfkKAHR2 zokpvpHtHD>{X(vHt_|59Mc;WY4Wo2m*|@%$56}LNAGJf%-r)Xb^BIBe$rrV58V6D(8#FvosX?PsAQIRJ7D82RaiW1}7+Q%yoo{M|652VF z&4wMIN~q2or3$nWQf?Y8GEEeMsiU$3IqGC;peZgQceyS*{9K)7DI zPDby%bn*yVJX$~yMoJzrXe1eBA2VFW9iQ!4{x-Lw`&A$?J+M58RjmIt3^d;>7ft}N z!tIsx`xsiXkhh6zJ%am_SM7SJd&*<$Pf>!p93%Odtnrf;oKv(t!c-;fT$rNzvL&qcXK5&SGYmsaM zNldJh&~X4?AeQeQc&Li2Mj9__>v9oC6H}266Xb#`+~~WuG~BIP2;yQT27GdrHgC;Ip#~O|~K`w7>>sL3b*Y|iSDsskcyYe>eb$2&UUOTPk*&$eufijL9 zNU&5>o_94^n*(9&6}@4(T)Qs+`Fio78{6d#OHumAG_E?Q?d#y$KC^*sVtVMMO7HlH zT9qOYe}m)RRbty_twv3y9L!iLINq}Pbm6TSmg@5;*EmH9(L1ME>0Nz=ND?}{zZKuJunSjx zsmofb^@y?UYxD+=*->-N6E}TfYr~_BPu6Y`zIb!w&6*Rhtk_P)F$Fsh%cYxedCf95Pt0QY?JM<4_lQ&h3(2@j+y^rV=iT&PgjgJ+z#2b zuHEsGeA|u?jS7Q#9pa&>N7bFf@kNVX<_BMYN%_rCSpUOzU)B|J%AwRKD$ivx;h5#Y zaW(H_TUZ~6IU@2k^&6s!Wy`aoq^%<%I$qE2MEZCtMAfh`UXTc1&K^9lPqm>bzW&)i z6xZWFi}i^7_qZO1LKgm9e%$Ggh)6~E^W3t9|QUee8XyA%#e31@N&c_jU2xS;Dmt^9)D=+{JkIT z2L5vrKxE5$%qOya(~ErM2=Kb}r1?kjfv*}lFZuozus+qvT>`Z6U!9gJdVrBNHpPE? z0zwFUDBBX3ZAm*WEfx1=1jb=zUoewbE~C=137|HwILm?E7!T(-K)+a^P_hEf$klqj`kd8)1btI6 zw%<$#xshD)Vlajb>-6q$h(LLsgI3`7*X`65z!wUfMo`$VU6GhrNt`( zkd?R`qq>z+zDD|(^4$4;nJ4(kw;W{`=({vkhpKnUy4OJhS1yfK52Wjc)B59t)`w$M z&yykO6-=hNfCZ6f-hM~*-27|fv|LJ0JUO=lZH&5VKE{S=77Hp{lGnkM7l}c=O`_N7 z-CAzUdN?oZ)=1DSi_9>5sp-m%g%fYcMNIe4iO@iP;n`L5*Sx7;I`pcwo}j!}(cfCq zX(F;NO{lF7KiW^&q#u~Jj|8ABwLoAZ0A`~jJM2U zs4zVhYteJ-o#)J)nYtC{m)XoU#vO-fAZ<5W8Xr8yYuR;UqxVq4 zM}-o!-r>)XG`;8QikT}5Q+Q$b3_@ zU2+9nX7zwwOe#X-;*;bR91%NLbDFq!K#kRovaU{ZpAA>8d8VkX+JRb!NIYAbtK3Ga z@1n?_-LJ`w6o|}x@eC7o#&JPO10r2WDZPmI_k1bqPp6r_B%UdjgZXYPtu;Vg!aq*D zr=hZ}P)9xpzsV;>e1DSFJ^zV^VMZCx&#PhKVw=5Psz(XI-ulaB*2g$1Wdy_Npc;&0 zRLQ9!``ly0=l4zqSGB}1 zn|4ch`tgH6i1M21v1y5N!A;Nc_(9O*dC7jutV8}e8^IV)n=;YvmOEjucAgW}HfcL5 zcy!16$)HEX5*dzmQ$&pHW#m3%Jza?Z!52F)0fX) zF}5WjqYIW@-!3XRPpgO3>0EmBSxnrNvODCH_LtWuo=Ac!SeU4M0I)J(S((M%W>quj)j+Ys=)tvc-3#GY^~gIZdU! zT6}NR`miOaW$Nm};s9BwloRbVow4l8psjQ1vr8@0nWq1BqOj|qK@=9s{EuqfKf0bG z*547rGCy}Q-m1GU#a{ch+<-(B0F?L}6LfHW&=OqY<5ED%GZOGYmoic#N6zxa?x_@D zQguo10;Mj%9|hiMe{hHaz8*h8wIp+aH`>}~e5L!1ug4d-KlpmzmNgbXj4pm7>wOuW zTq05M>t9P^_uqT0{cjPe|HXggm&X02asP4}w`?Vef{>$;AZX!3AT*X+30nb; zAfpU(fuaNMEgk~V9x4D~uy2Wl%@iiEIWeP_3#qd(^qmq`$0bagA`|e1ZLS4o)hG$) zM}i0wPmS4T6Dk)N(I_F!zBDXju)6x)IM7#t1>IF}zi11{D;qAM3Zop#s^H3ok}EMf z{jBLu<^CQ4h)&E16h|=Q=qn-3KoH!T7!7FaX^%FtpzD}l7!2X2Sb<(?dc^{ozGI3! zV4)-oeSO6Z4;67-7$*<6xqzxUHd!p18jiSH53daUii4Y@vMsT7m-5M2JCugyREyRW zYn*4)il?g!HxcykPlB#FKnq{_R3mdjsj!wctenT%D8{KH0)nhQvVc(|cyQD(f!&h@ zzZ6mf-cHk%#`{UBlt_zkx5f*3wt6LoaJ4l3DlSMQ)ljO!6mWUfbD@&}y9sbQ4+;(KLc zuFi7X>nG*!(M+`0TV1Fi%aB~VBnI}!%G|}lo^jp^e%c?abBcJ96AW63-X5#926yEd z>Q+M(i?dFRy4RQ)#ak0q8)s6PCVzyhhnv?9I8i7p?Rr`Bx`O?gz1$mT23ZX{YKf2T zWI;(sBgkX6iK;x^TZy*^>Ws(&f`g*B6LLSeY4k=RR)+p;))Aw;I$}nY8c0Cq`MWwSHP9(RWVWVo+D?u8yp05uWFHki2y^ ztW`uYORj96-sGM9lPOz3!<#M(IefrDSp^=Gq1hmn9UHtYLFYf15e+tHHt+M>xc7B? zHsR{0JnuCgDRTER1K^;}(+V4<8{DLuGFO2H*9>23MrAgfVC|#~&+IAmw1)b9%DbRm zTq<;AOuJcxrONe$+iGZBAqod?j zEMZ(IEp#AluVATjOc7oI|0HcMxM{}24zEKb2J7B0I*yN!^Yh!B$3nc87XDNv{dIAl z%f()D{m4mC}O#aUQ8x@|sZ(pO19Qmo0m!N(ZgHzN|-+Fjcyo zPWO0HwtsKx+={!iogr_14u-riR6eib^jmlUd{QEKg%m9ezRYc}74$)+v35bq>h3*; zon6&7+F;co z30(~=dn^g>pJ_H4Xr;n>v1^6_y-lfOgGayZdQ6PXfO4cOC-(y#5wj_=5rcJN)`vdf{)1 z#s5W7{U879zvTBX`TduZ-^B`4FjA$OVS%?Xqt`rfHS@Q`8&^{yNC^V@z9r6wRVl=S z5GSg|cpl&yA)*h9Rf(}8g$asB6Lo5g6Y$_Vs0Iftq*Oet!!o1gf*QU!a3G>u1B*JM z8V+RLHDc||DUL}8xuSK-mIQt3Fl1I$Z(DpFgfTMoebDI0WRlxIdXp{NC>+4ImT?7v zq29XVG`LJ46(V4+=NN%-ODzE5EEi~D2wj_e8bWQJtcN?yi3!_0| zH9YFKHj1d$@}w{r)0R;wtY!F=^6r)Fcx9tiOzw;tCdQ?@QA?KmSs&ZUofKA73&lVb zX|MAIB3tDhp{omVk(i3>`8146VYdaeQb;IbN}RQUGNA+opPX*iBYk1>l-Tl(U==;B z{Ml};0?@3&vLw2Ow3K#$Q2nj7P2i&VrYdNO87rS{fWP)7#@{6ADLJTw3=*)O4Fii@ zhbkSRgN{B8OG<2^vr5R->O~OfqB~qM1oDp584p*^ao5C0VJ%f6J|}S`g0a#9F?lRT z1vj#kL*wD4aInSu?txY58e-!Q;-u-n)dbTP)vY6*qx~h+@Ldb1lfYB!ad77}D;Q~O zp0HXKOyMA;J%2v#=H@JqS{1QHTinP3u5gbo zzg3&gkgJHSbES=`y)U3-WQ2)}g7qx%`4UExVpv!6nm8WI!i&H?D&_%E)apXxBOJ~? zWqQ_-$#xrZg{d}veY#?~wy`tJ3mGwF_6BmIScFeP$#6Bwy!PRKTY~2rV;rh$aZ=CJd>r0`pCCahJ6nRPHyUBOy(XhH=FZ&==$0DVMvL0b zR>Asrqz1_wH>W?3y`V3=1}+6FoS>yY78ln4(&3nw)D}B3ofGA~vS#|YK(d`fCQSpT zry8~S;Eh0cV_P2ulM`0HE}PsHFANhjv7~r+=yj2{+g|WompBE9WkPUQOPf`+$4&{% z7Ls?(?Att#+B~F3MoOdwE)v)+&Ub-P-)xpSz&6PHG^<+HPvhn zbJ}@#=j04+9fA%~;yB*YXSqvsdNo6TqCTQCyE=H>dH1}F=fj!++$3nO;;%VBx*6y=eI9q zS~U>1w`JC0&(ZKVA{N$9>{Kg5l)}T%&pP9vC}YpTsp(r!RP*IIPsKY9Zo9kr%ZEUx z;o#Ss<)_k$S8rdH0c2L?)Po0lV|n1#jzlBYHJghj+rl!AGJUoUGrq(KRzGK?LaktH zBumK~Lxf}6x&)*KjD)+%0ZNMo%A?kW^2xNrNhsDE7wS-wuv5?Z@$GF91cUs`8omGw z;*|*vB7?f*MP?NDo^dF9`$i)bMVGhHI~Mngys_jENByqv?G`mSXjHeODB|i# zGchcPe#2%>o;-WF|K_->U}%WP5Eml3}+ zW!(c#bEU7oj0U%sy`F2Cd%VE=CzIdFVd^De#Lh6y`7n}HxQ?JvxSngcL2$THa`?v| zYtjz?wlMz@{6Me$qc-PfKY*D%z#x}*2DYR76gT|fLh!XY&>GgGzSG|WFd_yldTr9jbA z&LUv6=GUys9(o9rBCux8uM(DG>1X~@y8}e&@A2enH<`qMf>n_*9K$9vPf)3W-1MRj zenpyK19$}pd;~97eo6qf^GTCAG*gcSX|kkoP4!t%nxM$LexwuZ`Zwj}x^l4P`8d`4 zeXOTEMbW1VGtHia5cbN>$8q3@c-e@d{#DS5X+k`~9@X-j{8w$Hi_@dYf_Yk%`4;HR zh_loP_A=6Ef_~`^msZ`$YBZ-|h0A@Qcw8-H3o;-1UXi}M5!|oCju(${K)fi61hbI& z;*4BLF^+t7FlY5nBibn;rOM~KZe#C6;!ZpQ!Zq%!DmQPkClORTVP0FP_%bXK4~0ye zdJ5{HJ0P60BH@->AbZY}JuMnDh!^Lz<)m^Ykz7LcSv6}{5;qiI@P=S<0yNR?T%g-svZ+lvD<_b$n4J9prsK+2I$G2}H_$foi49VMS)!REt=8zq@)hd}uX zi~>;{staeW03o=MLE?C2H7|U=>0?n*0hF|`)p|Oip9!OYAP~#msxyug*OI+gupNvs zqGm+ooLG(4a>TlrUFI3fJt&yf{@@+z6|fuL6t>C7r*<$gPbeG?q2Xbo!2e}&DJu(w zSyT*RvyT}t1awLK$+ zuu)YzAD!=e;(|!iVzTZTaPygUQ(5N-USH1B9b)7}a?WJ@vV5**hwC13W9P&&Lnq0T(vZ2I1a zeHZ+;x+{yEyAv59PpP$WCy>+Z$OnAHCu$jqG^v6w$#Ovps3$4wrI0bNcEv6L>NhLC zV&0uy$?mo$Pwd$MvlcJj+GFDhinSAyUMzhTbHyANQ;t^*svnAxDiwK9T%s^@jQ!d= z*)K#Xy9Q(RzVfq)d${5hL6eNqmWz4*B!YdjX@0S!G4(VFhM2sDNln|0wu324e^LAZe=Y_%5 zk<+^_mdkJKt1BPAqm~d|F0f2mBrjZgWK9;jd)w2KZ$t8xH>s2+zhebnb)})s50y_G zxGZw+UiUklV&iMaN1KwRWS~gimsnZ$&9vrV;^D;l(!3?z4*A_#g(=%gSU-yd&hwdxjql> zY^iKYetBS{&oKOsgG{}{mLXTdFbq3HzkY$B9ml)Eb$|34&VpIzdYUeDaZVQ%{>pxs z@+KH(%KKHFKQ-*&O(wUNzc+0C)Dps*VhTMPv~m9YER{EX+xgMQt*xJ5l<{VA&paC5 z=e+Rp6>qkr_0ee1@=xU7&1ai`SK}_(&Oc(!OM&KZX=c8zRolu>eVBOuj5V+G{~>CZ zrW5(1)|>A+17Q!o?R+Zb`?d%WYyPn{%`BX{Uc4k{fhaS7U;1}r`FonVt%vU_clYzx z6F-i9%Xo}^0Yoi8`2}kEOO#)r54WUlfePIJs*U^~H=O_YCx2<&UmEu>t#OCOo`8_V zan?Qw96DrQB?B$Wi^*nTyGA}oucVC*`Nv~U645^g2V zAX!!)i`Pp$4JLrVfdVRlq>8F&H4+7>(hkzY6QsEM#<)WKG!kc9$wIDq)ouRzNVo_6 z#mYIddB-I(xw1xYfJ))M4#dNnO=D<9Dwr6SQ3E9qWNZLNiI_L55J3$Pm3G-MLi%q` z%_zM#W`P>mfedX{D%sUMxbl)8Z6)$NdFo@SO&g_w;>W}w&s`rrKGEXJDX%rz#Il2% z`0v5=ABk~7K&jIj9_lD1BF^Qp5a=ybwUOT4ZnWn7 zmHU!7^5uoW+Zdw*S%^x%)Y@)#-R3l|rz*ZyLH{D#{H|h@Oo%+`^et^!6CH5_T!z*$ zUUHtCn}|4u+$F3(K^vhfo>yJ=PSv8ROu z#a^~c8Jhaj59Dy;-Vz6lEs`7(HI9hROjj75Bsn;567}dv8&C<@AF(r_5765cP`qEE zSZGGFOxq2zzA)V=t`B0(s8DT?q{p6sT#(tgLY2sIcB1KdD9#M7&{>HKJF(&B6`E(Q z@+YjFSJPQiPqm`%3tMU~HnHWj7g5rI3PqD-}+_D^_*Z2D;De393_3%B{e zk@M;*wYT$hczp>{_Sd)Qrq`V7(vi$=my)WBL&Gd}JvI!(#r3_cioC*NWONm^&X!n~ zd4(~p2YWS7c{@CDH_w!MRe|$gUv;jxJ@+EHw|-M{{57wpNX8>eB6gLzh?jw=nAv5x zZxZFa|9HVAS7xn@YdrD*G3<5?47A>WyiIJ}6Pe(vG8~jo;0j56w%GPHFdjXV?t@&v zGZK~`lrQ0Vq2%JYd_!eW+za8b(6&cPff@>{&u<<((e&IE4=L@j>)cfSU^RSdgLT`a zdsvX#l-#&mh)&Tw}<-BktS4Ykrz_1ciu% zA9B&Hy0Td$Zln8K_Od;W?IVX?`c}VYrQ|<3>MBOXGMm|6Md$A(`r2emcV7*0cQMmA zV4b}EdCo5kWXT(l>(kc9P8gwjf=C(ac@b%#V1`LHW*W-&F;uz zV^4Bn5(UzAW*6Nw-&9gj8>Ombz1|y?eQNeQU63~5FktfPQ%i75!PU8@fi(-CT4{oX zOr+zW`LfTP7^lJv$>u?8)6Y*CrwebWI)1R*@%dSDOJSyA^N0Uzv{MMp-4Wt~9t6!tnyy5@+-BJZ~CxBT1fQvtzR6ubqMI63~P9WmImz&=f z>;|2V0yZiiw(z@?%C}L0I$h9(k>K+q!58?_^IPHpFjJR8#uJR&K*4V6oBCYZP~`_5 z?v(NE)x1i;Tm30UfqcVKsqXn}0OI(4_l_Sm=F8CUD95En-9NUs`b%a0Qknl0DibE@ z$m_E%%*sv^ zC1LZ|ZM^q459_^@Pz_sJik* zzTn++nu*ZNvPFw$*Imb}hVmLm9Uv)X4i;nSMx4OGiwlpN`ZRAb?J!zTnB}?(!2M*^QP{T-vH@`YeG%v%Eo}jI#srF0?f8>5jv6O z#~NJ|1-tV>OKNV&Rm4vfi!B-T&@&>Ch+G}tl{dgE{{tzO(hEj_J&`4$c-$af*RK#AUkOwFB~gf!;F(pkR?kZrS^!K0Vcuj1(pI_|xY;nV(!=!jjsvKI~#1OOoil4gF$1 zPNvWS`j|s*JV3VDisN_?vLd9m4m??tuLzc%a>biefaMcFVoICL7jecIbRiLWrIR8S z!yBhL_cQk*ZuGCz;plwu4?7+_U5(v-5xhPlEM~dK8x>pWNGTGCA9q3O^{zRi{q#cS z?bmhhOJYGJs*epwP6)9-*5H&+2unE~tn} zN<@)R2{k|E%q^j+!YcY0mLA7~Qmsf*>ne2OTg_tzI%sS>aXBSq$$rLV4(2WL0 zR5LxY`z^IhXB)%9!Y<0|-c*4QP^+zbqtaa8)hQl$>g+n{kvt891r&ulg-&{;6Zfm) zKTuo}XvnhuYScN>y36i;XXLOq)|mFv%s)?y9$R!(Ki<3k%*4d)t9b9a*PXn0BSF!- zSJmFuo$#x@ct`l&mCp3K(%^Wl6T}4SNVVu%39Fr(o_cI`SfwiXQd>!JeXRI}gDQcY z`SS1kqL=GJ$TN3irH=VTJ-pppN49fyOn&a6UI@qTuzpdyJtI6$>;UM3t9j$0urQZ$ zDq?kGEX;Zjz0i-^sA&7ralG}nl+}@-9a~s00>Vz+dvL9Ba^EY*8~2arCVSU$J9an) zx9;t&y4u*VwcDv%G_>KUG$r*OI;kk(q^y3VpK0d$kDm>K?}g~$Ok8pgU0EJ37dnD{t!RBr^jh2H!P#Y)8f`(?z?Et+nd!=FSdq+X z8QJ}YXN|5{IpJZGtQkR}fb~kVd=JOJ>NZhed7mQQK` zlC;8Be*`q}Azt4CwEX@W@H}tn%U74c^E@Cbzl|dUP9^{n{oY&)x&W*@05mVa%;b00 zz9~vRso{sEnF-w5D`)bn089fP=vCgZ1OfjZngs@wfk6m>&hY9j5R~N)D1R8``D zCr<{UVe)KFfsjnOTnkubyc>!>v~?1MwrLCvYdCcnNZ9IV^#rO|O%Zf)=L}CLLJg}O zU>JemXCREu8*`emV*$!45oY!%tyLh(Vj8M$Bba{h8G`6}KeX12( zt222&kY%=5>%%A`K0cQ=Lx8caX-VK8B=r)4vt7x|h-7H1j4Pd?&zXCkTNLylL;OXX(O|?!FS$aG1?SsN}~!i1H8}wI`i&wyPhs1$pX9EWE3z^_PE;6q*LPSehwqFj$vMr0kl zUmwWZ!5nK0hMe^$CuQNm^*THj8q!YiR2sBI*s4GraunhFL;G>&TdbWdX`U-dH`TY3 zb;J&YfwWQEW(CQ#)lL~;<%4wM#-|UG_EticOVQCz%y7mB0z&sTT_7d~efAMG`L^p# z_9+?~MOyD=Zri`2@=}B}bxQ0dZX2GY4OSpDBadZO3t4-$9J!d0tk?)c`?!QlS2HiK z<5Zv>NMS<3_fwS0GFPvoG$wUD6Dec?J&l3^7$KPchsbeb!;~1cpBhWu2475w{H*=J0&YkFkTN{j#D_FX5`7P z{#TuM$N_72FEomiDyEDPxGaGkMHA_v0IBFiR zxRAcxIEi-HqJcK`OyyJv^Pij&jX882O( z&f_D5E<|G18Pqo%GS8Ep=I&Yj3SA$SfZ7xZhcCB(>4ax^BF{%c))hgki;jtWR=SLt zM;3hTxhOg>CjG^2&)TyU+~TXGYZE0Um|3fd9CkBo&Q>BK{4OMvv}|{vsrJ)5+8tsq z!nbWNUa&deTpiWcEH8j~r&vhb>mmz+%3F|H9lRh|%ZH8GMl6_AW>~Zp4k1<`1@DZ1|37SF z4*ul?=Km){D<4n(-PLsam!h)=V)Dni7yu0RU33C|CXVt$ael{xN!#=BU^0%q%N&;& z_P}fU5=9n>hz?jC0;K2CwhZ8E0_t-KAv*+Y%K!rO8$Dr(n*fZ=@L$sbr2RK1a}vPG zW&jb<;%VU5Ony-GJ1`9BZe>0GS>O6m+-i6ZkQDezbcv+!ZJ>tlZ34xuZyPn=c?u)n z9@@vgHMoH1b^t#Mytw}XKf46N{|2E2)G8oU`C1kD0s5c%0f} z=`)O^v**rVxOge~a!P92m8;j7=^58=+|0an`_A2aS=l-FbMx{G3Lg{|mpm*jD}VI( z39F*As=B7Oj$Pl-*woz8%6a;%t^N6nj?S)^uey6)zv1@wz3qSZeqiv!$D!eo(XsJ~ z$*Jj?*}3^opBMNN9R$V5+U7DV!cn5?ZtUFjs%X5DU7BrPMoqkw?tyN0-u1dOf8IVM z&+nJ${3jBflw1m$*uB^sfZ*aBZO?GP!rlE$DzqSOF5tJ)yhs&$PU_o%T_xxkc|b|7t52@{C7c%ijX zyRy4ijcn0GiDA)J;9~HWO?tzQ^9J~cFFJTa;FVY~@C;udB;|b75iWmbF#?SY4xpje zm&;nhGj?yJ3u_I4Le#|j$Mc1Y>of&mH{%n+-e<_tDjUrsMi+E3uJZY!%b59eQKbdK zr^zN+O&t*_ydrrePl}+eBLEFO^GHW2At3_(`kFhXUEvIs_o>be1oU|W0U_ER?GV{L zts4bSL+S{!!l2KUc7Y<-hb5(xCF(@Cp(O_6KM8Qb;|s2WVuNwe!O`Om*ST7o2>EK$ zniAr{VeCzW%H5XSQ#(j>4F^L0N?3MexhKM{ zTX}ilB=l2JjrnBJ&P!;yDB_7!Pb=uX!B_<65Z1OtL8Tj&kIoDbC*rpuNPEDTX+Kb5 zd4-l%5;!TFd-2|FIvcSvR@4ZLHXJ8I1sOGGj#EW3_-z7=J8?p%d@z@S$-?F;5t7r+ zsQ6cwL*$FlLz#U@1q+DEF?@j(PE@oH+9lK-iwO>MK$ZJctg?C!OS!BqO6yi#>)7jT zbsz&w9J#Mhn*5dacWmYcY)Z7S^gqJ?Sysf z(wi9C1tRhwX+c32NT?fxb}|AhEzbk_wgiej#C2)v`qP%t5>6vxXjZG}JaAGT_jZQs zyN&u3dZ}=KeJlxb-FLf|K!EXKd#U9y{`9lNHK+bn`nFrRb&3F zB2({kMT`S`MJ_zNQotM0T7EwrhR@5nz#}THzn_leWTn>8Kv?RO*Q3o42&pjKJZ2!& zPs3Kp5HqOcKb-+N%1pj74nw#XCGDweN%FyLiZ?G`mg_`Py>jNa1P8J(uWi2y#BO6} zBIy46r6Z7(hc42v=EZqmZd^G;dptGu@=9X6g7C0-wd4EL45=hrq4{vkp%;&QGF~iu za~#_aldMjGyxH9XdhzANHmk<;!P_~P4t73#P4^waL2*$hHtKu&34-%b>^5^}3$SZS z!zUNcwpJDO(XEc?Rz3f?q8Qc_LTb4F&Wg=m-75{!ZOOvsNXR7TtfW#AY=ap zjM(5vNft^wGkXW-hLLRZA$4upWO5ZkA#*@9Kc4Kp=hH2|{Dn$Szn4o(KlNAoUpTeA z_hs*N)2TWE-*oDC(f|On1$s=gUMZki zfiXnj4c>pY(DX<46Tp1|niY742UuUg8~mQ)S;3lh3@}Rnkf*?NI{>r&+GhHe{RD^t zU$yBhR{(f-2jZW%fzNlO?GK$g#~7HCsz16;bLcNXp#t2mxpl=qLvH^C3iW3t{Fg=g zms`3vvMWP#vP&8%FAI)8|x;2$;&w3!@+lVs;b@mXyU zCz1=sj|I$`Ti7Z>Q40K?02z`a7??BPGX}$G55xvQ45r2J`aD0ATp%tT1`sUG^A~HZ zzV*W#_(IzF1a?smAqivsl*GNWyr03oJ!;73T=#q;a6zh&exX5BxB`egZE-p0K}@DA zRo?Rk!KF7TsEP(sNFza&ot{vrkB1ZZup3@SL11I-(OlRK?*veTt%)R7gp!NF0Zsoh z2JD7O;+0;s!{TZVly4`1++T2R$liuHmeo3VB#33(LmXQzH%5B1DdV2QtIdhlp#$6kZ^0HRSq7s}qxkmXV&~39 z5~s!F`MHnanCBU?VK>&!pI$?@5R;2{4Q;O(J=A>&Kq`e zl9_`T78zRH2I6dqO@^#MSSo*la0we*y50_CU>d8kni7QFmXyw5zHqG_AsK8Bw#!Yf z&O6Oycb7?1(`6e$2n`-y4>JTphA1l8Px53*4d^3mBCI4vD9IAiT<8RZ_w*`bmmy1C z!BUkqlLNA3GP`RN06`T9<(;QEzCpsZ{?kVDjU_eI)h*z_8Qv2NpI!Y65m7=Db{iA? z0vW=!ZUZoQ(MPg+AwSJS%rZ_JvcwdgSN4XL$lJw%x3t6}FZ6Kb!w_wIGC0MABUBS> zy4$8;x{@_h9f`3=Q|itup-h{*qjInMb_&<-JvwSad`VW{&VlIe2t~Oyq!%8dA1w#5 zwLY$QAzUj^QiKn>g?~y<+#7rNKqqVQ8XImZx{&YqMYM=oblsOUxz~vKLM2`-UE(8F zikkA>U{d+QQo~=rbmc7y#FXKJM^4~IwyQ6?a4(&)I-FOW(A*I(5%1mWi`v*EvT|)- zTDPHPziyI|F_8r|67i3y<8|fz*Q2=CZ=X9THte+9m5!hcRdK~2%nC-3&(XK&)7&xR z_RhuO{mSr)hg`i?DYVt5H`jvw#*LIe)<`Z5tNtiyOLJ0;=lZRLbg4 z;hIEk;TFz&;I=Inao~_)7<-+pY^MZG$<+kE`J8s^;S^fG)*V6`@RUNU4ZU3i-YsLLC0wZ7 zazAvU<^gKnnr77b(+|=3oog+Bb?N$Gu*!IT(ItH5-Cn+g@+m&J;mJ~cP)WCbkA3QM zdhSAI(vbm{65Fm#+g!%UqSme`xaRzu z8wgSKeUqtCnG0`+9Yj~0w7uiCQsYc$GZ-JFan~7o?`(LvWswxDdC}_hYe8t7ebzA{ z+;RGShubrVGB38T`#8MCLLf+SB1Tk*BI`Q*UT-b^{9x4o;-$O2uj4O&ekjSg*!bM< z&F=f3A5CAsc;!Ryo4ubuKL#n(3uXKz9L<>_WI%n3+I2~a!^|*tU%kl0eYadP{ea`_{YM-YW7zMSL*D@!&d^=Y&P}hFaeNF z1-x8<#x<8G_{zYY&87lf|2g&+u=xNq{((rr_l>aGY$~u3cI)Bn)We^o@eltN5XC=` zxN|PoEftlK^c^qygM{0!Ep&ABhA!;S za)a02ef_D+J&NUx@Hi@;C=t_{pSx^E_j-fm26DIJs;wUPKr0XTK+L4e&PnWF+%roO zDwz5xLWp{uXC@T(7yp_yV&d7yCTi2zZ!vFmp^$5V^^b}6LszoY&;Ht)CX`s#U0J~e zt@W+cg#4;!^JbU>H@(~pV^4q!2PtZI976BfbjrfG{*j)!kIXf&wONYITMT=W(e&uX zRZ*a|^V7mD@B(hZZJ}Dztq`33iPjZ8^hjTNxrL5En0b;B?_TCEOD<|%qZJo90X$Xv z$HQ{J=!3g%g+MPLWwpyN@D@sQS3Jcd#EliLz6YZCYcr^8Z5A3Adt|;Z(^4vzv{&7X zt+TQ(sbJA&yqaC80-_-UHo72^3Q7hu@EOf(ebK9IEonwHVLZn+R2yRc{;3xSqW@0yZkGeRZb|`As*fH3p zb#Q${aE@B03#x{ejx4K!tGpM<`afHQiekaYozxGpMbN$eBT*#UdJ~55rmrJN#?O>5 zuFSpVI}~)HZ0KY=5$uj<1;qsCx+rZWNw4{6shm6z@?t5O4br0QM=nYOqihIlc(d>3H=g6l4v^6v|Vlxlp|b2!5y ztLFwO4T*Smt7K7Yqq9oN2Pot{%)5TRN|ByJXN$R%sG*lDslvC$6l2z@9n*!Vd{c5B7@IlZ}P%JX-QJGM}23m7*@Kjz!nh zo-^26QtgU1$kSMPlx0+XPnz{{37#e5p;U?Kwi|qNS}KpUOK9OtqZ{|yn^{#$872$&v;q9Eel*LI2xZHnUfMM%t=pFTL;0Osl%~Qd3qz`4%hTkQu3e=}H8JDmss(%ahuq+M6UhdSCCcgpmN; z{8X@vUB76R#AgQ6jyf0Gcl04MKolFT=oxxlXH{HaR#lYxn$T{0DLQ=#W@O$IUPqSS z+vV0n5CWmO8Fz<+v(D-_|7TA+{7=K(B6t0e-|PP~ANmoHod8VeAKDwRpMMtKKm}}$ zs`Z^dFoz!aHah{-!K@jx(A)3h6Mw)603H4lkKkL7cjd1@K@5meyo#PxlU)%AI*|_6ous#Q5HF6!sW>H)s=FjTS)EWTx8b+f z9k*z;VHCuPH(*ZNfz*WK&c0TdOE(m(FzZ7rV67j@Lo8$Tc66*Z9BaFywNVcW2|jVY zS!qe2o|~L;6bL*BjObDk#{C4C%96#+%>;0vb`IE9>tP#qK8=tLn~w?Ke#544%+?NT z*mqvhgvjcGnBe=)URrLD)V)H$*ftL?;P2?RR9+zW#@v<)HdC@5ww$=>ki_YhE*AEp zA$1qa_I&700A21NiEto{`JQI`Pn{I(r;g{BZ(am}%fwq%4j$1ZWBA;nJfW&#Oejvv zgc1(RS=(@5*LkZero;i@Cw|7OcZN4k`|(~08Mb*$7ZMc zmboj0OkHM#vDP|uju3SOSF-mr@g`40)Huc-Aw5Hpt9b`WhI9|>9)9*&JO#Y{8Ce(K zDx;gpQJzT4P!RM$+66%Kj6w^J?ThrFq&#y}ZTC3d0{ZYIM4BO;XeuU)^N)23J1#LA zB8iMR?N|DyJ`*1M+w=q)M<$CFK-3ZaVQu+T-(!POBFXEjg1GRBBO3Qvbni=)(43rWy(Dr8DafSYS#}Gl^nJInjk&ZF9d`y%&@q1G^64SdXD_OE zx2WOnP2z2xszEn4`=Wp~xJ3@p*QLK(wt%|FLac0?A7}Rpj~(J4@2Fvg%b2tXwPZJ$ zxPjoL?d6w_nI7-Rc`@usDTq8b;|34oL$2kt6zR0C&D1OpW1TI=pO_iV(Ov=?s0c3* zjYf5x5)bQXwlrvFJ|*j4uFkgKrI<2<*Uv2P+(&+UEoqT z=8x`L^6ys?+N~K@HuG z&3SjL&fx5LwWPrXobVc--`1PvwWkUt=j=XJ*Rk0vcSY(o*JN-AWnIq6OON(3Ka~HD zL1Tid*XAMY3|C*Y8cYZ1x+^cX=z=fZ|H$Yr6M$aE*Ii0q34v5@Dp90Mo_G;K@Ste* z=ZlD+mv`nzMfUnK!3oJByyO-2$zcP@ ztEZD0_>>5{l&FxD=!BFQUdo30l-Plk&C@ANeCk%a)a@auc6j8sc3#YXCix#j7R{;t z$3F}IAJLPq^8Z_C`a1+-maF^Ipz`by@ZEg}Leq0cz_)SbKdJtp-E&xoA1liMj%+ST zJqslRN_>Fz4v-;$#pSQ_b8}(pZ@bI0yxp(J-LC=aSr7herw_2H^8Q(ymw+ZD>g^u+~L}yNB7Ceg)g6nUE9ev8q`2MzodBNmAnm}Uqf zpCN3)MqPZsMI>YvK-3o5R&#oaX@ZtVcH8n?MjjEEuGguoArzAOG!Y8nZG1u*HP`H8 zn`-0P+pvbko3jB%gQGj@cp=HXn?|v?Y>gxK)yQM{5VpMeg5l3^uG`T+Ukh<-LZeom z%W@m*0S1_{#Kn1RGpRbMX)E^Vx~o0U%#^Af&2ZS}w{p+S3LxE-2ilnsiXd^0s@R}YaL9rtsL`*_RkNPt$tSWM_YJ>JX^;%HAE!62rZ9GD?}1?B z*qr@e#A-$%>gb{v+43Dd$QI_R4j#pQ1(&h*w5*3r@SXD(?G-XQvJf)8qgn@O=ivy$ z>W;P;Yyt+OnP@OSh(wJfF(c=TBh3sut5xuka2*2 zgqMWiR)nHqQCX2o#ax+O(-cCO5GyYvbZix*H^f!RLJW;ft%u0EF_2$0&0J()qaf8v zdgP;iu7YCYlP%Qy0I#a+Xu+g%lefjpW@**dSLak^K1P(D~(Nu z$hL=SmADV^^U1?3l~JX2^!jxs^0}R*@gvCP@7&t7u31{-GEN*2yL99*q(T0T`H>+Y zcciqQOz!7%$`W3XPM=CYy_tCWFdZZpa))cV+odY%Hf-sluf+=3U*b8iSo13?7-BSPULX=x8MD8sObs)ayc-|S2`$FSD zUj{?4F2+SJr;AK}z)#~5=5_dLtnkLvM#68q!MTK#oMn12G=Zw@SeHzR*3VEnv&qOG zd&94he^KiQXA(<-oIM1tEtah70G)c^#XKMRqDN$3eQkhB;6sy+jT^OhSI5Vz;o8SS zEEnb_-MPcBh6pKGzC-fO;FbfLt4?cTDUBl((25X*u3YX1ZEirHf!YId(OX=kxl7p#VDSm>Lj zxWzYbQ3_1=)eFyk>b9LZ0&>TwDaOG&zn$hRiduNQJzNkHIgo8>aAlPI`&*Yft!<}^ zG$;D9!^!v+Pw{FUGik=3u=vjL0p-CNq~4UJ=#pJUMG>-Va#2@VM^p|3rQ&x zh0Dpwr7Q04;a;K*Yp?8#@uXR$)8pM`mLpoc7e}yPKwo{Km#$c{XN974WhiJpRk&YU z(x1mWe9Es0J@Z20PCkBopVg|2sV0TH`4r)P+hEN!&r_egXvW}Y3YR+!rSbT$P#rwM6O>SlK>rN@P$=q~w)++w2c;Javfi2j+Z|%E> zg&|>2bWZej{noQ}`VRNe^s|f5#So|&mZN1d`iQm0C02G#2|)g>bI}rRVissV9D645 zr)O`}ywABagWh^>hnBJrwBcI%_(*}m!WgrQ_i%LPmg0@KqsdzauZv>etv*5=3EmUh zv-?p-#;U9fZqSm>2Y!>w2owg)il>OH` z^f`@wwf7rS_(!h1ci>yJ94J2mBo2Ttd~am7`S`O^|B82;)$4Pi^0)85v4($|l>V;Q z|0$Cif9dtV^!mTIUI(DS3!YHm+KB`XQa6^)hJqItvSf&(d^gqg(xBLhwoubNsH~2m zm`PO;P`GMp#j#tvRwJ8T;K?uv*%@2O5_MVMO^n0Mrx4P*7u>Vk!;h;7*7A5JhbkXA z&=;%qkc7ho%xZOZlE118gfTFO_pc*_+v&VOvg3d)}KS=!HF}Q41aRf+~S~}zU z`qJV^kb<>C-mdw0ySUGfx*P)EcP+LSWpiwM**9m{rp0%qck?9{Ow&rIm{HxXMMh87SQ@Pb9` z@QX~=q<1j9-HWMq_cBlIP^v6O`9{R!&qEf(p(~lyEH$ECXnzn-_V|7b3e(dDj@?sb^p;8UK=aXhN`{oOwgho!fay|h=l!U8jttB9tMm~j z{Vr%6!;1>w+UBvqDCu&P)9N1RDMxo%-{WlGqrxcPX^OdaF30$2vut247%?x8?SiwlxHWu{$3{VLSlavy#v&deFiuF8EP=HEDH$vbX7=mQ^!LnRhE<1rrQ~iCH*_ zIAT>yv(d{KvQcA!vhroT^1@+OY|$7>Psoycy^Czd8^U>u2B_}CtPgP&&=}$%E{kGC znxW(tG1*Dg9HmL+@Kg`NPXQSrjviyzo zAO$;yP8^zM1v&x6#{4_JvXp7cd~?PA{62+Kr7;`2`V-Qd$OM>AWvKEBU`dfMj*BG@ z(wjBzSZ{6tVPmMu8|t{&vA}IE$6gs9T~Tu)S|6+n;;6<(b9=prkS)3fj7sq^}}@_)%!#tFjPj`HvMz`$#(4^|tbv1*nseJ_*O!@(qkqL5K!Ia}2lL*+2C zbAAg*g#_*}PDHt6gj~y~Y)VipN&gV6*i$gQt_{|cS^o&rTQD8bB|nq-DYz<&nFBLk z|5=u(y68s!z~(ky$hv}sYT|v!iZ1WVvfV4j($aFcIp)!@nd>8Vg(*o&4qMC8=xz_ys#Kq1nI z1p_(CMw>tEtXXNW636XbGvkj)>2lV@kuB6ehQ(c(Ty+_D;>v(R?jH2(K4S9YLtHRp zr{(jL`nxYaiN2)Q>~P>q&fQWw&_qmpJE|kCO*bsJ(t!;=&c$lKpuYqN%>Iv% zhu!J|il8<-tz>MVNoEE)>8(baBu$kIpo_=^IJF1YU87xhV##F@Le-?{4UkLxK$Z=dUfxm3$N}9BD)Xy zU9KCyU%&0uqu$FG-#iv3$?Ezy)=xa?EHGPhy|LllbMXGPqM7< z#5~Eidsg`*$8l=($vz5V-qTz_<37!!8B0$-&G-Gcm-#Y1MKHW_78?ffGz6pVv0ylU zhZ`|Y#E?>`T={u~G7=TV6GK&$Qi)qTgC-d+5Y5lPQZsfR&edP z4BV#fp;=D8{j^eS+2cQo<=o6P#B${Q$1o}A*vtZ0Jsq!6)riW;mI<$a0GB-~5GQvt5*WJ|>ZA=@Dq?vM zu%ZQkh#2dOl1z!#HS({?uFt}FybwAVfS>Dap}w218%wTH<=O7@h3w08gbz#4gbdYo z1`yBwLS|)R++UxgfZ942m+i|!8w4~v6R}ykmXF^m88k~2pFpOg!oe147|h_S!wb%; z)>tPBRds2rJG1yg29FWdez{H7!{!2dN+0~G0I#^c`EssbbD~bIJI3u!^5=&T$T`_i z%+ktC7$qR0>ONf7?KoWdCP~!-TcU)B1FcHi9APm%Y`#^s=Ei${n0^5Vw-F4 zlH7lDv1yvu4ngV{JTTJ2LNpo)?1Kb$=g4#S5JM0vNazMnAf#C3QqhKza$~FsnKW9R zeY~F0$z-84M5GA7={98&YUCmLDo)rzkXar#H;;-yBi-R{(mP3>b)0>Qnj=PrSXkb| z@cbk!%lH7rGT^KWME@4pSeXg6;bJfgIwSOgPO?6qT#B>Ds%xy8m!X{2lU_U|lrt!T zq45ximVk}TrzD~1kPJOnFnLK{5<)tms330EbTLj*!M1?a#m%bsu+I#B>Ji%?m)EN^`Q&XB8c9MGgo1 zqX%)EGQ6H^-jnnl%}0tEQJq>Jqr4ic_m|T_sH2n=t2DNZ$62@RF9W}MAKen+3-}2U zlq9U=E^Y%x9eXbUR(`Vx|&pLDXaNvkET;e+af>;cqrzjV_8Vp81z!(ja?6vDrU zjU_Tgrkxw_N+H3lTGJu$p0F`D@r^we+ufxe?N_4%M|$M*bTXOmSdQIiauO7ac`URyxuaiH$ zan<5=_Ds&2h;0kDwN%(DUMkMJK3vMwdODJYx)v(`2)|SG7-C!BqV2yfL$<->LEZWK zUcaY1&)2>^b>^*qNN>z~vBup-giZAYicGZ9RCj;ywk6itCup{M#hLQx@=f+HJbg57 z`Nf@gbA7nh>ByUY2QY-7rS&45H+W}NU-dp}Qq1rqpQrvc~ouD_AB=Vk)u;M#M!96;#LdHz5G z|0l%utnCjBVgsndBNt~&vOnbhcb3fGD1Km2@Q3sNHJUS9o1McR&WZjx=l^R!XEvGt zL-hX~&i`5Hf6eDh0rual;{V$s?JWNA&j`f7oczC>{C|ImA65j0;Q3UP)fkqm=&2R% zhIQy+a1cl--bEn%6c$EYM8oR%8u`h=wV=ZW`YKr<0y-m}wgZQpfp5n_F=vfC6EBo2Y}ffj0uLWrzvP6i%J zmG!O%*Q)6vb>!vt-iU=`*egdsnBbWigj~_iB#`1_pXPWI!sM8hqFeD^KPY{=${kfv zIP|^;7$4iS5L>TvUUQL12Mt+7vpBDeopJVqwiJ}XWh$A1Jv~dOUpHDI`YpC8O65rY z-cWamg>;TD1an#B+sb@z516H9aX5YB-A$ExGLeF{190{1gOySE)p`c6lZuN-uha z-C@)w#iZdS3)Hmek2)hrt*fkA8w|U_3$|jd$O1vCI=6g+$!?L=pHM~8G`g5~GjXCZ zS)W9GVi>E*mjHrj65JY6^3eBQ-4Cl>*V z)`NvUa2utiSUFsQ$dHr3#w(bJe5Z0qIg8rEWOObMVn=P}5sVV0;?BJEVOTknCGQ%X z?0tw6hnqf(BlWTHGjHUavB|iI<930kIGKjqhKwjeVcs$-5MC#AU5oKq8kWUyAq;9B zNJXLS^rGL(9wi)ok%pWJK(_g|5!_SYegx1qawG(f=>ws-1cY-88>7yK=kKs8Jx&pt zzLzBV#ZWQ~9H0a>8L(WB5Vb17RpUC7EAKlZ!#is1xTu`XYhoy2DV3JHSS&;k3q}F8 z{(fBmP1YZQlcCRCJi|FWJ(3c_l!_PZglIWZk67)2Sm{l$c_oaaM|jj8>s{#>NAQ95 zEU5St)0JjNh_({0H^m5``FZ6^C}Fc>F+!SZOs^==zu#=Xe|I_|w@S8*1cC&SmK|Fg z4lf*qba8~s=y-P2vB`=>y9mjUPZ;@#1Q+CdDm-63{Pd<{qLrS(9X|LfxUZdS=(=Dl z-AXU9hkS!)JJXcH6sDy5*~)eZbTLo3 zp|keo1K-iYD92S?unn{8<)v~~Kt0HWfVI+zS5pc$9Q4vvWFNjx!~_W0XfYmvV^$nD zy!>L%fLl7hdq<}_pOClgg4VBh6BOFoCp7V$DNFbRUW{P!V zv#dX#jUZ}4##1mDjdmCocWu}w)+*{vnVW1P33}h74yzmjv0g8U^nDPbu)C_-DBsIc z)@LM*O94qEp27BqbD9iWkLR1QyYpV$RMIeA!2EEjlc%_?yC9d+6O2N`rib>EO}83F zds&(t3B@6>+d3`P(JK5+QR~xwGjc=SbyyC`GYm8|ozGa4cW}77FxRllbp5E;P+pXm z6b5n0h5vSJ7+GRhqk|4z@5Nt|eTYs~Iwj$1rpuHdvIG}WZl)2K$l;xN5ijps=8zbR_w8Y9-gnkip!_!HRuGuCZlbdUZy+5 z{N}&NkYj5#qL|GvUB|tXdoko$SK0nY1)*vz?O98G);mxK>&t8&K&T?whw_e&22UNcCdFZSz;V?yr1Ygs{7iRIzcr zL()KJw2hjXbknAIwdDSagLN&DeuM0DqCO#g`rJbEXX$sXZ)hl3m+LvdEsZHTG;fR5 z(#R_+TJP{X$h$1na=*MgPhlZ^a|Oxdv2cg9W|76dPd_HC|L+Og3;r1r|38H7;}cR7 zc&WSVQxgYL_fDs>@M#>oG;T;*N9T5C{E6fFj z{@|mZy!<25Kg*y5#(IEY|9^Na06^)pFv{M6*`wj>a1Ss?{%s2K(KBGg2Z#>M=KKK| zC2&Ik%aF4n|G)EC@O7sAD}d)G29Nabz8Cy;I{bAy{M(-n3tCwSgF*%qWe_8z2o;P- z9E?j)T)U34bb0KAdI(al6^SB+=We|=jGop|Cs?nCkgVmrfV$)Ua3S5}#-(QHMFg##(hNwm!L!mrOqO*;&C>wEE1jeSXII)Td;qt9;KzFzGrLjwH+cP3Mv>iz%Px2SZo) z3!}tNhPm#lOYA0fDjPKr7Me-4rNfF^D2d=G*3$c zAx{+x(&>t@OIJ1=mR*5$l_z1*a)niLs*NLNjh>dqt0Q2Urw7zl=eGOP`yze|d}5Xm zLskriAU6^Q)gAeifCPS2i1>+F53OcCg98aL9n^?mw)%_uBEo{6&Wn=LE!7-x+l-VT zGK+>e`CXKPsrle$gYhJ=99IG(u-+-^ zk&JBpz}GS^l;;;An~ltjQ?)`CfaQ_R=rT%5?Xhz7eBpC_d5}*AD*Vu~A%ixphIAR_ z=BPDvyi72bY&Wn~!J80iIMtBq=CWN`>3j&*PS1bq(lN~9QLsvwcTJYJK9V!Lu0yZU z+#Uf9WIp!vIi9Rc8$lSYHPP)im^Cs9vs$^9g)o4F}!Y1X(cMxkN%Po)c|s&NPs z1?Iv`nwMC9%CaB{&&5I&`X>}qm5Jet!Ur-wD&iC*6bx`bosWJk8(2?8>N8m`-umZN zHOHbC^o3@0-BDCYplWDj)LJE$%b0dj$Yd&{{(7*|1niaJR!MT>QjGj!v2d+31M&F(c)U)pvB;dAMAj=WP zLSe!Z$-@FYJ0e4aT{m&5W3u~DNW|h@cB{_OGdJxdLf7^&SPzAbMxIm6ZA!Fo)JM; zi{S_0p*S_8P@RomkVq+WcRx=E+SVXRHmoFEUN=LkRw)0_EFQ&onM+BF} z8*(~>^);3}$mi?zVuhL7MLnsbb(5Ye>oe8zedRlIZ1tU|!-8&cxJC};SM>Cn^Os@O z@Wercj72)Ms0Z~h9uD=JqNI32b{aw%<}jKiWJMV6omI(~fpwN&eo4fQDlO{rnYvOC zIC96B`+lCIr*rXg&SRBroLWz|)A*oPweoTPRnKAYhy1Z!i_eM1Bc@U`+!~dxSe=pN zZ${m&etq{K>)_a!?|V-z))QkZmn&xEOE;aGUhPYJ(8DEd_f8nP|60@L-g=+KB`Wea zvuRU7SPv6j&eoru5w4^_9PW%q_XI&NNVcJaU+n<`o;g zu9DMkSNAy#Lxjn=@>()(%sg}W{iAr_mB|wUUtX^K|3y!?@BgaP;dnwuB`@PteMZ$l z#@Xo%0Y0nA-HwhtKMGIILzjvk-3cu2ug1A+g`f@ zFbrXN{|OamCu6=Hr!%P)fbd41sTF%iF{~ZrL5dwW)lUq&s|5NkNmkoHKj^7Nv6EQa z8z<^**IEh!C&^$55Vi~nq}SF@{dGypz*7>zO&pCWhd}d5{1$99%p5k9jAhx{z(N@C z>-1XETO*lT5d8YG5PsT7rmL$EnS4GACUXe*j=j-Y!d=hr)>AHC3&_<$%LE9tWH420 z0-@au0Rt_|5QMqD?jO5iiQ9A-()_|qA;8hvqH4?oQzeqvcUU;S!Jsx*65C~@XRs2g zMEfe0Gt~{OrgyAxoAHLPsEkc{Hmci7QJKF|k4?lmK8jOGJFQEexxibI+7v;Md3Y+wbBSyA1#Fgp!s@lF1N#6b_!0pG-^fpbW>jQq z8MyWgjiObyW6;Gcu*&LUxJH$ta`6)$8u=o_Cb|k<%y2}kI|_T_t4VfB5`G=raGPEoCprs7VBzulEhI2g%@Dmq7511YS~lP%C@6; zC95TD6O6TdFpopCeU`k{rX@}5a&v&|urw)WQ9n+`6zt!jUQ3j)aM)3v!f`Y@afmP%zbLMK6Zav$Y+dl6-MfEzn<*{BHY!AL&# z=r&T9wbn>-vD#F*PAT=_fU*r6BrBwxw98D=%mqQ$M@OKw&X29N%?r&2PB$1IgvrI; zEp20?NtG<~1?+p*&K6xrYvV$lDX?ZlFWO+h+}QLq`Lx5OrcuZxa_ zXr8t#7;12rP6Zw#6|JbOq0mJ6q;L9K@2xm23#?Qp zgb@-bHC#SOF$c~4cy^#P_K=&!qB?`4j1-HORO!T`xBPcMA1T0dXY zY~C5|IMyQRX5aXVT#!N|D1}I&!ZS9D5cbBM;icAv#~DK8QV{!#OH2R!x_AS@06FTz zNVDeWihA7%QTB^lYNxNes@(m8+`bW$-kAHI^+G#cdvjH4BPgQdO7|O2A@;uDc=E|D zA(D+diOKaLUsnjw4N$~IirZFWLNgsD6UEYUP|n)Gtp*M$v$%N3!M%4`oR zwg;-erB^!+qgq}rU+#8ian_q9pc}8kFTyZdue#{5ghx+$R^Kz9Xztw*m zTMa9vEs&m7p-&rEF}lP3NB5qaEi>B^bzPWTtFT4Qho;>N$79#8EIs@fc-cUW%NkcU znpC8$+8=rb9R!4;#F{pJNiI<7)PXUpBAC`CXJy@(4`cg1YVVgqpo>XUua_OS+VT03 zGSaSOUg}|);xFUVXZXCfy~Nsm$ypNdnl>TY1IDH5h5O(+t%Ra4Z%col84bAl>Fy2b z)aBp5NcLTwc^>flr~AK4r*B-9ez@_w^fQn^#&BEf@ z|J#M&5C2}bMdLu`mFY|&KC8tpOB9mTo{-ha%eq#d)iaQFeL72w&%SAw-B08G2u890 zxIj`L&XS1i9zhoUKoUKIe&24LD?ZHaV10ko0GiFSl?NaRMWFxP^W*Q}NWbl4{g-`* z**A{wSI2Do`3IErYa|NblFrhK*av5UML;m>KlY)4#}42W`GGC^KK(kou=O*u2v`sJ z53thNLd1`Q1eg@~@xTF`B0om9e$Gby3^D>%VgFty;%`ucp(&rZEM+c@>|)j1); zY)l|h-8fd=X?%LDrpM;h*m<#s*?4V#@W$~A1JS3)>mJ0v8oxM{V)nZJY0<{l4Wq|T zzrHk9_v-a!NxRvb#>qPy-!x4>JN@R$%+xEO;w?i2z(H!Ul4hhym81n@J0@wxdJ-o@ z%E03euz@gpfbARu#=wB-+D^mb*tcD#Cx8PCfUpA7wLmVc#~Ro`=(T%Z1&o1x0CHgz z8S_c8o7$$yKAOpy$(z2m-H|nfG_Xc8^^&*o)&+_n95$A0BMKyXnKjgy&~INFODB82|8?WwMNoH1C%rVcnJWL<$RQ2`+H9 z)iVm(B?K%(;H^8`@QfLv=Z2Pda~^=(hE;!jQF(Z8o19wO^}7)Bki1W0wd*#!%gWYo zE`~alE&2TB!r?yG(Mzpu6opvOxy13&r}9a;!jT%VdWApI#@7qN6}YNdRL@f} z9e(kW4=Jvsq@DntTh65w!V@IhHzC2kE<>W;^;Axj<27)=PJ~%Y6m;VL1I3YqLRG`Q z9P)bomx#`e@(|Fk2TmtxY{WrGTdzZsmA$9^@3xgzf_5xPGo*(|+z!$wwm-aO7=R}= z^{&;+u=4`p7J8;UPhV={G!UV9nR-jhf;K`Qd8cX8z4sT6X!X0;al0a*wiE( zl>%SEf~s?c`;DYjij~#fOFQbGBASjOAJjal-tW)n{e6Fazwh_+xn1A<=XUd#+t}`} z=i~l(kXYJV?kF`!R$~zbJQR-$CFPBXWZrDZzP6!Y<1|m}s7J7Ouy&J!OmQl{25bxD z>zyn$Xn8nFl>0r#4=MPJCHV+F5!fMIAC99(lC{fQiDAFONn9ynPY5_N;$_gq7n>-y zomPX-dSE)7CQ%BUZDj9>)2a+Z&YzC*a9)MjAYh_=r{6QlXM}*G$jDtaJ2BQyq0Cz6 zLo^n3u#$&^6)<Xj1Jwt$y|Lr1_}iJs z?dpX!IFH?f`6;*abI5h1g$m4oW{#(#wQS3sy_&>1xIHOhuv1#7sjlZldG1UN*{u5} z)lA6UU@3GDdO^lCNY6zU(;Po0TJZC^Xxvx^1?xUn>+HM2DV3LY5%)52$@25*H&^{W_zxoL@* zMJ?ufBjDvh=zIA&BrMgw!CxDbqqP7AHY6)^r_Nqa8%;NNXs*w5GBj~XVtPyem znK{++zEk+4qgx4!{0!xg?jYh2W`kP0B;+4p#N>BT{ zuPMhb-Yq6P#g5M`qfms(;Y&>E%~?DoXK?-W)^4pZP9r5$5D3Y^DVHjq)g6UE( zxPC7Ym9;H!{*-r*Wj!S9g3?Z{ggg(%UExkBOQv~%7G}sQ4bta~BxP8=TJa9xLeyJT(I3Eam)0hjgNxt!jDRh21vnk zuHUsJZQbJc*#=x;+##LW=Bc4D_mY?r1fPyBD~D# zJ_0US^~hoH@yXTeyO%wYFGZO~96fh6q&+XF&MTxZ=lIm)+wZRqr#_th((k(L#cN&M zBSMFLkrnV_)WcC8=Onk!S`sGf3zCE?G_7ZH$N7hkP1=)|48CNwGcR63`bjp6Dg8MIoD zqw{~ZqT_4kr;WvZWU<%QGhil z#CsI##ugG+7m_Lp4UZKX-zqfyqmXP+MDZx1#uizuE}~ZySsyF1y;WrYM-jt7r`XA( z*d?~uZFRAGMJ^cpv8y)qFEGsh42Iv%Q+z7EQURh2uubt93@2Kz)Pc9pY)Fm#N|XWW zuUr%V5@kN$q9$kJfYs#KAOFFB&z_vB_-MheC{_dDkl%q4tjS2*%iq=G%76{? zSCZ{t8!-Pa%X~jgeLqe8?N3uSJDCWRl6s}4RUOku!+?&h_tmWwLh-Z5>k%g8`H0Z5 z?kpWE4yX%eHKxeA94b&XyIToa=_F=e&q|s`9;ltB9P%S1O4 zQ&D$Mz#-L}9T`1K#3wtqceJE=#B+t2BqIoN^$Srke5t;r`>m_dWTemALWHh_Fk@%hjrR%I7IW zdRAaq@oG@P0fnf`pDEMGRPpp{6DaoMWT|(8t>&hhb|fbo8rWDZAU*VfnDm2;IU;mK zpb|x@4`u=Rc=}0_{v2UT{K0Y(q`0O#)ZV8{?-#AzKCJ0EVgyN0UEYu-LOiN#H*?6AO3IW~L;{3Hm9tAW znxRZUEPXBlrghy3@6*{gWxBN{ygU_A+6U50am#X$*P+ZhRkS3Ylk?T2<1Do`*oFa(urse!{gGg4ww1(cixrgyEz-*$Ah)b^yqo-g~ zEU+6KJM32yHg@#Q2L|YL#!8arW`f}^i%^#mx)1NT$WC@}1G=xsn%-!rjwfSQaLY}8 z{l=%Xn_C*1m-s+~xJLNs`oNGr*ZG-x2NxgB^)O*SMY#;^r*`K$wgva%4HWY%kP4x` za5Om{t3<#IW&09r7d$v34Ry|ryqXWHvv{ZU4<}~RNvrTcFVi}QWeJ4|Vvu3-qpssB z(YQ8sb5ej1MB~4`44y|hNQ@hz88Rffb8ImVssuzv+Wn~PnfR8Dm;k$Y8SnzED5}`hZ|M(9&%dYxit2XZ7Ui9md-P zE<0OU580{7Y&0wf2e$S|;GF6$`P-amau4NZH$FW47l;;h9rERN9x6ge(;n@Nng@xz zSX>}DOYiFWaL^3n+q1+BnI@8~7G5eMvo?Y4P^_f9f)XK9`@KijpZ1i-GA`q680WWu zCdc_{b!_OG9;r=QKhh}eRkdAfKtl+I!&ng0CaH$GrD&J$(ljG<*KH!P(zZj!; zsN8SAX&jz*ibPnt5zU{6$-SHpTV^r&1N$95DlY2{Wqcw0NVy3a^CV_p3V=`>sw)s}PkS>w+UCcxJ7{lQinGJUxKj5pj#*$J-gxgn9R+yen zTzcqIRLPERw2RR3fa^Jr*kTjBXn$<~-R(#a5(K6uFMlY0x00h6zqnwIeCut3XzG+? z(b9~k(<~1XUl%VvuxK9PPT%>JZg#z?i!)}wr&bb=T-uSEvPIwTir4eiyRuH}dYON? zB3`*BO3}S>-)5^zbIxcM-VT?uui2ArsJ>k`;FHe)Bc%OXykHNQ3XD4+6 z4!Ar`5=edP#}cl?Z6EEL&p9{%KfW2TzSaM(Z$O=cn>;>EN;Q*}ypuUNHH3WPkcpd< znnON~XNyC%Lt zKk_}-R|5{%H85AYD0{-LF$}(5Uw`fcgDlaVuxn;^DnJ*;qI%j4)OL-*^eEvgFCy$k z_T|7g@BOhv%u{WsXH((m_31~e+AfCe*{ReIYKws5z0?)E=6ULN-4P*Mk6`{GOEY%s zLm@UWvQUDIaaJmj9$ZlqR=eF!8<{W~-=Rf_acb3?H98DOihnkjTz8sg2C<~j9n+1R z*q1hHJ5PH7rcZHqJgmKazJ!T&S{ebdqPdu+W05ssS`gpPx;DseThN+r|LaTEx-i?{ zcl@$92XuD0&9~UMJF>1W7#7)H>HF$pC-yM**h7;i_U~&#;7`p=s$@B@pyI>q&T!{ZBq>M_h7_P@VFS9NH-wW%toVZ zHwh9uw?bFFI9X(-qfcQNJa%i@pjmzh==eJ}AjHJ8U=8Vb(VeW7(t3=PD-{m+zvYlBa}6HkIoSjt9z&O6m|rf~>(ne>OLUS*UkMjIehUHP6DJ zs-pbB{z;D3Q4p9zp90zvgG6-8*HfVo7^8pchHb5&2DYC@aJB@*=7VWzO47;ttSR+8 z$Vpu(T+VZHXd!Pc9+G!>7Ia5)iv;Fr7E~v))FoyZ9Y7MnG|eQ)vSH+|rgo%vY*=I; zpd=y9&50wBRb_Qr%rq7(bAiabd|1mohC(B$f^)AN+Obnu(V=Z1gS=NsiEAbL1qz5( z3#gn3ReHI;2+R!y@2qK2+0Y_{rlhE(r6ivahe1dfStLjh{zkW6qhZQ{z~f(47<00v zr72#1(6-tugGlSr3uTQ6gv?YNA|QMMb}7;BmDgf>TA4Su%6mmNZtE zJ0m(g^UC^Co-k;K@M=X@m8N~Cr9~jO(fZ~Jf*Ji5l932DWV0|qi`sAk9#|B{-$6yU zCVCXcWF(2f#PU`g)6m%?$4t|;6J!Be=y-8SG-1_|J|pJ{uzpnH-oUkOg!lsR1y6B( z)H=J^i|1vaWb&%0X%a$;>Uv;jsUSno-l8_easLuN*oJI(^(^mtkg!z1FSQR1xj8qK zt=i+05vOSZo>jDhb8>UwW6somv0Ztcrhg`M$^7hW%V5YUeTjnwF~%`Ji2~^$RHI$$ zA>-7HszZ8<+H~%tW!p4oD$2$zJ0M$RkUX9iNAEU-3XCEP$2KrV_EAWT8JM_%N@AR? zg>@RN`aTQeOqas^(_nwxH`DUxE~duBIdYGe<1bKe{cbM;>5sMWxoKu*SO!@CJrA8g zk`RLBe7~H-{6}6dsTjr0X?-v8Iz4F}_nFWK_A0PZCd-@_(Vc4&*EENI+t*5{&b+m24lh|@*s@p|+#zVD*LWU+5_Dr;kyXKgG} zxA+cRAZ{?Vsa-IAM;xUU|9+KK$vLl`vms#rp1E&Snwk%~Y%{}-vcUxjPQ57MS{f_18>qCO%MOG-T{Jni-F)O$UnX(SI!pQPxd&!mOxdXaftHI% zy!LKbi`jGZv2WF3rxV^uOv3PRK)=(p`}YN|As?Qx3Ztog-U}B7#@4RikqdFh@X@`3 zvuzV2z0B4?(3J2*Z%oVrE_NNT=@9^^#t7T-xV|dAp!T-5?}UT*zq64-oC+( zuf2Zt03U!IlScoiCNO|J9s)CbU(klyx^bWX7jsMi$6rlg;Vb_m&H(1Pfj%&G_-$$a zN8bjh{LTC{%Dr~;KO)Fy!T+D|$HWrIR|ql@f%}gf|4$%t?=6sg>r<&I zVsFlREQIm85wL~<8=EOGRFGlB`MQ)p9+hkmWnme~T*W|E5J*B;&b5C#RDGczhRIF8 zKO1Tn!+QIqJ`za0Y1QU$hO^pn@1C7Fhm*paFRuXO){QKA|7;z08Ea&Tt4d;eF5t`w zQ}64S*3GeCFIhJwjsb4RSmgn0FXlB2D3+6k`#`dYUwRYjM>^!EV-|Cn3#E+8vtIal zsZPh3VB4NGbD^3sQiyAx@>zS2=+7T_!Fwcgb$t|tfK|V8O|l4jY(UcICxVjunY#R6 zC0Yr)Ku9uVSiyi4B|SLd z=mo``WHLp#{=ybmVnzh13l&8cPfHL;tIfZ z&PB?=Su=$_5n*VvLWOQ%uM`O*o4?x`Z=AFRua%dtLA0`DX_CbZq_alwE~JkC9&q(` zDq<(}S9VkZR6mUg3ASTm?pk>|*GHIBkb7r^`kd?f-E1EkD0b+>YD`b7Lb){Hi} zhoLTqTn}Ele3ejS`$JrzLEe(;&KrRU|IHAYE(k67afz7}3qgSjkLw1t4mlOf-IPkD5>EwDz-SO6aMg(`R=|NVOn|&hTc+LcMz$;};4+ z8^ZPz7BYd-IjD7x*~zO9+lbXnXml`DS+bRp<@z$={O?YCb+If=nOvjSd$Uex@(%Xf z5Rc6V$0&F7Oqi}SL1-xxiG017Xi=STrQyvvl1#XKS|fGKiJ;G~0Udjq z0}r-7?p^Y7#R8saoSkRmIl5*wrMlF3p$7$m4SA+rzDR65%<*u^QEk?)TKvoXJY0Kl zScB1C@Q&ZHVt5P_=E_tW2#qw%m`n%eHzPsqdzoeMX_j4IiKLIeK*4Fk{|5Ik83^HhnAF@Lo0l&}ui@T0C|;mx%a;2%4% zizJyYlt{g~vo=r1LEWR5yI;(KZDAg_E`Mvz+GcFhG8g9*{_HNXpSgPq8rs5#?XFIT zoUmHH=zQWR1)bJffo_0frLdan$k(T7c(96co8mFn{AjoE-o}h(?7G@9rGYs7{BO>u zF8!FQH9q_!PIP|BLjue4m+Px>w(hUB!x#+#hStZ{RL9@MJ4iQ~*}~i^!CJ9BF9PPg z4=Z|LY<7;b0DSjk46c@W!K`YvShASEGbEVA3`|75@wZkjG#1SDXUiJ9bL%6Z7 zLmCub2J{NZOg`iNL(co7xLfI7cOOnynR`E)?>*$a^hBFC3W>kuyJkRd`YP^peLB9a zSYU*l)@7bPg@kV@PB(WCJCiP^w|bf!6*u}$vu{}o{7bS<_S!A+bfpsvu}~i#Ts%8& zbFs(tS^}Ig5rLb(CgA_W_W1YM+kX^$BYhcrEA~8A>~*Wyd-Y%Ww|`O10EkilDIreA z;XZQWXF@cO{Avo)ZqApq2yo(8Ymk$)$VvZZ4n{o$GigPAX2Ug`)tiu?Yu`R~zJ0W! zCeKrojnR`z)MPco*B2^vK<>-))TgaTz>QMRMFKN17jAw8!$~Ck+|Ka%Ff~#5_TlM> zdLr`c!_-Fx{I3Gw_ruip!_?pYFy-tF#L#lc5Tp?Yo5nUhNrvgo8!`jLpz)tsSy+cm zu0jcq7=aLyxqul&+1c8T)=a+}4z&+t0cKF7Z5BWvd7I!fDsitaP22H80(ZNd-ilo| zk~(^68D<%)=b1}=n^8c(saHnRu6Jj6TCr1`jALxCKruGuTnNgd4&7ki{G>N5UZAnUWRg{$A?Th?$T3Iw zS@2v7r{1h;Fp|Nv2xBz5gY4EH8Efs7V{=j6AdRV=pmBSaXYL1(tSMP|iA_8nUaLSa zC}=a>$B=M@Ji&raGI4I<^g_oM1R__AY9os|QOo%KaSv^(ds@S(a=2GzpMkIdh0Wz? zu36UsgIGD*3L#)-%+}5|48IWDFad!huud3fG&(6?jF zJ+m8n!3%Eb7cCBEg1|?p?eH>2G9<}5FXq~H!5&L_y^l+JC!F| ztYJ89cUvZ4H`*t(&3$pDy5Hoymyp_D+;A@lu8 zc+-}g@yeO0d)}U6`xxDlVOltXW%8vE(*hAe1wuvVwB5c*&NkpW;~R=&r4IdFI-5`FmFpLwM+yZ4({H}n{JVvsQM+mb~S$yZ=_tmA-K>)n}Fns@_z4e z=SJ}aoN{Mcu9xFu;C^IXL(+A-fQrn`J1@>}U+LG}6T(zzP@&>VyIVH`!v~bQujI6! z6c=P2BKYqe?Tajl@bK{Jjk)$UB>Gtdjj@IxzwT=~_XE<-!j0fut27))%eEh<_8v@L z=Xi)9S~!(RK2xHq*GgkR`%@^r-Z9P8m4R`|k^E!l&%$ty>lQ6`rfk6%n>i5cvy8R? zSvg|^&Gf=#S;NS^qS~YF?8O^q?Z7@L%2aipW`g56!ZY|bvVz7^6dLppQB(t{zNzfb z&~D`YpE{lf5}COnke{f|$+mO68s4p5hkt}#eRei$`P!q;9~B8*|8$$43y(40#5g2% z^+QaL<{Vn%aTIpk5`p+>GcZAeep_|S*ykBsKKOQf-}90sG6?2J{sDsGn(s34N}ElC zQS;c~YH!CLnSHPB)>VCWxMSsxtwUuk@q;T*y$(SFE#SVD1Ee=Ek1rUfEb-qj)(*x# zW4Qpxn3>-FesEQ|z%FI(yDgewTrpl<&G72!h1)kXx$cWE_fI!8+IMqx1jg=om1XSJ zIWcb|RNdWs10G(Uvq`f|ywG zd|Hfh%k%gDLu%h1{EZJ&V}C{9e){Vc^_OY$pGDxlzD0d2-h2TYz&Yxx?aBW*0{8hS z_0NYVCwSwp0s6`21)z4}OVR+A=z$2_WWn_3`nL)FW-7X*kRW z!41_BxGBj@bp#IErV}oW2$-Udz&Vm4-h(D0a9lXBwl@)hYcvW{s3UMLDkWhe0vF!W z14Q8BRle$i>2xFScpw5t0(Z zLAnQAgnBjpo6%h%tPyR?O&obp-CA z__~v`Is(UVJZx;wzI0LB*;yTdOSXTdy?tIJ2*T{V>xZf-k!N)?$pxOSaO|?TlMy(- zzMs~*9N3CE3q;_s{@qNB&PHv=fQCkET{iBp_NA#0eY$-|?rTEEGq&Dc{kluY^yr$= z&R6JITmXCgan_5Q+4b9H6Y7S-rv~)shjQ8f*aA- z!uob88K>q%@m5m_zV}UA&_kt|)h$?27x!H2+<4VGJ@YF2pB6ZJxEzokqi^qMDp17R z^3b$JrkJJ6L^}&HE32`l7QtL6PvqkDM@Cp(thQ+e3Z{P=0K1SS9o+zba2xm!fr4qExEj0C2Rff@U{WKW z5t36N2nPzL>0BpUsTe+|shr?aAUj*g$<1ZMF~Q^hP_7G8WAWiWU4{qBu*4QoA@IWo zuVjbw6e!w$UmZ#T3SEMkAPs+u^V|}}dZH0j(+!Bg9ccv}`xt=}DiQRWKE0N5l+K(w zXqT5CCfE(KAb0?*x$_q@Ypj%Fnh4oSnjnpLv+A@LX0&5!R8p%^GJJ|$f$-?bqMRmg zFHL6Bt)geF%omIF(gjp&71SA&j)`_xqJ7f9NLvs>QCCj%=|P1=+iD_c@Lt>O3xPQ* zO^f|dlco`=X`UjPw${hSRRk;g(X3`CJywUZ?8;R70WE`FB$K3DGSd>wo+=)->oG}Y zR3l0`Ys}Jeb{v-!72@}n_b|Jn$tb;Y@IJjbLyS8Y3`SnT+t3YY4YyIw<7s$bBsJz8 zSHmMC5$Q%}AwZfad`aGx)EjJMi-%0BhlgQqv*~z5*03BB!VR%|sMmv>@)0Wu651^! z9Sqj0XKIAWCECvWf87zJ{>=WN%zO#G}<)D@fdUkme+ zYp|X|O|CL}Ubpi0J_1W%~7;5nGL0n zfOSWCnxQ#9CWR;&qUU*gSzk@kRF=qGHxo&5W5bZqoq^n&dC-53>fr@JF;lB5dYFVuonmfgRPF4=qZHn)0FD<~lV#GDF|FY?e$g6y zYE!w9gQMh7^l($r({>Z9vU8C$C>wshDAhSQlI>ESh}`=DmU<^IId0t2N4D4&^rKA# z7^hGnE^Bqvy<_^%_pJtUZ>^0BrXj~xigU!3dykly`EFcuf`}fn?8ADkrq*Rl5kGJZ^XeB<-zbuzX4JjU|sa(?O^2 zAY;NxmL$DEoS<1uJxmpHpA@968FZVy=*T?rBx(HGQg&y2`eg2nn`*ELq>)u-pc;Sn zG52-{>7UkYP`hz)&|0I1(+ylZtY2%*zH^eETb6M7Lh8cR#8dPPx1?)39FzA2WLS| z6UH}X)8DB5p9tf#(f{QYD;w*?>BcVmCd;goylkL>R~#B0kn32CmobvXIjzPT5g z58OFA{@>kl_TO7__W#Dfy_ztLG8sywX{wqqmI3jm$nuYbvCJR}h_r+3|+HV+UW8|(2%21;=89;nwBg#*t}<^ z*uW9Z@^bNP=X9Lk$6@+)dwMpfo*4m6Chn6h=^|s|J@Gn#-E(FXhx7B#`ixHI7 zPus7auql4QeBaSCcR8+kWJ*^KFkw@#5JZic+7Z)E6}18rHfaij;3UN38`Y3*V8R9h zOxUmw3A)<+P@L@J+Rp|cL;GV;E5KeGx~djhbZ5P=eGP{X@&Pxe;uSx01KN0_p#BM5 zGuU6F>P0=#n{J>RSOvzh71<>Wldg4KB*^%Rp0=7W^m7U1e)Q}fA2cNmg)Pa`GCs+- zX$fegiK{_|1xh39GPn`XCzoix!*HG%9GlIDFq4fshPZ7Zz*JvkpPDcl?Q#a7vGiDy zX)-_oAlyhPAm^Uy4kZJ^xhoeq_fTzI0-VfOQa})e0?&!g!tj(3+I+F~ ztO#LYEC#(939{8`5bD(w@K^MK4IBa3Xh_UF;R4qPE`tW!3gMI2Dnle>TBh31t1I) zSKT~ntd>QU)MMrWzJEQ>BAM&-bHWjV5xoL!kqEJh%1BuO@^Gl$c(v!gvhR4#+N3!x4<5JUNG=cxiP(oint z+nw#Zn?yN4T?@7(7J$i3#Dy6JN)$4&!@sXokh#L%qA{i6z;Zq$cr2ykep+Nu!S6)_ z9c*wBpy`yz_r9YZ>{4J80;5U=O&gceQsy+gPN6{D$x94{a_P9k&{6(u(y!(@a~z$J zB!bD)wgA^ck#SL-c0?x=9xRkFYRr;iv5(DLm`)W5eR!DPAj`^3LMYDDc8C!&%nL*Y zNETmjr!R4iFvd^d@}omD%rbPpOcMhZ{b~z?GwUVRQnT%@+y?X1xP~Z;3j8%{>}#hN zV2FkR(s}R&GMX#!U)RHr7;mIv$icZ_0s+_8y5cv*AlKzEe~EB+rFm=c2HG>cL9Mu} zOcfihDiVZ}TsBUV$#9u{{3Rn!^speO&=5oXqXT`}HmzdE5?i1`0nV{Wx*6_Uy@`sh zay>J0v!(esVSP=-e#=(>4actFU9k(N+$Y1e#$hdl%(`;ZRUdL}%knmq=77+RyetQD z;)$vug~5XER6lCN#@9{l5K2MlOzKvC)bL8`y3XGD5BbMfD|a2A;@Fm}w_M--djCn9 zNOa*KL*K5h5B~o1Ah2HWLoLYOqJXtwaeaT0JFg3$j7Dt9D6!C7X^u0BZ-o;b4>FFk0tf*j$3lm z7Mf^o8!n;?TkjyBs<|ULYpsRFRAWAwg0uHb3S%jM;ZrTn#cp3>? z%NubH9{aymGd=!yB#eJiGyS>btWOI0Ec~zhXV;F8y<-1X zs0t{b{sbaw=l_d>v44UipSAzVP!&KSpL10c{P7rA)clmI`h4e5OE&*-~nW(8zz_nvS_>UW1mxa-bnF+krj-FIsJFWrO zj;Sn&C6(@Y*wBuBNlV*#s`}dD;^+(r|LGvC(<0#0qJ@j8GghM}>>`-mnJ0nlrhgLt zXS8<%!hb%IXMpy z{t0T~-v|)?3n9fpfbh@#Ec_?XWA$rhZ%_;W@qY>b)JfqV{Ym)WJt6#eObGvIweUX! z5dLi^g?|gW!G!QXEEj}=vVRL~mQb#W!CvOKhJJb>D%!}Bgk@yC4lHZu*zk;^yfNdrucx#fyw~8=xjVpNB{vR4%h{h^7LT>t#fa; zssM(gzQQkS>JwP)mmQxoynagoNZVzavz1&SF9Owd><*m6DJT^r-DrpMN8mNB{hIbd zMcl(VcK}OC5Oq-si59~5ElWfYcqz2g!A@t0`gj;J#X_4aUO)4IHeV$|cpIVi6mgFC z9$-g5AxCo7@wPfngD%R-fnf{Y;DX4vh*vkDPTe%yw7Ery4Sw52Edgnq+8ArJr9N`J z^nBr&&Ez4k#5*~tA)%rp5AukLh1zvuFuhx0&_RvFkd|xwY`taZ!9@)=HOx$G3|Nm* zhoEyQjYRVwWLC>Ui?TBD`ePKJrR*|`E{BDZ8AhpIGQ*O()@k`{aDK3(P1FDcXInu^ zDmdd~tb(%WdkvGAsD(~$=S$rIwcnEeM?--I!LJ=2y=bO&4IY1tT7mE3$OyA-i%LL{ zsdsqN7uI};U9woeWkiCJzrj^gEAsy^mOX54!2`w2W;Z|xnpAZTUyp2HXhBv=px)G`JH|c zFHe1+-7$nx6O?ILH|+B1tklpo3sR<0vWZ*G9CTHQMZfgiDP$ye%`D%b7hRV%R3<%P z)BJeOb;GO|WiVLC*(~=vK9DB|B>F|$p8M+73pARtAfY!E;sA(H&)laujwQTX$`NXB zX20jGyb=@G!jDT^bk;1wJ3rh@Z_1u>!@E;o#-GbW%Ac9E+q`~Kwv(`CHxd4O-GcNG z;o8pMEwWyg_r9tyWUaclwvN8e@~}$p9v(L4(G_nA+9grKesME+x;^2>>h!|CO8ULu zS`Ny(E^<&)n$}S3!o8q?UZj%)O4RiI z>3gqOj@Ug%8k3Wqne%_DaJl8LP}Qn`h8h1^s0zdSYgzMO-8=qCsLC}_efap&;P|9( z082OOP}Ss_W0EmGiyOeAO=ihcK;Kwh_N~$XY0gH?8xvO#b+ihYv-#TH07&E8T-9g5 zn7naJ(#6DGxirUbIwyEU#pwv?`+Ckj@ zvsdP-^$l%o;;62B37~Ia%7qeLe?mW?ZwTcbm!jI$`bImm1csjoKcJN;qi?=o_jL zCtbC^q3iGv&^PQ(a=y?vFo3>c4Cos$)=NV`-^lxxVR@hEOAy9%j2PXGgpAQm_r=l4n%LZ7)M`NAxKDPnj)#C}#~5`Sl#3$( zeIuMhwT=h$4N`nHG=fxNv_?3C+s+f%11FCXMx%K&9}-$1=(w$stC?qu+Bd0hSPA&> zCB_vxP98ZBjvSg%(yq&PLzoR-)iojA(sHT-TNdPL{%8z?0;N?nc9o`=Nz8Gm=J^z zk`Z%|79Hn75(76exUr<~J;+lN9@bsBC5MSw7uevY06{H=M7n{VPGoF4ZgV9`*F9MC zKqzMOR#2-`Ks4M;+P{slNP@R0gcU9n?cPbcrS0Adno^!7_p*_A(Hh1jg=Vh01kx?E zy9h)8%}gPrLrAn2;=)s-`!@F|I-`3~7^J9h<^>3@kuKBAORY+NDkc5gDbrGr(Glqq z{WWrkCY69^xAPOGIf@Gp5C{Z1SgTrbwY*fM=?wzUu~He<|OD7;M~X5WW|N&+eI4iBkWmz%?+;- zl)Le53#nU1q6!bNc0`jabdxJ&)iZ}{U!Rf&&=51n1G!9jb%|JqBLtHaM`|4DGz)$} zLxn{j9@`9MnKyt)O{@3|dVDZU1?ctuhc;eV^?n{S2_nXS8_y{txr zaIpm$)(|_KbC%BdbM^dSHsEX&!!$CvS#)Y5+%V@k(%sgnA!z_%?!2JbGEry~ma17A z!_=U2ANXOn~E;diKYOESqjrZ7IZt05yPl?au zM_~8R!mJvjOy}SUwW$(T735d#QO$=N*&NzU1Z$olZf#AB+cXyVZiFqytA(9vncW!~ z0@NH0upvgFxGar20 zSW`151K-~4t8>s!W|}_?yL-uRnPn1tc?cw%pf)*FzsY{0zNkAiLWjubw z{FeWG9A9?t`J-a;j`Mz}bIZ;YDj4fw2mjE29BHe1xTD_G4q`GiLV*u^Z;} zo+i2x%H^pGLgM`A-)z1hQ7-)O;o$X4T-R$G_{nExO}|<)_;w~>ax|{5xEvq*Zf3ph zjbob)F0T1`bW?vqiiNMiiyy8q$V}U$IV~|~lTW{o<&dFjlcRRthiCtdy<$)PA31qs zN=T51>@ogoFZ2DMA3lr&U;leeVE}bN#S&>&_WB%I?uNXL z`I`y~i;7E1%Qlx+Y}s15ZTk*+RrSuAUAy)Q#K}{q z&nQ}zZS5Ur&vka4ztDa0(&e5jSFc^aakIDY*6llY@7;f(>K}Oc=$FA?hkkqfWccZ` z=OZs(z8d}g^_#Ij-oASejC+Ehn*WV!lHY??MV!Asbr4z+Q*y{k4I{RiIuvBK?!1rG zfdgu*GI)SA9t46C7EVydo>mxUQW|GYPzPp08V`rF!v1 zvU`?lUC(;uztStdL@2mjGipFz&uQV3S{L?ccQnv(8HxkI`{EpngW(!aZf98 zdX;-&=*XtM!q(1I9!k%vkk7}0ty0GsP6o^(z0HIQtknzg*pG!-Ie|<>yj+YTsY(mW z6`f@xL9<9?f$ml%AUy{bR*4WBQb8KY+${UNR!#RzA&AO?&%5cQXF@X2DT|fC`grRp z#SmnjdyeKw6{@ePjmRrF>p#L1m}CxG2^dZU?qR%fjCn^N2zJ611oP`L?6}K?MR_Y> z+oJYZJ)YX&X6uC4$`pCq3?7Fi^AP-c^R8NXfb@L0d>2>Mj;xTObXnDuI59G&UYeFa zjQ%B+?LZ>}#|?hf%0Q)sH;+Y*?k{jOYSXd=P-8{wuAL+UtlJf#LHTHMDno2+29_3r zU3GD!TNwAkaS<&rl+W)0Ys|cz11R%_;Wye5{>_lk)I6|lpU?H45g5++I?jf43!!|B zvVB=kpyZfbtzklco;k3dTVs=OXRi$AqJq)x#Tp$4!LUp+0i;)90Y8DlVTlACtVrj2 zZWFCi4m2UL1y*jc=aZBNb)QtxY?)9i<5EF1{eT51q=CMLNSLo@fVRCN#C!D@d0h~r zTY_aRxv2+_cCe%T+-?Lhgiudx+oJi+QcRk1e?G_F0z-}pE>R(``Q66cx0dbB&0Bf< z0F3j4r_2nrO0c9;te0Su{rZRMJ$fMy7B1F~`TkpunNp=lyrxx+2du8 z-{4`TG|m`Pz!fhuuYeLu<}W(0&GL&n4Mv|Nx+sVjw-Od|(C&u{Fan#v`% zc~$6WIaq`E2gvZ`Y<~2JjdMuSFTv6xe)d*2JZc1j4m^e>g7$n!NNXu{th!jjbnKve ztlDX7A`JI3^`vlIRG6u7{6{ObdA7o46!Sn{gGfEaAF7Y@G{9Gp6 zLfpT*{KT(XGL7vn*N*0ZI8Q+c+^ct3m~jPoaUrwFaYR)(_Mkma{&e=;d;wTGRtEKI z_@j%WBs>wfy8eWGS;#@^&4YK+&UzO`4%~Qu!r7Wcej$5t>z9%~xpLav+}~#D{91;b z+M!5$?qjn_FobwZ#ivQ{E_=RBK4j7@+>;SPVh-spx(AX!lM%}AWIG-5q++nz(i1%Y3yniOE zGugN(0lKxXGs&&VHFH7gd@p+C*=PILBxudLc9Nb=Ot{=;yD)|L!7^=S(zW951^1&* z(PI!Py>AMW8W;G%yl<}AS%LZC*k(Ts0U1WeoaF0EfIlwNb+IJggfw3M;JY;bfB3io zv>AUPjekoT5cm5KkN@nx@z133kG%0cN%iKBFZLVX|M~vw3CDlcN&Nl3@%_H>wNom}pP938Y_0KpGDPc2mF* zI@#SZ{nKvBGKiI>!0h90ieG2t$K8~G$=#H@K#ZzH<@dkXJM*Zd_r2dU3y6wjx^;vXnfeKqY;3{nE*8Y(Q6zUxBLQ)v%W&()l){H zapR5}6*Nx!9UAXndBWAR<2tF%=nCNSSOK91`8gO9zmnqW*uoTy!MagAoPx*_=o;+M zjRQO8bE!CF14u&#f*WSiGApnq9Tn8}h#O6Ek~CU71FFsu!|Xnu}n8piv_F zJw|ww`)&w=velEq>v9$zH9<|Fa!k!fdLb6;n$&4sAW9^?+c63FX0a|Q=M$yc|+5PWL4(2BbZ=vf)iBLqI- zDQI04KVHNS;`gGA4rdv3VuK0}gHa}x@#K73jco-`qq^Z~j%7hkg`U%-T>_a88C^=AhG(@hu(=^H6K0JT34j!Ay^MwcHY zBwJCiSO~eYo}Iw3>9`4kuVnM~=-%V4w&#WlpGa`K*4nixfKRYlR}z+Do7E>TpEDxt zUVf?wTS@tRCfAVfnHVK*YW5P(-1?9MDM|u;CZz~6qEl)moaVK+nAtjywZK+M^0v<2 z-~iVv?A>I0iX33VgT2})D_ZbD%oc<~u{kzIPEKJue0&;-Lp-)^J4i!KkacM;!8RLc zfVmSGN7-@AH1ck@dlnI*8s4ZBCWT{E6}eWL+C1_#sfEGUez@;?>870yU}>j^@G# zpSt|iQ4u!3=h zli6vGb0Nq>wy64I)^+l|(rYfBt}P}Z%S9_n&pg^LIQr|zIfS{w(d2C+)ZrZ_b=|wx zEBSA8Y&gLw364$IF4osexAZR&sKGBkU3YnBbnrmQDS9{T=KGSvVB~Vm&lc%#A6z_* zNxB{W*)pbm@zo2}?KOLhF@;?pD$0Tu9NpvtHhh?6g)9Zyr9JII#_RfKa-axrY4eXu zYM9ScQ4^_$(u9{hCDnR!K0jd;}o3d8jg)o&WWk+>3&V{d1rG%!o z5SEXsQcl~qX^g5;rX-E3QV#lP0IHO$2!Dl2mD0j(Mbuwt1LHGQs+3G>lS-9B;~S|| zDMr33RSFeQr5Ljq@qA6kDw!90Ql~6SJB%YaJ-ASjdLl~8HGZ9*cLi&jw?-wEuGcx}yI;n{sajJ@+9nLuBIGakbqP0Ae zlIWF~zLj$s+XBqx*;h5n1i^coo|Vd5ib%AdD{hc<3%npGVF=3Jo`Yj7R8!m7ZK*}< zeca_*FlFOGjArKiP=)0&iyr=_!WBH@^$_UAC1rU|Q8XRDM<+c;D!_|~MiVL`3s9Aw z`M<5G2-)s>%Z! zH$OXMdjiCf%EM)((uAC_^l0LvKy#`)l?ekIjJSGYVmMrqH6P+Rz%#rr&aufE4JdRTgl)Dwoe2-45wrl;n5`V9NIx#kY- zu|PFF=3_Ym%XrO-A;?o?4M)c&Ej@1F0i91hhGo4WyAijck6CM*Df?E=M?&B*9tW2> zD?O9R3ot2% zvHFXr=6CD&nd0P4^LP2>7|=*&zSvmfgJ)tkb7=Pv`V(WzN#ddDZTytrD`f83B z$|+icnDwHGdLFsX$0BY66NKuz8Eaf6hqU|hPn8cX6WhOvJ(KNXhC?<}b{5aJn2~To zeVc%p=3$FaA_NRyK)Jocy6BPo%*4(S%yo4+#Cj2hjjdHL+**R zFCZXwI#D2X%(SD5eKM54@vYUD0wu(-rRw~X3^wIRkC4EDg)^7zEb9V;Q$eT-jbsU> z{F-CpbyF>)>ZL9x&Kar0WQ(@P7&7%Gx-(xO4js%DS*`LB%2~%43&38K)GRxeD|Ur! zC%wno{Rm>MDIzzWlp7!+Ce2NoXL-<*M1}h9k5?mW%MxdGl!d` zO=^o2>Rz`V+bGxW+PRf?+=>m&4NHIqGoMdbM_a_Vk--9nA%^F>_*#miCT2QDay46t z^-RrfZBK>TNR2GVP1&TrW&s22tl$xWBA4E>+!V_C^>5P}O&$=og_wkKVAf4Y$0S$( z+x|ywZmu)EUSa4`;O3rc{MqD!;WnqAyn?%Cyk*vM$fS7J$R}0 z^akUq9(~B!j*ff_b-B}n)T0@>shkUq?E-6y(`SwaCcG@Tu{t<6t89_;tk2)}JzeZZk zf9ky{()pP7Tb%!zi8p@AhiCqr7IOM0y6d9VTZ{R^aKcHS>mhDV$e$kvkd1C_o}mq! z{dT200U7H(a?!g7Ecu{o1sbxt>IF{u&CG_Fg;}jNvYr4MxKX;s&zCs0<;X-cZP6{l z_BaV)U2OV<^j{22Xs`qtvVw-8Lm*1+LB|>1GRPsnSyu8HpR<;!D}VQ=SSuh8v!EKO){l3=NRMlLk@>W+94KKy}~o-R)gXS+1sH*Sgc$36VL8nK?<) zoW%_}DLpw$hjUVi>(gA8BB~eCmC`YD-u{$!%e|Ygv9)*; z4h}G>ycv|C$OfHP$f}#M>P2@T_!M&%=FezRmk(hPS8tf(UG1+iP2GX*~$qr-4 z5av!$tW7o0gu`yyD{WFPW};x}y--{v3^H4e_$Ud*O#y0Q*pUt)MU;{&26Q9<_d=zW zsTpBg+cDi-E9?d6<_3kbP~ks^0F>f(Hj~LTnB`Lw%`h4mik6@8oJ~V+Hq<9nFa*}Q zHX4XZiuH7=gHaF!9=)~4u$>9j?Cb(NJce}K?aE?=^RfsZIZiXn7?Khe&cm|Bb%PwT zLYD=bNxEiOAr1(X(h8nA`Fu7vUq8wHE~3Nmn&CcX)-IzJn+OIiC~6<)aA?ZUV54lv zdj?7`7oWHQn65B&IX|IOj>|5U5*z}ADFLFQf=ZeuDZpWJL(?k5EPU9^t18SC>O%7*YK^z^9K10=<=8fHG?7i} zeg#k*twf+F!W6|lhv}@93eZXr+KCdS=i4Q~i$o>Me{DtjzC9o0B!hV=_bZ(uz#*Sz zC9KovH%B}>A57?l*flJA$frWG!pb)i@~RRX?IVQmnfP}iql@L#taf(up-{ugk!||~ zAQ%biD{bjkkocN0X}G02`Y{XE3ib$X_H7~V^VnIRVL06OV^6Gp3 zL`5-fKab)iz5qZ#$RP?08bZpRwuOuA`l&U;qCV%2^Ly>>glm14ecWL|3fe80ueJu1 z9R@LhCMLpwS|ZLcZ<9uhctNN%l$|7c zW43)bf;Cc@!44sb`Dw{ZKb7#`pCC(9K-{x@o7J6mAUc*Wke2$cg7>_`ZD6w{Z4*w;iXSh64H&ha;^=%mQA9 zk!G$2Oezquc&aCiMQF^r_L2vTi}jbP^eNrmTu9oTt_MM@=-~S&+6tGk)9vT3x-!`_ zOgg#jkxHM!oA$dt<Lwhl2%6=)i&=b7|fNn1DJz{n)`T`og4)Z3| zQU6SmU0x0f%(jQNv^n^u-Trud6uJ>E`}Aj5R$NIlq9Y8`gx&-hS z3Dwt=W3cGJ*bD$*Sos5!Gder=-59`;cGdFnD3j2OiJX&9_RYz@zCM(MHg;T&qlNSM4&W9LP$ONaY-R{mTA_G!L}S2nWx zS@YA`4qV&TjYt3q*JP`~jq73H*N(AjwbDXurZ_zyR{$<#xzC`9MZR1bIIy_AL|&bq zj3gNfaK0CPn#_NyGbFrqCFn~Js?V$FfK)}g4{N`&(9HCHa+BJ&g~<|Bto0r-K8m+2 z(iFJ*bDuDk9ou4hMVrlbh5Vf4HpA&qp_^6tgHExs)P|(7E7{a$SsM4AL^Eevyyp{; zNn`947;4v92s0?jjZ7>s*X%WV;yYY`Ej+Keb=~g3dWQRgeHBHx_{0b8mFJ2T8`EWm z0%({FW|v;3W`HfH)BW9T3x_E95iIP9GF2NHMB1vhT%q2;THo#=lH*zhcgj>ein|O6k?k!7OMq_zVLD_H5 z)tKs7#_ELZ%ZG^0r^QK?ke_?cp6LUl4%sMSLgwtVyF54H!O$oDEYSAy`_Nqm5Fety zJB{H9JIn`ZRYV;#cOsZ>ue+&MwFZ})9|9)~@`5MpA#EE$Ymu@h!@ze4eGcB#+R|!n zaN6lJaEMGZ6cQEal4F?S1P_~X%Xp2vTjRTxzsCPC;W(kq6>uPGD#>}nAL*~Dl&LQ2Jz@D0a(WuE((-lnEB5XXi zk!I#+X|&wifqQYV*A&^K(0)ieVc$sGuGi=J=!-|b`9>OZZVwf^LUY)dR(O0`@@FRDL5|aQ+ftV)&xbw^x~86H&z7N`9PRhwfn64 z6YBg48C34RdHj%-PC%r#H4WP zf#&VG-~mjIkOnGlv4O01c$4< zN|*bPUA4`}tu8)2<6mg%Pjz`v2MW)o(-6T7?+N)`;9p$$6&31l6=n|LhZCYrjk|bu zBhMA^>5gPDo@4D}erxWlrKKk22VyEF@<5uOWa@ED$Ow{sf0MW&?d`gw^oB)l%R(wZ z^I~fKTm9YA(4S4ZtCst%c_AT0Xl|WZjC4321={tJ|3r|Qc*X4E*^AYRXKvbw5fSch z*DGt%>h7Z;Ph;I;>y1o_G|Ge7CHU~|26t91%e}MUV8M<(4g)wr!jtPXaA}a@T;V11 zU5Z1NH~ShT&uN>P#Y71$+!memi@#>D3lLAyH}0M~C5Re()MLxfrlws}9~5FgY?g0N z`$M-|ZMgfb5j{^D zf;`K$jiyQX1=KUMd7*n84Q4G{1g#FCE0)$kX{g8AHyo$k!B4-p6Jnh@-9t9Lzrf=q z5Kn=p)%Z=bmLk`tPBXW}wV5rMRO!(<#G{l=&2-K>qwC?Ei#v#4;m(*^e<`a&&)rSx zQMuEdZi(Mm0E-2!Zr<#+b=KNIS3F(;&dG8WdS}n+$(}cy%_8QoU2}fKQ(~;X1m`9p zL`ig4ONb?s2}dP{*CfX8B_#d7i>D_4!|~MWJTQ1Hlv?@w+4#>(H^&dgZwILVnIP&* zZ}IWWjK`s?zFdV*qJA15YxuH64FpktEGmk2jjd1rA%FV2mg1MwZ*-19l{o=s%`auXi_ss!UFu%5)f32kE|hQGO~--}?(cH2}el zN;eseD(NPZ1JwukDMx)*CNM*-^IERrry6~=bX3yKDHSSyYEP(&pPJ9p^{?&YV_jP1 zKz@)*1!kyklK6PM*@0{nz)x|s7?V7`Rnkok(#eurrv>m+8`UCS_wzCMNCz$^1Q?`N zLo7@%_A4gX0sNGPqd_;=(uiokLSt0AIZYV^M^%VH*`3oyl{lYBD>S|+ zaiCw6I5oP(dvMLV_U~vOPEM_*t!MVp#q>@mk2{^}_8+@cN}R4GDkaW6K#4Pi%>#Q# zOA&w)XNWeY#EH|+{M4E|^OaWpz>c>EQAdAK;-CWR5h^8)t7VBcC*D23uQ#_Y33P$sd@K%F zbx!Cd5n`LBJ5lDZ(!Lo?ONH`{l5 z^DhPOOr*_a0exW}XgQCqthlKSa^R z%%$uaTwYZqjvOGwJjCHADtVn(ScsCt4zf*HNXJ3i#Za3eLog8|jA>T%0>$%D135)HwjJ(BZR3%Yj>Z9yMibDr4 z9WcE&d^2#kfDPIOgD~XR&Z9wKs~#Hyl^UCyaTWKpPCD0OkYlD4shiL_=;*~YQ~G7N z)VdzaJAtU=e4DiexwL74?TC?2x~7Nilf5WsqN-QmGI0ngyNy%AiYl^Ezi!kDNjb~X zoC(>YQ}8g`DjqP?*lw5_`A~-@&b@xnL1SiVD=fg7uQSW^q)x$ovQrn|Dab~HiL5q> zX^#`ygLCqclnzAyJx1Xbc4jFIVohV1_j69HF>BIpq`{376h|aTtIV?K2R_U?c9jMk zVhjQ!JwWHg$kev`J&FG5-RxUy*hmOa^dT6m<^+QE8yB`~?{n#W#!?(7i?7R0~x)1hr; z!`nLf7O8;*)*aoo+d$Y66fUzT;c)UW1x-q}+x=#Lq3yMOQ@c#VTks+DZiN}63 zKU~~8^15>7iKh`4K3q9I@AFtmSdE0Q|#EVrIKHmN~@=l?3a$x<;Pj?M| z8&=Ld`KtKBf5T8JKubUx38~)h_h-T*9i&e*wP$H8gSMIQ;S#>dSA35^7rB0He@A2W>os zIP>fK@!r{&iG=@}nie|!R z6sq`_;z92}k3uW5R4SU<2_9pk&`t*7mVHnSn?hPMk|L*NX$3@fw|CD|sc5u_fQn|S z7~o$t#PSw`ufZUoqFJYCJ0E_N%BA3Mvf9qatONKLDotYuZ=53V za~Dw242|+Hs!?buO^C`ns+@a$21ANov#m1%KbWl;T=lUv)9#ga{o|R{ z+QSCEXoh+A^KLfyl0nH0$Z#Hl6Q2;rnKzj%_KDfwFf{Uybkt_EW1bf0$$S_#+2ncQ`<*L((U{jOjS&|N!q$;vm z$+r~fDweUAoh(Fa~I-;Z8_VDg$9Tfg|D38pIIgTel`lYkZghF?B<$zEKgXH3HeCw22hxwpHW6W z5Q{{=KpF>eadzCT(o}>rwx(=D?qj10Y*?6R7F*HCho#CxNZZT!X9}AE7a~lux(ra! z02Up4u(8N<@hTRS5Cj^T4)fChAD=#05@h8ys7AJww zGTN=38@OsXq+;5n<#QxUs*V>oJTXcO5U5qMDyADfZw2<*Uig+*67E6P*>mqqElkI0 zu$l;G0;@+HJv^6v*c_>w1mXrN2^*pHtzMKXIs2^dLT9oDTF0a}1rOC(!Sy<5|BnIo*ipzq`r%0lN+Z@^pAMaM~b3rBKV=x{H+tkh2 zcss+@xR<4o9uf}}l>bJvy%dHC3#hi~?M=<5DUh$-931Nka90hh!3{yEIYP`ii2{UE zUPVmmqCs*aIjC|4%eIb#J4v{Pdu$lO2=O}S+so5$1ZC^acGcEkHt{TW=a{B&aJvZC zHtTB$+^$G)$R3*dViHuVt^tb$>^ZH>92=5nVWD`D!Kc8dKDiQhf?+mvIyTE-1TY!p zu7oYN$myHsXPQU2VT$t$4_-L6S&#?!P4?@LPo7ww8*QUlySm#)FuD7Nq^nOEL|q#D zNnBb*e`hw&wVL>f4UUkPHB#ciXSP%ItnNEyynCL@nQ7B=IIhfE7b5gAa*Z8d;LD3s+=wRWiSNqG6TR2JHHJp3qTfeH2cWEX2-`<*R z;@YgQxm-B^rmxx#LBqMpY8l6!QEAvm()Sw%w=1JBAA5UPF5$oyOr3k36V$kA{z-hu z&dIZPW#sJJHjm&PIQVpaQ62Y`F~RlYtNyr$wV8Le6Kp=dd2xqPduLKCBB1MYcTkSQ zz0>6&4Jf3Q-JYGdp#S0dJw7l8raX&+`FKt1)bQzn!4kPRS1uuv ztDDIsO1TpnxQ0Dk<6$m|$TM~2kt2ELnLJA=&$@wU)5EhJ=23}R4uk)}mqw(hJyWEV ziq15MI(tOthech=--R>_{@L5(tBvN*L=3RdcK;g$2Ebk(PEUI1x%kna>3V>930g5u z*Z*(oOyi4de+KDaA2{_L%<}b$7|$riy)vr%;oI60a6gP0W&R4A|I^Ugx6P%0P%ZPX zF&aN^j~}dG^Iv5`*R-o(dZ`(vc6p+#8pT;ypymVvYEJh+8Vt3jW<;c8GccRJFbCw0e<9I&O{Fm;9c zXwAt{nZj4A$fWW+9YOWc z%%RQilBzk+He;3|KEa_&$YvygF46Pm5~{s#Ncd z3Q`ZA8gDCFSZ!iM)l-)mb(C7P%nj;IB4@?gc`zMpkq6cv=6H6j17R*nFbGBk9GdA{ z)BX7_gi_$8wzCKQLLw40rIxoTPq#%VLD$KRlRtXu#|?r=;X%mFQW{3w z#WzY&Y!Fr|G>TY!B6%ZjgV{CsBPp6t7z8iOKBqcjPbf++0=1>kwnl`VF6BhshUM z+W>BQ7zg)yQk3=l4sJ|Q6{;;AXbmNT7i@2qknbrRE$nG=Ygn5Nv5B1-;&Z;Ky#=?O z+N`XuWKW)64ha#L=$^OYq@U?W>s7*_PxUT@l@4w!PTDnnTJHtv=d{fQjD$80lNm<6 zz;;v6rz~iPPyK+C7Ae6Uh0N~Ix&v%GWvlOA-<;Wrcj1&ti!6)Vn}58JW!_Qaf`TP=B|Mv)V7E)@c~lv_6ERPpL&p} zrK5pD-`|{lG&R1B#aQH@wB_tEQf=Gg8;cl0saaS>8#FSxn$lByIgjKCS!S7s*b)Sj zoA2pZ%uEWue?9@;d6@igVU704X?9Bjt$Ba;iQFNb<5w$b^}4;MQ~YHm2~)5utaO0V0GieZ8w0G_NEsnUCuK_;j%4hz)^j!}8;tAKDp!!W*1 z$4xb^r7jhF>-bLW9t#&DI!Rm#t}}HkT(AQ?_XL&ao?w4y5b)eT#;zcI2^XFz+?>_0 z;2~X0F%P0k#V=PpxopUxKS4{&Igjin*-w4mjTubS+q@@?r)P%;dpNl@1_9v$jn;P7 z%?3ai>?TUqPEs2S7oa>ykc4<* zGaM5N!XW#K2vfbW*70zOqzrV54p;NdfCk7(7_wOw&ViYW9tLe8n0aeiS9=PVleX?j ztxyKh1h~uMgv3-H0$~C+E)=sPSe}$1WEyJnq&5S;*%bZlkQ3=2e#;cE#_ zJ*n~&#$5=zSdA-9@$v>HnygD{2>fQEK6|x*9wI^;QnIg@KRg@oX%M-BP-1XJ95%Jk zbCEQOr)xtN zxo@#4)GXQ49L)s(GGU2ESdYRynpz{@vKc??exEs+)V=L!8M?f)73Hhjb3Bm;Gu!#d zoW!{(-PQ-&MygaYSdk&5jO~(X-VYO);emA$cHx04^H%}Y#vAL=W;)jYO|JVOwvRu9F>?V6EG7t#1cr&StOlc&Vk> zJ6&HYLr+@*#owMQn18bFWHGI>^`@+A#Ltza#>$K`SUdm%XDaG(Z@Eh+R&$0;dT_5Q zq-={ONU^X=!#(l=qFj7ivZO3aBDQG@dLJKm$>rO6gIhN zm`QVJ_(R(b#KZu8Ci_?+U#*CG+S!S#5CCIo2Wbe$b@8a2Qka#G?>%=v(+1G4R&W3n zW`nt?#tG*`BfGLlovd?()aq9EXGy*dK?&5HRB63T5Ub@AsRQ0Y6`Aw%(D$h*>-v(U(+uKlKANEdW(4r>Lw0)3ERYaPKMX8 z^^;M!js5(i3=@BspryW*YuS4bwp9i9EcJIyO^D3}*^+4U1hMkl`NUo&I!PUtpTY%g z;{Rrz14}-|106BY2jOi6?<6TZtC<6>{eFY~>qxu2QirXbY^&d_EX6h4j;mUEB-L(v z>9+G`Q>-fdP884e$|MhYHTo}aynpQ`PK^n90n_G$_G>1d{CJdt)@qpZ$=(E#huk$+ML`c3-0d!;e=E3L5kepxvmRSz6T` z-2D;R*{MSYx28!BSFU`X9Ph|Qoyn-LtJb@NoVd=SG$W?}m1yzW;zskFE3?lU1Rw9e z(rA&2NV%|nXkob@{A|dQ50Y~>LwhH}VbjA$HIvoFJ}o>@wRCwOTOYsr#X>L`L+EFr z@FN5NEjfm+f5QX+pPDDmmF5Z?az#D48;5hnL_xl*pfFNUlqrx(1zQ>fr9Fb}!vYym zSnevUh!pP56jn-w`x=B*J;H;-LOC(7#x<`lGOs=}uR)r3Eb{kdt-m}i{&$MWui3%h zDqp_ArT^0R0&HqM_^P!3!*wwhD9ruk>G*us7t_na+-FIGFG~Bd>E6{vFMi(gXLNeJ zw=|YD{27`aZ7jX1YgGwez8)1SyUXZq@1N=Ek3A}-{dWh(BniY z``lL76;E$=)b6>kgO-Ih3aG2>-pMGijy+Si_tGBb&VX$Jhxh%uKeBf5tuu%BUp>TX z5gG;7S6!=3y0kC$Z2f^7M}Elc|A)xzNn#oVIV!U^R`r&~WcH)IrOYqAC2w5P=xMQ2 zGTK|xg4&JsmfF-Ys@+~%sp_=Y0Uq7$ZNh#zEikIxUTW9aX)(In`{lGC4SH+X$bhjZ zD><`8i@^e9_LE|kY=qK@v2ZQ($a6@j#Q-h4o9^0M?`o1+J*49j$r8X_VybKPOg?=+ z2gvMi@=>MIE#E&S@z>2ZNCqu%n)pIG=ajPK(QVa+$z{Jpp0^ z+9Nvy)oD=~@=C984;w{H$)IbiL7JZ(;Sg+_%u0jd8{9viQY9Wkf4W2X?l9_^L_jqBw ziXnnW<8@_}NAz38av`In3 zrdw7|p@D_#b3vMnr1cJ;I5=IRK8~?h2;qy^vw`XptGL-xk&neTfG0nfBP?c@qfMtm ziK|zmwL~dug}of&MZfGf8h63Yk>-vCOo5T86MEUB4da^u2}od}?UJ)}8lQ0Vb8Cw> zRt-ZdkVpy5JMG8qekvQsZiacW8}WPv_?h(g0cL>mGA+x+E|99x+T zuJPtRMboX?B`lo)tOVOm;({=pxWwe7$ApdkC~|J6x`k1ja_J(}jN1yCZ?d;eQh;Eh zVfq%gH+(~%@T?%Z0zunQV(@V9h+u-qM&hqB*tbK1JvfMWhWfgV0+g<(zaZ*4pRlR{ zrA94W7{hpMzHYd+E`tZ_zYl}bgl>d%_72m6{jpQH5t73NcuV9Y$GIeCAgGAVGqN$i z5@2tPD^g!7jmGpBqmG4%D)V*BBV4p0?2si0Eh;E%Qhd0iY)V~mq;=btEdp$$Nv+@9 zEDgCkYQHJ2UTUcbNe+bH^j)Ii(z}E#vaZqIMu-|dm)|IWzgIJh={ydN;tVz@JoP=Y_pt$pD-b7i$qapn(Y0H+2R;M z+oqF+tcv(a%de2O}CPI-Q`>HQw3&GplBp!pBCG0#QdCbk4l?z3YAuuKb z+IF1;BkxH|xKDmXW_K~-y||l`yTH~OeO&XPG>wHE2nt6PFomL)=pufKU9=w#307xI zd6+5@5_40An)$d1(c>W)zFwwrX2XzayQPDsZ}~2R0UBb0fzUY&gBEUw>00e>Guzmi zS7KZ#vOrvqVP>#rV-AyZrEL(`V!fC`DQ=FDz;L4t{Lqzb^v|w|(T>g8_$(7UEX`Xo za;@vCM5%BHmZ}p%QZ$IZ&g9Z*_I@{-FB0b0*BNyyBtJEE9Lc4nQxcn&1bT7I%w&@_ z84mC*Q*ocSMrx;NsNazE|MIek|B;c=8`-mp{pRdDa_i}3YijS_IY8d8FsWYjS;I|7 zJ$IF!-aM4X?y227b8o-4T#91N!eFl0whiW=US2c-yo!fZSZ1g>-r3x^$9NC%8BF$y zSwTBdy>|GlStw}n!s^Qf8xAY$P7DRmY!m%^S?4I#>1X3LFZ-OL_aY)1S}04Gqc?q^ z^qLHlj)y5hh6X@MesO(GKhs%kWzMBD-Lh`$LVeg_-?E9BP`;h$(5 z{nx8TRVV+CZ6noVf1Fkr4-|lLTtMac^`-yaEbjNO{_oR-e+X6h*Gfh|7L|US3+5wx z@BdFY7lt@+{S>(;Le~RGBJ^ZfZ)|{Q6mzi9reiE)R7r#<2ci`^dM@}iLD7KbLknsF z8ciZFtti#G0H@Ma=fYI*XcEzci5^IKeSU5ybM#z*=mMC7qpqDQi68?>gs%7f0WUNq zvkR;Se9+vi?uMyu>kbeDNrYw>s}5_E4kQtnbOjIVdnxtZjXO!=*7M$#ST04olG=LS zKMBAbEC9?w%P_UMNy~ozav+JQ!wzZbbILun?2iDL0}RlYb^5NOol&DJJfM(0v%F~< z)FX0^m3rpLD~-CV#^;`rCxx!IHnbUhg=zL~X+G;&QFR9D+1Tkdbgp#3LF4!l9_Ymg zdD+IF940Vq(=gRoEVLuqb^1wrP0VzM54BY@(r~|=nkc$yc9o_6o9RyONRB5YA6~Y$ zE|T`f_hCJFga-~HUc*&Hok{!1pR(XPlf`jQXJp=Ou7)K@UniK2cr1!_Qk{hZ8R0D;-~l6jpMzv|Dh|mod*zGZ+n>A(PTtvrwbtem$z>>a*ixoY~=>PD7Ied6UeVT!e0Apjvtx+_xU$ z72>s;d~cV@&+lu@F?if0;x%~wYN4;N3VOb6Yd~+zl^X zqj<2D@1^yR$Wb~}CJG@6LcFl?(YJ8+3ry#r?|)LLao#)3+gE_gDUHNJ0?LU2oDpbOa=VJVUD31Hj0=*StZK+2Db(8CYYb+WAH;vWzsjmQND`~HL65Az2F2xQ z&F)(eP)T?8sXzBVq#X3NkZ9Xo88{+&egq4vJfIXY1?&(T^r0yOW^^kD&wRaOdyVY) zJ_B(tLm)+_1-o)Av~LThrQrzjzE&BD?M-iJ#X0g|uGh}%1l|Sr8+m(Lgq|i__91S} zfkCM9EOW96f}oU}6-}y^eQ3~zZtKzam$<`hKoy%nWy2VE~XPioGMC36awf!hW4-RC7eWwYPKs5gZK<#LK(7z=and6x%r1Vwasudq3$ zGL>y3sw3MTSP+{Vl~D1k6Pe`dKuLL}t0jKkTEtu!YEjNHn<|@3VALRvx#K_;ks8Po z!W)tx&XFSeCx-8gs1Z&kW?20#`HWx6yd8IYB2#zNocmNWf%BfAu3Smn6N}PpzkX(y zZ2OyrB?6yWDX6)&KCg=WmIjhorFNILk(yD$+fA6v=fFaA=QjVV-8b+P#r7SE#V-S~ zoJ+AHM+=9pN8P$HcuAhVmIo08{6m5I?$cVPoq4!E&MTEat7+pT6L6b-$aUij^qUXs zA;;ZJm#uv^7aI0LP~~$VIZl19nkd=1F4Qe?$xb)RQsG?d5Huslf9F=r0`|X-UKIua9>4KH)p446bWIgF z5&noWKYl(I20Z`HpYez7)PJFE^rLF@qiXb@Uo|poLQE7HGSvfrXI~3YHOlhDE>%77 zm%_NJ2fiF?pnBjNOdaEx>kJ}^-B}oGDHDP+uOxYE`LYJvyW>|$~$I$eOrFO~y5@FxQvKO8yLi-)tX?FJtB{n%REM9wRKV}3cx zF=Jt!F{QLKsAz@Z7mgXb%Z_yhvi(%h7{?qpdpjD%YBU5qevb#z0FR%kC&BI+;PIQ> zXv2STfJAcX7}*-P0|R*cFo4Gojd&I_B}a+4jZb=iO5?qs>cshZ;t!u>?GR z>ayEPmB)`t!k9q;kDoo@@w55eeKjZDS97nAr-I z$4`ACKnSZme(L~_AN7mJ576R`d;Ex)FY>z6lzl#PRSct|7`%&@hvSGa> z2OA~?Od96uwvym_K~!x$c@u7nB1;1_6Q~;fFZSL8sOd%D_D_X`8hWUPj({3^*8~tk z6#)?tl_sKqpdd}$CZYE#9SlW8r8g;}p@X6ZL5ejL6$R;16ypoJx96OF&OPtm`+xWU z-aR)=CO8?HVa9Q0eSYh^)|%Kg9TSI4NMOnsC-Xe$V-gXuK zb|ZeUQQZ_wQn*+u6wnh}Tf`JE(#(z(k?nVS!p!)5-{53nik<~Em8QXixOcb*9c zBfHqFh`#h^!g3)daU2PX%$@GRT|xH)A|(&n5lzQQS0(%n z*v4T*g$RFlYpYXIrkDo-xy8Tnwn<3sr9fO;(>y@P4*rGR%IeJ+Qj#;kU=e-bN|HW- zr@lnm;|#^M3J+O6_J-YcE5?v6O8Iy0i<%yqg*mhETs&nQ?-0&nuEK4Em=Lhmj*DGK z@t|t-%~RFEY5K*?lGA78q|nNOo*>BCcp+hTXPPaJ9_~JJx8ue@$QydlezPJJ7!SEU}Vz)kQ`Op;dSh3&}6{;@xu_UKKZZoBp^T>_i<$676_S z^Eo)0T!NRy4c^QS#29Jd-)~;<(l~FouJ&$I=}~J_ zUJ^*1;-TB9qoiRzS#`C4cTX$gxVf{ft5AU$tvAMqYGwo%2B!pvGag(Qf$(_EUi13`^Nv4QT zvJtyoEK(hOxdrLm`?BVx{%ljpIeUHS3uxtlBznCn{=H~9!erZeux(H@0+J%!En^GH zXZ ziO)F~17em_GEKe8J(!m5Cc4;65Yu#lYdE7NWT>FsF<90E0BLD+mhp-yK`ysadqI;9 zJgYYftbV=QU6!fO*i1j3ciNTPn91nSfvMO)D3gb*$3Yvj&X{A0fPj$6gLGPW#`lgs z=3U8(>b0RXdqCLWx&}@(MLeqpTay&p*=p~!eq@z*QJpyOQ>;ZRf8PGd2I*zGAK(IN zP9X{eX=fKfphZEwm#0#Ams4u`YB!U`z(OlF@hG426fa@E8J&I&`wXRn26| z;rn)vY6B~Dd1Wz8D`Fh}I9}58W44+yMgl6QH|}y5L{4z&2K$?+e!GyP@OkLhB~d=* z#{Qonggp002>B}MM+iB}R5z%koyXFwY9z2J>eegTar%GSrPrxt4fnG^ zr?tg&2g8`WyP}DwQth_;J(!&PlJ!AKX#J^V59JJp{rphRaZVI}{azU5~iYzD~ zdl&}7Y-a!Q$bZYq)XM+o{eWMmMx4KlfzW?y4E)&@_|rTe!jSqWdicX3nEIJjpr?}m zRDtwsnC}NYyw&me`%|Ky%M1Tz9n#OsB9G{~(=j`jMPBj$V2dHX^dAg?|NTu7y#nd) zPlp=ARP`zpRBn#uxtLF06dsi7Wiw^1^?J9vIxf;D&#BZrEo7fC`6U zK=57O82Z%0MSM7ybp)5O*iHs{S-=KKFkptDovfgms)Qd?3(7(k)SV2ns#Q4ej|{T) z$j;P)6Q+A-YGGB-z=@tgMv4HV=^13UJ}%_W)B>h?CxhH3-c8RScY%;5eFP|v{u07~ zMUF($XVZms81mbMcj%A4)5Sxc+HL!RMiW%=ot#HdiICTRSHPVDdTvAE&`f&@m|yRT zxIXpG2&!?=DxW+6w-}r^Vo&i0cMn>H0pggg2H6bXk0JcXT*^U3pxyE{qN`lYBujRn zNk3Zzs7!7tWYBcv+$GhDJhrH}H}es_^IZn327@*g6)aGj?rnqBM$KrCZRA0V~XB z({;KrPz-dHb3oFK0T#t%cNaiD_~P>2G;vM=S@gsQ_2zii>}prZk)B1xcT7d8Xn~&k zY<@&GE7ZHl-8fi$?_NLEwDu|ic{xE5r*Z>Fwjy^cfYAq>QG~?PVxX>M&g^fKgtP)| zxTSaGIxe%@S#ij9iU$L%8;_F2&yJc|ChsrcT@kD^%R1Lpbg{#`6-LC!WOkPV4$o<*yyN>47d5^k}n(&XBt2#5K zsTIO6umH?Tuey6#?2#!vTU+ir1yqB58o5VuF!wx?+S&sF;^W|ODyG@?q5kt5o#}CQguh>>xO;7$8z_yBEpV*3G2U)yw7Y4@1c3qRBK9#IrV__{Cs`z#tEAj- zJY75CN@~$nkmR*GnRB`0LP}#bU#?LsEw1p%{Y*c1x7}EvO7A>5+=|RLbF5ai)QUU1 z63Kybf}cy94^3|d2)brQa`SecN=pRu$=6z@HKupd!w9?z9#B(z{C$XYwYZQonB!qH z_h^H?5KH{DQN>f&nDlN)9P0Jg)^TU+->RI%s$5d=Xdf2u?VtLr0QG9{o?d`C?wp6k zrt=fYp;aDgt9zc;7n$EriV~02k7|f(v~B^QOuHgpho#IEicgliz3(0^TUQgGclJJ| z^MYffX+Ecgwr7Eacl3_cZd3z^f5P7}9MUuozP2Z^BX(Eh_EYk#mla{u8VPgYtBr?94$T_BXY?orWR={ZORAx-F8sHcTDbS$ zha3JJQSc=Enr!gYqxE{@7{z2T6mUC8_kh!G{HU0ke$gChn=FhJs8A0*rW5J5jGfmz5MKnIC4h%OFeb3(814oIBm#mytacQ)Is zAWAUcPmnC&Ssk> z^Wn9MZZ>Xvi4Hc?HIak#%{Fj2eX|V+l10Ik`~}g5j}z&eZ5=>45u{T6&&@X7{_Sp9 zX+llJpze<{qfL5u;LkFn@4uHB@n+osb@D2$(#wq0x)bPSMi{)|pqehdO;u^*uQuC; z>19TX^vyP%Y^T53Y%~73*;e;svn`aq*_Kas$NkM_8=t84DkwrgBX%OTLfr3iWZg~Ygi0B0r%B1-n7ml@?iKV-+zr^=WzNEnIT z{89YlO9)gCyKL`6uRJsC`wxGh3pi-JK>ZXD{J?q%xrx5z~dDCwBu{sSd;^=wl+(| zJs@)qfS`VJJxbYWm0MFz(98fxNE^WLEac}Rt?`FV`bqBbFK@~yTPX{8OF$fPj)LPi zX>frIMX>4TZazYPEdGmmF;q@Y#?Y!x-s2*Vn4AMln~Rv1HqRz4Coer?qRg3pmFLVJ zSy>i8&=KzQmDvh8#}{wKRyr!ik=+m&uuMGDCoJw95)S@BWW%d z>#}Ee5BwGv3w6#s>li#QopcLFaV-W&hkuafuOSYu&$D<|7+RXh*p1l{z4*JXOY>7f zy+$L|{I~Vb$);MzSB~7t@+283V4Ysv>!_7RR}Exbial%RokVGj(Ayn#$dnfVdA`Tt zER=k7&J+l~>WTT*=>@;wXx^A&k3pIRM)vVj8)OW+IApO$<73nAW#H*;N2e(?`&_m= zkr<4RTT_H7h2%bIxFp49HKeh5ftxe9GcZd506(psoMGkB(@B~%&3Nh>o8Aoyuu@)- zAT~+sg>%S>6Vl*CJsCB=KiZD$o#A;2pjbHekT)1#9&>$#MeUps_+mcZjT@@)E)yCs==!qkVsNJwkp-?S-Y#c^KtU{zMkH4 z`es{g1sUz#Q)lmKLf>q2`5Z}lv(#;5+!-w`3?%s|b>As``ZPJ)rRQvaJTxZT9nADu zQjR*x_pUgS?^4k%X`q+J9OwzZ|K|!(@s2bTaZocJ;J2r#<2cO>1cgP&Dk44Wn1yt> zK^57Y>W|`H<|N>sWOi?xmr?8!He6o~u1h}d^Eq2G_2PEKwPxv#_umH^d0ArudtmM7 zd`%BMx?Ur;{?P}1_?S0~FGtTxZlA9iipt#f^|hA4vQ7@Xno2hn?(bRG1}bjzNNP3? zoMm1%<0XxrQ1y~E4QfsDa=oC!qfeGjZFw~GVkQ%nKZ&@Z*{fyw3jL(}?doOo)p5MnuBraIkI&w#6E6}tSjru;%1n5=o|W&7D;5`++kY%qwndDk z;39H9mtAP$@MN8&q39>y@`)#7mMpM{`FRsog9l3%K}R%c=FB)`(*U}xmTf~%071rg z=#qhvIbWClXKc0w{oeqI*wh&9z5c6mB6^nKSCD}Iod5q`PwBst0~iFr zAb@{;0Crm5A5OlQD=(Ku0iWV=~e;-EIERY*r_vB=2lDC zApk{`KF1FN(2A*{6M$h&C)W-Ea48tltpx7or3g9!Y)7zivweCDl2hFw01d)Uo#`q8 zVPen$W|vO^fS857$v~J?IR?y0CxC8dhrD4jD{hfqbYrhlM`n_p$FH%nckkg~!mJG% zz!CN!EL?Yu4MMLom8931PLqJLLL+E@9tp$8>?|tNe)Kw1Dq4l5@T375xVL}XfVnh) z5&T8`sIst@{-L>fi!0XqZ)=`PSZx7%y zRfl|hHU*>;0M{=9h-CV)+AQ&l0Mz~<05J5OK5+j}0)YJ>fP>7Y>yVw*W(7Gxj-A!! zN;(19|6FZ$BDov?Ljt&u6d$;N={>4Rjpm!iN{f*}C|(yPUOx!b!wQ0`Arn(QMFs#9 zMz-|*VQEq~c-FX9$`8*af+P0eF*xH4lDnjwl!7YFSXt5(bY(A_goHLJ;>%$W$mcea zUG*jlC}Gf5ryL@=rwnqKp9tQ4*Is(tqgIj^f3=)m4{DA8nDUByG^!dhUvQ|Eu$>C$ zzYRbiI*&{9A!Vm$69#jgAF^jCd#IFmGoiICZ18EWRul;-xh0EqX&XRuMh^E1E*4sv z=DMyxA7w`NnJN0`d3c>3$gLrm!RlPKDYCnj%T3L@RXh&i-3Bt2`pqbKcZ}7n+(HPH z&z%ScSvc~@htiu^%}a{>FatPJY;@d6W+sZ>RvK$@)4XpX%%*k+i_S@arRP4#sH13yB}|X-OiMX1B}` zgB;$&G;B8CaMq`>+xljPOe?c@aL<h#A>dLm z&J!sD-<4SbHXiLknAjQ0n7Kyr-4@@+y95?>bl~Q8en+2F?)==j^e{zECH~^FD_=4F zQ^g#FkvA)|->9o_SpAPl<)4eng*%JN9jFI2JB!Mio+g7&+yPNNzrAU@Z)7|bmSUu; zAoFd%nGLb`yReu7uhnea+wtL4I^LA^vCO$}KFcK6^+ZvotQD(6YMQ!%t~G6oE-JkD z({q+C_`pH5{^zdMJml&FLxjB=heo=~Ai$CNp0dE=fE)2mGBO(VLL<+)b6&i>+2{lR zxi*kLO*KAeF<5y{b{wzGRSRHW`{aA|+=fh(dSi8@5B(|qvFD?`hjZF3-jMJ@r*5jN zNjtGm7Rxyv5iD%DULZJCOvwq^O{*uli16)wi0#m_tj&G&b^5v=reEE%QL2=!NA6H$ z7pm+;0=;@d*-6Gp}W zJsv^;0)B5EWoYs5-?qPh`}XfF2mN=d>i^tdV`y=P7H4R2h8AaNafTLWXmN%XXK3-{ zyEC$fwjLa#tz9Y~k6x#cua zcl}`&+U-HUNj+muHWKMkJ{ctvI6E1Qijtd(k;?R(ij^xXpNdm#nw^SA_sUHtsE&G0 zCu+VcpH9+UpPf#|Fzud6G2}lplZyKvvJbV7k=Ui{0r#E9V$x-nTeora^CR0u& zvZ>Ef!x2VulM%djo|6nMp6RvFGFx_gp>@7#ZlP_dS7Gt)+NjrJ`{ujbi}$wI=N9h+ z7+Rdsqr&J>Vf3gldQ=!aDvTZ#MvuxCLyI%Cc!}9H%l6jKbK~`1ZyvX|Z7fo|;&&ao zcXw-bcKG(mC-)dyeEs8GHJM3azNVYsYreK$=JtHup!(c=J;g}jQ^Saz*QdsDkK3P` zUIxy6xj2|~>Tk#U09CIN*cN@xyfpLd$D8G4w?5vgX!`i^c1^GRTt&m^*}2N* zcem!M?lQDEqhFlSFV5%}XY`9-A~E{K8U5m$Pwvw;o_wc$rTgPZJV+A{vBxt7<6+r& zmS#NLIG$q@k3bT*H3_`-1pZ(GlA*=FQr~}_p530B-DYh4P==lkk31V48=rXo;^nK? zZ>W<~(=%`1y`N=haSB6=GqgBk>xZ%R!`S*^Z2d5{ei&OnU#Xn;H~S9JR`R}Y&mOw} zW$X!Uz3uzArR4kD?+<VIk|cH1%=m0Ma3nh*UN5{-@J9ZqOz*G zrnauWp|R;sb4zR6-S&I;$sL_t-95d1{R0mk4nBJPgrUXfUO#HPv-pM_&brI;Zu9bV zf4aiS$9G#+-!ruMM}`(>XmN%XXJ~PT7H4R2h8AaN@%+W`!o`Sdi;>qBql=ajt}kcY zUe2ss$*ox}Zdxt5vs%{7(Bhd{*$getqi|xdxpulQMbfO$yru5#!)z6=*Mlwf@1Kwi z;>9dl8$Jw|+uT0!sI_r!tj6tOp+#HMrx(rs3@tuel42zPp)|wp?1$^w9=AS}W3zxDM!g3aV z%U!_dFA(wxtjdBuIqDC&w5M$2Kn(u7iF{e>E?rHn-51f2gkN3&$otOeR=l! z%Q*GR#N^jE@8}0D+cO`xKP+s2T-=^p{5HSzZDHlx;>x$B)o;sdw3W}ajZNCd@Au`j zuiM|ZzkUC<{rwxgbL7WP=Z|mnKhnSczqgDt`o$Uj;{Ve9;%3eu4xAs5Nyv}d!MrP& zOkhGfp$K63=0ggIm*$QjvLH`aEcXgVrvRa>ICBJ8AdGyzSLJ0&IEVI(Ul*HvzTXP7 z02+1S0FyZd*ry32KzQx*#n&i?Za^rvK9zi)nFs0TuLp&Z$WY0AR6UCdY|>D`FzD08 zvE!QJkU^!}=uRk$?w({2Ukd&_n=%C0GZrvrp~{QxPf>#N8&(AB@Fb+vvK#yPY)l3Q zosVEYnvCvv^ATNxWm7754(E ztCkD%su^`VkP2xdh{KRNKnTE|9qv8|3%msS&fDLSUVvggRFlW0td3BX}l5Y{<&ICT$AY4Y}XwF~}p~znfJ*|4`JTT#4nx`H9 zjr!5uU_p+=DEVfx=IO&`4=-0n&N;n>hb=WeP9&dMjp%`(10mIV;@4iVxr`;@Yx|&U zd?HprHa6o1c8P$iT1$=s&Lj|r?g$?n87bWME+YP1J>hssiS&WExC^()R}BqFCLt~0 zYAn!g#r>wdxjMMo0+^tJ>EvsmMhFKiK{Wh`{57PA<6rz(PJ~Y|2jtS?pw8y76Ox?* zr)%yNg%mN1%mWWT!9#D{OM#u>0rlz|9kH|CN4T?a*(PaOa9MV1kXRp%IOoOm8~Sg%8lwIVj= zHQ5U@D;1tK=Zppc8)at!ks6bPwf4ZP!c7Ws?U~`oVCU{!bdE}!j17C+M!V>5CFf#C zyKiAc;1*4b*KRG7d&vq55ZuZjB1g7Vi!_`hSdkLOE zr?!9X=M4J9B)cS+rGRZK47BLLSF8l?f=^aG!gP978M+)Hz0ph#NwHaQ!9Vev(6#Bj ze(lIU+x@Rj=}AeZ%fhkV0p#YZMo5Wh#$!^dG9;;vw0cj4*qDIV#}X zt5{|HtqK>h^@Fy<7y4c;PUvXP`nFb$`y4O?u9Oq8*Jv&|{_m*?ZR(vo|;Qhe##5C$V7c>~dF(koXRtsaoV!P!ut0s;I98@(}qTV)FP zHF*D2*CjO=oW&|s-dU%)MCa}__&$$rmyK>8*zDrWv4c3c&u~aty0()hPIpF|4}JNl zXE-ic>v(X~X|mP>g9tYq9Et)G!<8a<0z5a>;<_}IrZrv1qq3X<{P_Lc(i#{04~F=w zg}FtBHN$OqqLJxp$HJpdpw!y})Pu8P3Y-DFh{MAE;Qe6LFaD|~^{N(bu{SWvGUy`JcDnBn#QtgT=#j)_ZDJdec8>iJ){6S(WK!iYiH3`6h1`4DAg=>J!t3Xi-P&frB zfCh3{#oj|EKGjSdu}>TgP8`opeBPW$dpVx?dNYxVOq$Y6nz2uM7o0Sko%FFeX?{Fu zVKZq7nY^Nzyk?)g9-O?Ho&2Rad3!vWwwVkNOaW=7Kpaw-LQ-HkDJ(51Y!fLQTPX;^ zRBo+QUWZivkW^$&s!&U+$V95xRw_y`O+qV8${|fABuy?SO}-^faUyN+RvKC`U0Ew# z)gfIyBwaHnUArY+cOrfNRysy7LtiVy&>_PpBmmK9OO$m0=}#)mrPSt;1Ej zkgN7NR~=ifI!#G{BP7!^C-ZDeruRhVxvfk;!K@2fSpg1NfgxGJ zIa#4CSz!}dzinmV1+$4-*%1zo*-;_cF*(_BE!hbZ*-2a3DS|m^S~(dGIhi3j**Q76 zEjjrUIfYv}B*ENbt=v+F+_I3|@|@gTEx8pFxm8=aHG+9{T6ql)c}*dC%{h6kEqQk* z^6rIX69545EeI40@cl=K_vR1E+d(|o{-1pJhFzb^X+Y&Rq;eb4L2pvXd{W3_TIR^K zy!{UA?Qxvh=R_yIx7zOS_IvKIp2_)H%ZnduLq8l1``~bShxkqscc9Nba_)4@{Mq^+I&iEAkgZ@G?7efBRfQ$Ga^!Hcjx5Irui7)l$FNfxL=%W)~>0eBmwaWWz zH61(9cc*v#?t}GvgTHg%Pw0Cz{yX;9 zf_^KXzpbv**4AmCH-6Uq(9w^!gMNQ--}fEx`%ge01MwJ$_b-Zgw@#D6e9kpkX7LmZ zh(!)2LSzd896%fDb21bhYa4>{*E+cs-ey3KY`;05^m?UVn*Lg6Gi!1*&8vhtK3ZWbX7Mxa@p3b#W=Cx-pEU&=~_*v=o)$&~P zs3-6WMl-!l9RvZ6M83nlgHQ^1iatOJcubjyF~!9|@GF_=TlgWqvZw4Gp0YhcvqOiS zNbV+pR~%+%n^5?@aOpOTnb~Ar>TVuZ)#KuOAKfvIk959Kg2N1iIuDTwePARN(Sh+8 znysZd$(>Kl^Ke0^s-WTsyRfu_Z$582 zR%vgW&Km>fkG>*9yQ~$N4p@~5_tt>xMJLZ6lXHMZ<-yrf%$Z336^_uYW<`KFlM;aF ziPeaFDwfDh(wXl;laHHw9|@!`DSjt_G~V(K69~;n9fnj8J_3~P05t`@?B*RIF8@u zV4M=UM|g>6;Gt%IQUXM&%n*)KAL!M?CMa9^ej02$QgwdxyctR`C0sE!#5Dn)Y^K0j zbjit;MjCLstuS4ztITWF@<6JqZn|Nc3X88|J=s)}{R-oekh3+If?Vm38*G+5pwvFc zR}iw{)g-G?^;jTJxlmMTI`vue`S>u2q^#`;(F2eBkTz?@f?TfgiR0&`Pl%tZzTqlX zmwkS(`b3#%hjYS2K)}-sp@_rggDfYrDTi%j5V&`fNA^wKyPUWC)Clav-4wX;k4VICt)*(lfFY521(0#qOHNmbVs#;MC!y)coMHxBoqb zftA(^22NLtv#)C%b$RzJE8QEUw@Y|Hletx#O|K+*TC=x2Hvky$-1Wfa){&@N{zs0! zLhMUiFA?r@sqABeX*~Kc#tyVjo5Yl!L*1MR3XIfhz2mBQybV=#qE@SoHd*YyD@QwV z;bJ>aakHePoW~KN;K=<|MbhErlW_4TY0p;AgE_Z*NC55M(%7Jd`MToWAxeD*IF@pE z-Ng!iw;W=11=cnp)!qj?S95tr?f)U9n~i^KA%_?a>V2wGB2jZMIXo%!`jA9R$yuOaL2w>I*62 zxx8$Akt5h}ANV)(h|nnBgT*#bR(qwRGx%uIWdR=W=9s3oyXk(2p)?JrG!spXL?50F z(l`A!s-Ufo$PAX5tgase+vL$D_ZeCPFe*3bXHmXTS-W zDQaD_YP~UV%dW6P#%jgQ37Kfs+Gr~io7ktpa80*Uw9Ofn@vOvLvU1pIW0ev|>Lwhe zlH}yCJRY1>3{VmxC80}{M5dFfYxaFx*#}fXLk&RU6d=4F{mwJ_zdzy?|JNYiRvuX} zzf&u}+abRl=|3ORs;6(o8t$d1L!Bee*5r=}&kb?1?g6Ay-FDD9KZxv7l3#YUS zXB-OOg%r-_6n<H8wA|6(Y4HzKe5>Q}J1rXd&YJtvfpPXw;0`nX1jZADzcAyesGoM>$I~%%ew;fU zJ5PW2jNNe$|HP91X>^=ipd;iT2I7u;NWbcfy!O}3_|qk%pY-jRgE!mgocOu^hdKBY z63LG@`-cBw4n7+H-5Go_{pID)CDl`m?VdG~OPocJ7K3 zHEXJvsP`Pcb^Kvd<%>HsKL#rPi=kq*0h8hq2EvWA!a}!~eMQm=@w6Ns5#)k;a9!x^F9CwJpz4GbBhtBhf`UBa?T zmwT^1+GXoUe)v@`1^Y;YSu_AHs7S8YWAOwuP|V*r5t&#-M4teWBQN!b?R6469$VL| zU^^Y6Mb}_F0R@jiqA`_$eTv>M2}2&~DjiR~#tJULPxY}s1`3aV+IS@FSGl3imcP9* zDVK!+fy2GPKzM-UUac-E3}sWz|4@}yU+_uGM5w$|d&_KI^f|)&A^cvg4=nMoiE|ZW zmp^|f*C^4RQrotQ;I_gMdKT?*z=PZex2?Kn8pa9}Akj}y5T0W-;@{Rrjy~z-H-{;8 zO@=7=vO#F68s9=^^$lIVZOtCq6^T&V^l91XMw6DGtD(4zzHHvu#l)@Foumd&2tSGD zaMr9HLcve>Ujq#XMM4**en0)TAr5ocr^^+1`AGx1(F z9_o*WLal*teJb{=5I0&K8rlqf{!YC#7b{W>TVcw*J!~#fF7X|R;^=#__}Vj~HB)_+6(6go+6g>-+RhNiNzM zEZ;bWB{58D6pc2qhj4kRkxM_PkWKD)P+{+1bc*HJ5zDXE@d=R~*F+!3 zFqAQYDtKz9Ka87rdWe_ev8No%bv-B|m+4dSunyS5ho4v&+F4?5p#QlJKm(_V@iGOM zigD+@Q@(L_Do`UFi@PoWDPh?Id&b%&=#!~i?Fx#=^5}nV!dMF_7O@@=1|6^&C5q?* ztIe!-o5OeOiKF)gfCU(^O2S#tF~A_ft%Z$`fUHAcC0t;jAeNt z0%r<*WjB?l@23A5k8oP!%5uq!{IqtDtctQthMRlc@RtRS<-w1JmRks_CgLU{1@9!7 z$9Fh!>by3AJoQj3FXYS3JjB$rQTO5Y>EQ~i_UmQdkk5$`!0b#bTBYl!_W4M(-Z3+? zo7PWA*mP&2a0g!7G9xtVa!p`*+<{TYBQEy}P8dbn^|0@o0$#M${~U}^hkH@FW$l2R zw{F-J>5+R9V*tY>tM)Y}cCye*=S%f6CqH5dXSe{$lG(Bi>890e{DW0YvTaSzO$leX zQ&uF(MO2BVoNO2Cl`cJuZS=C_WR+sC&*l-QiO3QJZ~m zZ=;FiNIm*vm``29tmlU_^j>l=YF8moImSn}I~S=1haNj+|H3wN&Uyp?V#KDAqNuCK z_Qt$xgr9u*Nao3ppR&$;Yup?8VvlnfS9U0qksxtZFJ|R=LXCH`THomHGaI8#p@(7? z!y=>XqgVm0*z~=h%M}{-!9>~|&$$QPH?v+2&A)@Ts9nP=G^|?s)(t&wD2&W>La0=> zhzS7BxSV|+Y)}EO=0+|;+4yb!7;XkcMWFAZAAwh-~vfXZIL{#`H*2x_Y?aHWh z$PTo-Ok!_EiBu`)oUE=g8wVlRgjDZ?0_!o6%}u_e%cOAHGY=)Cg7Aa0qj^PFL(iUa zJf_F-EacE_V#Z(mFne_KlNd{~#a-?A8I z;*HWEfSZOLIKR%N^j6>An-eM4WsRhdrO9%`HG1vE?@qW}%X%Fb*>w0RXD0>SQ@{2b zy07#8!b{)%=SvGX579cC3bkm*$my*|Z+sixLJ0_Qb;pKNa`>3@-+hTaz7U3$LwV^L z-_=w2(kcQgWEUJ$ZM3}-nPPS~&~LY}n`YNFJ z?}^?KrZCMT7iKQr3o;IwA*c@^;UEi57%TdKL;Y{S zC__`*%OdrL7Bdh@nJX?};xSJcHd{@x6k`oAP;O9C3ovL4+OOjtA>S3@BM0N-RTo&h z0%T$ehU%LbF-euG%dSO7I|Fi})tF1eP3&Av@Iekd*rXWPaeIx=1~FH&?Y8UH_W&?? z*)RlEL&<7?QSkn`bOO5#Xwg3|26fhJT9;xIJ6@s}y?VAG26pAWMvD!^grYmvB*R8BR1S=%UZVhzC{S*fGTAt-%uh+sMq?L`vf>sC z#0?EoQAbEB6{)2+Is@4J_HEVC$rQi_NY(wXbpvVtZ=>Q?;gaCB6|HM)4%gO0u5IRA z`_gi4d*T{x>l#3a1kxr!97#-}Bv>wqrIp0?oW${kgb*s?)-K|8EaDF>Lgp3;wHApy zFB1Dwgc2&2&@Ps8ES3o^mdh=cZ!K1QUc47_i}x3cp8BV@CH*+{&rnJ~QKkErbR4BS zmm(HBI7&ZMrC+Ja9o@N7Rdt?G|8b(K;Y#-}{{p24&%HPD-7zwMqN!ydolfc3tAAr^ z{$f=64J#c)eUpCLnLF@Fw=L<|Nw+Fvi+8S6e;SrQ^JLc=R!Be2Qp?-u@cH{?YD4#q zPx+HS??0mZls~=6t(i0{p)*HhHc4U(SIct6_cm0A@bVdfplD4>R{fwfX704aa25L=|lt>%xLZEv=7Ff+RdSxbez zR56HE2RQ^0a9dmWx_D2+rJG~VVCB~Q1JqK>s1j@$vP3cd{*_0+yC#r1UGjkWwA*b; zI1lY<^gbHWa*fnEF4SM8rxfY+s1xCsu>F5{FwMP<(zQwKi!h0hX9!Pwi76TP8rbPB39^zXwrZ z9ssvaImx}i+{o#@5Ppa3_|(G>x_lf9L*s?mA}C!;$6c5XcL6y3#R=s=Y?yg@2TQ#N zQ3#C_awxm9xrmL7E@Z_oJdh20>z_2lDK3z-Y}P$xrOB|VL6F1Ok_vX#?ZpuoS~+E zB_nblSYT2X2^4?*WzC5iemrL=4)^>i?k39%;3wuGx6Up54`@ErN{|DaBeUmC78{Tc zL~UtWBIE;_*O@yQ$M#$?)*pYC&98hCRa;YrLtEys&c<<&$4=Z(DY^9Hml_}QG2LSbQ3 za#j{goSs-*ss7P-I4V@!6IS6V>+PVzw^koy9XxBaD~h=PizVw^g&?!x^H?T`4~#NA zZF(dSJPQ~1lq$J-kWfb414xGJoSM*ZVQENV`OGa0aO5N%rS+EHGH0Sp11aiDw&p05 zXZ4yW52fF7m$m<2SE?l4Hn!V)<04mYJHKZ5;8IW>X5Gyq03t0*4ZNytH0fGAWiZHAItXc zb9c6-vIEb=e-q_x`Z!?{lX7Yg{sba?-E!pCs7poSYwvI-@a%_+r*@V5NZkvq7X=(* zG4a3YE6)FN7AtV(sc07m-stdK2~d^dT=}AFtg5ZizDBZ-&sx8*>gxJq7$&bYh-auf zPYoEXjT1W16@7xsRwL9=v+7X*;I0h7Cw}#~p{q|Ih&I~}IQu>F#92w*SEcQM(4=qn zr+Mzew4V<`kx4?4SNfoU!i_r^6~cMn%mW+>#f9?1K)V|^8o3@;-#ax748hKz0|XUw#$16h~@O z_{!1er~q0DLtE|>o@!FKByncgb87ay_(PNU%EfW-`kB@igr8kb{^g_3CB_6pgHGfX zUg~?FyS4QsJf^O%ds|02`O#pzf&b{pcAHVXcXo;xB>TGgTeI6iVYyMcm-@(Wa|zlb zAY^0T1%R%^*ye~v@9LwBmpU>p1_x@QY9Dw2?#j|$I^s`{sy#F!O)D*BpE8YT1Ux^g zf&lO9Qg6Eun=I1E1U^KLNpAx1JE`!27duSaRwB-SYqNbZ-#PZKqFEBq@RhdrKJG>J z+Ludj0kVnY`zlM1P^5cS;aMfuM_2A0x%5{4jrX&q_MEU+-ox+qYqYZ7*xPnEZuyPR zhR3VV7f1&(k5NDIdp>#`km;lAMB>|cp>e69K{Tj-h+F8)4WBzz#@o+Hdve1t!}w+> z_MA$U;(KcMdY>&~R0)@PN?CI^FQBcC%b7no(qkg3=d$0`0lwe>_T1ykaS*>no+ztL zg{P3OI-So4YYdF>uf0dtlu%b)+}SIS46&#-anOzeJ?)# zxj8iYUfU5JBjR=ILW=l>k>2lJhTlobZ}$?OxrP zFEqgW4W;lhi#I`9_jvU%}-RPY~t%9Lks#v}NEWezd z@Cf#DHmp8NmFDl+FN1+JglVLQ#M{G0)}st+&Zo-heU`L5yc(Vr3}Z$daZLy5S_Ktk zTfS3K7Y0O@AR~ZC)kpp@KnV1izn-{2Jdp&b&-QI`^IehD?RL{`>yHQd0q%KfN>e~3 zHro3UiMJ%dd;B89O0;TX5+Z97Xw6w_eI<#BBtY4CBCa0T2TO|Z1LWY6)NFtgF-Zx? zu=#O~OjvRvKx1`N>7rY5MvD5@CfcVfIUS|ryqYXwr9L2+l1T#0#a!a2*s*A(SPm!J z@TBJZ0gTga4ct<%;ZyH#Y8rr3MOxr0lF7-EhXpXdNoujk`iFW+DzhvlDZp6-d4j!4 zfRZZd)p!6$3R?2LCy$Mi_8Ha{{eA1ieP25FiBk6gB+>6R|Bqj${tstS#Ft{UP>Hg3 ziK=6X`bX(sTs>GNm)>57%^3*n9_8e?}@LZFY`r ze>kYWj&14j%4s^g?z~)P)SPGNIm5KcZPs@h5C|po zjscV+2%&ckO+dP+R5gmyQ4kOWOX#78BGSYNNEbry8hS^XR7C^@=^!8onDYklc%OUb znVGjd_w%kbbJogY^=5yYItOhfe8Hjq>PrU0nO+j*`Q( z3O{MjSz?H{%$|94j>|GrEAzDxhx+@<^7KpNR~A{dTB-UicD!fpUg!wAHH1<)U`p1#uME@!NAOry>Gwjw(C)YFG1dXHW^B;@Uj0f~y)sb+cQ%9(` zvN@Ko?k!oG_-n!CKD`INf36S@czZFGF94>F`q;YE!fss8ZUQO!KF&9t?k8R6#|wg~ z>s~w99(!#>0T+k9QyL=mo?%d1xY+Kd#Xg?%>>;~O%evZ7Rm3CO?*`rYpuOGM;vm{f z9*9R$q0U?|av17>6Zzn}h{jGzW%VBvU^l}};L^Hzh?wF>sK%~3gD)nK?*IkWacg4j z!o5DVi+2k0z)SM=m$QijA6-O%=-H~J*{1Q(i^LC1R{iCLc_!@CMDA`ET=3TAYfvOQ zWdV&063dc=$)mZTX*-(M^}TknU=3gi6$MWV9hFH(ItOODVJFxHe6gh!l5{C(S(`uH zzf7H@#2nI>EOoWtnLRQoEY z^lfm<73NDMxU8%O6B`_!f{3W1;ITRH#!qa7L{xR)zpuv^PCxC%x~ZLXSxxYdNQ33N zsR=-O!2}lyiU7)>rBl}^stw*jFRg3L#%|b|!0b-a_v?g@qa#}M1EgI;AhTh>XiXK2 ztf{*H4W>d0ZE-%P%6nzE*d$@9<(9JTmf=oDg~=_}AeF$7H=_$fcE|Acq9YD6$2ekW z(%$9tS`fQup7z__V-XSg!Y<8LIOt_(^M*|FbbPg!cc*p36|D4gq9W?D-R>yXVcqHYV&Vk&-oiut6l zh9#+t1NYn~*v6?}qaQrmO0+9Z$UoswTPn!HKx5@<#S-ofNtH7xd_oX58_=oe&U)-9 zFLH%lgGL%o+-4GbX(<&JI#Ne-3gU5}7j95hnnaRgYA#IP#^#)Fo)UlDni+6j2iMeo zP9qNCp}tYnU;aUqA7<^=MC&9E7Ixu>o$Jr-Pt#Q$59o083Wh6^cMH*XH9E-J6m8{Dy>kUU$^W=0x) z8-4TX=VAfWe#zANN+%;?y8nvehb5)wPNz;xd02*6Qws-Vu)zFPuC|Y+_5x_RByI(i z%m=@vF?lM-ofpPhV%;Y92VT82ed-Cv%-WI?7-IWyLO!ES99zaddD!)m0WmdYZ;B0 znjSe@Fx#u#h% zPx<4ib?gdv`xD+N3+cT5076N%URthYn{=V1UMp&7>|eo`0NTZeN?wZ^NWoqgl|EUy z6G?4%`=rdu+am6gcPI(KAEl9Fil&%#Ux%d%wS({4HR|m!v*Rp(3#i z=`EcLubyUsi40JnJi>n5D!=I0=x8?iHKrmFMmV9`t(YDn?eGeH;+yvkOZo9sN!ASo zuy4C7+qFl=-ZujuT)uY7Po_NQW3sr1Lf+aH&B8kRwDPN#SHh~yUj(4iBG>_znw7Ul zwf$oo|FHNpa<0De6Sf!&sOHgC*?m#TMwkhlw~@k z!-f3=k-p-AMr~zA13Gs)S&ijnjFm+I5%F<{H(PiSx1@-a)z@f#S@5EoFM% ztp=lkeqy@8LAW3VO?|3he{7k4!Nf48X*6xJD;qI^w z1$`yzTY(8xZ{tnJq31Lovo;5qi&EQUJ_a$%Urwer+r%caDp|-Rrs8CcI*kx0pjmEW z3L3z?9$D3HOqr9zZ5Mz`Z898X!q$B3bkuup5_>|L+@<|GVO} z|7wr)`Cso+-%Q1nOy$~4)rrj0dzmP%EDhx>Evu}vzFE2{S?6lA3?{OS_OeX4UYu8c zalz`vCEphoDKD&QU)W5%xU%;G&6Ry!Is1lHww-UbLrS(&ZMMrq_N~2aH?EvJ$~m4^ zId^??d{T0JYjf^TRe=1~5#ar#fb?N6@Iuj3f5^^ZvL(S6LRKTW=m$u(5+Uv9&hqg(mN*gYZ; z30?f_q5SJI{#j2YbBGR&U0t_BWA`tX?&1~y!(j0dis)yIm`o!gCyB}Ip+giX88Gy_ zZb}9W;SYhJho^Ait3v~~tog8FTGK%`aDUT_Swnr49{}aCLZx5GzD3hz;LBS!R*s$=3$f)QTTx?u?!sEX&pC6mCe`7x9l5QkA z&Lul!=gpEhQvNZdfkUXyik0~;ew^7S9r*VmfiIyUMM zT2f2Ix+Zj4Y=ayoHgE^B3kDHEwB9aXJ3*3wI~_p&bwC%geR&NGCG^BJo#-yy>|_){ z%bccxEU))zc|-y!8AROH->eQtporQ!QD4E-$oE@dP5qbKoeYI8a?0xV4clY9`v+c1 z5LJNOxQoZT?eUqQ_ut+LrP3)VK#-`NDIpoR9eKyiQ`M9De;D=-1qw^JL#}Z183Gxx zhE-H2@Hh<`k%Vdg8A|B1qO7sbR3){{I;MpgomEu3Xrby4VUSHic|$1guhP!MvH$R= z)zmH7TOBPX#boL`uHiwb*rgHO$~sMB0*~>8$;tq{42RxWxg#Y1JzW`YHUD;2f1a=xE7v;nbf&KvXP_G&Y zBZNxR6Q(Kka32`xEz0wsBH353^S7j!16jyc?Kwi@k8mLnw+Pw5MX3)%@MnJfaAW&1 zX-NxGY~Uy0UBx*-+lBDJjL&P~mAd=`Zm0%+UH97}@YyXl6ItdAQ#PESK)dX8;DXe1 zig0p*_{BV!4jvWm9jVP`o9&O#Wq>J;VP+00fb!=gp&`TLU?viE#OKy!hX=HLEEkY^ z*gODD(D4*rr97H%yoPp(5I&|z^K;k-0P4ZaOre(@=Pu-$+DYN27^E%rv5wQhjbfR7 zm&WzYpe42<(=%&6COy#`2pXHX2aY9yyj9cQ@x9oppA zumHYJOCT+P-{(yKaTPs(z|$Ipk1j$;O`#HK1G*g~Z9RWlsiY&`3-I`LVAC9>lQaX$ z)5}CxxQmBiV#0#5FR|ej74?;7g&04PD!8np(uhh5L#56vgM;3gCuvk z;#d>F)nj&$=?78-5nJGTH11N%xd33qHaoO*UFC$9Ay^hkZndF6NwF9zJrT0$o?j+R zicaLNC_H}0PMQ<&hEjV7#dt|LxczP+#cc{OqXl;v7r>ZuGU3#52tr1wh#sPy30yCn zwhk)+Wank751;_`{2h^bU4~j`u7&td2k=vyPOf+s>=TwKV@kEV`EQGHPifyDx*-IZ zqRSBauzj|tp;7bpz%794c%wni_K6mAL!tMi4<+VybF_S3lM(OVnwB}l{dju!+FTVx z3{;jJ<+ez08+{s!p&3ebqX6)ziY8P#@Zg*lB_d1d{WusUy9?DX&RgbH;G6O@B_eY4 z-{#g_^3v5^jbh}NanCk_T9pxTkL)QBIYzDLnVZ(q5oIT2lIx`@!B$oBH@{!Abh>t# zm#udBvxX|`&0~NobRC!Gq)sc=5(8H{iFKbEnhGIAKj7q|_(v7?6$+x5de7ke%`=&i zMX$xajzJr0Wp1zJzaEz>E zi!{0AWndiFo8lvU?fg>MAk`v9_KYKU( z!Rc1UqRmEUbAKqdaucf9wbinnwP9e~V-#;}`_eY$IO^60#ZndD=- z%l3ln=000L6g+I_Y~HFraiE)1Z11Z7_|$#Jdx~|Z2aJ(RdVb%l`a}vPWoqqIdL%_7 z@2vqB_$D@HvYQ?|UTJQ={?wmzsa(xxqthrAB3L-maW6VKO7F^Mw6^4DoE+!Ni&P)L zF=_zq4@p|JIX?9 z8MXKM0YlkZ;K$)~bKrX2>$gkb```bVA!=U~9(el*P0H)e?NMBOsE#{!^N-{DEpivQ zkZ$>bCeovi0sxN~z{Umf#<wNohwTvo1DP74EyOMKMlx4CeRSEhk;6OF3 zqVmvvj^KwcJkRBo%XE4_@XwTqlGV|8q4+o`0FBYp(e+)WQhL}PggSBGPf&NrOgD6x z3?_iG`$(%NDQlUyFr(x}Fn+I_AF6hQ1fzXL%Cv_yA!7YfULrE$m{6z6K&j?O_Z^@R zxZK$wEqOTTkMme*L6F?ETO+f!86-ri8bF%G3^8kp=}XMa%N-L8^UsbGzWt}xl#t5DeefRm=2wwI@8V(HEn;! z%HwQP2b2;i|DnvCG&pvBu1s#iBPt3PW!nryuKT=Kv>c6B%M*$YcLTU?0%iME-YcrM zdZ?~Ksn>NCgizq@O^D5yaxt@t-%#}TYUsYA;?bp>=7EdrkL=IUYlOyzB4U|qOuHRo zLjmEO<5EQ(v5D&;oR+cVON+;ubf?bpRbcQEn))#RNb`3*FEAjTZVJZs1<} z7aYn4jDKFYM*r1yJ4NovlEF$p+p@p#xrc0}pM_aY{eLRVlG#e+wyexm^8HGN=>C(f z`}>L|+q&fD?9X`e@A53!%3UF!uw<0(Pngo-rp3=ei=!AanU!>i#?7kw#YZ9^uQeUy z#_J&hcXIX+g>=M0`Uycggx~(|v>v96e==_mE!+RE$fMsk=)dmE-`DNmHt>HF8`z6! z`WBGlI9#&+YnL^q4nmk@1a1jUue}CP@vPT>Ule0}4H7O~Zz4@OBQ-aq$u{sGq$cb2 zX7INDMjQ9lNU1YW5Ao6t`bTMRIz)0@O4S&1mZjS%3VDpXB}ePsd!)-W%X(GyBR%@& zm)~vn)BZv0smRa#viuF-vEHbDeVwOnLq@jXieU?|i|5-Bo2T2OU++Ai8@nMXE-!a8 z=jr(2qKk@VC72zHX`(q*J*@!~!y}p~=yAL|(iSoVbsD+l{+5|Yg{fV7xhw(@ zY{3w1Fiej{X~LtuSMSZD`VksnQ|l{{qoU?;F#K87sxLFD#l(NmI&})RD0my)yj1`C zRx_p6=q*192(4@5YJ>1vEgc)J;r4nZ%bQKG6yo{8_Dey=W^lqJ?GFi3wHc2F!`PD# z$_)JL;s-k=L6YuZsU*oqOH#Nin|sT3*Eb6120{c zq+(vbLbAJ7Mt6X^r|P2)1?fmp1pz2kO{N$y=4I4v8om->f4HwXgwqFa$A?pA^c9A{ z-@OSc&P|45i7Na=6o_nV(_Y%G6~N+y6mJCYvrq3Pv6|t&k(s% z2^6R_qT=1PqVil<=Es@bw9;zr7IIS`Z6rRt>I|U0vJ(i+7LRaT4(jIWe?7w32)QK# zWUzh$R*V*pd0~-3oEcR{q?x*Mqc1O^r=?W|n3yGC{!0%@$hxZU1t8Z0o4tOYPGh{u z4F<%Ac}%~a@x$|R=}V2^Rf{fT5hirxRvPDJP68e6pobLx=BaJ0G)%GI1M}%7(E!&l z_uM5Zt@`t8+`Q7clV)g-gEYDzYD0qz7w}ctPjWxr0;C_V#wsk?37tRN+ZXJf23kTb zRfd($=WQ|$8lWhwguy;1Bg3CLpXgb&47)!!=&pgmoMEN}N-9evy*d8nxXB#ALb)#m z);f2xRZlAH+)M&DbK`tCpe6Pu5rUY`ZQ@!7GTQ)dGPzx!kM_}x(GYkhyK8esn-a)_ zETWQ3NTRwh4&f2Ga09TyLuX>AmrAdZLQ8O%4d^0CJ(Dkj%G+2l^M(e--a|ir&z)<= zz0rHzCz?vI4l_^a(n^+>01LvN&rgY#mc)785Z!$TJKNS%VaJNL)}HIQvR=cYHCz-1 z5N&lrbj3cvd%65DN2_^j$2tyr$SI0nXLvpqCR*g7JB?`Png(~+d6hoh^gqWr2dI+1 zMV0d2g~BoO+L4ki|T-Yt9Of_7g#NisR&Pac8$QxFDF^4DFm`C%HNCC9;ZFM zb3TrD6h6q3H-BkedRSwpSj4(<-r?lP(rK?7BD*%!PIK=C0@!b!*yW+Q?)QHEp+vRl z(u%k1x3??Ng?aLi?O>;=%u_3Ns@4oGDNm1rNPB$jHzjs?D10eFQzsN}vh1e8NX}O@ zP!>%rm2PjOmuu)o%bS64r2oCU=yvU$o3L*-fiELw0Ar&byV{l!j6EOTxbL*^CffO` zRZXp)9xa!PD4w6ww`H*(Z9gmVAwoy!%A45HY7wKNro_pbxw)N=`c&!m?4_E;#Hwa1 zqa?6Pgf-Ik;%mWPsn(FC>Y4MjL_R~0rqfH+{n3%-x<9NIsagK(@4r0 zUnBZa3%JSSle3?CkOk64Js2-nbM282eIy`%Ay1uLk!hmYo0SAxwVON)K6C^!fGSr| zKYupSX~}xY56!sDjD2hOg{D752?lhkjcf0@Gk+E} zvOLKxYGQl|JrxmuvrGQ+tii3)1t;)}CBELx=sMajcy8q}frZ*YZ|((FW6oojciK^V zl^(&KoD(HW(( zAK}`sk7N%?OgF_Gu~A%m#aYT)|fFD7eTx z?t8=+&TZW52UCu>6IC;nH(wi;zzXXRCS=QchZ!DzGc)jBAI)A(rg^9%Zs=tqe5NGO zt9$fOnj03q{j!ZNZm)0%sv1*Lt{jb%kWIm( zi0q*$XzG0wl>IqW@(Vt6v{iBh79zJgkL2@cJ=EaP4;(z^C%E|aOeg8DscY4Wy=2R?y93-{ySv*_jUE( zM)WTVWCK}N+lm-<$ z3E{S`4#xrl>5V*>H`@6GpKHPdwA?n%u%zL@9pY67CG^53ZqlbIFeZWBiu21_bO;`# zhbjdEuEC(p9#zJ`zkA@J!o7^%8d6*%G!8DRBEZ8Ivpj*|3#s4$xMk@3QaHl%6g^0s z3?k|lw{W?uK=+RD?H%GnKXG!>U>f}XzTa{)#K%^qk-?eSznK=PO504UNL%ua0Yhcf zJAI7`s0kGkW+K-lA&l~$;`E1zQx@$+|G{V;qB^bRzMJ=#J_KTCNT(dGbb`6u4Kl1? z!2?+C&idg=$Leq%NM}+8IFLs4OK1pF;7~0?HzgnSfYIy?%@lZxY0m+YhAO&2%AEZ& z7@UDb2M$O@8uw719l`@dX%JVphF8IXfOh3cP}{$fi_y-$2+{S4u*z*^QT{&u~RDW7c;@iu%@iDvGj8?g^z~Q zAk^)v{62~s;mg=$X8`1WClx6NO5sCv``Kc2qk7( zibog2$lPy9pRO1|^`-DZgd&FZ%-JAXgaDXxS%8Y6u{JF%CX&E$txu5%r7JIt3c=WR z%MzixpT&cGJSk}Jumve`H9;i6pAe97X=daMAibHBmWi|w4qAV6GxbIgm0Jh|!SfM{ zs(#+B+K<(qF`!Cwp#XV)L!A}DL^y*%jI92|G*PL<+-gjpbUT!`Mao&L#US<_2 z!^+z+4o9f#73vK#MmJkhr6-3oeWIm`&CMPtTENQH7DC=>Q82j6gY|Bp9&2j`a0^NW zrYT81&DK@#)8M4GVWWe_yS?Z>k9l){&V?d=?CC%>GK`gH%bS8XSkpbkL{FsLf%b8W z*5ykB*l>+!DQQ7xyeLidpyf9q+qohm3#E5MnA4@xgpV(VmHFkfuuQdZD(2nm$%rju zoO9t+zD*PEFyoRE1D_vySc`S3bxGCw5rp(OOX|_)FmvtngvfZz_2k~Yo=ES~a%w)i z`|K8z{p+noq0{5i4^LiCkP!PUY8EDQNqQzrJn)5;+DFh?G;X)ZLAU2&ipeTZfeqVfg0h`Wx_2hi-brMtKlALk-qHY1o3am+{o52p1}w zyA=>DkqNw`Acxoi+5&MxzIu z^gbByU|vdWJ`-i>f1k)mc%9ne()UT{3~7IXwiMc@^?fh&G}c$+!P$8AASHjb%oSq5 zv-R|WAYujG?TmY~?+S&q09T(}eAAK&PanYA*Mnva?jh%bmhqQV#xw-H*-u%m-FX)_ zaE*>Sd-4`PoS>Y<*6XG94f46vPN_%qy2sP~w3y6DY8tqatEQsO%q2o~o7$~zo3@~- zy^*TdFO*o^Z8zU7f3q{i8}?mywtlL&A*XsK%EeDU`0YWV3}=F3f3^eHb4wvPt%4bV zrgb?pF8hW~;0!>%S?0}2*9Ft8o{H<;>OIPrBO+^1R7Q8l>2)t%JpV!98q7I~<^sHg z$wd5R(Maokk6z~x0DhE6Ur7ixT)s}?-XH5Qsw{odyKJYjKi(f*S)OCK;$*!)G1gaE zS=GC8%Wr>jn!c*K-Ej3z>i)YgMpd<=y{mWY_TR5ZSJlrOuK7;xPwnGST}Oy574M={j)hZ=2VaR2zCYg{|{ zq;D%*<;Q|aOzm)v(RRM|k41|&wIfx1+eLmqme34!W9>%YN>hI67 zUDl+pNpI@s6yALA^CNBI85+Lm81D_HlD2Y<8y3yq?2Xiswh1vm%E7>2i8#CeT-8E; z?(H3U2DIvjp|~TrfSiRR8wN)$vEQopXp-RwY(j2^{bZXQIS0RJn}2lAIkp^-E z?ndw-!{pEW+ffzl->xiVRgqT~w#f7n@~+;|sNSF9H}b^7;jSK;p4s{K9{|nY>w14m z;D5y7eoEj&kKwOW6Ea4VJhMmM*dq@ukah826!D)$u|L5k{{m_Jx2pYH)&5UWwd;*g z;X=0)bh>Wj**zPCIv7S0^i+o_u=s0p@_6@1v1yF;H&IYtcxMbc@yR5(UA*d@JF8Lx z4%4|~fN1WLm{0Ryl{P??sj^KIgZs3WdMM~w58m~G2LC)JuelyMc+jkPWe&wxqoGb z;UYcnbU`A}*h>0B$xMwgy+~9iR4=H(YqcHa_WdoA2i*xo(mvQ`Wq{u{7&1Te(O-y9 z)nATokeQrkA?azMbOCX=GrEv-Xjk=}rfIhdrh?mps6FFZ;%OxFg)_CnaECQd_S1D& zC9ki`O4t;`=emQairB!wuQLEsA1+#5U|^26`d#`KZR+$y2rbujAdiSYRAgFR3n%Fx zsEb-ptE{G-5uh^OLdWgF)SYql~h2^XJT*_60qng6r?4K zrXbC7z%}so>aqw56-5oEhXl|Df74y<0*y|bZUjuV7ZSEhWU%@MrjOhJis6s7r}qc& z@-;z>>j0dN1E8FX&x3+cjWlW_6yh$|UrCxYN0<_w~vHpfkI`Ag+Lcm;r>IKdG+l)n~==xBla zEXFlmE`|&Midh^V!K?#OOrSWWh-XMMeqfGVEF%LFG~xpXsR)50wc?4gme<-cR)~xa zepYOX(>)rwr4GJ4IVVp~%kIlvhndd?2);8fXXx-q-*yQCu758-wLIiVIuJhDrC07D zApqpXP7b9^W4)P9rPIi1%SGJn)e=WQ)QBmJ8SPNFMT0a>ISQ!=yB@9M(_j>Uo8=M_ za8_I@MO2OARG3}2#sv(eqnQTHgedkZ+o>caIc?F1yXUlm(0S;kCVCK-gf+h-o0pw? zW1u<|%j6*Ks)Mo>z*xzeUVqH;fYw$;iWr!v-Uu~N%+j(<49cGRnk^Ck$x^4$BqMA) z@D%nsXB+_($Atl(`2y;Gi0jw1U`_Yq4Q6_o45codrqWYvqBk)aQs+QGPzVRk6avVR zsVPf^+xCVgP&21<9Zt6kpfN!DpJbZJlo1JF^yvpB@MU0)RA!vCOVo3`2u##?6!aVh zc>AjxPRseDn|dsuzSbomhyx>h@{7)-(GD}@{sd6HgqS0@UiZA?!%+IPHi z@UElH(DfN$|A`c}&#>^d%crQBpqTF=V^9_i#A_|TB)B-Dxp;?$s?6Me+K46w_(q3QgL{EN0o#V}yY6h6xJ$^Vf(`Lk z0nrp)7ZT-@9uw=rih_X>i6u`&&y|xjKf6=TrBFbB!wU&3hLw z)$P3{L{}8r8!lN*?u}IURTO#mE?wE*`&-o>sanzhTdMZ{hu@;r_dge{WDeiaYwTZw zF8@iN<2RY_AE0>htk|D2mb@bUOUeF3^c~_1^bc_cM{l)<)eZ8p*wLc&Pcr;pHS9l7 z@V|k4N1M?J1-}QQf3HO!&WGjKA7Ty)Umao&iiwAnj^BWTKeg>II3JmDK$f%8ES za8X^GJ8Ep7@OQ{hu{@OY96da5C{8=1ZT2g@9?*Pqy0{rY=L}!j>USO{q6WX*N3{-F zFc?x$Uw9%D*l!uy`;{B%$x9E`#lDp9(>8FGSD;rd`Swm+0oXV>(PFqW#dF48VQK`~ z5BU%@I}kL9F*eis7|a~ID~m+-?b60*YJ$c*Z!=P`T&`}c;y!j^DiUN~+(5}B;eaSZ zKwXFdjE2RA6f+ruX3Y~oW*sp|8ykm&h9D8Wn1Yo{4k9&xO2E|se&e#j6vs$K> z>>bpj)JLY!YKHgmKE`4|zytoE!jD8|g^me0+gQX0wG~*WAOvz65XhMXco2=oP&}2V zj59^D^LAL#GF=1mx-`-{TQqY|p(*%tr@`MfwLTHD{h8;QC@ics>FJ~bWodh94U>RS zx{sJKrCy5DE!qr(kRUBx{CzE%X8OD4*mAXAD%1L4CIY3l*8OQaqb1NNJ+LL`1b<{@ z$JCG_4$8V!>=N1m7%2p_TX76H-rl{+&&8po$^`;`a31I0Q-nd#FJa-h%uN#<_7plQ zwiE*x$spmeT62-0Ff3?98mo5^32-(eWNfhTcjYMI69~i!Hl}MJVdbcpurHty2(|u2 zpF21GwOVLh^kn&ugJO;KH6^d|>t$@O!;whMkqbB|{jz&tWbViAMA6^S_0Uc?Ru#35=Q;vHGnMB3XIMNLScXebKD0!3xe~Hyh1lcWn72S zZ$aow?F^n|XF$L#>iSX}{#Q#Q?|CNJeK?0r3niV6eLkPqN+ijB zmt$pRLro7gnNx#pq+D)crY@RpfEOPyGYROP93U!Qx?qFGYpL*wGN_kQP7`xZ!JMtl z+*K+b04X)Kv>yY*0Y-C7)qz+;ZR79XLL{{KX{?E2 zh|wg=3q7bi!7?`-O|LV5TelYk=}2&89`ry)iIc1O5JS{F)9f+@0nq%+igWgmqgkd%yLccwkh_N zM0@wl^6l@oqv%UxW9Mk8kNR9>G>q2^1ag}x-=oj;PXlA?_CysrHNHNpC$ah zccbaclG+XCq*K55I2e_sjP}gQ*M0AGi!Mu>H<(wR{NCr&SC+ohGk<#j`x^{>IiAY! ziw5^zKh~%`gT435S(Uv3Ty%Msu;Icv>%GCGzVdAHMwXG^-VmO?;{UN|b@)H=6q_dc z+kdzHk44|V2{r$(wcgKw^KY&9PhR}*6;2yU`4hYR z3$=VC?#O-JBib_Apidzjdi0r9o7pu-;_j%d`%iC_M`N&LLHG8jrW^lAmUX{YVL#0M z!dQ_5(SMSxer>@14n+TYqa-iE{v{dxAM3UME!O;hE&6Z}U`AGE_KVz{{Jg?~qL+l? z(vtGB%8Kf$+M4>hR}I8h_~w?@w)T$BuI`@RzPQ%|jYETPhet=o$0jG<6W&aJoSFUf zd2aqo?7O9@mF2b7jrGlqg>O5%-}m+p`o8|L1p@Ji5D<;lKbTJ1bP%3v-k}uaOVD-C zXbsQfb9&cNlGz>uk_c~6EIr;CKZwe==`4NGeO<&hB~7$!uJOs?5Kv8gws9)z5lur| z+2Ih-cZ$o(<)TA)y~81(?WCas;}WMSMbIyMDUCIP<6OXc^w!%&&?n$P=M@3P6}2=m>B`#S}*Lj_gdQ}z4LmS(#dc3wT)kK5c_(z*NL z)gQh46e0-WKUl{;oB<2vB2G|oeZech&Wd~#V7N4fmSeWdeU4za`tnhNJA~t7=<&NE z5m*s=hwEYD>2Wg=dle#?VaO4V58;Y^yHQc9;W@U^sKmip+ysSVRntlC9${`0PI?78@?S2(=0MZkc#vL})Jg@q@hVK!?g2i)6Rxxw$m|myS7) zJm>D2r`>4qC+1X7CB7C4rq_xdmZw}`XcSpfV=J$1*IbgQr z?ylYPhB%MM!A3_>Q2j=W$ZOlu*5g$!U0tj>;+yhF&E?W=xihMpeM6rL*Lzi;EXy>i zgQL3oA>5a@x^?&K$_F8`E0V+d`tR3axp_8jppZb)e zr9bzcyCOT+VU;d1-|iGG^`*&ILTaHgyiaDaK85epQeA!@a=Ehh7ILMc>$J=&Vd9GT zTJa)1ay@^qNOB{O=9%=@EUsr_o0%t#CAZR**Ce)|o;xG;Ey?P`$sN)Yrx=OdIA2ML z@3G;Jkb99S$4>4?PK+bYe^Dj;;QH$j|PvG0CI)@u#CXmW16mm>k5N~ z!u>tYBZ?4Tgs4tN1h~dcS0k}Puy0|3_JfE5l!y?+UU<+orfXFu9VeLE!h)^O^XH-+ zPOx`{hg^*NSm6de!JQZuYCOpQ0+W0ESV}lnk7=e9r+Zw`E-Xy*yg&wiOi4)6LD^w$E>-+o+x}hk&4OVy9NqNS{(TN z6qn3r%Y{vzHO-F1F9!AR(NifD}^T z^>xvSNW)Pw7*hCX;Nuj>jcb{=r{1Jtp- z4i6zXF^Xrw{X|+{C6u7uUAz!5w&p7#rB`EJJdjJQ-A*B8mj}diQ2MNI_QJ}|7*|Y8 zRYc!Dd|crwFO52GRYNEmHhRk4aS+}UMrM0O6gA56l z{^)g~y4h~rO+uD-rZB;R`xu*);RPEQQ(5(KVWF;R zLE=u#*p6BhcIb1Ko(ze{(2~Wa2+|*l!uf*;+MQZ$(r#{M{;cZ=>g!Ol=&KLn%_4%X zsecWAt2#5PN~F-{Ad5b6JO1)%;M1Ejp%pw8Ll*#47Wgv!f(r%r1-$8fA>9naW&jt& zw;z{XM$3VGtOe70Q@v{dO@}WS4JpwG;%KrTl{)mX0I1T9q~x+*3FYJ6B( z`2^{of!IGbJTh^e$;8<;)erhIdbR4qHP;sW#JlxZK;seK7`Ni5sr zjMWqXo;HzVv$=95^J>Z)>^=YdM?`mB7Q|xSE%kxhx9(&LX1{wXA21{w3wZ8V3ze_h zLlyERQDVEpSep$1}i+76EJo0))&aV3g9`rm2PPI`#7+ zmDkHzbB(YR%cy=8i+x1Gsv}=Q{?{S+ffe!H0uRr1phHd>TuTzm6c8|I`i3=aT}NxcWy+35lKAr}iKO;eiXG2qk(v4FN4y zJ*ew{i1r7i+krz7n834`5I1nT9q4-wrlSABU3Jj9J#>7;QQr-!I_)Tc!|ct|(eARg zjXHj`ht9G)0!S9nd0_|QC==Hg7>@-zC;nc)@PqWT4}wepOuF`i-@HYu>BYXVQm^|p zjyks3LqE(r_U|w%CBalI*bCVmi|nDaCV{p>5SSaZa@4UpG{Ah9M*j=zi803u#Cw56 zK$C*K3Nj>w+#VfuRL1!^j?q}^vWwxIWZZnhLMbe!A<<8u?DLM|ZoYcC0d`aztazt; z_S8HkL7sEoE8AGb_D2{-`}FL)i3Gr{`2gGYu$wtIu^&O!=D|@WfHQa}Nx1g|5!fSL zb_PtC=QnV9I}`@EoBk~%$0DMT5OS3<(9t|BiU_pc#W043kGVy7ngVNe?JfH6M6Ls* ziQc61-a*m2kp<|;tLoq;I|?qU2NVF1lG}rPJD)eu=sZM}XCt6b$i>3VO%V-NML_O} zxR~`vhykPWblrC=Z?Cg~dMRS^5iwr=k(7B(GD(+d!f0loY!rYH25LtQ%zbK6Tq68$ZhJ_;(1@(ps03PM(^B76E?i;B0{c1Cnh_ z^#Epi?CfapvO|m_KFo^q@#SO=hINppl7sd%$W6q_J~{EB6i^%w?p3tcBa*;k=!BM% z$M13yPQ0}TnE*HdAOSQ;#012L1M(zWJm3sFapG~Dd!k%tl2mYFbTUWyci6*ZwwLS4 zIbp#WdYr`w&X+Zqv~kXY??PoY{>8}`X4o#K=7rm4NO?U@twcU~xB+Ybo(kbibCplK zQ*y3k#wB zH5~6b&DS`imn=DF7SgsYX(siaC5NP+c6|EyZTf?XXE4rZuc!q8PI!lV&$PAi=56@w z{%7~R(n+0oP)gF4i6hfV8kTeHkXWk^j<-MNNxalfx3EhG@MrL*JikY(d@g+Q`7tgL zmgXm?7V+`?aGvmtKe97u>@tDjnT6Du?xLAcrxZCZYXzD#IqfXH=TCJ~F6z-d)~`)7 z3`am+^IY$I+`SaGn64bh zb2-b@xvg)XKetTJtjW1Bk%RVqu};W5don*gHt$7k-ouH!>w8&v-#o{W7meF5@H8oR zDhggXS=8?pOq?iebh^}fuCO+^u-)lGcYa~Y=fYm6^8++51GHZbIhl|~onBhKcsagk z^uFt*GDXpcMT6OsMO-(FK0E0zgct3#6fG_4tt}Rf953Ej)Y(2)TpCoov#7nFUmX6a z_{X9q8N%X3CdnC&d_xePC`l;meiQVN@#ABur8@^MwBczmvApB9a}2t z5-jCkQaGVsnjcsyJSituP#Qj4ddgW=3RdQ%Stc_nt>9c{ky)m+B&F6}rVcJY(~Z;= zE0?w{*VdQRizsJmF4u>hGF~d*6R0qa5WA>fF%wW>4m)XGP%$!7aXCWd8m#h_Mx`xG z*xtD^JEPJu;)H8=Wi+Vjc7dRWSk>L@RbJf!_adsUG*$U6@jqH3Rh<>6_FqB->sKoV zREI7dizujOpQ(;o;){jV?5NkoFY!Kct{Ht^lf1<9w7aGrSo>^=J5#JS|61*fZmztD z+9!>*1*x3HOSMq8x^gl03ctEr{B_lSY;^^7H$T=jsGx}|^#u1uI=ZETSL4&K zR#JV}RbK1qz5W&f+wgl`i+}xHANHgBb>;4Bkjpc$4e_}X5fn)TEI+47Bf<`dw6u+| zcSL}ABZWcZAI^=;g^iq%jXO(?-@6+RU`^k|nttdvtvELwBNaA@MmDW4HGS!B+JZH& ziZw6kH-C0+mMm;mifsO{)cmo#c@fq!CD!suzh&IH_s6{jPZDu4jc^d68Y=OI=ajT{u`bR;)W#zdO{qyST8sCbIkC zQn!D1cMz=SzF1GNevhAX&+EdT&d8oSOFdrQJwC8rS~s!Yd-}b%oqO+a|Jk-j|Hto9 zQ()zP3tj)&3Yms${UXQx9s~Qc6+)(||F5g|~y<7pP_zY2D@9iJihX3>u^)JZD{re}Z|N1=&|2!iz z>qT}>ZeD&t;me|8LP=>^c|~PabxmzueZ#BQ#Kxw-zDK?39~c}OemgQcHa;==?)}t< z-|tZii%ZKZt842UUpKe5f4xVM>oNc^4UaAX-xvsG{`nr&910gam!?~i(Hg-a^Xokd zp&8DjSDMusFJgA|9`yui+m)tQmff5B_b_$t#}J;oUp|H+LPTb;#}gf9!bGxjXTrrR zzsy7++eBs~Wk(!lqZH?IXQNfWeVL6xQHp-TX|Xweiq#b&<$a1X_#bCNlE=W{I^yn+ zXh;@rO>`=>16s@`B8)BcvRJe_h$k@wL)R-5 zfDklj+@;Q?Y5X0eUt`j-VWu;=1np{@(Zf{e7?R{k`di4e zqK8!rP}rbQq)lB6E*~+CQRNvt(E3)^n zWkjF|jQ64G(Qw1mhct#GXC=XriLxNg@-d_(IoImxTgaw^(5$^Nt{|P052L^JTvVSN zp=U%rQ!sm4t@?}FMs<#>lCrm7@VjfL&9g5Tw1uAE{nR|oVc~`A>-1~!+O#td19I;! zaOZ~1<1RB$$>mcSmdfQ>XUyj~Txzs@4x*U6XxM8ao$tU651DujQFjNVQX)REJc8m}Z%J@vG9?5t(?coyRQA-c({ENmib7rgb> zuxc~C=i6Spu-!YuGHQj_3cOwV#cZWXOUx|IIP&|)JISIsr{L2m@pH_CHdzH6F4izE zM%xjTeN7~;e)|xn#qPn)a>}ysjD@l_u;|G+-sG2W6XFkx5mRt{f~Xxf4&#Tkci_PT z%j(M}_g)YtWd|6~dQ{=tdoj5>JJ7!J(cLY*c_M61(2QA)_mA}EXL#hSUQpTi@M>>C zZc^V-{tfuGMeTC&7=hhvnYL=>WHk&j6g^n;4*?2r zaRG?~prUA~hL<^#K6nmv?GB^U54Nqr(xL&F8nJB+F4BAtATUFRE_)-DB~R$%!6T+B2#Lh6PdiuDx1rGa8+|h zS*IfoMsca8)h>3y>3jrI2afyk-S-(^q}+RNlZEhF@7fe+H0vnPEjn+L$3*<>mAbp& zb0b3SD&~5Vd+jOVVZD!yg26?NO~UqxO%Vwc$dgCWIK)%#Wr_J)37NoX%Y&tWf}u=0?VkErFiZK)|-Q zYYO}n;>YXKUgPp_I2338e_v$&zuiuN=2)unY^%wW)-ND84>R0Q2qHV zTS~c?MtHg}<^!o@YH!Ex3l0Xg_k9Gmb8?d63c)&fr378?>Me2o`VX$kBT!azLXrC; zOV!S5lsZMQ;|00;57IO%=7aXEURl0`5>LuE7|Q@hEY?W#@ujiT4)8hNZguO`Kp3Jn3YiB_|;O>El8C@Ya z*RL`gOSLUL`~hk2L&x~Mh6%TLC~G`8YdZP$l@gxk+04SlbDK}gCuL+l51YH~F)?7( zgSkGk4GVLQXpWc8n;$Jp^*eR=X+bes{KC=p#B{f*9UhpXo$Wx{6qSJ z4cq7y@lS<Yp7!k4b=X~!q8TL{E-I2e?up#%n=Y}^U^ac2;ei{P=Z1gL4 zDk@I^1{=tMZaoAz=|^NO1$_b2_M>f9U1$)d@BBodFNKB*mhu$|x??31(TlkB7JEYg?~v)`Hm$cl;6(USor*R)J1VjO?zR z2(^lWyPbFe)?}@Gl1J3>p1KR;8En~mCs-`&u~+&^?QNX+o3!Imqm2yqIQ+zQ7?iWT zmP_2wx8x!b+p@$1vi?hGKVhx%SS&8q-V=$7pD{7&#jZTum5F1cJvKjE9lq^~HHLj- z^9x_uw@KDhY^If|&v6ecB_%!Me74dInzm7E>V6Q9f)h%iZQ)t;p0*N0`ehB%1x$if3-y&b=RhJW41iE^#Q_YPD>e^;NnVVKYgepSbX`#A-YX>y zN(?K_UJ-UAUB-P_K^8M$djgpaf%?0WnVf^bpdpK*yreLebXSNsmLAcrcyo7l1U1;# zfon_<-#O!a@kDwqufboo(NZtQLPu78@e)gtf4;# zaVa!ELnM3CaFHX29MI;2jX7fZ@?r1wHE>dO&2?eWM6jtQPEQ_kc;|NU6SggS zLQHSJS~jybCyg!EaH)3~FD0HoQm(UXQaxC_mw|}Nd5pmt1Bnq{trC?9~rVOVSSX7!$9>wY{)f2o7ElR#3OD`D~su9J;Z+ zvFvO!Vn?;5>3B}#rRQ*yJnu8C(^|$(P1AfL2OxIHSU8F~n)1Snpi$ zn!JPrSOgb783iGl1YR(P@sMUR@#;JO1^G(;SE8@q2R|qOiyrzz`nVyC+wu1??k9#* zn*Iz!A0?;_H-9TutcDk#fAGcwIY>nd_>Y3x%PE0?rUoop4W%K0BJjaRkJdR6KMXyO z*ya@}NriKMP+S9)wSjx(Xts+v0T|{-8tn#c^MxZP%YkGh5R1%}06aI){V~XMJ(o&< zKsv=3^k50d&_PoXlpIxm_vPtJMNo2p=M<*;Hy?mDyy1vs$KaK7_|U0HNsije8iu@4 zX8U2t`-O48FzzpfaU4VST&WXoeu!0>cCcKSTB^?MmN5{@$T}{DnRxGZIe>BN^a5~n zCz$T*SL>G zrq83B7wIQUZ6{@3P+!n`JRFrCQ?VY+qI4y&0#!;qkoeM)HY;XuCPp zNjtd)QlAXe^)tDs`sj1?y&?F$r8~ zt7grQo0jc_JHOELysno>Bn)`q2yCNl%!$RR!-;UEc+&{%F)eH<;)dN#&+DR)ao9J; z+PMyyH&P)fc)Usb>C~Wr`imT~nl8J5XjaBh4z*{A+dbCD3k42`f3O&le=w9HN73N@i&CQMD7hE>U zAa541Y0Bv`$16wXZQOA3iHeVm*R)v#pUNrv*nc|a{O5UUM*@z$4FBXaTj+T)5z1KM zv z>|*5!aLL9Fga4c>q=+TLBBOWrUEYZBH|?_hpU{IHoLhBpM| zB|5_bwytMruezPnNkrz~z$%B9=h)w#&~PjXy|&FVLSy@~xs0cL<)!rIIu2;lbAFb% z&_*Q)y!rXI*(%leL&n?ruWE9oo1Z5{-K~PoQ~nU6=JYkU80V3mXs3SKzN`4DSBbcn zf-jMk)ce+-t3n7)zDM94?e~K59up`u1UW*)Z7%~I>s24?`dp$;Pe_Gn%XO|%Vp{5u z`{+&6N-SnV>@zN0)c)|SiCOpZOOaEf9lMi@ab{6s2(}=;G?#Yk^BaBe*)P6w$1whB zQwjH)E4VSTT?rZ@S#7{&kB9Xam}l%(Gbq%?+X$4cxS;_j#F7VPG{zz>D8v93)02Jh zhQ?h6f<5cFK9dTYke`ZON&;xls`&H+acrJU^dKcyaPEnFNJ8NW)E<)rvq(!sd=RLQ zvoYqvxHR~(EQtE@J>t{vRq#vI8lh@*-uVN5iRWF#_1ANqvH-+ed9ATqR*qJR%u$Lb z@gKyB1kaXu#6`N7DxY^LXO{0;6%JfBk0SWYbN+kgKj!Jj%Z>BxOwy3cveL(?e=5)m zxxf0jdx;8TlG~i69;o<;bgBMM6eaiKfivwd9waBD=yo}K1VKghxSf?=I_zB=LK=1P zduC)=iIUGq8y*;n1U87!B!PfCCUrB~Y_V0sqU(p%uL}g4;liV*lMQRrq|D$z-t$EaP(+oEOX9A@pJ*-!syg6| zh+vf!#`qzflg?QXgb;E@_%0evGP___g6iUI^n;fTq>Of`mgD~G5?2u1v7L%zv9GuP zJ>t|SoB-jm< zTnu2_fcP6sG-z&gF++&U6DsCY1vH~2KF`C`Bdr#P_=N^%NL`$O;BaMIwL9QXka ztpDX(>u7`<`TZBm{bISl6w9?2X{eJ0#d~ycbeNKyn!V`^N#xH~JGsNPUf zT3~2daNiIG;?}-)rIyq!{^A%7^EqU|*I06>I!{AC+Hw~*@N#t?cJ}`?cj=ts~oK>OiH1aM7<%C(wL63LoZFg?DCtzK9F^2si5f-p^ zd!h1i`@DkIxO&!SYs0Tt7lPe>DHuTtXYsLaTrYbJgm!(4l@iOZPtC%H%moW<#C)~T z9qm)BE$g;9KiExsVyn4%`s_q-(dA=Kz4G0LLTG(v@G^I$&_k*Gai)cBc|`tEy{fw_ z4(;h3rx%f$5ARf)NPlcDg&}s~@~m6M5#PqRV5$yAc?O9QbO(qko5q7_ELU1_jq#Nf zW~)5sB-qd7@i+24x~kg?=!&fn14n6;MTCX2V>?&r41Ll$`glB^%&3V4fwQWmTC`SQ z5-vi3as;npacN3BG7^o#EtPIgEO{feiyk)?;;-Z&!E!}Wq#&7}d%AP$X@os9f*WkT zxCG1=$0VCJC-|krd`X|rXSQ>L9etRPL|Gm+g}m#6EA7!_p}>M;shp7PUsFMIrCrsB ztSF}Gze=`o&i7nB2Xw+u)_>$ixYQy@CSG z_~o`#+&vtQ3n6SxcKjBGMKv;Gtgme>Uf`(~;OHHVu9$x_{2(M|$=qgrpH?7=fjhi2 z!l<6Xo;{bF8*-{C`c-s)H9y{e|Ke+WqY3!y7cC{Jr+wIuw0)G!pNm7R#X+X>m6v)} zK;WTSBG;Mp>8xG2#637Vs#2r+z+T9 zXie7%sfoGAANz{s-gCV3*La#7*WYh^_o|0q+Pog-gm(zUxH=F#uNZ`6v7-#D>efua z2AhNnCYPknJ(mtzvgEf*@O95O5Gf5=&uHxn=GL)tSDd8#&A#VQvM~o)z9_^L{kq|- z7G>+610g2b?81uA7M$4Jv_PxoYgaZOTp2MY$4q6buYabU`tm6`8mP~{^Mi6OF3Sov z*Ky&0NL{n#M(ulZ6&d82{+d;6_3`Ey4*y`Ihmvu5_PSMcu$D!0&fKF5t4~)dC$36d zzMiOc$34*d!)JXkPDtBa{mzqir?>CwUH=sA4Ks~A5&+zX+tbJEL2b3Vxn zip09N&4$~!UkDpmO}IevlCpSr`p9es5y*b7zwNo7Y*pP(#zkpN(Y%qTVeu8yJ(&{V z*IhehnN`vKH}1KxI-if%OJLrIx+IzlW5qIQt>}?Y`se0)_q+3>f28);!*iI z9uS90K!@`(WcS&k94_?9g1WzLvgN2vi@?Xt&Wm~;|4!;)L!qf`M((qp2yQs2_B7_% zVe|DHUdLa(5`VzYU0t>j!MVnC~I>6_amPE3<`q3rVg7#lG|J#0Pinw3RK zPHEllL|J|VTW2-~!aVa0+A1_`k7_8JHNjm;zA9mW*y?s|PZ#G3gIc7Kdq@e2@>?0emVme2KCSguZnY|&Ksr`=kPOylIK|CY zbGpL`ib-3T8aFM(1%F}VH73Ywp^ z27kEzSdGX`NaH|vrV8+wR4(i8LJZl zyk_ljNcT?)n`H}snsP)wGtgxoaqg+NcQKnD%q5G?`mR`rPk%JeyM>%>k;kJ|PDbN7 zyE2zi$%_{F*=DW@J$D`_`4DsjzVW%b27)bdQo0>O684-wPXj?*M4nfiB`XCtoZ*2~ z_@+P)%-m#2mHxE^1c!^5Ri3OfJuqfmoeb)<*nH($%7r)&(b23wIs4i4f7U#=3_skm zvHib(@%(*E;rClrKvLny6DN=peQEFiar_;44D;5{&bE;z4j?l+2wS7& zvH@osKw5xe1{^&T(%W~P=>VdlibB}o(bj>y!XRS}h-Qk~f56`cINN@*wTsrjl9M;=nLvYKjy>mbb79c9biDKHf>(*gt{d^7-Ky-F?&RQ`Lwc!hmDsrUkml{Tdc`#)v;=mGIDuv4UUMRGQ04C z{i`!-QDXIV3+^$X5FM^7)Y6-BStIuK_$uYFt-P%U<4`#pYbucIX|=1q2)`OA_lq_X z^o?)sQ1qO;wH?cG5YK|jL!@5BsV9hrC0Nf%(<4a?R}3+F-5PUW*BR4tXMv2OA?EAZ_$f_6fk_)ASF&cR;K|8RwXfQF zlg2|s>ZU}ioj^oufA%6NgT^2Ul&NPnON4PS1WX*rW43mzS}$m^(wEa_GIeBox7MXw zX@l&r;kkR5i%ys%fXh{$wy$FNtgyP&pFagy3(y0dy8B!@W1-6O#MxUJ`cGfw8`AC{ zy5`zc+k`7+=+GeIl1D^CZk1mPD8$mWWa4hotfcBx6y71wc70e;)+yFe6o`krPK_f$ znxU(8&P>o2NwP{m;>Ye^X{95uwJe!?qDDk-hybxxbF4#n7A7{Gh)WI}R%%u2vW6xh z3ml10E2n|XE|f*>@UJ6T2^MKkH{IK<4F&rM9}~B)oD&euS{o8ngmveF8wd@-{9fZ4%8L$MDFS%Rq z0KR|@v||^CE|!4TY*5-72o#J&2^5D)fVPI$mij9n{&=W-GLjAjWUkMO{tiIt0+z|Ja~!pIu11#`e(7Hly?&9vOH2D7ZiBK+=>5?S7q zap6|o_b08S6y1Bn62oe}Uq?p6Scm39wB~Kvwq9#ofbK4^V?=0gwWHvDHDqSW``(Hf ziP;K}kj=zR^LP}8JbnoTHhEfwO43_8qhaqv z1G?4$Jngl`k%X36hkl@AuOuhm;b{+94$ z$u%p8kwMC`4aB#7>v)e^RzBy~htXKSji1!+i*vxk&Rc!laf!>QzsjBJZb4ICGEp0{ z_5$dWRnAIrFbJm7E+B;Gz}2ohzs(E;n!~veeG)^XP8K`Cuo)(wThgBKkcVqzAeZc; z>tn<`eUaaaFq#v=PIkkoZTBiaGP5NFrEKV3jlBivPa-z`K#oKSnD6OHJ_t2>ScIOJ z1wpEIa1FERLBS>vIH6gRy23AU>3(>9hEa?__c<)kM_ZeD5H$w%UYR5?u*~eAk*y0+ zGF{Y&OA`q2j%!!U0v#i-=-{3^%i9wZkv_&sz8Q5y*AG2kz*n`S&h&K^1+O#lr=WID zv=v|2U+l2rK{;0d&)}^Nq;v$1H+VTIhF6?9Gk2ek zD_@In#ma`rgJ!0jnLv{km{~jr8`Fw3n?$h|7&?rI%Ajq%0NQT-o*VDLg=x1}?1U5t z&U?q0F%^xSzA-1k@E8Jq-7a?j9BBHyFWgzDB#`q@)}OvhZRw575DC8{Qrr{Bq^A&vr;tg1^Yk}p!T*E1pMsBmnj}*Aw~XffBvB1CX^h%Z z|ACu^9r-`r1~>jZUIZBQ70?6_)98LP#d&bkfq@_<(69kO6EIXc+;8>+Jpq3GgE<3E zuaTaO;oIQAu8~5z8p&mjs8>IgYz&XHE0F5*gHbT``_-eLHY|q%nxp30f0DF%`UV!; z|DcQG-!+GgxWs<_^3z`cB?rM#e`4(|=T9a?d4k^To7X>ewbo`WtGRjOOJDno$`iA1 z-Td~Yzw6zznp?Mk;unO8j0@8UlJQVR88SY`u2mL=17?__iSvV+|IO3qpWS*Z&n+{1 zm!1D`^}C$HSDEk5UGIJS?z|Xb-j-XU5!`m6+$gK18@`j%l9^c1r0k>U5Eq*0OzJ zJCqa~a_;ln%rTwLswCmA1t{O#HDBHz4Nm2QFV^%p=@%k*TpMH8{`A_SX{hsG-v_00 z92aSUZhh^}nn96tt#YP+>&<-J?AW_Pw;kEn5)6a~0yeYcpIM~c@&%^Zw{B{num5&H zsk3I;t#6Cq?KJtj1juh!^%06(OTRzN+37+ik9P^sxLn6%lS zi;;eJRRll^WW{PgP=2LYyoTPPd~AGojIA zj&t~AeHij_6xcj?PLz$wN0rGwG=?WDX4b`Xs`IEkHKjC=sprS7#ryB5rD$C@4ggVz z5ez*(QeYIRM)46ngI@Gq!)+nEjeat^WIDJ9+YPt%gbaCb^$i)uFi(K^LwY zrral^#i!as#Ip}K_-%;`3ZOSpr&=}LBU`eLYiMh$A;bN)L^!yDAly<}Gd&IQh~8e# zowMs)33$5CQ%WvZh?4njiDjeEjpD0LB>LX*p*z8zqT8~2U?fUH10Q-F8><6Cc((FM zne9-nM^?od5o|bj(OTIL1Rt$ zTA#^NtE*F$3<_Vi82$QZ0C0ibKJ!UFOEElq8|*?4&WB#^ti#OG;q_a|H<0hKbsH_{<+(m zf9P7<3Wp7qg2azv)Sm%$bVl^|_B5bqcjRa~5G`;A(ggzo-tVhHM$V{%1tEVEP!+l$dL{YAbbxb0IeZ|O9%rx-(aTn_qWx7K?}5@G3jGO06}@o(K=Ats zu73UNf6HG0U{vTYM*YR8zZms9qbAya=zk%cG5!;NlOyUFie1I)_350I(c^i}D$n)co)A~e_(uLOycqoxyn1i?zvaLhVgbx_oAWspcrZc1v|H#hlDij(QH{8u1+J**1^H3 zO{p8U2RW&E(&)Qz&3s3x$Ww(C?O-wiW9%TFp+bxOx`7_!Fo~v&&TzC2;%=8K?c^fu zSVht4~h^i}+dz?O+0QJ63qc9$^5w%-rS$^av{J~(R2?#;8(?_gS~H?7!Y3L;rd zY@|(@x}S&Akv*pc2yf{{?=dpg(bHygaZnCfc?)^z8$+QGA){=cTlm5~Gxz4CCJ=>0 zD(dN`!jXoC${k<$`YWE7bbO*9P>1Q*^L??}hK8t)F;P19JNH6KlqZkmf*#$l6^iWFEih`=a$2gvC5<=7Y>)h$8EPp2&M z2Pt=hFmWMIbgs)Fv-AxiGiWP&zus|b!59{*2oaDW)V`j&HHbRS z$$=IVpC&;deO9lQMH%?8#s;(P zh7j!tGl9LkAH;K;nfC-X)Wp32>+8VB>SR91HDN=?7Oq%WU-9tL)t>*4DyIC;oo4v6 z8P(t)FzU3~wBal&cN8%GYog{*wTRZNAzB2^y?~IZxcCm9dx!dfe=^#Qxa@#N5rxan zb7QO5rtd~O#W=$V9x9d@e!@ebA$U-~9HfIEkW);v%U%yvi~QuZ117Q*1tUN`u!0JKj*&kWCWm1Vm~T+T zR|o$A{0jX1w}8*D|H;4h7x*P={t`8RiJCu(n%{wO|AIB2UM8ocBRLrD6VJX`>I!Z#hCawn9$CXe zhy(ULw%*GsCdIOEMpM~wI~sVZ%b$ZS1RQ0hJ0P_=4!4ZBG(J+RSY;p8Iho2u11!bR zp+>{bQBXuzSGA3T80(wS;3+iGm<3!RQDDUjAoIRq_D1QZNp_950-;(CiH(A!WM)P& z^ffm+It3Ij2%ib@XJ7vmc0LYuRs=swD~SpL?K>QP2c0gu-FgL#wlGPhQ*j9VQprZ- zOfF^a8v;rsLxm+rjVaj_qZa^*K!WM&Op{nuedZ305Xc0-bs&OFgrLYk)_8xgsi0jM zE#aXSQmYSR)=_3ikAvQ^U@=tDL8U4Psq)dj)f?wABtivdV}bydCVDT&8iB$o1aeS!xeU5+8qq|H#2|g1gtUf%52;Q9BC|pW zHl^z%J&cAHh~ZY=bo2}|82(DBHir#@F(X&aj&rL^)9%S|^~juasG{!lj6Pv2`bQKx;g7RifZgwpr?>!N&}HpwS57Nn_XGAIyte?85I~FE zz!cY@t#4=mLV6ldDf8u2q0N8x-j_nm*{`~4E@XQ_a`57|J+;dUwOh5xaG=69djK?U?N zqgpIvOO?UqA%6B+vjASeuQ}lrjYweAHp=8Haqq8N;7YiqV^;hobkuiEUb6|WX+kJ@ zvq?t1X+c&K6%oU5JCHi7L=08CO(=Y1&6;Hn^cRQ@_-C)??KKm5xLurR!|P<&vRSZR z!#;$81qhE3J=1*(k}LwkjR@&ceM2t%vojAWDCD9(3MB-z6UyC7#w7Q>}Tz}{8#;aY&+7r(>zMfgLrLpUHf7O|3eRpcM zf9^T~!e-ErZc@H>w+Q8t!O*Ob#!l`|#U*7hjot3W`*x?1sxw^dEAH*u(tVPQJ?lEd z?f%{)-RUMCXWbT5+&_4=`xG_ltous0+9QqKryZ)#dTy$yJ^s1-3=Nyf`diqu|Ig;0 z-(ioD#qhp>-FHNY89{`Rma^et&fzYL;WME^_!$UR4%S&HUV6nFKjgz#4;chv;=Nqy&R=(eIOO_kqKK^J;YyOt%HP@cC7e;!XfBdok`u3WSUw-5A_)*a@ zv2lW(@d=4ZyLJor?A^Ejz`;YwhmRahId=TSf5y7FyygTg3a#swpKprt375Qgt z&#+Fq9dj$le30dnxB5v%L00{Fc5%G!tV`LC@`7qJmsDQLd3^cL_F4V+Jk9cdbzc0> z_F4V2Hme*<@ZzkTc}OY;1VbC+o5BZ=ySz?}GW{|O0<+93qM@wnAM+r#=l6n;U1d!Sgic=y8g9~3#kl5@RYXIm zEdR>5>2dx!2sMFS1wqX_v-drYl*6~AP`Gn$|e%- zmDYo~<7?Lj?**Eq!WY>P+AH3Dyy1;J9*^|;?F%2N;;`LKVwxw+eVJ~P(xpV?jCX^O z5|3Rhi%YnB=k}!9DHq?KNNL(4$C?*^xKo)|6SCFVzUBkC=GxlM^-@#SV_Vt}u{iwu zT!RxzP`}$vg9c8dz z2EO*%-Z}z?pt7gocN!eO(SBgMCvALy9&HiWk~gW%Pqs~YfAnjA#8s3hKm4?^)>{jb z(!&Bz7_NnEK&J5@CCNbgka@)Ic66dgo;EulEyy=(JB`zQ`@JH(eQ^oZ#QiQ~Kn#treh*m4;Nuxav=er00Wnz=&ZPzmEBOQrB z?kBbD%ggMpb|i5UPwL2DyWXDM*s&|3>g3qI^4rrsckJe3(#gn~x<) zm4=tB!@fU~itlK^7CzYH`BPvH_=r~QSt~p?fWZdne;Rx<|8PI?rR~6swc-i=?)o15 zYX0u`9$ek|!Ampz1wAlht=LZl@^HMAAAH?F83FLgygzI7YdjE)8~joR$_T!DW&khu zXczZS1q8rRWF!WsC|g%tL`K}&1Lu(8cYBmi=KG}e&(k`JCw9Kr!8!=pb0S z8={@ej#8N@lJVa4;n-pb@x_NPA3s}yz;J@Q5Y*neUmAs*W0D%JGR~13IR(+mxmdG2 zAPibrduBZkFHig}5l-N4T6P!ez_z-q^6KbZzD8u6ALGjl6A|>~`nYCjOLx>n2_f>R z7M?7f&T*wFfuo~{W-ReqZyH)@F(0PgibbI)JojV}{MrTX*l6C`se8aYT8G!AJ2hW%2b2=r1VeWG~_H6pD2())d^NQ zXdxG71_H~ccEtO%U`r$F3oJGkLrs#wDy!KLtk1oKdMZdIjSY850k81%0mG#cNh&6k zNSl*PV2%*-Bs1cIk{&7G#96&LZvkEY~0|h`)XoR1MYO8b}hsSEATz3^{9N zAQ^<@wTwYezJfu(DElJ2AedO!3V$*eq104_{_wD3IZgx*Z8=IDFD>=eSPq?w65)+n zX9bAYtznVCmI<3N28M)H%UZ$X4sT9G6D6_J5)P{zoLRkmu^8^=@C12G9IX~!yHA@W zQC=_V8h{f2>=hux4|N>9Y8&!e0Ez%W79-V0 zf6swCEEfEGZQ&yl!!OPLmuCMLi|AvZmq8G$`F;@GSYAhk5t#YyJQ!|9h!8Q^0bfQk z+)as5(G714qoERWnRlqWQ)BQ(*;Sngw-TN8Bo`lc*L0OOQJ2)_YtwEpX|YxQT~8L< zX1aOMh3>n0jyGnj%$bdys678&6qMw9s3``sJVRksUOr4f2 z6~Fv!lM6;01?7U?WMBU9`Cabq@n72RQfOdAe63ssLda;3Qe(S%m0-=Y&wZJU3g8qI zmXv&Ds(R|3P=PzyOwZS#1+cGlH=9VKdgQYDjW4TMn>ZR>>YGRS;Rl)mF#rRgm2 zr*$Y5BwMtO>7GV7RL*pU=k8=BK3}0B0uw}BD2803cB&tPOa`Ic-W93s1;NxU*a?e6 z5D*J8)JVX=NFGaYwHYqR67h~%wG5><4T-R1E;`5wtamsSbSzk~vd zXU2lr((+uM1iptEi+L({D9{P$B$8l#s<7DT>TxD8M@-VHiH2NaFq1jS_V0B9)k>OjMyLe3aL z48?H)xcv{7{0zax$cP*uXDDJnBPBn7c>W(u{tV&9=q&m`$Mar-C4GP1g`9Sgl+ZMPO0!Oe{XgQHq`(Nx5BNp0Edw zF@k#Yi6OZmc{lnXbti7c(Q1h1>b%9pcSCQhNeE$;l2XiuN;RfSC^;E^WP#qu_hRIaLmSky2fruTDK zEb92d%a$z@xKG4lV%vh~QxxGCOauMP#f`CKN9h>L@}t^`o9Js;WaLuLvzEyXNq7@U zr2Q8@A#FxcC{?so?dw7n7b%02LPj|^@QJ5IQ5u5tu`&lSg36te2JR5Jy8H8pxjYpi zTj17G26K}ENe;TQJC%V=OHNX%6QNfWKGI4T)5p&#MlLAV)@0{SnK%uK2%A`hY(gcW z*p_Rik#uwqQ=sK%la#hJEw|RELBE9Y;Gx78t628*2_@t`@rJQ5E_?bUvBlnUSFUQ2 zoOIcAKYm}Ss~DXtv^R|a?JpP82%Q_D-uh8sQ!=@(4hLVLVvY3YYL7`{K^B?4fcuu8 zs=nC{)gTsuZd$m&R^wnsG`i9>A^7dyvx&+q5Ddejea(222<80mcLUt|PbQ0K*zipx z{O{Am?=K@5`si)5KeiVRHslOc365k-2GhqQMuVTOBm<6vL3|jPrv(adfMK)1xVCkB zhH9FDSTT?r0cx5f4-d)~gY#xP(-iY&e{dX80EHq+GOSzxn;6{}i@!Grj?ypsN9t~X zh1!vkGX+)*rilkEg`)x_16a|~{f~qUpg0gvG5)zun_o2Xizfb>G-2_Rw{W;9W^bsN z4mGTQLC3guD(Wb`OM_mf>^en53?z809_Y>*=aN z;m3<%f^O-g8uor*EW;@J!c`3u@Ev~EjjWSl zP}ud`>%>TF#|veebKQYqH>vSO`b&A%Es34J75CmJHA9r%Hgf|LN^Ij2shF-$cE!ub z__b{>hfgU#Zb!0UH-7fL0Mh7R8_aIt$uVI(=tfU8*_DY55W|Z)+%dCUn?MW0xCC12 zdbWVBpR75p$}|mZKnA#>J;v6Nju?xRAr^pnV@Nsc7x=I#+u8J+hruX>4-+?$#mAR( zVsi><>P2y}>SPGqFr-P-9mh13r@>w+FH^0yUkO*a19 zL?Hum3WJp%~Zu$;4&fqY9&Qs*3iKL8C?MU>mW*ZZQy50P0E}6@c|(VB}trL>=6@9|Vb?d-H}o z7{gHU2ebF1@~8uH#UDpf{|T=6MHIh?;ulf;R6S>%k4Onoh3JSmQ5bUp8w@eKd{T^X zat9;EgcaV4!Rgms_k;tU~0_*JkqWq958 z8v>}IRO*DaNM!L|Y`bk;a*t}YcoeD@h~iROy-sxso#2;nD-+2O|v zG<3;nMZ`-6Pn^-onsX#rf7rQFw4~-HT6W{M#04S1(6@Y?;=T<9wTblGs%c_){;R1R z#k?1JKSnRDv_H&-2i7-efBJ=>9a-ZBoi2LjToKpqI8E!}7)Z2s^>QdW#psr|2^pS} zw?v!E6`+LRZ6U6(t}RFylE_lm@?mtPQz1+?SE;oY(EYhL9cYrRnnXB+MWyF#OI?L+ zlJwta!I%NG9o6p`=y|Ci^^}@Wzd|~kaG^-!YAD)_7L80KIheF@)OA}WL{K@xI)bNU zYO+k&G7UE2swH*?h_0{0iGpoB zr)=qJK*fO|dW-$G-0Y&iAkrbmHXl(^HAAXdE<`^lHQu9vj<%3QKPI2ldyA0BGWtypBy2bOwQ#9*Lepph47KFhv2L=z+P2A9hemyeN2gYOl*!!uGt zlLo^mF%WqimM8|c4FIpj?lO{NVo3Xyi>}uvnhy4uw-)pg z9(~W4k}l!(G>=w-=<(w=g0x9R@h)MAf2%oMopNunAgewKl=g>3*dJ<@h zhTw?`B{%WaubFBEnyCcj7W`sn9{NyejGB1N{3uSBj45CGD7q0?{)F*_Qpku7yB1_U zG?wD;ij(tlUbRlp%`1Lg*i*x2vnifI_s3>3TbmAt>ClhXBuApzWdApxX!gt)koxJS zoqf7U_CaHAh37~uZ)wkXQL0f2E$}g7LefpE-MGlwO55ckDf&bJ*mrByogyBF>NE`< z%&B4=fe7e`jQC#(QgCoQ(X2&DB8Q;upHUJS5^+*OJkNYd#aV9xNbM0mN<1M!rIqy9JC` z_$oP!WUbB#rEkTC!4H9_0E`n#sr%Z^khWZfp(fJlgzP_SNN*bP|3=Jen;Fss4=J@> zFFv#}wG4Ag-_o?&$16LSTJQnm^Fw&Q@@Z$bv*pFxZ#thw#6s6mr5~scL#*?!A7wk? za|Kcg8F}W|!}Ia)UOp^6llABlgeEzJ?(meW=T5!4tD0WAbJY3MZyw|I9PG=-iz8 z$Hg06re4cE`|i1R&&XY)FPwY-s^a9_N7pW#|4^sP|Iaiyky6M%zY*RAl;0Ju&|!c$ zZHd^2B5#de2lhCk7SMj-97hu^Xv!ErVu8BAc3ETYW&7~gV$Idp75c>M!5{pw_yLyl z)}nfCTHkmpRH!RP+liIX&0Auq;MTY-DY_@A0FF*Z<{l5EdWLDe@0Mlra1~)Al?qIt ze0}!)AzV|ReuInoaW{TdLJE+3h@i z@O=eSN@=n&RqyOwm=+1vhw7+FPg7iVd`eiLGP|SP;WCKP0BHj?)xvyESW$G0G8&?p9h*Ymq$=7X z6$T(@7Xzewu%f*N(g9~OVmUkdriS!Hci*FJ@Vbj;=yt5=?t8#A&Q9OstLf1V&2Gq3 z{7^G=wmg3L6T|>P3=rgG@$JdNu)VV~hKJ`?Fa;#GNWv?5%~10xV`A4Q+0Tih$_ZOA zyp!IhN?pOV`A$b;>E7PDVh}b!G|T|=FJ&OdJEQT=h-EARYBf!yA^JH{lk9$>Rm(8r z{r2#w5trW-SvYZGApGEP&0^coW@cX5JQs9=b;URa+K?iOgD(m+8Pupu zAoUCf;&sOf89~(%_8O3F(X92YozckCu+3CyLYrx?(}QS(h1Y&}4S}vLwmNNpBY<|U z&(T8ScKfkXv#GQxiKN0u7m3xHK0A_d3c|vrde{XCMh}o=oVRZ6>s{B<7w=EKaATF@ z*uszVofg6_2;k^%acf;x3VNt2E07&L%rU7c2?+R$wJ6#y@vS zpinZT;2&9u2Yn&ZojyJuwc^E!_zW!HCea$cxQx8j!xGw>f`XLzP;P?#4GPZ9DH8i) zq!7E5hkLlb8XxRkfLkjW(w`(!JZQH~c4j8aG-v*jEgmt0`& zC0~f}2RG4cuPEMM50LPDSubH0;k{t52d7nsVhN?IhgWEb&LSw#iHEy_-eH+{VE8nl z8)~CB20e?3JG(FPPki*#{z3}IO(iv*Su3-YDW%~r8|F|bQqnYWf{jGI^>S(u5JLai za83U;)ekf8j_SvZA1RB!J8IZfT$l?C3@9Vd!Z>GWWI=YAA;zueHu!ft$)f!@5jfvK zeuS~#ZFLVgsc8sk8m*6R8!&Ny8X^?NQv_V}=(^(!-y!zrz!6Mi{<0fLs=4I0!RWZz z)*ppqmmU4luNcP{Z`(1BMnuK;H-^85as0Q)6hG7v-+vKN7KpMyl*RYT;(+TozSspDQTf0sJa05ctH_;~w*Q0SGJ!EP;SFe;?NAN%)i7t0L z?dr+%{7@;%1*B|xqq49@IH?|8mEt7HGY=Oz2njxpW+Z&DXvha@5Bii~^g!~wK@SH6 zD~k!j+#$G^hgM%qAs>4%1V^6W$PS=gT;~}`IBOojr)+%CnvXeme(bXP>4f@bmXCLx zpQ*-P7EsrEdOKxl;~^3M3q3S;YVeC&HW@=$gVQJHn$>MwkkWKfv6NqrOvtiETRJ_db9eDuvIO6HE=h` z&H*h{;zYKViLt1d$|iHAHUQt`*vSCPBt2@x_!~9@AJ{rssHN5gsd!(J20Q=11O$2R z=QKll1u;8@L>6=x5`UkBMdr8XDcXqA?U9PE_ldT2X4g~&%&2Hz5rIh+9bU)RY(>Ww za(lMIh?6!diur3^ciRkU>wbI{6>amz?aXN7j9h1uqN~5rws73l+4zvJHJBU50_n|% zKd?1Ac@=HU=&vxWwircgV`mog2WN@D=VpAb8GiT`#PmRf1R^AUAS6<6fs`2l%A{wM z8Y;O5?=z!uya13iJXRV+9}Cpy;RoI%uR(JfMS-?r--QV#REk;wI(b(Y-3~v0ypY17 z&GU96%DHIDa4xHWWaB#x!25|qgYHaxu9n_S7MWrzf8Daaz+~!mILqnjRNZttWDGw6 zy_%xtQ^mR!i|K(9B>@-YyK^yJAk@aWT33h@pNbn{g+Y0u&3QT>I*zVM<|y-QGpFx> z&k>huc;rb1Rai4TGX^p_d-*L6Zh|!M%=0YWg>R11^-|iE>7FRIS!G(T{mj=80W&V5 zu87uJc5*k5e0NI*`u*s5^Hvr)cg0|Obygl=Q8jWQ0mLt_UO``_to~vhyLxJ0vKm{r zgGG(hSJ^C$Q@ovQZbGDpokwrU^(s3ety+Y7Mb1EfF!8`qH|hE^w&wQr2dI8}@#|=n zCO{65u58T13l%BMOv++E-)fc!5LExB!GMecP@+w&n8(7o?XBjFPfH{oV#<>wYO}`V zbKEDqMXP)ru+>Yj_Tju$2NY_G1>LVF?0qokJ!_NH;K9CmVE;@My>dd5ixUfHE$K-g zxlra*$(<`=@+l@6ISh>X+(>nv*|TQ~QZAD)l7}+2ET3i`H9l! ze@-EBb^c;B*uG)gokjt|O2UA;>SRw>b*+&8<9Uj%X2%Z`6#b@lcRhwgJ%f!8L9_u~ z4Nun^=gHcl6x|aPaA*^zV8Q*5wvh@$m(=KbwDGSD3d0DefX^1&R0bdg-1cbG7T=^M z+9I0m_X{I#vx~53HbOVyLq-?x!w{C}Iz#sCbxZA=Ze)sfc>yCfzX?nH%M>hFNuUv? zCK8_z1@(QpDQx_2PyY;`b@1uth$SzcZV@N-eYSPR=HH(EEo%S4XWODrzj(G?Qq=c( zdhDIwp6`f%cJTSmb(5OxjG>|7ULFcBNTEW zz;DuYDK5xI#v_f(W;Nc5RYqcPCQhcNSWkLJqTN((bv|j7%L$F;9MPy#c0Soh`u8Kq z_4!s&qN9Nn`x$Eps3EBtr{P?rzRBIxJFWkX)$wAv?aG^>NmQ282EN6bag&S85^mm5 zn+$YXh_wmPsZiLZeJuEt)Cu#8%&nOlWLAHUTOoXQLc~Q|POJEWHX(2tWY)*=D+0;K zHd1r7nQ61b4=taz98S~ z4~p!DXWshd5rLTbN_ElEY7>SSgPGE*L-&CqO(${#$Q;UWF%v+$AE~580K;$orbF%X z4#Ft3*i)-CCLWwf*DMWWOQ<%Ps{GYziB3BH?FKtby3}NV3gR>0Zv8p8DT;nlC2?%Y znbL=b{;1B>!w1zNDi(D)PrzE@dxxV6CR-7PJc2)V#wR))4#S1Q=y1St;y+UNfSFbu z*@;dl#lO(?fLYz0M~eSY-J?B0@lQ8CTH)+O%fCaUfDab1r~nXAfrtu3RD8{3E|0>n zGqrhmb0;2jrH%*XSWp_j(i-tIjn8tzq_&T?}nya1cA$!>V^;HhsyKw7#^K$|IyEHLA^s)|t~6+KQ{(zm`z#rp6f zgKo{8;fcYdNPyE1L$@rHRh97|OwAnENdCQ~Y>978&~tUOyNT}!fI3I)KFpNHLDv3?M3wPQ@4-N906lKIin-Jtm-`7xY+^erX$G|69u z*6-d^k7nD+9hMWdHd!N3t$q9>&(H&)v|wBy#$y;wK@kP&e_gIW@!>H1r&!)!JvoVD z#gy@BFI^HU%~)uz;u_gcW%p&gr?f|l=_2t~kZlc}(*?2?BxgbtXU^&3HOgfqS1dS0 zfAQ8Ypj-xs^)LWk2=NHhRQ9wQ>wsTqOzcYm8c(T4?_M?E)K6!}CMum>N76kWzMJ5}88kqL~Vi&5wE(YZ(TG$X|RH9wMB!?>0XriaBKp^vvTr?F1My$xh)}d34>UdVNgt`FluaHxXUbNMDrZdCyOlEy7o#Uhg9pPS(kSU$@a}8eo*CZ%5!(dm|M+_DX%;};mzTe6E z!L0(86+fKPG>VJPwuf`LF+tJkceKYRU_LjTpfF}9V8m4$-wI}9cHSZ0z@zAJha+*9 z;R0b?MDG~BGL3L<*zD+9-S~U4ihp9m>xWK9w=W_I3dHz8jF0ZdhuS0zlA`pff7k@TWt4hnFzd5E)t{6 zh7PMwAocQB2V?z&gHPT1b+6j%P8m}Tl7l6li!J*_OJdosAq$)C@#N~$?o=@sM6HdI zH={30L%ZfNu)4BHGCHQ0<4e?0|1jOKwQDMXaQrbs6*c~hYuzvao6 z6l}V9nIKsH`E~L+K_-t_XfMMPGE=ZR@v^Dm+gY1c7aYX^)uw`P6Yhhx;zF{61i<3- zmLyXq3cvT=L(+d@Ly-3?p8AYrE``S)|PB(=n4?BFyzUK;prf@IPcR z^mb_!u?L`y696E)Hzk4ob{@%F8OerI5teFzFiwZEh~l9<$JW!_GAGx^sPhF906#I9 zVIxt3!*7CAb6 zXmfz2L@dLNZLqQ03idu=jbknsZ^*E$?7KP=BINQ+###1y8#ADEt`mfDtB_je>E%6? z09y5WW`71GCF;liq-~G?f^)?JIKbR4D!QI4x`~QM=t19z3ix92eJr!9z%ZUJ?ArIn zYC2ZB4J>XLQvp{<`$x8WAe|c^u=`<@8AkU578`Bl595v}tS;ISS4NGoYPWv%-gc#7 z=f%DbM_93F-qy-6cCbB~rl zWtSLS?`y8j+(f&XoX~s|8@jp}WKuGc7~!)`appZML%iM0H%ZVICToX%J|yqXg2I&0T@U#o14T@WM@+xI42c<#0f= zIj#9g_?GH?j5Ht4WDJHhXBl(I$E9qWCz7HUJKj-1wuy>4@OAiHO+al{2rvK5fi1@c z=#wUGavIW6jCF8I{6!gu0yI8EW>ziyCuYne~=1;)4#7;)tlpM`5q z7OD!GpE@?EUsY|1Y;`tu0*Ag)_sqhvaTSb)Jju{s7)veV?&sP@Ur`MG6)Qeg$PqOO|o?z79?Z&cO23qF<=5WSyLu*>13$q&6N0GrC9y-{8=e0oqNPF4-3R>P0 zo6HpD)8f-)jsx<5!;F1>%~YUGEo3rNjHV~)P?NmaAVu{z_jTnENerMZl{H>J-#+)% zpWg#%XH?v!N;{I8|9D62J9*KiPugLK=-N;f#{JTEJ;9mq7(Q4SB?TPTgy%iJhhMc( zDU2Zsn4k%#Ccd^r<-5L~DvXKDZW>~5&NtbKuHfyn#qC+l&fX~8{b)N_eCpH?#%qPq z-RPXlc2DYg3@TR=o zJhUlCb)vs{rcQ1x&dk8ke_SxP=Sd#uR)DvNYX$o)#<`XH)?HK zqISl{9))n*BL={Eg@rb0Ln|N+m0X?*!Gr)w#wV&hgBSPw zs5LKevd||eK{$hxi${oQ|GUk z1EJU!ydhN!S=4DfCY`V~1y{yfF|8J^d_WkCS7gF?p4ghBNGUm(MeJRnB;C54Xvbuu z1U#`taC{07EXL ziafg}m15M9X*Q)5MT44-r>!|MqtD2DB@>%YY`uD9mQU%uYfGC>Dou|@4I6p?#VR{9B~f&agw0lb1#-iIOt|I&?|XDkg~0;D*dXnyD~y@Ujx@zLgQVF7 zFv-fuu==VljHXDJgT*(oOe4ms+o_^0oY~$r{eBU>Q*{{j!#;k^Y8vhoe-~-h&GRt+ z5)l%JkU)gQ_d;Uj1~s;4nu?FU6gLWTj zw#H^kteFkdLSyQ?+CABJz^0wWpj|O9@bWX(V3<~H68>Big+Hq`9P8|R=QFk zhESm}(aJw#=>%Um@Bm?2Ls>H1ktx;#whpz4*ThZF(V#;npd0@N%94wrCgGU?>)kb| z{=QQml&KPOST#Vet-IMirM2)r0eClz4Dm6_LWA;b_(6}{cmUl@pE2^9Qh!-SA^#C%}J1i$94-jzU=V?x!&jPk=()l^~W4h7~7lq>(RH9 zBlJSM*8D!9VB=Bl&cSy39K8aYB(9nZET6qY1`{uD+*JbJ7_%UVT`~KwLX<*`YToZ7 zZ@gDWGX+qew?Ya`@tBpXwm#G!6J0`Ys{wi!Pod9;6nIzZig7$4db5weXE@i&DmYJn zLobKn75IDo63i){Qa9BYQXgR;7@!(bzK=g=6$c_=KFw@j2$#fo0LBW-;0%KD2 zfMrrLu9sMuIw%#wi?k?Pl@2{64D(>AB(ZhJ8vOc^LR6Soa63?ng~&zd;8sB1H?5j9 zQVkM%>vM%X=I?9z320M*%OR+qASH^|*9HVFn$;TzzY3tGa%JPs#n|ChYQhvKp+^~j zS=F-7Ys;0gS%cpFq=|~3dhVkV*D*&L-(5{~>5_IWl6DJG7{OM?6Gf+>=n~HShQn<* zQAEO;qH9Fc&>sz!7*JQCaqZMh<02_cyMh-#Ix8S>bkj)Sj{DOvO4=5#Ft9VFJ75m? zH?GL0!$w*04TsxkjI`~37{Z(<^1tblcFvu*oi1P^Ry(KSN24E|b03|_3PY*1i^TY! zGb@lQ1#+c8t`y&2DGrdwfzAuYfuzA?PmHk}IAy_Sc$#==YbViJdSxnO_{rQbfZ1bS4kjFSU%- zGs$DJ?U?kb1Z-&S&QF#WEmb4HFwU+f%RM$0^2XK^@3ezi?u4x6#EX-%N-FP@-ukm9 zWv?7&RcC$!^RlFm=fzL^A&<}Y+wA3kjXjgpXf=)8@L2|aoIu1Z=l?OChe4Gc$n|07 z0q7$U_VleOSSJ6EkTjjulQY=6y|Px!)G?ijX|kq+8mz@@{^u$RM(C|GY1l3!jtK=! zd^2QYlxi%W>;3dkKIYg){^vW&gdRI(3w}+T%s2$00(}93t$0W=+I6d@hAT>=JrGjWmhDw{c?pfFc8x<3@qP^C}oUCYGGb1kq> z7U5dl%n6GlFql}%(4q^Gq?%Vfoyo0wz-$wMb>V674!|m`LQI$xpKo_an?UguOOrVO zMy!;(7Py*Bk@Tb30ba6hWch?jh7Yejr z_iUzVK$mfI125BPdwfH;GR7v1J_oELV8&I4&jF(-;Hn3lyZovb=Bzg2w%fPM+wKnE zpfQa{2l(93DGf5u8&<*Ea8~Vw597>e*R2lt5@FN`+WVi38BF6|dDn4{r>|O!en#zE zWAxHM*=`F@7^Fd01Eb}CdUr5hAO4w-u%n z&)pJ9i~5W`Ls?_)E_}3MxI>kAxo%GkBlgO>kl_ZvsOr# zj0bqyhB#u;;4BkWKaAy}19F1(Zo+MQ8P?V}1&pfuy}xfdD?&8bI$A<;$#fu&F6N8K zOw4Vx6fmile)(lIsYfsdmzn0@H$s_sAZ>C(^cDqLt6Oqlwlf> zy!kD`c55Vy&BQp3A5EZY*({nK!4!Nr^OPHmF?H}|IFedJ!95^I=CjXa2D31Ir zn!@K$XZrGoz-=Sis(bXZD~JO2H;nsWZEX(Yf=8#h0p~8eDh7kC0bd?M;|y%=Nh^&} zh`LTHRoA{o+m5I~J#Tf#s788z@PeGhVuK+X}!IpPQBh$As`2(BssmFB9} znD|pdG3GtPfOjS5IDiIY6~@(|(!6yVQjpjaOL3L}(wPy(|R|vu5ZE zy_N5Ky#(bZzFtVajILiny*#r13#}##MqWH}tRD2NWO}5J&7(={m$V#AtJ0s-4;2tZ zOU8vWSZnncSQ0ZRQ~gN4o0l!1RWIX3J!H*N4}E${DWiA?Qeyk~Ir;)r&sv>649E+B zc=7r90eA;`-q<7X5J*oc&a@i5U}{ceh;&Q`aRR#GD9J0HXF4WB>clZONf8LqQ<(hx z$PDa7KOrt&8Ib=GK#%kHXz&xaULMO+Vn%9v*eF{ma?9EyREiED zLR_pXts3i4!Rm=p0ZNlMp!X3cXNp)#)hh`CoyNqMcO{Ui1WgsaoKU5!d z{lT)CKdrg((~pCRO)>3V(V5+k5r5C%__iq8MNza5f^{@Qjk921@!D`3G*|)$B@FdX zqlE!OC#K2_vmJ)%@}#dp37EDGdl|5ivHWj_e!-V8(pJ?$ZXD0b?kP z6wJ1J#Mfr1QDby^7REpXoQ8k}2HXQR9wT1XwZLOvZ|cAL6vj;D`wy*#Oyv(n#gCUl z|0U({_r4iX6o{fg6vdAf1)i&h6$K0#AaEe5 zuy|JskTgR3=8Vk|v%QhcHO%6$pP6U`Fr#{#&Z?D^-g%1dkw<@EH)1y7S0N~zU_*;hd}IaAbf z&+SQ73CME26i8GsdHD@fodw~5d9N$1HEl>lYiR$upU_f_)Z zN=k9?8TN7@^;a?$4f_zzpGKLua<;LV$qDwKt`Y|+0XvcuFfZm2#%xWe$pN$}mpNyl zci^+7O1b?MmWdxz>hQ4j8DOeqnoQE=S;VM8-`+K#J%w))te297;tTJ3F;P^x5ZYZo8R_!)kCcci2ceX&g9w&@l zPom5QqnNoCvHD9m>Qj1<8Vo%^GflpqhU}JaO$BeM&c_$+h}TZX@UNS zuvJ~v1Y&0(3Ib6OKT;4U=HTIXx=y5!G%4OeBGRB-Ud8ZmoLY*IGH9z9bTWZ}1dBGj3ZAj7mf-nuY}^bn=J5i{a?PXT3^mGn(}XpF zq!cHv;Q23ckqM8Ief8)Uzx)OHK07QN;`?fR1XK(n{iz1p`9fXNb>!1CKl z#~3x~ax#c!o9MLuX89*$Aj(ynh37450a4B6*A;Y!K)a}9s0Qun#e z9$q@}e#7RRvVHDxSN`kljKu%%6~q}Tq5Z1xohImVRp_b-x|$Tm%w#7myK`@xJ+{-T z_&PS;7I$dxVFWEOPJ+IGr@JPtG>CxC-Oo<66b!L64uE!?4h(x5ohgS-&%zjVfKLkF zA|l}FE@RokFbvvBvxGH)aUK+&)G%s-w!^|V_XK?-tOmZ{(`W-=eXN$*5oqG$3nv-IyygaA@V@YDxVx(~(RyUA zj$gh`EJjfRX`tN1p0}o-8$MPmuoWkpHksQ+?I=cjMY9G}OsvrJdXo35gtUpO9)T7d zZ&iOcJIe8<`#}+^VzeN(KCU7l_b37FFIpIH8(N|KP^EI!CRDFWc!<8LV2B0JB1^@m zSuWw=IV(=;=(Eo3Tc(35m`*j)`&kRB`D}Y({h%lIN8S?6&L_AHVskN5gGh%+yJhu# zoa&bK9YwDbvPaUhc;i z>>-yv?PrMO^+B=6= zne8W}0~pOs8G#d@g5IlKu`WN4NLvWl=8h)i3oz)5P3Igqko-UtWEvZn)3+7^6D(1+ z7H1SBIv6X|0%oD*0L@7{f5{{i5h_;TE0ljsN|V-vXG$Fz^GSn??_0qAQPU8ZGcc~E z=UN~b88#Zh$+uPfx^~#me|3B6QbN_E?f;_@M^b>xJb@-k=+1A7S2J6ta2i~<9 zVO;5i`u&YXrnp6(f~dSeC18HQ}1a! zH2oG-U>)JTP=F)y#%k~$T4n;tF-#0xKg|*6Q3M+!o9+qZdNms-f|1p;x4%iW8Yt4g zXA{$u0&3XSd4W`4IRI8<%hQCFijCz${4ae1q~I#R3}-sudn&p{wmflW7*J; zpL-^ZfX=%NCa-KVJ7W`*&^YUX#GmEnI_8r}>w}>yiL{E1U|_S%J9LOeEeQ~Q931A+ z+P7-swZex<>NQ`iS2eEr^6}kBEUGwpu(MOZ${UX#vB;vKSNn3I13X@%3Xc&onTsms z!mKRLU=ELBMexWgQ)Xut`$S7V1{}!^wB%YMH69tcMF>7+ga+_Rtsud7`?lU3q*6+L( zCr1Vljwpx(Ie-sT$?j!}Fg?-nI|L^$mwlUyn0^F{Y?J(+y z`tOO=Z6?Fljn3nF24f+&q;ngi9ohg3iY~jH?TCh|XU1WSZW)CyuiIP&Bdejipy-xS z__jImKRzfR3Ib6Oh=TZDK}@&gmAGDi!o&64#6uBmeID59=aBudy z>OwP1{gGg_8;zQ1Giw=GSUwN7gwX>#{=hdX2+<Imp3fl|9l%2V=*z z%pX9ry7iVwDcbcg|80U!n|rT6&m)+elhB%XzvOU0VPk8wh}FUrL6^o?59B0?iQi%^xeJCiy?brA%)C1)p5h=Qp?b4 zz?uvamrqZy*)76Yhp(S!Ss?|lTPHE1L#ZUX)WXpR$Jzv}nC^r{Ijdy$jpDg3O2CPt z1L4>wITB`d4bnob)M=otSV}q4%1iPTu?X%Jyw9kQtFcV=hGdBv%j3x`QkApz{@42n zyZ&$84*ng&q(#q;0j+62QVTyG`-blg#=UQtME#vwXiqVAO(MWlYMA>3*DGNpbyvT^ zs2O0v(1B)XpUdiMHo&xnt;gCqPMx60jsSw8AYmNPGPWa*=NbJ5IK0?gbmJS3p)&Giv>sjn1UNbD1?1EqU_Cs6t&3g_GHNMB zcf~8eB;W#F8r0;-7|~wTsO| zFi)31M`JPSg#8l8Z2n!JzRgNdN|HS{J3}CoHH!kY5HN+1Kh_t*hA2?gwM`gnT^iLq z2mGYopJ>Y*O~t7pbK)7SW3+NvAR`gnJ>b-#3|`ziE^uR0QML^PEKBC9(Ie6l`pjUF zLUQ;fY@mocUI3aa)uqndenagV(i9LCyj43tK}Qk7Z|~uUu5s)Et{B2^r&~XLZhIFDfB1JEe%MwqbM1`Z zc19gK7X9j?#PxdYyhriJ>Xz62rB+IUUG3Ht?~S< z4{_gqy*7L4)%oWi>2sEk&U#SSocqW1y3c<>(w}J#s&(9 zj68kh-pQz&hbEVvKKkH{wr1*Nw11WFL6T231uRh>wmm06v{SW;V^%uM3c zD4aG&)vV&|&#XytJzZO~np?zqoa%ii>hT)iXPJ-J`Zv`+UdO}reUc`${_V;7;NAzH zYzX;({1KU91!H_ku1W~Rwif7Ivu})@`{rc%=t*uTCr}^={bchF3WX&1hPh>g=PP z;`+iTv!e5g7|TMATi_%i$H2auqP3!uNWsSNZMQ; zk-y#Fn;5ugdE@orPAlqf^!DAsz11stF!y$djpkk9knO6)d6T#3->V~MkCK<#gr{(xX&MyyS*@R5pQ&s8tiSB>S4-pF1%G{MexCJLYs-f^xT|a^;s>iyc6x{qqD0vg zt8s($Qc9{4(yv!TGR)$N^Bq3vlX>Lbl;q$7wq3mj(wee+p96l6Z z9`dPv9Yo&C#1AhH_{Y!4|B)Ggh0rl?h`jz66c$}BzEVYG4)Xesy#6Dv|H$h<^7@bHe?5b93q+7jJZ#dM)?tyXV?HBX^CyaPIx9ij#96UAu7pL!B;vwd0tJ zxgX!v-aI_@`o#;MKj?U9)yw+WHL}H~qPJ%htbb z+n&B-=PqT&?mc_=?LUxt@X+BSM~`Kxj-NQ0ed_d?oU=&&=f%y;afhc|J$LFAlK-)u zQ=6gaeW-SK>VTKEd(wiOU+mp9e$I=1TW1}5u|Ivu%NGZfNzN}b_imo^@?hrvLoW{< zIsNkGVO5dyt0UQW=Da$Z^X$;8W4TQ)UuCIrF0WMu)^lGUFYbN#^$CRkhVb7I{#*O3 z7Q+8T_@4;>6XAa%{7;1ciSVBh{xiaVM)=PN{~6&wBm94a|Bvwh5&l2I|3~=$$o>nm z|AOqlAp0-K{tL4Ig6w}G`(McZ7qb6_?0*evSf7@<*Qw9&D?H|3vbi zNd6Pae#!zKau?B!_qTZk1j!Il0!(2sybg`=`y7(=lJ8xX+1~o3^{w^Y3bH} zbF0eEo_u~?DOl|=>RdLG|7?2kd>4dsu2ssB{3o*ii|qd*`|rs9FT(#s^8d*GJF@?- zqX?h+PH)(zdbdC4-Tt%9S8jiP^sM#M=hnae`l}WGVE7FGXixV4bDxm>Ka&4P^8ZNw NAIbm!zmWg;`(OJkp^X3l literal 0 HcmV?d00001 diff --git a/mobile/assets/loading.gif b/mobile/assets/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..acfef92ac208c0cf3b27f0334e8cdb77a03eac69 GIT binary patch literal 126439 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 Q7C+_8MQ{{$HU#Pa2b$z{aR2}S literal 0 HcmV?d00001 diff --git a/mobile/lib/common/background_task_change_notifier.dart b/mobile/lib/common/background_task_change_notifier.dart index f2555ae5d..b56f442a9 100644 --- a/mobile/lib/common/background_task_change_notifier.dart +++ b/mobile/lib/common/background_task_change_notifier.dart @@ -31,26 +31,29 @@ class BackgroundTaskChangeNotifier extends ChangeNotifier implements Subscriber final (taskStatus, error) = TaskStatus.fromApi(event.field0.field0); if (event.field0 is bridge.BackgroundTask_RecoverDlc) { events.push(BackgroundTask(type: TaskType.recover, status: taskStatus, error: error)); + notifyListeners(); } if (event.field0 is bridge.BackgroundTask_FullSync) { events.push(BackgroundTask(type: TaskType.fullSync, status: taskStatus, error: error)); + notifyListeners(); } if (event.field0 is bridge.BackgroundTask_Rollover) { events.push(BackgroundTask(type: TaskType.rollover, status: taskStatus, error: error)); + notifyListeners(); } if (event.field0 is bridge.BackgroundTask_CollabRevert) { events.push( BackgroundTask(type: TaskType.collaborativeRevert, status: taskStatus, error: error)); + notifyListeners(); } if (event.field0 is bridge.BackgroundTask_AsyncTrade) { events.push(BackgroundTask(type: TaskType.asyncTrade, status: taskStatus, error: error)); + notifyListeners(); } - - notifyListeners(); } } } diff --git a/mobile/lib/common/domain/background_task.dart b/mobile/lib/common/domain/background_task.dart index 5453da04b..c5f000056 100644 --- a/mobile/lib/common/domain/background_task.dart +++ b/mobile/lib/common/domain/background_task.dart @@ -27,6 +27,18 @@ enum TaskStatus { static bridge.TaskStatus apiDummy() { return const bridge.TaskStatus_Pending(); } + + @override + String toString() { + switch (this) { + case TaskStatus.pending: + return "Pending"; + case TaskStatus.failed: + return "Failed"; + case TaskStatus.success: + return "Success"; + } + } } class BackgroundTask { diff --git a/mobile/lib/common/task_status_dialog.dart b/mobile/lib/common/task_status_dialog.dart index fafc15639..0a2d2f151 100644 --- a/mobile/lib/common/task_status_dialog.dart +++ b/mobile/lib/common/task_status_dialog.dart @@ -1,10 +1,22 @@ import 'dart:async'; -import 'package:confetti/confetti.dart'; import 'package:flutter/material.dart'; +import 'package:get_10101/common/color.dart'; import 'package:get_10101/common/domain/background_task.dart'; import 'package:go_router/go_router.dart'; +/// Define Animation Type +class AppAnim { + /// Loading Animation + static const loading = 'assets/loading.gif'; + + /// Success Animation + static const success = 'assets/success.gif'; + + /// Error Animation + static const error = 'assets/error.gif'; +} + class TaskStatusDialog extends StatefulWidget { final String title; final TaskStatus status; @@ -28,20 +40,12 @@ class TaskStatusDialog extends StatefulWidget { } class _TaskStatusDialog extends State { - late final ConfettiController _confettiController; Timer? _timeout; bool timeout = false; - @override - void initState() { - super.initState(); - _confettiController = ConfettiController(duration: const Duration(seconds: 3)); - } - @override void dispose() { - _confettiController.dispose(); _timeout?.cancel(); super.dispose(); } @@ -64,68 +68,75 @@ class _TaskStatusDialog extends State { }); } - WidgetsBinding.instance.addPostFrameCallback((_) { - _confettiController.play(); - }); - - Widget closeButton = ElevatedButton( - onPressed: () { - GoRouter.of(context).pop(); - - if (widget.onClose != null) { - widget.onClose!(); - } - }, - child: Text(widget.buttonText)); + Widget closeButton = SizedBox( + width: MediaQuery.of(context).size.width * 0.6, + child: ElevatedButton( + onPressed: () { + GoRouter.of(context).pop(); + + if (widget.onClose != null) { + widget.onClose!(); + } + }, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + padding: EdgeInsets.zero, + backgroundColor: tenTenOnePurple), + child: Text(widget.buttonText)), + ); AlertDialog dialog = AlertDialog( - icon: (() { - switch (widget.status) { - case TaskStatus.pending: - return const Center( - child: SizedBox(width: 20, height: 20, child: CircularProgressIndicator())); - case TaskStatus.failed: - return const Icon( - Icons.cancel, - color: Colors.red, - ); - case TaskStatus.success: - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - Icons.check_circle, - color: Colors.green, - ), - ConfettiWidget( - confettiController: _confettiController, - blastDirectionality: BlastDirectionality.explosive, - maxBlastForce: 10, - // set a lower max blast force - minBlastForce: 9, - // set a lower min blast force - emissionFrequency: 0.00001, - numberOfParticles: 20, - // a lot of particles at once - gravity: 0.2, - shouldLoop: false, - ), - ]); - } - })(), - title: Text("${widget.title} ${(() { - switch (widget.status) { - case TaskStatus.pending: - return "Pending"; - case TaskStatus.success: - return "Success"; - case TaskStatus.failed: - return "Failure"; - } - })()}"), - content: widget.content, - actions: isPending && !timeout ? null : [closeButton], + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + content: Container( + height: 330, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(18.0), + ), + clipBehavior: Clip.antiAlias, + width: MediaQuery.of(context).size.shortestSide, + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + width: double.infinity, + height: 110, + clipBehavior: Clip.antiAlias, + decoration: const BoxDecoration( + color: Colors.white, + ), + child: Image.asset( + switch (widget.status) { + TaskStatus.pending => AppAnim.loading, + TaskStatus.failed => AppAnim.error, + TaskStatus.success => AppAnim.success, + }, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 15), + buildTitle(widget.status), + Padding( + padding: const EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0), + child: widget.content), + const Spacer(), + if (!isPending || timeout) + Padding( + padding: const EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0, bottom: 10.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + closeButton, + ], + ), + ) + ], + ), + ), insetPadding: widget.insetPadding, ); @@ -139,4 +150,19 @@ class _TaskStatusDialog extends State { return dialog; } } + + Widget buildTitle(title) { + return Visibility( + visible: title != null, + child: Text( + '$title', + textAlign: TextAlign.center, + style: const TextStyle( + color: Colors.black, + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), + ), + ); + } } diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index 273967e39..8115c5180 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -46,11 +46,21 @@ class _XXIScreenState extends State { if (taskStatusDialog != null && activeTask == null) { // only create a new dialog if there isn't an active task already. - showDialog( + showGeneralDialog( context: context, useRootNavigator: true, barrierDismissible: false, - builder: (context) { + transitionBuilder: (context, animation, __, child) { + final curvedValue = Curves.easeInOutBack.transform(animation.value) - 1.5; + return Transform( + transform: Matrix4.translationValues(0.0, curvedValue * 100, 0.0), + child: Opacity( + opacity: animation.value, + child: child, + ), + ); + }, + pageBuilder: (context, _, __) { // watch task updates from within the dialog. final task = context.watch().events.pop(); if (activeTask != null && task.type != activeTask!.type) { diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 6d1ef3d9b..ddb47a70f 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -217,14 +217,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" - confetti: - dependency: "direct main" - description: - name: confetti - sha256: "979aafde2428c53947892c95eb244466c109c129b7eee9011f0a66caaca52267" - url: "https://pub.dev" - source: hosted - version: "0.7.0" convert: dependency: transitive description: diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 8c2d6cc53..a98c2e6c4 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -34,7 +34,6 @@ dependencies: shared_preferences: ^2.1.2 package_info_plus: ^4.0.2 uuid: ^3.0.7 - confetti: ^0.7.0 social_share: ^2.3.1 test: ^1.24.1 version: ^3.0.2 From 33a18a174f009ffe3b461e500a47997717af0851 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Sat, 4 May 2024 13:11:06 +0200 Subject: [PATCH 17/32] chore: Move error details to task dialog --- mobile/lib/common/task_status_dialog.dart | 31 +++--- mobile/lib/common/xxi_screen.dart | 51 +++++----- mobile/lib/features/trade/error_details.dart | 101 +++++++++---------- 3 files changed, 88 insertions(+), 95 deletions(-) diff --git a/mobile/lib/common/task_status_dialog.dart b/mobile/lib/common/task_status_dialog.dart index 0a2d2f151..d8a4496da 100644 --- a/mobile/lib/common/task_status_dialog.dart +++ b/mobile/lib/common/task_status_dialog.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get_10101/common/color.dart'; import 'package:get_10101/common/domain/background_task.dart'; +import 'package:get_10101/features/trade/error_details.dart'; import 'package:go_router/go_router.dart'; /// Define Animation Type @@ -18,21 +19,15 @@ class AppAnim { } class TaskStatusDialog extends StatefulWidget { - final String title; - final TaskStatus status; + final BackgroundTask task; final Widget content; - final String buttonText; - final EdgeInsets insetPadding; final VoidCallback? onClose; const TaskStatusDialog({ super.key, - required this.title, - required this.status, + required this.task, required this.content, this.onClose, - this.buttonText = "Close", - this.insetPadding = const EdgeInsets.all(50), }); @override @@ -52,7 +47,7 @@ class _TaskStatusDialog extends State { @override Widget build(BuildContext context) { - bool isPending = widget.status == TaskStatus.pending; + bool isPending = widget.task.status == TaskStatus.pending; if (_timeout != null) { // cancel already running timeout timer if we receive a new update. @@ -69,7 +64,7 @@ class _TaskStatusDialog extends State { } Widget closeButton = SizedBox( - width: MediaQuery.of(context).size.width * 0.6, + width: MediaQuery.of(context).size.width * 0.65, child: ElevatedButton( onPressed: () { GoRouter.of(context).pop(); @@ -82,7 +77,7 @@ class _TaskStatusDialog extends State { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), padding: EdgeInsets.zero, backgroundColor: tenTenOnePurple), - child: Text(widget.buttonText)), + child: const Text("Close")), ); AlertDialog dialog = AlertDialog( @@ -91,7 +86,7 @@ class _TaskStatusDialog extends State { borderRadius: BorderRadius.circular(18.0), ), content: Container( - height: 330, + height: widget.task.status == TaskStatus.failed ? 450 : 330, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(18.0), @@ -109,7 +104,7 @@ class _TaskStatusDialog extends State { color: Colors.white, ), child: Image.asset( - switch (widget.status) { + switch (widget.task.status) { TaskStatus.pending => AppAnim.loading, TaskStatus.failed => AppAnim.error, TaskStatus.success => AppAnim.success, @@ -118,14 +113,19 @@ class _TaskStatusDialog extends State { ), ), const SizedBox(height: 15), - buildTitle(widget.status), + buildTitle(widget.task.status), Padding( padding: const EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0), child: widget.content), + if (widget.task.status == TaskStatus.failed && widget.task.error != null) + Padding( + padding: const EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0), + child: ErrorDetails(details: widget.task.error!), + ), const Spacer(), if (!isPending || timeout) Padding( - padding: const EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0, bottom: 10.0), + padding: const EdgeInsets.only(top: 10.0, left: 15.0, right: 15.0, bottom: 15.0), child: Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.center, @@ -137,7 +137,6 @@ class _TaskStatusDialog extends State { ], ), ), - insetPadding: widget.insetPadding, ); // If pending, prevent use of back button diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index 8115c5180..ba2a1f34a 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -3,7 +3,6 @@ import 'package:flutter/services.dart'; import 'package:get_10101/common/background_task_change_notifier.dart'; import 'package:get_10101/common/domain/background_task.dart'; import 'package:get_10101/common/task_status_dialog.dart'; -import 'package:get_10101/features/trade/error_details.dart'; import 'package:get_10101/logger/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'dart:convert'; @@ -89,18 +88,21 @@ class _XXIScreenState extends State { TaskStatusDialog? getTaskStatusDialog(BackgroundTask? task) { return switch (task?.type) { TaskType.rollover => TaskStatusDialog( - title: "Rollover", - status: task!.status, - content: const Text("Rolling over your position"), + task: task!, + content: switch (task.status) { + TaskStatus.pending => const Text( + "Please don't close the app while your position is rolled over to the next week."), + TaskStatus.failed => const Text("Oops, something went wrong!"), + TaskStatus.success => + const Text("Your position has been successfully rolled over to the next week."), + }, onClose: () => activeTask = null), TaskType.collaborativeRevert => TaskStatusDialog( - title: "Collaborative Channel Close!", - status: task!.status, + task: task!, content: const Text("Your channel has been closed collaboratively!"), onClose: () => activeTask = null), TaskType.fullSync => TaskStatusDialog( - title: "Full wallet sync", - status: task!.status, + task: task!, content: switch (task.status) { TaskStatus.pending => const Text("Waiting for on-chain sync to complete"), TaskStatus.success => const Text( @@ -110,26 +112,23 @@ class _XXIScreenState extends State { }, onClose: () => activeTask = null), TaskType.recover => TaskStatusDialog( - title: "Catching up!", - status: task!.status, - content: const Text("Recovering your dlc channel"), + task: task!, + content: switch (task.status) { + TaskStatus.pending => const Text( + "Looks like your app was closed before the dlc protocol finished. Please don't close the app while we recover your dlc channel."), + TaskStatus.failed => + const Text("Oh snap! Something went wrong trying to recover your dlc channel."), + TaskStatus.success => const Text("Your dlc channel has been recovered successfully!"), + }, onClose: () => activeTask = null), TaskType.asyncTrade => TaskStatusDialog( - title: "Executing Order!", - status: task!.status, - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - switch (task.status) { - TaskStatus.pending => - const Text("Please do not close the app while the trade is executed."), - TaskStatus.success => const Text("The order has been successfully executed!"), - TaskStatus.failed => const Text("Something went wrong!") - }, - if (task.status == TaskStatus.failed && task.error != null) - ErrorDetails(details: task.error!) - ], - ), + task: task!, + content: switch (task.status) { + TaskStatus.pending => + const Text("Please do not close the app while the trade is executed."), + TaskStatus.success => const Text("The order has been successfully executed!"), + TaskStatus.failed => const Text("Oops, something went wrong!") + }, onClose: () => activeTask = null), TaskType.unknown || null => null }; diff --git a/mobile/lib/features/trade/error_details.dart b/mobile/lib/features/trade/error_details.dart index f439cba56..ce54f8102 100644 --- a/mobile/lib/features/trade/error_details.dart +++ b/mobile/lib/features/trade/error_details.dart @@ -12,65 +12,60 @@ class ErrorDetails extends StatelessWidget { @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(top: 20, left: 10, right: 10, bottom: 5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Error details:", - style: TextStyle(fontSize: 15), - ), - Padding( - padding: const EdgeInsets.all(5.0), - child: SizedBox.square( - child: Container( - padding: const EdgeInsets.fromLTRB(5, 25, 5, 10.0), - color: Colors.grey.shade300, - child: Column( + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Error details", + style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), + ), + SizedBox.square( + child: Container( + padding: const EdgeInsets.fromLTRB(5, 25, 5, 10.0), + color: Colors.grey.shade300, + child: Column( + children: [ + Text( + getPrettyJSONString(details), + style: const TextStyle(fontSize: 15), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text( - getPrettyJSONString(details), - style: const TextStyle(fontSize: 15), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - GestureDetector( - child: const Icon(Icons.content_copy, size: 16), - onTap: () { - Clipboard.setData(ClipboardData(text: details)).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text("Copied to clipboard"), - ), - ); - }); - }, - ), - Padding( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - ), - child: GestureDetector( - child: const Icon(Icons.share, size: 16), - onTap: () => Share.share(details), - ), - ) - ], + GestureDetector( + child: const Icon(Icons.content_copy, size: 16), + onTap: () { + Clipboard.setData(ClipboardData(text: details)).then((_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Copied to clipboard"), + ), + ); + }); + }, ), + Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + ), + child: GestureDetector( + child: const Icon(Icons.share, size: 16), + onTap: () => Share.share(details), + ), + ) ], ), - ), + ], ), ), - ClickableHelpText( - text: "Please help us fix this issue and join our telegram group: ", - style: DefaultTextStyle.of(context).style), - ], - ), + ), + const SizedBox(height: 5), + ClickableHelpText( + text: "Please help us fix this issue and join our telegram group: ", + style: DefaultTextStyle.of(context).style), + ], ); } } From 3f06a7400df33b6c5773c6a3c902855d21613ef8 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Sat, 4 May 2024 13:17:27 +0200 Subject: [PATCH 18/32] docs: Add todo to send trade error in case the coordinator fails in the protocol. --- coordinator/src/node.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coordinator/src/node.rs b/coordinator/src/node.rs index 16fb62e50..68150633d 100644 --- a/coordinator/src/node.rs +++ b/coordinator/src/node.rs @@ -126,6 +126,9 @@ impl Node { ); } + // TODO(holzeis): Send TradeError to user in case the coordinator failed to process + // the users message + tracing::error!( from = %node_id, kind = %msg_name, From 5cd2288c0beed9091d8638206333cce3639cda7c Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Sat, 4 May 2024 18:31:56 +0200 Subject: [PATCH 19/32] feat: Make error details scrollable --- mobile/lib/common/task_status_dialog.dart | 2 +- mobile/lib/features/trade/error_details.dart | 79 +++++++++++--------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/mobile/lib/common/task_status_dialog.dart b/mobile/lib/common/task_status_dialog.dart index d8a4496da..748772bf0 100644 --- a/mobile/lib/common/task_status_dialog.dart +++ b/mobile/lib/common/task_status_dialog.dart @@ -86,7 +86,7 @@ class _TaskStatusDialog extends State { borderRadius: BorderRadius.circular(18.0), ), content: Container( - height: widget.task.status == TaskStatus.failed ? 450 : 330, + height: widget.task.status == TaskStatus.failed ? 480 : 330, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(18.0), diff --git a/mobile/lib/features/trade/error_details.dart b/mobile/lib/features/trade/error_details.dart index ce54f8102..ab800f2db 100644 --- a/mobile/lib/features/trade/error_details.dart +++ b/mobile/lib/features/trade/error_details.dart @@ -19,49 +19,54 @@ class ErrorDetails extends StatelessWidget { "Error details", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), ), - SizedBox.square( + SizedBox( + width: 300, + height: 120, child: Container( - padding: const EdgeInsets.fromLTRB(5, 25, 5, 10.0), + padding: const EdgeInsets.all(5.0), color: Colors.grey.shade300, - child: Column( - children: [ - Text( - getPrettyJSONString(details), - style: const TextStyle(fontSize: 15), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - GestureDetector( - child: const Icon(Icons.content_copy, size: 16), - onTap: () { - Clipboard.setData(ClipboardData(text: details)).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text("Copied to clipboard"), - ), - ); - }); - }, - ), - Padding( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - ), - child: GestureDetector( - child: const Icon(Icons.share, size: 16), - onTap: () => Share.share(details), - ), - ) - ], - ), - ], + child: SingleChildScrollView( + child: Column( + children: [ + Text( + getPrettyJSONString(details), + style: const TextStyle(fontSize: 15), + ), + ], + ), ), ), ), const SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + GestureDetector( + child: const Icon(Icons.content_copy, size: 16), + onTap: () { + Clipboard.setData(ClipboardData(text: details)).then((_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Copied to clipboard"), + ), + ); + }); + }, + ), + Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + ), + child: GestureDetector( + child: const Icon(Icons.share, size: 16), + onTap: () => Share.share(details), + ), + ) + ], + ), + const SizedBox(height: 5), ClickableHelpText( text: "Please help us fix this issue and join our telegram group: ", style: DefaultTextStyle.of(context).style), From 47f9329bcb29b10b3f85e7c4f88d536fc8b60fa2 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Sun, 5 May 2024 11:35:30 +0200 Subject: [PATCH 20/32] feat: Override active task if types are different It feels more logical to show the new task event event if the previous event was of a different type. --- mobile/lib/common/xxi_screen.dart | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/xxi_screen.dart index ba2a1f34a..e9ab92fd6 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/xxi_screen.dart @@ -63,19 +63,11 @@ class _XXIScreenState extends State { // watch task updates from within the dialog. final task = context.watch().events.pop(); if (activeTask != null && task.type != activeTask!.type) { - if (activeTask!.type == TaskType.recover && task.type == TaskType.asyncTrade) { - // in case a trade protocol finishes we get an async trade task status update, but - // there might have been a restart in between as why the recover task dialog is - // shown. Since these two tasks are different we have to handle this case here - // and only update the task status of the active task. - activeTask!.status = task.status; - } else { - logger.w("Ignoring task event $task while $activeTask is still active!"); - } - } else { - // update the active task to the last event received on the stack. - activeTask = task; + logger.w("Received another task event $task while $activeTask is still active!"); } + + // update the active task to the last event received on the stack. + activeTask = task; return getTaskStatusDialog(activeTask)!; }); } From dd93510f13ec0fa43c14ff8b3966c881dd9b1cbc Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 08:25:25 +0200 Subject: [PATCH 21/32] fix: Add missing force reject case for rollover offer --- mobile/native/src/dlc/node.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mobile/native/src/dlc/node.rs b/mobile/native/src/dlc/node.rs index fd043c4a7..898d83be0 100644 --- a/mobile/native/src/dlc/node.rs +++ b/mobile/native/src/dlc/node.rs @@ -245,6 +245,15 @@ impl Node { .. }, .. + }) + | TenTenOneMessage::RolloverOffer(TenTenOneRolloverOffer { + renew_offer: + RenewOffer { + channel_id, + reference_id, + .. + }, + .. }) => { if let Err(e) = self.force_reject_offer(node_id, *channel_id, *reference_id) { From 5eed0913fdc853848a844829f089bfb817bdd114 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 08:34:08 +0200 Subject: [PATCH 22/32] chore!: Add remaining rollover dlc messages This will allow us to clearly differentiate between a reopen/resize and a rollover protocol. We need this in order to be able to add the order id to all trade related messages. BREAKING change due to a changed protocol message --- .../down.sql | 1 + .../up.sql | 12 ++ coordinator/src/db/custom_types.rs | 12 +- coordinator/src/db/dlc_messages.rs | 20 ++- coordinator/src/node.rs | 18 ++- crates/xxi-node/src/dlc_message.rs | 48 +++++-- crates/xxi-node/src/message_handler.rs | 131 +++++++++++++++--- crates/xxi-node/src/node/dlc_manager.rs | 4 +- mobile/native/src/db/custom_types.rs | 11 +- mobile/native/src/db/dlc_messages.rs | 20 ++- mobile/native/src/dlc/node.rs | 73 +++++----- 11 files changed, 274 insertions(+), 76 deletions(-) create mode 100644 coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/down.sql create mode 100644 coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/up.sql diff --git a/coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/down.sql b/coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/down.sql new file mode 100644 index 000000000..ab290eb4c --- /dev/null +++ b/coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/down.sql @@ -0,0 +1 @@ +select 1; diff --git a/coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/up.sql b/coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/up.sql new file mode 100644 index 000000000..340fae0aa --- /dev/null +++ b/coordinator/migrations/2024-05-06-082611_add_remaining_rollover_dlc_message_types/up.sql @@ -0,0 +1,12 @@ +ALTER TYPE "Message_Type_Type" + ADD + VALUE IF NOT EXISTS 'RolloverAccept'; +ALTER TYPE "Message_Type_Type" + ADD + VALUE IF NOT EXISTS 'RolloverConfirm'; +ALTER TYPE "Message_Type_Type" + ADD + VALUE IF NOT EXISTS 'RolloverFinalize'; +ALTER TYPE "Message_Type_Type" + ADD + VALUE IF NOT EXISTS 'RolloverRevoke'; diff --git a/coordinator/src/db/custom_types.rs b/coordinator/src/db/custom_types.rs index acf4e24a8..954abbe9d 100644 --- a/coordinator/src/db/custom_types.rs +++ b/coordinator/src/db/custom_types.rs @@ -105,11 +105,15 @@ impl ToSql for MessageType { MessageType::SettleConfirm => out.write_all(b"SettleConfirm")?, MessageType::SettleFinalize => out.write_all(b"SettleFinalize")?, MessageType::RenewOffer => out.write_all(b"RenewOffer")?, - MessageType::RolloverOffer => out.write_all(b"RolloverOffer")?, MessageType::RenewAccept => out.write_all(b"RenewAccept")?, MessageType::RenewConfirm => out.write_all(b"RenewConfirm")?, MessageType::RenewFinalize => out.write_all(b"RenewFinalize")?, MessageType::RenewRevoke => out.write_all(b"RenewRevoke")?, + MessageType::RolloverOffer => out.write_all(b"RolloverOffer")?, + MessageType::RolloverAccept => out.write_all(b"RolloverAccept")?, + MessageType::RolloverConfirm => out.write_all(b"RolloverConfirm")?, + MessageType::RolloverFinalize => out.write_all(b"RolloverFinalize")?, + MessageType::RolloverRevoke => out.write_all(b"RolloverRevoke")?, MessageType::CollaborativeCloseOffer => out.write_all(b"CollaborativeCloseOffer")?, MessageType::Reject => out.write_all(b"Reject")?, } @@ -128,11 +132,15 @@ impl FromSql for MessageType { b"SettleConfirm" => Ok(MessageType::SettleConfirm), b"SettleFinalize" => Ok(MessageType::SettleFinalize), b"RenewOffer" => Ok(MessageType::RenewOffer), - b"RolloverOffer" => Ok(MessageType::RolloverOffer), b"RenewAccept" => Ok(MessageType::RenewAccept), b"RenewConfirm" => Ok(MessageType::RenewConfirm), b"RenewFinalize" => Ok(MessageType::RenewFinalize), b"RenewRevoke" => Ok(MessageType::RenewRevoke), + b"RolloverOffer" => Ok(MessageType::RolloverOffer), + b"RolloverAccept" => Ok(MessageType::RolloverAccept), + b"RolloverConfirm" => Ok(MessageType::RolloverConfirm), + b"RolloverFinalize" => Ok(MessageType::RolloverFinalize), + b"RolloverRevoke" => Ok(MessageType::RolloverRevoke), b"CollaborativeCloseOffer" => Ok(MessageType::CollaborativeCloseOffer), b"Reject" => Ok(MessageType::Reject), _ => Err("Unrecognized enum variant".into()), diff --git a/coordinator/src/db/dlc_messages.rs b/coordinator/src/db/dlc_messages.rs index 99ba11cfc..88bbdff9b 100644 --- a/coordinator/src/db/dlc_messages.rs +++ b/coordinator/src/db/dlc_messages.rs @@ -32,11 +32,15 @@ pub(crate) enum MessageType { SettleConfirm, SettleFinalize, RenewOffer, - RolloverOffer, RenewAccept, RenewConfirm, RenewFinalize, RenewRevoke, + RolloverOffer, + RolloverAccept, + RolloverConfirm, + RolloverFinalize, + RolloverRevoke, CollaborativeCloseOffer, Reject, } @@ -103,11 +107,15 @@ impl From for MessageType { xxi_node::dlc_message::DlcMessageType::SettleConfirm => Self::SettleConfirm, xxi_node::dlc_message::DlcMessageType::SettleFinalize => Self::SettleFinalize, xxi_node::dlc_message::DlcMessageType::RenewOffer => Self::RenewOffer, - xxi_node::dlc_message::DlcMessageType::RolloverOffer => Self::RolloverOffer, xxi_node::dlc_message::DlcMessageType::RenewAccept => Self::RenewAccept, xxi_node::dlc_message::DlcMessageType::RenewConfirm => Self::RenewConfirm, xxi_node::dlc_message::DlcMessageType::RenewFinalize => Self::RenewFinalize, xxi_node::dlc_message::DlcMessageType::RenewRevoke => Self::RenewRevoke, + xxi_node::dlc_message::DlcMessageType::RolloverOffer => Self::RolloverOffer, + xxi_node::dlc_message::DlcMessageType::RolloverAccept => Self::RolloverAccept, + xxi_node::dlc_message::DlcMessageType::RolloverConfirm => Self::RolloverConfirm, + xxi_node::dlc_message::DlcMessageType::RolloverFinalize => Self::RolloverFinalize, + xxi_node::dlc_message::DlcMessageType::RolloverRevoke => Self::RolloverRevoke, xxi_node::dlc_message::DlcMessageType::CollaborativeCloseOffer => { Self::CollaborativeCloseOffer } @@ -139,11 +147,17 @@ impl From for xxi_node::dlc_message::DlcMessageType { MessageType::SettleConfirm => xxi_node::dlc_message::DlcMessageType::SettleConfirm, MessageType::SettleFinalize => xxi_node::dlc_message::DlcMessageType::SettleFinalize, MessageType::RenewOffer => xxi_node::dlc_message::DlcMessageType::RenewOffer, - MessageType::RolloverOffer => xxi_node::dlc_message::DlcMessageType::RolloverOffer, MessageType::RenewAccept => xxi_node::dlc_message::DlcMessageType::RenewAccept, MessageType::RenewConfirm => xxi_node::dlc_message::DlcMessageType::RenewConfirm, MessageType::RenewFinalize => xxi_node::dlc_message::DlcMessageType::RenewFinalize, MessageType::RenewRevoke => xxi_node::dlc_message::DlcMessageType::RenewRevoke, + MessageType::RolloverOffer => xxi_node::dlc_message::DlcMessageType::RolloverOffer, + MessageType::RolloverAccept => xxi_node::dlc_message::DlcMessageType::RolloverAccept, + MessageType::RolloverConfirm => xxi_node::dlc_message::DlcMessageType::RolloverConfirm, + MessageType::RolloverFinalize => { + xxi_node::dlc_message::DlcMessageType::RolloverFinalize + } + MessageType::RolloverRevoke => xxi_node::dlc_message::DlcMessageType::RolloverRevoke, MessageType::CollaborativeCloseOffer => { xxi_node::dlc_message::DlcMessageType::CollaborativeCloseOffer } diff --git a/coordinator/src/node.rs b/coordinator/src/node.rs index 68150633d..78354e07e 100644 --- a/coordinator/src/node.rs +++ b/coordinator/src/node.rs @@ -32,6 +32,7 @@ use xxi_node::message_handler::TenTenOneCollaborativeCloseOffer; use xxi_node::message_handler::TenTenOneMessage; use xxi_node::message_handler::TenTenOneReject; use xxi_node::message_handler::TenTenOneRenewFinalize; +use xxi_node::message_handler::TenTenOneRolloverFinalize; use xxi_node::message_handler::TenTenOneSettleFinalize; use xxi_node::message_handler::TenTenOneSignChannel; use xxi_node::node; @@ -154,8 +155,9 @@ impl Node { /// - Any message that has already been processed will be skipped. /// /// Offers such as [`TenTenOneMessage::Offer`], [`TenTenOneMessage::SettleOffer`], - /// [`TenTenOneMessage::CollaborativeCloseOffer`] and [`TenTenOneMessage::RenewOffer`] are - /// automatically accepted. Unless the maturity date of the offer is already outdated. + /// [`TenTenOneMessage::RolloverOffer`], [`TenTenOneMessage::CollaborativeCloseOffer`] and + /// [`TenTenOneMessage::RenewOffer`] are automatically accepted. Unless the maturity date of + /// the offer is already outdated. /// /// FIXME(holzeis): This function manipulates different data objects from different data sources /// and should use a transaction to make all changes atomic. Not doing so risks ending up in an @@ -226,11 +228,15 @@ impl Node { reference_id, .. }, + }) + | TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { + renew_finalize: + RenewFinalize { + channel_id, + reference_id, + .. + }, }) => { - // TODO: Receiving this message used to be specific to rolling over, but we - // now use the renew protocol for all (non-closing) - // trades beyond the first one. - let channel_id_hex_string = hex::encode(channel_id); let reference_id = match reference_id { diff --git a/crates/xxi-node/src/dlc_message.rs b/crates/xxi-node/src/dlc_message.rs index d41456b39..67464abc3 100644 --- a/crates/xxi-node/src/dlc_message.rs +++ b/crates/xxi-node/src/dlc_message.rs @@ -58,11 +58,15 @@ pub enum DlcMessageType { SettleConfirm, SettleFinalize, RenewOffer, - RolloverOffer, RenewAccept, RenewConfirm, RenewFinalize, RenewRevoke, + RolloverOffer, + RolloverAccept, + RolloverConfirm, + RolloverFinalize, + RolloverRevoke, CollaborativeCloseOffer, Reject, } @@ -99,9 +103,6 @@ impl TryFrom<&SerializedDlcMessage> for TenTenOneMessage { DlcMessageType::RenewOffer => { TenTenOneMessage::RenewOffer(serde_json::from_str(&serialized_msg.message)?) } - DlcMessageType::RolloverOffer => { - TenTenOneMessage::RolloverOffer(serde_json::from_str(&serialized_msg.message)?) - } DlcMessageType::RenewAccept => { TenTenOneMessage::RenewAccept(serde_json::from_str(&serialized_msg.message)?) } @@ -114,6 +115,21 @@ impl TryFrom<&SerializedDlcMessage> for TenTenOneMessage { DlcMessageType::RenewRevoke => { TenTenOneMessage::RenewRevoke(serde_json::from_str(&serialized_msg.message)?) } + DlcMessageType::RolloverOffer => { + TenTenOneMessage::RolloverOffer(serde_json::from_str(&serialized_msg.message)?) + } + DlcMessageType::RolloverAccept => { + TenTenOneMessage::RolloverAccept(serde_json::from_str(&serialized_msg.message)?) + } + DlcMessageType::RolloverConfirm => { + TenTenOneMessage::RolloverConfirm(serde_json::from_str(&serialized_msg.message)?) + } + DlcMessageType::RolloverFinalize => { + TenTenOneMessage::RolloverFinalize(serde_json::from_str(&serialized_msg.message)?) + } + DlcMessageType::RolloverRevoke => { + TenTenOneMessage::RolloverRevoke(serde_json::from_str(&serialized_msg.message)?) + } DlcMessageType::CollaborativeCloseOffer => TenTenOneMessage::CollaborativeCloseOffer( serde_json::from_str(&serialized_msg.message)?, ), @@ -155,10 +171,6 @@ impl TryFrom<&TenTenOneMessage> for SerializedDlcMessage { serde_json::to_string(&renew_offer)?, DlcMessageType::RenewOffer, ), - TenTenOneMessage::RolloverOffer(rollover_offer) => ( - serde_json::to_string(&rollover_offer)?, - DlcMessageType::RolloverOffer, - ), TenTenOneMessage::RenewAccept(renew_accept) => ( serde_json::to_string(&renew_accept)?, DlcMessageType::RenewAccept, @@ -182,6 +194,26 @@ impl TryFrom<&TenTenOneMessage> for SerializedDlcMessage { TenTenOneMessage::Reject(reject) => { (serde_json::to_string(&reject)?, DlcMessageType::Reject) } + TenTenOneMessage::RolloverOffer(rollover_offer) => ( + serde_json::to_string(&rollover_offer)?, + DlcMessageType::RolloverOffer, + ), + TenTenOneMessage::RolloverAccept(rollover_accept) => ( + serde_json::to_string(&rollover_accept)?, + DlcMessageType::RolloverAccept, + ), + TenTenOneMessage::RolloverConfirm(rollover_confirm) => ( + serde_json::to_string(&rollover_confirm)?, + DlcMessageType::RolloverConfirm, + ), + TenTenOneMessage::RolloverFinalize(rollover_finalize) => ( + serde_json::to_string(&rollover_finalize)?, + DlcMessageType::RolloverFinalize, + ), + TenTenOneMessage::RolloverRevoke(rollover_revoke) => ( + serde_json::to_string(&rollover_revoke)?, + DlcMessageType::RolloverRevoke, + ), }; Ok(Self { diff --git a/crates/xxi-node/src/message_handler.rs b/crates/xxi-node/src/message_handler.rs index 00e386e95..98c403efb 100644 --- a/crates/xxi-node/src/message_handler.rs +++ b/crates/xxi-node/src/message_handler.rs @@ -132,20 +132,21 @@ pub enum TenTenOneMessage { SettleConfirm(TenTenOneSettleConfirm), SettleFinalize(TenTenOneSettleFinalize), RenewOffer(TenTenOneRenewOffer), - RolloverOffer(TenTenOneRolloverOffer), RenewAccept(TenTenOneRenewAccept), RenewConfirm(TenTenOneRenewConfirm), RenewFinalize(TenTenOneRenewFinalize), RenewRevoke(TenTenOneRenewRevoke), + RolloverOffer(TenTenOneRolloverOffer), + RolloverAccept(TenTenOneRolloverAccept), + RolloverConfirm(TenTenOneRolloverConfirm), + RolloverFinalize(TenTenOneRolloverFinalize), + RolloverRevoke(TenTenOneRolloverRevoke), CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer), } impl TenTenOneMessage { /// Returns true if the message is a trade message. e.g. Reject, Rollover or Collaborative Close /// Offer are not trade messages. - /// - /// FIXME(holzeis): This will also return true for any message past the offe rin case of a - /// rollover. We proobably need to add some hint on the message that this is due to a rollover. pub fn is_trade(&self) -> bool { matches!( self, @@ -163,6 +164,18 @@ impl TenTenOneMessage { | TenTenOneMessage::SettleFinalize(_) ) } + + /// Returns true if the message is a rollover message. + pub fn is_rollover(&self) -> bool { + matches!( + self, + TenTenOneMessage::RolloverOffer(_) + | TenTenOneMessage::RolloverAccept(_) + | TenTenOneMessage::RolloverConfirm(_) + | TenTenOneMessage::RolloverFinalize(_) + | TenTenOneMessage::RolloverRevoke(_) + ) + } } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -214,28 +227,48 @@ pub struct TenTenOneRenewOffer { pub renew_offer: RenewOffer, } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct TenTenOneRenewAccept { + pub renew_accept: RenewAccept, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct TenTenOneRenewConfirm { + pub renew_confirm: RenewConfirm, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct TenTenOneRenewFinalize { + pub renew_finalize: RenewFinalize, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct TenTenOneRenewRevoke { + pub renew_revoke: RenewRevoke, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct TenTenOneRolloverOffer { pub renew_offer: RenewOffer, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct TenTenOneRenewAccept { +pub struct TenTenOneRolloverAccept { pub renew_accept: RenewAccept, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct TenTenOneRenewConfirm { +pub struct TenTenOneRolloverConfirm { pub renew_confirm: RenewConfirm, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct TenTenOneRenewFinalize { +pub struct TenTenOneRolloverFinalize { pub renew_finalize: RenewFinalize, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct TenTenOneRenewRevoke { +pub struct TenTenOneRolloverRevoke { pub renew_revoke: RenewRevoke, } @@ -411,11 +444,15 @@ pub fn tentenone_message_name(msg: &TenTenOneMessage) -> String { TenTenOneMessage::SettleConfirm(_) => "SettleConfirm", TenTenOneMessage::SettleFinalize(_) => "SettleFinalize", TenTenOneMessage::RenewOffer(_) => "RenewOffer", - TenTenOneMessage::RolloverOffer(_) => "RolloverOffer", TenTenOneMessage::RenewAccept(_) => "RenewAccept", TenTenOneMessage::RenewConfirm(_) => "RenewConfirm", TenTenOneMessage::RenewFinalize(_) => "RenewFinalize", TenTenOneMessage::RenewRevoke(_) => "RenewRevoke", + TenTenOneMessage::RolloverOffer(_) => "RolloverOffer", + TenTenOneMessage::RolloverAccept(_) => "RolloverAccept", + TenTenOneMessage::RolloverConfirm(_) => "RolloverConfirm", + TenTenOneMessage::RolloverFinalize(_) => "RolloverFinalize", + TenTenOneMessage::RolloverRevoke(_) => "RolloverRevoke", TenTenOneMessage::CollaborativeCloseOffer(_) => "CollaborativeCloseOffer", TenTenOneMessage::Reject(_) => "Reject", }; @@ -428,7 +465,7 @@ impl TenTenOneMessage { /// an offer so if an offer is passed the function will panic. This is most likely not a future /// proof solution as we'd might want to enrich the response with 10101 metadata as well. If /// that happens we will have to rework this part. - pub fn build_from_response(message: Message) -> Self { + pub fn build_from_response(message: Message, is_rollover: bool) -> Self { match message { Message::Channel(ChannelMessage::Accept(accept_channel)) => { TenTenOneMessage::Accept(TenTenOneAcceptChannel { accept_channel }) @@ -445,6 +482,18 @@ impl TenTenOneMessage { Message::Channel(ChannelMessage::SettleFinalize(settle_finalize)) => { TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { settle_finalize }) } + Message::Channel(ChannelMessage::RenewAccept(renew_accept)) if is_rollover => { + TenTenOneMessage::RolloverAccept(TenTenOneRolloverAccept { renew_accept }) + } + Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)) if is_rollover => { + TenTenOneMessage::RolloverConfirm(TenTenOneRolloverConfirm { renew_confirm }) + } + Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)) if is_rollover => { + TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { renew_finalize }) + } + Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)) if is_rollover => { + TenTenOneMessage::RolloverRevoke(TenTenOneRolloverRevoke { renew_revoke }) + } Message::Channel(ChannelMessage::RenewAccept(renew_accept)) => { TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept }) } @@ -507,6 +556,18 @@ impl TenTenOneMessage { | TenTenOneMessage::RolloverOffer(TenTenOneRolloverOffer { renew_offer: RenewOffer { reference_id, .. }, }) + | TenTenOneMessage::RolloverAccept(TenTenOneRolloverAccept { + renew_accept: RenewAccept { reference_id, .. }, + }) + | TenTenOneMessage::RolloverConfirm(TenTenOneRolloverConfirm { + renew_confirm: RenewConfirm { reference_id, .. }, + }) + | TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { + renew_finalize: RenewFinalize { reference_id, .. }, + }) + | TenTenOneMessage::RolloverRevoke(TenTenOneRolloverRevoke { + renew_revoke: RenewRevoke { reference_id, .. }, + }) | TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept: RenewAccept { reference_id, .. }, }) @@ -563,9 +624,6 @@ impl From for ChannelMessage { TenTenOneMessage::RenewOffer(TenTenOneRenewOffer { renew_offer, .. }) => { ChannelMessage::RenewOffer(renew_offer) } - TenTenOneMessage::RolloverOffer(TenTenOneRolloverOffer { renew_offer }) => { - ChannelMessage::RenewOffer(renew_offer) - } TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept }) => { ChannelMessage::RenewAccept(renew_accept) } @@ -578,6 +636,21 @@ impl From for ChannelMessage { TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke }) => { ChannelMessage::RenewRevoke(renew_revoke) } + TenTenOneMessage::RolloverOffer(TenTenOneRolloverOffer { renew_offer }) => { + ChannelMessage::RenewOffer(renew_offer) + } + TenTenOneMessage::RolloverAccept(TenTenOneRolloverAccept { renew_accept }) => { + ChannelMessage::RenewAccept(renew_accept) + } + TenTenOneMessage::RolloverConfirm(TenTenOneRolloverConfirm { renew_confirm }) => { + ChannelMessage::RenewConfirm(renew_confirm) + } + TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { renew_finalize }) => { + ChannelMessage::RenewFinalize(renew_finalize) + } + TenTenOneMessage::RolloverRevoke(TenTenOneRolloverRevoke { renew_revoke }) => { + ChannelMessage::RenewRevoke(renew_revoke) + } TenTenOneMessage::CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer { collaborative_close_offer, }) => ChannelMessage::CollaborativeCloseOffer(collaborative_close_offer), @@ -661,11 +734,15 @@ impl_type_writeable_for_enum!(TenTenOneMessage, SettleConfirm, SettleFinalize, RenewOffer, - RolloverOffer, RenewAccept, RenewConfirm, RenewFinalize, RenewRevoke, + RolloverOffer, + RolloverAccept, + RolloverConfirm, + RolloverFinalize, + RolloverRevoke, CollaborativeCloseOffer }); @@ -678,11 +755,15 @@ impl_dlc_writeable!(TenTenOneSettleAccept, { (settle_accept, writeable) }); impl_dlc_writeable!(TenTenOneSettleConfirm, { (settle_confirm, writeable) }); impl_dlc_writeable!(TenTenOneSettleFinalize, { (settle_finalize, writeable) }); impl_dlc_writeable!(TenTenOneRenewOffer, { (filled_with, writeable), (renew_offer, writeable) }); -impl_dlc_writeable!(TenTenOneRolloverOffer, { (renew_offer, writeable) }); impl_dlc_writeable!(TenTenOneRenewAccept, { (renew_accept, writeable) }); impl_dlc_writeable!(TenTenOneRenewConfirm, { (renew_confirm, writeable) }); impl_dlc_writeable!(TenTenOneRenewFinalize, { (renew_finalize, writeable) }); impl_dlc_writeable!(TenTenOneRenewRevoke, { (renew_revoke, writeable) }); +impl_dlc_writeable!(TenTenOneRolloverOffer, { (renew_offer, writeable) }); +impl_dlc_writeable!(TenTenOneRolloverAccept, { (renew_accept, writeable) }); +impl_dlc_writeable!(TenTenOneRolloverConfirm, { (renew_confirm, writeable) }); +impl_dlc_writeable!(TenTenOneRolloverFinalize, { (renew_finalize, writeable) }); +impl_dlc_writeable!(TenTenOneRolloverRevoke, { (renew_revoke, writeable) }); impl_dlc_writeable!(TenTenOneCollaborativeCloseOffer, { (collaborative_close_offer, writeable) }); @@ -696,11 +777,23 @@ impl_type!(SETTLE_CHANNEL_ACCEPT_TYPE, TenTenOneSettleAccept, 43008); impl_type!(SETTLE_CHANNEL_CONFIRM_TYPE, TenTenOneSettleConfirm, 43010); impl_type!(SETTLE_CHANNEL_FINALIZE_TYPE, TenTenOneSettleFinalize, 43012); impl_type!(RENEW_CHANNEL_OFFER_TYPE, TenTenOneRenewOffer, 43014); -impl_type!(ROLLOVER_CHANNEL_OFFER_TYPE, TenTenOneRolloverOffer, 43028); impl_type!(RENEW_CHANNEL_ACCEPT_TYPE, TenTenOneRenewAccept, 43016); impl_type!(RENEW_CHANNEL_CONFIRM_TYPE, TenTenOneRenewConfirm, 43018); impl_type!(RENEW_CHANNEL_FINALIZE_TYPE, TenTenOneRenewFinalize, 43020); impl_type!(RENEW_CHANNEL_REVOKE_TYPE, TenTenOneRenewRevoke, 43026); +impl_type!(ROLLOVER_CHANNEL_OFFER_TYPE, TenTenOneRolloverOffer, 43028); +impl_type!(ROLLOVER_CHANNEL_ACCEPT_TYPE, TenTenOneRolloverAccept, 43030); +impl_type!( + ROLLOVER_CHANNEL_CONFIRM_TYPE, + TenTenOneRolloverConfirm, + 43032 +); +impl_type!( + ROLLOVER_CHANNEL_FINALIZE_TYPE, + TenTenOneRolloverFinalize, + 43034 +); +impl_type!(ROLLOVER_CHANNEL_REVOKE_TYPE, TenTenOneRolloverRevoke, 43036); impl_type!( COLLABORATIVE_CLOSE_OFFER_TYPE, TenTenOneCollaborativeCloseOffer, @@ -726,11 +819,15 @@ fn read_tentenone_message( (SETTLE_CHANNEL_CONFIRM_TYPE, SettleConfirm), (SETTLE_CHANNEL_FINALIZE_TYPE, SettleFinalize), (RENEW_CHANNEL_OFFER_TYPE, RenewOffer), - (ROLLOVER_CHANNEL_OFFER_TYPE, RolloverOffer), (RENEW_CHANNEL_ACCEPT_TYPE, RenewAccept), (RENEW_CHANNEL_CONFIRM_TYPE, RenewConfirm), (RENEW_CHANNEL_FINALIZE_TYPE, RenewFinalize), (RENEW_CHANNEL_REVOKE_TYPE, RenewRevoke), + (ROLLOVER_CHANNEL_OFFER_TYPE, RolloverOffer), + (ROLLOVER_CHANNEL_ACCEPT_TYPE, RolloverAccept), + (ROLLOVER_CHANNEL_CONFIRM_TYPE, RolloverConfirm), + (ROLLOVER_CHANNEL_FINALIZE_TYPE, RolloverFinalize), + (ROLLOVER_CHANNEL_REVOKE_TYPE, RolloverRevoke), (COLLABORATIVE_CLOSE_OFFER_TYPE, CollaborativeCloseOffer) ) } diff --git a/crates/xxi-node/src/node/dlc_manager.rs b/crates/xxi-node/src/node/dlc_manager.rs index 089208a27..1a9ec9d1a 100644 --- a/crates/xxi-node/src/node/dlc_manager.rs +++ b/crates/xxi-node/src/node/dlc_manager.rs @@ -74,9 +74,9 @@ impl Result> { let response = self .dlc_manager - .on_dlc_message(&message.into(), to_secp_pk_29(node_id))?; + .on_dlc_message(&message.clone().into(), to_secp_pk_29(node_id))?; - Ok(response.map(TenTenOneMessage::build_from_response)) + Ok(response.map(|resp| TenTenOneMessage::build_from_response(resp, message.is_rollover()))) } } diff --git a/mobile/native/src/db/custom_types.rs b/mobile/native/src/db/custom_types.rs index 98a8348d9..84755747d 100644 --- a/mobile/native/src/db/custom_types.rs +++ b/mobile/native/src/db/custom_types.rs @@ -255,11 +255,15 @@ impl ToSql for MessageType { MessageType::SettleConfirm => "SettleConfirm", MessageType::SettleFinalize => "SettleFinalize", MessageType::RenewOffer => "RenewOffer", - MessageType::RolloverOffer => "RolloverOffer", MessageType::RenewAccept => "RenewAccept", MessageType::RenewConfirm => "RenewConfirm", MessageType::RenewFinalize => "RenewFinalize", MessageType::RenewRevoke => "RenewRevoke", + MessageType::RolloverOffer => "RolloverOffer", + MessageType::RolloverAccept => "RolloverAccept", + MessageType::RolloverConfirm => "RolloverConfirm", + MessageType::RolloverFinalize => "RolloverFinalize", + MessageType::RolloverRevoke => "RolloverRevoke", MessageType::CollaborativeCloseOffer => "CollaborativeCloseOffer", MessageType::Reject => "Reject", }; @@ -285,6 +289,11 @@ impl FromSql for MessageType { "RenewConfirm" => Ok(MessageType::RenewConfirm), "RenewFinalize" => Ok(MessageType::RenewFinalize), "RenewRevoke" => Ok(MessageType::RenewRevoke), + "RolloverOffer" => Ok(MessageType::RolloverOffer), + "RolloverAccept" => Ok(MessageType::RolloverAccept), + "RolloverConfirm" => Ok(MessageType::RolloverConfirm), + "RolloverFinalize" => Ok(MessageType::RolloverFinalize), + "RolloverRevoke" => Ok(MessageType::RolloverRevoke), "CollaborativeCloseOffer" => Ok(MessageType::CollaborativeCloseOffer), "Reject" => Ok(MessageType::Reject), _ => Err("Unrecognized enum variant".into()), diff --git a/mobile/native/src/db/dlc_messages.rs b/mobile/native/src/db/dlc_messages.rs index f3bb1fa0a..7d332165b 100644 --- a/mobile/native/src/db/dlc_messages.rs +++ b/mobile/native/src/db/dlc_messages.rs @@ -39,11 +39,15 @@ pub enum MessageType { SettleConfirm, SettleFinalize, RenewOffer, - RolloverOffer, RenewAccept, RenewConfirm, RenewFinalize, RenewRevoke, + RolloverOffer, + RolloverAccept, + RolloverConfirm, + RolloverFinalize, + RolloverRevoke, CollaborativeCloseOffer, Reject, } @@ -98,11 +102,15 @@ impl From for MessageType { xxi_node::dlc_message::DlcMessageType::SettleConfirm => Self::SettleConfirm, xxi_node::dlc_message::DlcMessageType::SettleFinalize => Self::SettleFinalize, xxi_node::dlc_message::DlcMessageType::RenewOffer => Self::RenewOffer, - xxi_node::dlc_message::DlcMessageType::RolloverOffer => Self::RolloverOffer, xxi_node::dlc_message::DlcMessageType::RenewAccept => Self::RenewAccept, xxi_node::dlc_message::DlcMessageType::RenewConfirm => Self::RenewConfirm, xxi_node::dlc_message::DlcMessageType::RenewFinalize => Self::RenewFinalize, xxi_node::dlc_message::DlcMessageType::RenewRevoke => Self::RenewRevoke, + xxi_node::dlc_message::DlcMessageType::RolloverOffer => Self::RolloverOffer, + xxi_node::dlc_message::DlcMessageType::RolloverAccept => Self::RolloverAccept, + xxi_node::dlc_message::DlcMessageType::RolloverConfirm => Self::RolloverConfirm, + xxi_node::dlc_message::DlcMessageType::RolloverFinalize => Self::RolloverFinalize, + xxi_node::dlc_message::DlcMessageType::RolloverRevoke => Self::RolloverRevoke, xxi_node::dlc_message::DlcMessageType::CollaborativeCloseOffer => { Self::CollaborativeCloseOffer } @@ -138,11 +146,17 @@ impl From for xxi_node::dlc_message::DlcMessageType { MessageType::SettleConfirm => xxi_node::dlc_message::DlcMessageType::SettleConfirm, MessageType::SettleFinalize => xxi_node::dlc_message::DlcMessageType::SettleFinalize, MessageType::RenewOffer => xxi_node::dlc_message::DlcMessageType::RenewOffer, - MessageType::RolloverOffer => xxi_node::dlc_message::DlcMessageType::RolloverOffer, MessageType::RenewAccept => xxi_node::dlc_message::DlcMessageType::RenewAccept, MessageType::RenewConfirm => xxi_node::dlc_message::DlcMessageType::RenewConfirm, MessageType::RenewFinalize => xxi_node::dlc_message::DlcMessageType::RenewFinalize, MessageType::RenewRevoke => xxi_node::dlc_message::DlcMessageType::RenewRevoke, + MessageType::RolloverOffer => xxi_node::dlc_message::DlcMessageType::RolloverOffer, + MessageType::RolloverAccept => xxi_node::dlc_message::DlcMessageType::RolloverAccept, + MessageType::RolloverConfirm => xxi_node::dlc_message::DlcMessageType::RolloverConfirm, + MessageType::RolloverFinalize => { + xxi_node::dlc_message::DlcMessageType::RolloverFinalize + } + MessageType::RolloverRevoke => xxi_node::dlc_message::DlcMessageType::RolloverRevoke, MessageType::CollaborativeCloseOffer => { xxi_node::dlc_message::DlcMessageType::CollaborativeCloseOffer } diff --git a/mobile/native/src/dlc/node.rs b/mobile/native/src/dlc/node.rs index 898d83be0..846b0652d 100644 --- a/mobile/native/src/dlc/node.rs +++ b/mobile/native/src/dlc/node.rs @@ -43,7 +43,10 @@ use xxi_node::message_handler::TenTenOneOfferChannel; use xxi_node::message_handler::TenTenOneReject; use xxi_node::message_handler::TenTenOneRenewAccept; use xxi_node::message_handler::TenTenOneRenewOffer; +use xxi_node::message_handler::TenTenOneRenewRevoke; +use xxi_node::message_handler::TenTenOneRolloverAccept; use xxi_node::message_handler::TenTenOneRolloverOffer; +use xxi_node::message_handler::TenTenOneRolloverRevoke; use xxi_node::message_handler::TenTenOneSettleOffer; use xxi_node::node; use xxi_node::node::event::NodeEvent; @@ -163,6 +166,11 @@ impl Node { BackgroundTask::AsyncTrade(TaskStatus::Failed(format!("{e:#}"))), )); } + if msg.is_rollover() { + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::Rollover(TaskStatus::Failed(format!("{e:#}"))), + )); + } } } } @@ -314,8 +322,8 @@ impl Node { self.process_rollover_offer(&offer)?; } - TenTenOneMessage::RenewRevoke(revoke) => { - let channel_id_hex = hex::encode(revoke.renew_revoke.channel_id); + TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke }) => { + let channel_id_hex = hex::encode(renew_revoke.channel_id); tracing::info!( channel_id = %channel_id_hex, @@ -324,37 +332,34 @@ impl Node { let expiry_timestamp = self .inner - .get_expiry_for_confirmed_dlc_channel(&revoke.renew_revoke.channel_id)?; - - match db::get_order_in_filling()? { - Some(_) => { - let filled_order = order::handler::order_filled() - .context("Cannot mark order as filled for confirmed DLC")?; - - update_position_after_dlc_channel_creation_or_update( - filled_order, - expiry_timestamp, - ) - .context("Failed to update position after DLC creation")?; - - event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::AsyncTrade(TaskStatus::Success), - )); - } - // If there is no order in `Filling` we must be rolling over. - None => { - tracing::info!( - channel_id = %channel_id_hex, - "Finished rolling over position" - ); - - position::handler::set_position_state(PositionState::Open)?; - - event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::Rollover(TaskStatus::Success), - )); - } - }; + .get_expiry_for_confirmed_dlc_channel(&renew_revoke.channel_id)?; + + let filled_order = db::get_order_in_filling()? + .context("Cannot mark order as filled for confirmed DLC")?; + + update_position_after_dlc_channel_creation_or_update( + filled_order, + expiry_timestamp, + ) + .context("Failed to update position after DLC creation")?; + + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::AsyncTrade(TaskStatus::Success), + )); + } + TenTenOneMessage::RolloverRevoke(TenTenOneRolloverRevoke { renew_revoke }) => { + let channel_id_hex = hex::encode(renew_revoke.channel_id); + + tracing::info!( + channel_id = %channel_id_hex, + "Finished rollover protocol" + ); + + position::handler::set_position_state(PositionState::Open)?; + + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::Rollover(TaskStatus::Success), + )); } TenTenOneMessage::Sign(signed) => { let expiry_timestamp = self @@ -656,7 +661,7 @@ impl Node { self.send_dlc_message( to_secp_pk_30(node_id), - TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept }), + TenTenOneMessage::RolloverAccept(TenTenOneRolloverAccept { renew_accept }), )?; } Err(e) => { From 17e77dd8f7680819b47a77eb6720c5eaadfb321c Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 09:24:13 +0200 Subject: [PATCH 23/32] chore!: Add order id to trade messages This will allow us to uniquely identify the affected order BREAKING change due to a change protocol message. --- coordinator/src/emergency_kit.rs | 4 + coordinator/src/node.rs | 4 + crates/tests-e2e/tests/e2e_reject_offer.rs | 2 + crates/xxi-node/src/message_handler.rs | 168 ++++++++++++++++----- crates/xxi-node/src/node/dlc_channel.rs | 29 +++- crates/xxi-node/src/node/dlc_manager.rs | 5 +- crates/xxi-node/src/tests/dlc_channel.rs | 17 ++- mobile/native/src/dlc/dlc_handler.rs | 6 +- mobile/native/src/dlc/node.rs | 60 ++++++-- mobile/native/src/emergency_kit.rs | 9 +- 10 files changed, 238 insertions(+), 66 deletions(-) diff --git a/coordinator/src/emergency_kit.rs b/coordinator/src/emergency_kit.rs index 5b4202c77..4c8dcea1b 100644 --- a/coordinator/src/emergency_kit.rs +++ b/coordinator/src/emergency_kit.rs @@ -5,6 +5,7 @@ use bitcoin_old::secp256k1::SecretKey; use dlc_manager::Signer; use dlc_messages::channel::RenewRevoke; use lightning::ln::chan_utils::build_commitment_secret; +use uuid::Uuid; use xxi_node::message_handler::TenTenOneMessage; use xxi_node::message_handler::TenTenOneRenewRevoke; use xxi_node::node::event::NodeEvent; @@ -26,6 +27,9 @@ impl Node { ))?; let msg = TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { + // this is not ideal, but the app should be able to handle the scenario where the order + // is not known. + order_id: Uuid::default(), renew_revoke: RenewRevoke { channel_id: signed_channel.channel_id, per_update_secret: prev_per_update_secret, diff --git a/coordinator/src/node.rs b/coordinator/src/node.rs index 78354e07e..6eae68247 100644 --- a/coordinator/src/node.rs +++ b/coordinator/src/node.rs @@ -228,6 +228,7 @@ impl Node { reference_id, .. }, + .. }) | TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { renew_finalize: @@ -279,6 +280,7 @@ impl Node { reference_id, .. }, + .. }) => { let channel_id_hex_string = hex::encode(channel_id); @@ -333,10 +335,12 @@ impl Node { reference_id, .. }, + .. }) => { let channel_id = match resp { Some(TenTenOneMessage::Sign(TenTenOneSignChannel { sign_channel: SignChannel { channel_id, .. }, + .. })) => channel_id, _ => *temporary_channel_id, }; diff --git a/crates/tests-e2e/tests/e2e_reject_offer.rs b/crates/tests-e2e/tests/e2e_reject_offer.rs index 78787f7f5..94a3c9e5b 100644 --- a/crates/tests-e2e/tests/e2e_reject_offer.rs +++ b/crates/tests-e2e/tests/e2e_reject_offer.rs @@ -69,6 +69,8 @@ async fn reject_offer() { // give the coordinator some time to process the reject message, before submitting the next // order. tokio::time::sleep(Duration::from_secs(5)).await; + + tracing::info!("Retry channel opening order"); submit_channel_opening_order(order.clone(), 0, 0); // Assert that the order was posted diff --git a/crates/xxi-node/src/message_handler.rs b/crates/xxi-node/src/message_handler.rs index 98c403efb..1b5f6661c 100644 --- a/crates/xxi-node/src/message_handler.rs +++ b/crates/xxi-node/src/message_handler.rs @@ -53,8 +53,10 @@ use std::collections::HashMap; use std::collections::VecDeque; use std::fmt::Display; use std::io::Cursor; +use std::str::FromStr; use std::sync::Arc; use std::sync::Mutex; +use uuid::Uuid; /// TenTenOneMessageHandler is used to send and receive messages through the custom /// message handling mechanism of the LDK. It also handles message segmentation @@ -191,11 +193,13 @@ pub struct TenTenOneOfferChannel { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneAcceptChannel { + pub order_id: Uuid, pub accept_channel: AcceptChannel, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneSignChannel { + pub order_id: Uuid, pub sign_channel: SignChannel, } @@ -208,16 +212,19 @@ pub struct TenTenOneSettleOffer { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneSettleAccept { + pub order_id: Uuid, pub settle_accept: SettleAccept, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneSettleConfirm { + pub order_id: Uuid, pub settle_confirm: SettleConfirm, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneSettleFinalize { + pub order_id: Uuid, pub settle_finalize: SettleFinalize, } @@ -229,21 +236,25 @@ pub struct TenTenOneRenewOffer { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneRenewAccept { + pub order_id: Uuid, pub renew_accept: RenewAccept, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneRenewConfirm { + pub order_id: Uuid, pub renew_confirm: RenewConfirm, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneRenewFinalize { + pub order_id: Uuid, pub renew_finalize: RenewFinalize, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TenTenOneRenewRevoke { + pub order_id: Uuid, pub renew_revoke: RenewRevoke, } @@ -465,46 +476,75 @@ impl TenTenOneMessage { /// an offer so if an offer is passed the function will panic. This is most likely not a future /// proof solution as we'd might want to enrich the response with 10101 metadata as well. If /// that happens we will have to rework this part. - pub fn build_from_response(message: Message, is_rollover: bool) -> Self { + pub fn build_from_response(message: Message, order_id: Option) -> Self { match message { Message::Channel(ChannelMessage::Accept(accept_channel)) => { - TenTenOneMessage::Accept(TenTenOneAcceptChannel { accept_channel }) + TenTenOneMessage::Accept(TenTenOneAcceptChannel { + accept_channel, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::Sign(sign_channel)) => { - TenTenOneMessage::Sign(TenTenOneSignChannel { sign_channel }) + TenTenOneMessage::Sign(TenTenOneSignChannel { + sign_channel, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::SettleAccept(settle_accept)) => { - TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { settle_accept }) + TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { + settle_accept, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::SettleConfirm(settle_confirm)) => { - TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { settle_confirm }) + TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { + settle_confirm, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::SettleFinalize(settle_finalize)) => { - TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { settle_finalize }) + TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { + settle_finalize, + order_id: order_id.expect("to be some"), + }) } - Message::Channel(ChannelMessage::RenewAccept(renew_accept)) if is_rollover => { + Message::Channel(ChannelMessage::RenewAccept(renew_accept)) if order_id.is_none() => { TenTenOneMessage::RolloverAccept(TenTenOneRolloverAccept { renew_accept }) } - Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)) if is_rollover => { + Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)) if order_id.is_none() => { TenTenOneMessage::RolloverConfirm(TenTenOneRolloverConfirm { renew_confirm }) } - Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)) if is_rollover => { + Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)) + if order_id.is_none() => + { TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { renew_finalize }) } - Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)) if is_rollover => { + Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)) if order_id.is_none() => { TenTenOneMessage::RolloverRevoke(TenTenOneRolloverRevoke { renew_revoke }) } Message::Channel(ChannelMessage::RenewAccept(renew_accept)) => { - TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept }) + TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { + renew_accept, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)) => { - TenTenOneMessage::RenewConfirm(TenTenOneRenewConfirm { renew_confirm }) + TenTenOneMessage::RenewConfirm(TenTenOneRenewConfirm { + renew_confirm, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)) => { - TenTenOneMessage::RenewFinalize(TenTenOneRenewFinalize { renew_finalize }) + TenTenOneMessage::RenewFinalize(TenTenOneRenewFinalize { + renew_finalize, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)) => { - TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke }) + TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { + renew_revoke, + order_id: order_id.expect("to be some"), + }) } Message::Channel(ChannelMessage::CollaborativeCloseOffer( collaborative_close_offer, @@ -524,6 +564,43 @@ impl TenTenOneMessage { } } + pub fn get_order_id(&self) -> Option { + match self { + TenTenOneMessage::Offer(TenTenOneOfferChannel { + filled_with: FilledWith { order_id, .. }, + .. + }) + | TenTenOneMessage::Accept(TenTenOneAcceptChannel { order_id, .. }) + | TenTenOneMessage::Sign(TenTenOneSignChannel { order_id, .. }) + | TenTenOneMessage::SettleOffer(TenTenOneSettleOffer { + order: Order { id: order_id, .. }, + .. + }) + | TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { order_id, .. }) + | TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { order_id, .. }) + | TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { order_id, .. }) + | TenTenOneMessage::RenewOffer(TenTenOneRenewOffer { + filled_with: FilledWith { order_id, .. }, + .. + }) + | TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { order_id, .. }) + | TenTenOneMessage::RenewConfirm(TenTenOneRenewConfirm { order_id, .. }) + | TenTenOneMessage::RenewFinalize(TenTenOneRenewFinalize { order_id, .. }) + | TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { order_id, .. }) => { + Some(*order_id) + } + TenTenOneMessage::RolloverOffer(TenTenOneRolloverOffer { .. }) + | TenTenOneMessage::RolloverAccept(TenTenOneRolloverAccept { .. }) + | TenTenOneMessage::RolloverConfirm(TenTenOneRolloverConfirm { .. }) + | TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { .. }) + | TenTenOneMessage::RolloverRevoke(TenTenOneRolloverRevoke { .. }) + | TenTenOneMessage::CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer { + .. + }) + | TenTenOneMessage::Reject(TenTenOneReject { .. }) => None, + } + } + pub fn get_reference_id(&self) -> Option { match self { TenTenOneMessage::Offer(TenTenOneOfferChannel { @@ -532,9 +609,11 @@ impl TenTenOneMessage { }) | TenTenOneMessage::Accept(TenTenOneAcceptChannel { accept_channel: AcceptChannel { reference_id, .. }, + .. }) | TenTenOneMessage::Sign(TenTenOneSignChannel { sign_channel: SignChannel { reference_id, .. }, + .. }) | TenTenOneMessage::SettleOffer(TenTenOneSettleOffer { settle_offer: SettleOffer { reference_id, .. }, @@ -542,12 +621,15 @@ impl TenTenOneMessage { }) | TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { settle_accept: SettleAccept { reference_id, .. }, + .. }) | TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { settle_confirm: SettleConfirm { reference_id, .. }, + .. }) | TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { settle_finalize: SettleFinalize { reference_id, .. }, + .. }) | TenTenOneMessage::RenewOffer(TenTenOneRenewOffer { renew_offer: RenewOffer { reference_id, .. }, @@ -570,15 +652,19 @@ impl TenTenOneMessage { }) | TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept: RenewAccept { reference_id, .. }, + .. }) | TenTenOneMessage::RenewConfirm(TenTenOneRenewConfirm { renew_confirm: RenewConfirm { reference_id, .. }, + .. }) | TenTenOneMessage::RenewFinalize(TenTenOneRenewFinalize { renew_finalize: RenewFinalize { reference_id, .. }, + .. }) | TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke: RenewRevoke { reference_id, .. }, + .. }) | TenTenOneMessage::CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer { collaborative_close_offer: CollaborativeCloseOffer { reference_id, .. }, @@ -603,37 +689,37 @@ impl From for ChannelMessage { TenTenOneMessage::Offer(TenTenOneOfferChannel { offer_channel, .. }) => { ChannelMessage::Offer(offer_channel) } - TenTenOneMessage::Accept(TenTenOneAcceptChannel { accept_channel }) => { + TenTenOneMessage::Accept(TenTenOneAcceptChannel { accept_channel, .. }) => { ChannelMessage::Accept(accept_channel) } - TenTenOneMessage::Sign(TenTenOneSignChannel { sign_channel }) => { + TenTenOneMessage::Sign(TenTenOneSignChannel { sign_channel, .. }) => { ChannelMessage::Sign(sign_channel) } TenTenOneMessage::SettleOffer(TenTenOneSettleOffer { settle_offer, .. }) => { ChannelMessage::SettleOffer(settle_offer) } - TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { settle_accept }) => { + TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { settle_accept, .. }) => { ChannelMessage::SettleAccept(settle_accept) } - TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { settle_confirm }) => { + TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { settle_confirm, .. }) => { ChannelMessage::SettleConfirm(settle_confirm) } - TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { settle_finalize }) => { - ChannelMessage::SettleFinalize(settle_finalize) - } + TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { + settle_finalize, .. + }) => ChannelMessage::SettleFinalize(settle_finalize), TenTenOneMessage::RenewOffer(TenTenOneRenewOffer { renew_offer, .. }) => { ChannelMessage::RenewOffer(renew_offer) } - TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept }) => { + TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept, .. }) => { ChannelMessage::RenewAccept(renew_accept) } - TenTenOneMessage::RenewConfirm(TenTenOneRenewConfirm { renew_confirm }) => { + TenTenOneMessage::RenewConfirm(TenTenOneRenewConfirm { renew_confirm, .. }) => { ChannelMessage::RenewConfirm(renew_confirm) } - TenTenOneMessage::RenewFinalize(TenTenOneRenewFinalize { renew_finalize }) => { + TenTenOneMessage::RenewFinalize(TenTenOneRenewFinalize { renew_finalize, .. }) => { ChannelMessage::RenewFinalize(renew_finalize) } - TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke }) => { + TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke, .. }) => { ChannelMessage::RenewRevoke(renew_revoke) } TenTenOneMessage::RolloverOffer(TenTenOneRolloverOffer { renew_offer }) => { @@ -659,6 +745,20 @@ impl From for ChannelMessage { } } +/// Writes an uuid to the given writer. +pub fn write_uuid( + uuid: &Uuid, + writer: &mut W, +) -> std::result::Result<(), ::std::io::Error> { + write_string(&uuid.to_string(), writer) +} + +/// Reads an uuid from the given reader. +pub fn read_uuid(reader: &mut R) -> std::result::Result { + let uuid = read_string(reader)?; + Uuid::from_str(&uuid).map_err(|_| DecodeError::InvalidValue) +} + macro_rules! impl_type_writeable_for_enum { ($type_name: ident, {$($variant_name: ident),*}) => { impl Type for $type_name { @@ -748,17 +848,17 @@ impl_type_writeable_for_enum!(TenTenOneMessage, impl_dlc_writeable!(TenTenOneReject, { (reject, writeable) }); impl_dlc_writeable!(TenTenOneOfferChannel, { (filled_with, writeable), (offer_channel, writeable) }); -impl_dlc_writeable!(TenTenOneAcceptChannel, { (accept_channel, writeable) }); -impl_dlc_writeable!(TenTenOneSignChannel, { (sign_channel, writeable) }); +impl_dlc_writeable!(TenTenOneAcceptChannel, { (order_id, {cb_writeable, write_uuid, read_uuid}), (accept_channel, writeable) }); +impl_dlc_writeable!(TenTenOneSignChannel, { (order_id, {cb_writeable, write_uuid, read_uuid}), (sign_channel, writeable) }); impl_dlc_writeable!(TenTenOneSettleOffer, { (order, writeable), (filled_with, writeable), (settle_offer, writeable) }); -impl_dlc_writeable!(TenTenOneSettleAccept, { (settle_accept, writeable) }); -impl_dlc_writeable!(TenTenOneSettleConfirm, { (settle_confirm, writeable) }); -impl_dlc_writeable!(TenTenOneSettleFinalize, { (settle_finalize, writeable) }); +impl_dlc_writeable!(TenTenOneSettleAccept, { (order_id, {cb_writeable, write_uuid, read_uuid}), (settle_accept, writeable) }); +impl_dlc_writeable!(TenTenOneSettleConfirm, { (order_id, {cb_writeable, write_uuid, read_uuid}), (settle_confirm, writeable) }); +impl_dlc_writeable!(TenTenOneSettleFinalize, { (order_id, {cb_writeable, write_uuid, read_uuid}), (settle_finalize, writeable) }); impl_dlc_writeable!(TenTenOneRenewOffer, { (filled_with, writeable), (renew_offer, writeable) }); -impl_dlc_writeable!(TenTenOneRenewAccept, { (renew_accept, writeable) }); -impl_dlc_writeable!(TenTenOneRenewConfirm, { (renew_confirm, writeable) }); -impl_dlc_writeable!(TenTenOneRenewFinalize, { (renew_finalize, writeable) }); -impl_dlc_writeable!(TenTenOneRenewRevoke, { (renew_revoke, writeable) }); +impl_dlc_writeable!(TenTenOneRenewAccept, { (order_id, {cb_writeable, write_uuid, read_uuid}), (renew_accept, writeable) }); +impl_dlc_writeable!(TenTenOneRenewConfirm, { (order_id, {cb_writeable, write_uuid, read_uuid}), (renew_confirm, writeable) }); +impl_dlc_writeable!(TenTenOneRenewFinalize, { (order_id, {cb_writeable, write_uuid, read_uuid}), (renew_finalize, writeable) }); +impl_dlc_writeable!(TenTenOneRenewRevoke, { (order_id, {cb_writeable, write_uuid, read_uuid}), (renew_revoke, writeable) }); impl_dlc_writeable!(TenTenOneRolloverOffer, { (renew_offer, writeable) }); impl_dlc_writeable!(TenTenOneRolloverAccept, { (renew_accept, writeable) }); impl_dlc_writeable!(TenTenOneRolloverConfirm, { (renew_confirm, writeable) }); diff --git a/crates/xxi-node/src/node/dlc_channel.rs b/crates/xxi-node/src/node/dlc_channel.rs index d8ca4c55e..beee90151 100644 --- a/crates/xxi-node/src/node/dlc_channel.rs +++ b/crates/xxi-node/src/node/dlc_channel.rs @@ -35,6 +35,7 @@ use dlc_manager::ReferenceId; use dlc_manager::Storage; use time::OffsetDateTime; use tokio::task::spawn_blocking; +use uuid::Uuid; impl Node @@ -109,7 +110,11 @@ impl Result<()> { + pub fn accept_dlc_channel_offer( + &self, + order_id: Uuid, + channel_id: &DlcChannelId, + ) -> Result<()> { use crate::message_handler::TenTenOneAcceptChannel; let channel_id_hex = hex::encode(channel_id); @@ -121,7 +126,10 @@ impl Result<()> { let channel_id_hex = hex::encode(channel_id); @@ -284,7 +293,10 @@ impl Result<()> { + pub fn accept_dlc_channel_update( + &self, + order_id: Uuid, + channel_id: &DlcChannelId, + ) -> Result<()> { use crate::message_handler::TenTenOneRenewAccept; let channel_id_hex = hex::encode(channel_id); @@ -412,7 +428,10 @@ impl Result<()> { + pub fn reject_dlc_channel_offer( + &self, + order_id: Option, + channel_id: &DlcChannelId, + ) -> Result<()> { tracing::warn!("Rejecting dlc channel offer!"); let (reject, counterparty) = self @@ -482,7 +487,7 @@ impl Node { })?; order::handler::order_failed( - None, + order_id, FailureReason::InvalidDlcOffer(InvalidSubchannelOffer::Unacceptable), anyhow!("Failed to accept dlc channel offer"), ) @@ -498,6 +503,7 @@ impl Node { pub fn process_dlc_channel_offer(&self, offer: &TenTenOneOfferChannel) -> Result<()> { // TODO(holzeis): We should check if the offered amounts are expected. self.set_order_to_filling(offer.filled_with.clone())?; + let order_id = offer.filled_with.order_id; let channel_id = offer.offer_channel.temporary_channel_id; match self @@ -509,12 +515,15 @@ impl Node { Ok((accept_channel, _, _, node_id)) => { self.send_dlc_message( to_secp_pk_30(node_id), - TenTenOneMessage::Accept(TenTenOneAcceptChannel { accept_channel }), + TenTenOneMessage::Accept(TenTenOneAcceptChannel { + accept_channel, + order_id: offer.filled_with.order_id, + }), )?; } Err(e) => { tracing::error!("Failed to accept DLC channel offer: {e:#}"); - self.reject_dlc_channel_offer(&channel_id)?; + self.reject_dlc_channel_offer(Some(order_id), &channel_id)?; } } @@ -522,12 +531,16 @@ impl Node { } #[instrument(fields(channel_id = hex::encode(channel_id)),skip_all, err(Debug))] - pub fn reject_settle_offer(&self, channel_id: &DlcChannelId) -> Result<()> { + pub fn reject_settle_offer( + &self, + order_id: Option, + channel_id: &DlcChannelId, + ) -> Result<()> { tracing::warn!("Rejecting pending dlc channel collaborative settlement offer!"); let (reject, counterparty) = self.inner.dlc_manager.reject_settle_offer(channel_id)?; order::handler::order_failed( - None, + order_id, FailureReason::InvalidDlcOffer(InvalidSubchannelOffer::Unacceptable), anyhow!("Failed to accept settle offer"), )?; @@ -569,13 +582,14 @@ impl Node { OrderReason::Manual => self.set_order_to_filling(offer.filled_with.clone())?, } + let order_id = offer.order.id; let channel_id = offer.settle_offer.channel_id; if let Err(e) = self .inner - .accept_dlc_channel_collaborative_settlement(&channel_id) + .accept_dlc_channel_collaborative_settlement(offer.filled_with.order_id, &channel_id) { tracing::error!("Failed to accept dlc channel collaborative settlement offer. {e:#}"); - self.reject_settle_offer(&channel_id)?; + self.reject_settle_offer(Some(order_id), &channel_id)?; } Ok(()) @@ -597,13 +611,17 @@ impl Node { } #[instrument(fields(channel_id = hex::encode(channel_id)),skip_all, err(Debug))] - pub fn reject_renew_offer(&self, channel_id: &DlcChannelId) -> Result<()> { + pub fn reject_renew_offer( + &self, + order_id: Option, + channel_id: &DlcChannelId, + ) -> Result<()> { tracing::warn!("Rejecting dlc channel renew offer!"); let (reject, counterparty) = self.inner.dlc_manager.reject_renew_offer(channel_id)?; order::handler::order_failed( - None, + order_id, FailureReason::InvalidDlcOffer(InvalidSubchannelOffer::Unacceptable), anyhow!("Failed to accept renew offer"), )?; @@ -621,6 +639,7 @@ impl Node { offer.renew_offer.contract_info.get_closest_maturity_date() as i64, )?; + let order_id = offer.filled_with.order_id; self.set_order_to_filling(offer.filled_with.clone())?; let channel_id = offer.renew_offer.channel_id; @@ -630,19 +649,34 @@ impl Node { self.send_dlc_message( to_secp_pk_30(node_id), - TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept }), + TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { + renew_accept, + order_id: offer.filled_with.order_id, + }), )?; } Err(e) => { tracing::error!("Failed to accept dlc channel renew offer. {e:#}"); - self.reject_renew_offer(&channel_id)?; + self.reject_renew_offer(Some(order_id), &channel_id)?; } }; Ok(()) } + #[instrument(fields(channel_id = hex::encode(channel_id)),skip_all, err(Debug))] + pub fn reject_rollover_offer(&self, channel_id: &DlcChannelId) -> Result<()> { + tracing::warn!("Rejecting rollover offer!"); + + let (reject, counterparty) = self.inner.dlc_manager.reject_renew_offer(channel_id)?; + + self.send_dlc_message( + to_secp_pk_30(counterparty), + TenTenOneMessage::Reject(TenTenOneReject { reject }), + ) + } + #[instrument(fields(channel_id = hex::encode(offer.renew_offer.channel_id)),skip_all, err(Debug))] pub fn process_rollover_offer(&self, offer: &TenTenOneRolloverOffer) -> Result<()> { tracing::info!("Received a rollover notification from orderbook."); @@ -670,7 +704,7 @@ impl Node { BackgroundTask::Rollover(TaskStatus::Failed(format!("{e:#}"))), )); - self.reject_renew_offer(&channel_id)?; + self.reject_rollover_offer(&channel_id)?; } }; diff --git a/mobile/native/src/emergency_kit.rs b/mobile/native/src/emergency_kit.rs index d63eeb3a0..6c492bd79 100644 --- a/mobile/native/src/emergency_kit.rs +++ b/mobile/native/src/emergency_kit.rs @@ -23,6 +23,7 @@ use dlc_messages::channel::SettleFinalize; use hex::FromHex; use lightning::ln::chan_utils::build_commitment_secret; use time::OffsetDateTime; +use uuid::Uuid; use xxi_node::bitcoin_conversion::to_secp_sk_29; use xxi_node::commons::ContractSymbol; use xxi_node::message_handler::TenTenOneMessage; @@ -154,10 +155,7 @@ pub fn resend_settle_finalize_message() -> Result<()> { .get_signed_channel_by_trader_id(coordinator_pubkey)?; ensure!( - matches!( - signed_channel.state, - dlc_manager::channel::signed_channel::SignedChannelState::Settled { .. } - ), + matches!(signed_channel.state, SignedChannelState::Settled { .. }), "Signed channel state must be settled to resend settle finalize message!" ); @@ -172,6 +170,9 @@ pub fn resend_settle_finalize_message() -> Result<()> { ))?; let msg = TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { + // this is not ideal, but the coordinator should be able to handle the scenario where the + // order is not known. + order_id: Uuid::default(), settle_finalize: SettleFinalize { channel_id: signed_channel.channel_id, prev_per_update_secret: to_secp_sk_29(prev_per_update_secret), From 70c79d27acbc23677994e76427d68c61cbbec8ed Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 13:02:34 +0200 Subject: [PATCH 24/32] feat: Report trade error from coordinator if trade or rollover fails --- coordinator/src/bin/coordinator.rs | 20 +++--- coordinator/src/node.rs | 44 ++++++++++++- crates/xxi-node/src/commons/message.rs | 6 ++ crates/xxi-node/src/message_handler.rs | 56 ++++++++-------- mobile/native/src/db/models.rs | 71 +++++---------------- mobile/native/src/dlc/mod.rs | 6 +- mobile/native/src/dlc/node.rs | 49 +++++++++----- mobile/native/src/orderbook.rs | 6 ++ mobile/native/src/trade/order/handler.rs | 40 ++++++------ mobile/native/src/trade/order/mod.rs | 12 ++-- mobile/native/src/trade/position/handler.rs | 38 ++++++----- 11 files changed, 189 insertions(+), 159 deletions(-) diff --git a/coordinator/src/bin/coordinator.rs b/coordinator/src/bin/coordinator.rs index f12af76e0..21e8e0d0f 100644 --- a/coordinator/src/bin/coordinator.rs +++ b/coordinator/src/bin/coordinator.rs @@ -153,6 +153,15 @@ async fn main() -> Result<()> { let running = node.start(dlc_event_receiver)?; + let (tx_user_feed, _rx) = broadcast::channel::(100); + + let notification_service = NotificationService::new(opts.fcm_api_key.clone(), pool.clone()); + + let (_handle, auth_users_notifier) = spawn_delivering_messages_to_authenticated_users( + notification_service.get_sender(), + tx_user_feed.clone(), + ); + // an internal channel to send updates about our position let (tx_position_feed, _rx) = broadcast::channel::(100); @@ -162,6 +171,7 @@ async fn main() -> Result<()> { pool.clone(), settings.to_node_settings(), tx_position_feed.clone(), + auth_users_notifier.clone(), ); // TODO: Pass the tokio metrics into Prometheus @@ -244,18 +254,8 @@ async fn main() -> Result<()> { } }); - let (tx_user_feed, _rx) = broadcast::channel::(100); - let (tx_orderbook_feed, _rx) = broadcast::channel(100); - let notification_service = - NotificationService::new(opts.fcm_api_key.clone(), node.pool.clone()); - - let (_handle, auth_users_notifier) = spawn_delivering_messages_to_authenticated_users( - notification_service.get_sender(), - tx_user_feed.clone(), - ); - let (_handle, trading_sender) = trading::start( node.clone(), tx_orderbook_feed.clone(), diff --git a/coordinator/src/node.rs b/coordinator/src/node.rs index 6eae68247..db83a2150 100644 --- a/coordinator/src/node.rs +++ b/coordinator/src/node.rs @@ -1,6 +1,7 @@ use crate::db; use crate::dlc_protocol; use crate::dlc_protocol::ProtocolId; +use crate::message::OrderbookMessage; use crate::node::storage::NodeStorage; use crate::position::models::PositionState; use crate::storage::CoordinatorTenTenOneStorage; @@ -22,14 +23,19 @@ use dlc_messages::channel::SettleFinalize; use dlc_messages::channel::SignChannel; use std::sync::Arc; use tokio::sync::broadcast::Sender; +use tokio::sync::mpsc; use tokio::sync::RwLock; use xxi_node::bitcoin_conversion::to_secp_pk_29; use xxi_node::bitcoin_conversion::to_secp_pk_30; +use xxi_node::commons::Message::RolloverError; +use xxi_node::commons::Message::TradeError; +use xxi_node::commons::TradingError; use xxi_node::dlc_message::DlcMessage; use xxi_node::dlc_message::SerializedDlcMessage; use xxi_node::message_handler::TenTenOneAcceptChannel; use xxi_node::message_handler::TenTenOneCollaborativeCloseOffer; use xxi_node::message_handler::TenTenOneMessage; +use xxi_node::message_handler::TenTenOneMessageType; use xxi_node::message_handler::TenTenOneReject; use xxi_node::message_handler::TenTenOneRenewFinalize; use xxi_node::message_handler::TenTenOneRolloverFinalize; @@ -69,6 +75,7 @@ pub struct Node { pub pool: Pool>, pub settings: Arc>, tx_position_feed: Sender, + trade_notifier: mpsc::Sender, } impl Node { @@ -84,6 +91,7 @@ impl Node { pool: Pool>, settings: NodeSettings, tx_position_feed: Sender, + trade_notifier: mpsc::Sender, ) -> Self { Self { inner, @@ -91,6 +99,7 @@ impl Node { settings: Arc::new(RwLock::new(settings)), _running: Arc::new(running), tx_position_feed, + trade_notifier, } } @@ -127,8 +136,39 @@ impl Node { ); } - // TODO(holzeis): Send TradeError to user in case the coordinator failed to process - // the users message + tokio::spawn({ + let trade_notifier = self.trade_notifier.clone(); + let error = TradingError::Other(format!("{e:#}")); + async move { + let message = match msg.get_tentenone_message_type() { + TenTenOneMessageType::Trade => { + if let Some(order_id) = msg.get_order_id() { + OrderbookMessage::TraderMessage { + trader_id: to_secp_pk_30(node_id), + message: TradeError { order_id, error }, + notification: None, + } + } else { + tracing::warn!("Could not send trade error to user due to missing order id"); + return; + } + } + TenTenOneMessageType::Rollover => OrderbookMessage::TraderMessage { + trader_id: to_secp_pk_30(node_id), + message: RolloverError { error }, + notification: None, + }, + TenTenOneMessageType::Other => { + tracing::debug!("Not sending errors to the app unrelated to a trade or rollover."); + return; + } + }; + + if let Err(e) = trade_notifier.send(message).await { + tracing::error!("Failed to send trade error to user. Error: {e:#}"); + } + } + }); tracing::error!( from = %node_id, diff --git a/crates/xxi-node/src/commons/message.rs b/crates/xxi-node/src/commons/message.rs index 0583f128b..05e285b1d 100644 --- a/crates/xxi-node/src/commons/message.rs +++ b/crates/xxi-node/src/commons/message.rs @@ -41,6 +41,9 @@ pub enum Message { order_id: Uuid, error: TradingError, }, + RolloverError { + error: TradingError, + }, } #[derive(Serialize, Deserialize, Clone, Error, Debug, PartialEq)] @@ -117,6 +120,9 @@ impl Display for Message { Message::TradeError { .. } => { write!(f, "TradeError") } + Message::RolloverError { .. } => { + write!(f, "RolloverError") + } } } } diff --git a/crates/xxi-node/src/message_handler.rs b/crates/xxi-node/src/message_handler.rs index 1b5f6661c..6e217f466 100644 --- a/crates/xxi-node/src/message_handler.rs +++ b/crates/xxi-node/src/message_handler.rs @@ -146,37 +146,37 @@ pub enum TenTenOneMessage { CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer), } +pub enum TenTenOneMessageType { + /// open channel, open, close or resize a position + Trade, + /// rollover + Rollover, + /// reject or close channel + Other, +} + impl TenTenOneMessage { - /// Returns true if the message is a trade message. e.g. Reject, Rollover or Collaborative Close - /// Offer are not trade messages. - pub fn is_trade(&self) -> bool { - matches!( - self, + pub fn get_tentenone_message_type(&self) -> TenTenOneMessageType { + match self { TenTenOneMessage::Offer(_) - | TenTenOneMessage::Accept(_) - | TenTenOneMessage::Sign(_) - | TenTenOneMessage::RenewOffer(_) - | TenTenOneMessage::RenewAccept(_) - | TenTenOneMessage::RenewConfirm(_) - | TenTenOneMessage::RenewFinalize(_) - | TenTenOneMessage::RenewRevoke(_) - | TenTenOneMessage::SettleOffer(_) - | TenTenOneMessage::SettleAccept(_) - | TenTenOneMessage::SettleConfirm(_) - | TenTenOneMessage::SettleFinalize(_) - ) - } - - /// Returns true if the message is a rollover message. - pub fn is_rollover(&self) -> bool { - matches!( - self, + | TenTenOneMessage::Accept(_) + | TenTenOneMessage::Sign(_) + | TenTenOneMessage::RenewOffer(_) + | TenTenOneMessage::RenewAccept(_) + | TenTenOneMessage::RenewConfirm(_) + | TenTenOneMessage::RenewFinalize(_) + | TenTenOneMessage::RenewRevoke(_) + | TenTenOneMessage::SettleOffer(_) + | TenTenOneMessage::SettleAccept(_) + | TenTenOneMessage::SettleConfirm(_) + | TenTenOneMessage::SettleFinalize(_) => TenTenOneMessageType::Trade, TenTenOneMessage::RolloverOffer(_) - | TenTenOneMessage::RolloverAccept(_) - | TenTenOneMessage::RolloverConfirm(_) - | TenTenOneMessage::RolloverFinalize(_) - | TenTenOneMessage::RolloverRevoke(_) - ) + | TenTenOneMessage::RolloverAccept(_) + | TenTenOneMessage::RolloverConfirm(_) + | TenTenOneMessage::RolloverFinalize(_) + | TenTenOneMessage::RolloverRevoke(_) => TenTenOneMessageType::Rollover, + _ => TenTenOneMessageType::Other, + } } } diff --git a/mobile/native/src/db/models.rs b/mobile/native/src/db/models.rs index 493a3aae5..bff8f00dc 100644 --- a/mobile/native/src/db/models.rs +++ b/mobile/native/src/db/models.rs @@ -155,33 +155,21 @@ impl Order { conn: &mut SqliteConnection, ) -> Result { conn.exclusive_transaction::(|conn| { - let order: Order = orders::table - .filter(schema::orders::id.eq(order_id.clone())) - .first(conn)?; - - let current_state = order.state; - match current_state.next_state(order_state) { - Some(next_state) => { - let affected_rows = diesel::update(orders::table) - .filter(schema::orders::id.eq(order_id.clone())) - .set(schema::orders::state.eq(next_state)) - .execute(conn)?; - - if affected_rows == 0 { - bail!("Could not update order state") - } + let affected_rows = diesel::update(orders::table) + .filter(orders::id.eq(order_id.clone())) + .set(orders::state.eq(order_state)) + .execute(conn)?; - tracing::info!(new_state = ?next_state, %order_id, "Updated order state"); - } - None => { - tracing::debug!(?current_state, ?order_state, "Ignoring latest state update"); - } + if affected_rows == 0 { + bail!("Could not update order state") } + tracing::info!(new_state = ?order_state, %order_id, "Updated order state"); + if let Some(execution_price) = execution_price { let affected_rows = diesel::update(orders::table) - .filter(schema::orders::id.eq(order_id.clone())) - .set(schema::orders::execution_price.eq(execution_price)) + .filter(orders::id.eq(order_id.clone())) + .set(orders::execution_price.eq(execution_price)) .execute(conn)?; if affected_rows == 0 { @@ -191,8 +179,8 @@ impl Order { if let Some(matching_fee) = matching_fee { let affected_rows = diesel::update(orders::table) - .filter(schema::orders::id.eq(order_id.clone())) - .set(schema::orders::matching_fee_sats.eq(matching_fee.to_sat() as i64)) + .filter(orders::id.eq(order_id.clone())) + .set(orders::matching_fee_sats.eq(matching_fee.to_sat() as i64)) .execute(conn)?; if affected_rows == 0 { @@ -202,8 +190,8 @@ impl Order { if let Some(failure_reason) = failure_reason { let affected_rows = diesel::update(orders::table) - .filter(schema::orders::id.eq(order_id.clone())) - .set(schema::orders::failure_reason.eq(failure_reason)) + .filter(orders::id.eq(order_id.clone())) + .set(orders::failure_reason.eq(failure_reason)) .execute(conn)?; if affected_rows == 0 { @@ -212,7 +200,7 @@ impl Order { } let order = orders::table - .filter(schema::orders::id.eq(order_id.clone())) + .filter(orders::id.eq(order_id.clone())) .first(conn)?; Ok(order) @@ -361,6 +349,7 @@ fn derive_order_state( }, OrderState::Failed => crate::trade::order::OrderState::Failed { execution_price, + matching_fee: matching_fee.map(|fee| Amount::from_sat(fee as u64)), reason: failure_reason.unwrap_or_default().into(), }, OrderState::Filled => { @@ -685,33 +674,6 @@ pub enum OrderState { Filled, } -impl OrderState { - /// Determines what state to go to after learning about the latest [`OrderState`] update. - /// - /// If the state should remain unchanged [`None`] is returned. - /// - /// TODO: It might be a good idea to introduce a different type that models `OrderUpdates` - /// explicitly. - fn next_state(&self, latest: Self) -> Option { - match (self, latest) { - // We can go from `Initial` to any other state - (OrderState::Initial, latest) => Some(latest), - // `Rejected` is a final state - (OrderState::Rejected, _) => None, - // We cannnot go back to `Initial` if the order is already `Open` - (OrderState::Open, OrderState::Initial) => None, - (OrderState::Open, latest) => Some(latest), - // We cannot go back to `Initial` or `Open` if the order is already `Filling` - (OrderState::Filling, OrderState::Initial | OrderState::Open) => None, - (OrderState::Filling, latest) => Some(latest), - // `Failed` is a final state - (OrderState::Failed, _) => None, - // `Filled` is a final state - (OrderState::Filled, _) => None, - } - } -} - impl From for (OrderState, Option, Option) { fn from(value: crate::trade::order::OrderState) -> Self { match value { @@ -721,6 +683,7 @@ impl From for (OrderState, Option, Option< crate::trade::order::OrderState::Failed { execution_price, reason, + .. } => (OrderState::Failed, execution_price, Some(reason.into())), crate::trade::order::OrderState::Filled { execution_price, .. diff --git a/mobile/native/src/dlc/mod.rs b/mobile/native/src/dlc/mod.rs index 75ab1254a..953530572 100644 --- a/mobile/native/src/dlc/mod.rs +++ b/mobile/native/src/dlc/mod.rs @@ -820,7 +820,7 @@ fn update_state_after_collab_revert( } }; - let filled_order = match order::handler::order_filled() { + let filled_order = match order::handler::order_filled(None) { Ok(order) => order, Err(_) => { let order = Order { @@ -847,14 +847,14 @@ fn update_state_after_collab_revert( } }; - position::handler::update_position_after_dlc_closure(Some(filled_order))?; + position::handler::update_position_after_dlc_closure(filled_order)?; let node = node.inner.clone(); node.dlc_manager .get_store() .upsert_channel( - dlc_manager::channel::Channel::CollaborativelyClosed(ClosedChannel { + Channel::CollaborativelyClosed(ClosedChannel { counter_party: signed_channel.counter_party, temporary_channel_id: signed_channel.temporary_channel_id, channel_id: signed_channel.channel_id, diff --git a/mobile/native/src/dlc/node.rs b/mobile/native/src/dlc/node.rs index 682c78329..02698de80 100644 --- a/mobile/native/src/dlc/node.rs +++ b/mobile/native/src/dlc/node.rs @@ -40,6 +40,7 @@ use xxi_node::dlc_message::SerializedDlcMessage; use xxi_node::message_handler::TenTenOneAcceptChannel; use xxi_node::message_handler::TenTenOneCollaborativeCloseOffer; use xxi_node::message_handler::TenTenOneMessage; +use xxi_node::message_handler::TenTenOneMessageType; use xxi_node::message_handler::TenTenOneOfferChannel; use xxi_node::message_handler::TenTenOneReject; use xxi_node::message_handler::TenTenOneRenewAccept; @@ -48,7 +49,9 @@ use xxi_node::message_handler::TenTenOneRenewRevoke; use xxi_node::message_handler::TenTenOneRolloverAccept; use xxi_node::message_handler::TenTenOneRolloverOffer; use xxi_node::message_handler::TenTenOneRolloverRevoke; +use xxi_node::message_handler::TenTenOneSettleConfirm; use xxi_node::message_handler::TenTenOneSettleOffer; +use xxi_node::message_handler::TenTenOneSignChannel; use xxi_node::node; use xxi_node::node::event::NodeEvent; use xxi_node::node::rust_dlc_manager::DlcChannelId; @@ -162,15 +165,20 @@ impl Node { "Failed to process incoming DLC message: {e:#}" ); - if msg.is_trade() { - event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::AsyncTrade(TaskStatus::Failed(format!("{e:#}"))), - )); - } - if msg.is_rollover() { - event::publish(&EventInternal::BackgroundNotification( - BackgroundTask::Rollover(TaskStatus::Failed(format!("{e:#}"))), - )); + match msg.get_tentenone_message_type() { + TenTenOneMessageType::Trade => { + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::AsyncTrade(TaskStatus::Failed(format!("{e:#}"))), + )) + } + TenTenOneMessageType::Rollover => { + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::Rollover(TaskStatus::Failed(format!("{e:#}"))), + )) + } + TenTenOneMessageType::Other => { + tracing::warn!("Ignoring error received from coordinator unrelated to a trade or rollover.") + } } } } @@ -323,10 +331,14 @@ impl Node { self.process_rollover_offer(&offer)?; } - TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke }) => { + TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { + renew_revoke, + order_id, + }) => { let channel_id_hex = hex::encode(renew_revoke.channel_id); tracing::info!( + order_id = %order_id, channel_id = %channel_id_hex, "Finished renew protocol" ); @@ -335,7 +347,7 @@ impl Node { .inner .get_expiry_for_confirmed_dlc_channel(&renew_revoke.channel_id)?; - let filled_order = db::get_order_in_filling()? + let filled_order = order::handler::order_filled(Some(order_id)) .context("Cannot mark order as filled for confirmed DLC")?; update_position_after_dlc_channel_creation_or_update( @@ -362,12 +374,15 @@ impl Node { BackgroundTask::Rollover(TaskStatus::Success), )); } - TenTenOneMessage::Sign(signed) => { + TenTenOneMessage::Sign(TenTenOneSignChannel { + order_id, + sign_channel, + }) => { let expiry_timestamp = self .inner - .get_expiry_for_confirmed_dlc_channel(&signed.sign_channel.channel_id)?; + .get_expiry_for_confirmed_dlc_channel(&sign_channel.channel_id)?; - let filled_order = order::handler::order_filled() + let filled_order = order::handler::order_filled(Some(order_id)) .context("Cannot mark order as filled for confirmed DLC")?; update_position_after_dlc_channel_creation_or_update( @@ -380,12 +395,12 @@ impl Node { BackgroundTask::AsyncTrade(TaskStatus::Success), )); } - TenTenOneMessage::SettleConfirm(_) => { + TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { order_id, .. }) => { tracing::debug!("Position based on DLC channel is being closed"); - let filled_order = order::handler::order_filled()?; + let filled_order = order::handler::order_filled(Some(order_id))?; - update_position_after_dlc_closure(Some(filled_order)) + update_position_after_dlc_closure(filled_order) .context("Failed to update position after DLC closure")?; event::publish(&EventInternal::BackgroundNotification( diff --git a/mobile/native/src/orderbook.rs b/mobile/native/src/orderbook.rs index 8a9a8085d..9d60c4398 100644 --- a/mobile/native/src/orderbook.rs +++ b/mobile/native/src/orderbook.rs @@ -276,6 +276,12 @@ async fn handle_orderbook_message( ) .context("Could not set order to failed")?; } + Message::RolloverError { error } => { + tracing::error!("Failed to rollover position: {error:#}"); + event::publish(&EventInternal::BackgroundNotification( + BackgroundTask::Rollover(TaskStatus::Failed(format!("{error:#}"))), + )); + } }; Ok(()) diff --git a/mobile/native/src/trade/order/handler.rs b/mobile/native/src/trade/order/handler.rs index ec08820f7..e1e446fc8 100644 --- a/mobile/native/src/trade/order/handler.rs +++ b/mobile/native/src/trade/order/handler.rs @@ -285,29 +285,29 @@ pub(crate) fn order_filling( } /// Sets filling order to filled. Returns an error if no order in `Filling` -pub(crate) fn order_filled() -> Result { - let maybe_order_filling = get_order_in_filling()?; - let (order_being_filled, execution_price, matching_fee) = match &maybe_order_filling { - Some( - order @ Order { - state: - OrderState::Filling { - execution_price, - matching_fee, - }, - .. - }, - ) => (order, execution_price, matching_fee), - Some(order) => bail!("Unexpected state: {:?}", order.state), - None => bail!("No order to mark as Filled"), - }; +pub(crate) fn order_filled(order_id: Option) -> Result { + let order = match order_id { + None => get_order_in_filling(), + Some(order_id) => db::get_order(order_id), + }? + .with_context(|| format!("Could not find order. order_id = {order_id:?}"))?; + + let execution_price = order.execution_price(); + let matching_fee = order.matching_fee(); - let filled_order = - set_order_to_filled_and_update_ui(order_being_filled.id, *execution_price, *matching_fee)?; + if let (Some(execution_price), Some(matching_fee)) = (execution_price, matching_fee) { + let filled_order = + set_order_to_filled_and_update_ui(order.id, execution_price, matching_fee)?; - tracing::debug!(order = ?filled_order, "Order filled"); + tracing::debug!(order = ?filled_order, "Order filled"); + + return Ok(filled_order); + } - Ok(filled_order) + tracing::warn!( + "Couldn't set order to filling due to missing execution price and / or matching fee" + ); + Ok(order.clone()) } /// Update the [`Order`]'s state to [`OrderState::Failed`]. diff --git a/mobile/native/src/trade/order/mod.rs b/mobile/native/src/trade/order/mod.rs index 55f1d6e30..3d89b2f34 100644 --- a/mobile/native/src/trade/order/mod.rs +++ b/mobile/native/src/trade/order/mod.rs @@ -103,10 +103,9 @@ pub enum OrderState { /// /// In order to reach this state the orderbook must have provided trade params to start trade /// execution, and the trade execution failed; i.e. it did not result in setting up a DLC. - /// For the MVP there won't be a retry mechanism, so this is treated as a final state. - /// This is a final state. Failed { execution_price: Option, + matching_fee: Option, reason: FailureReason, }, @@ -227,9 +226,12 @@ impl Order { /// This returns the matching fee once known pub fn matching_fee(&self) -> Option { match self.state { - OrderState::Filling { matching_fee, .. } | OrderState::Filled { matching_fee, .. } => { - Some(matching_fee) - } + OrderState::Filling { matching_fee, .. } + | OrderState::Filled { matching_fee, .. } + | OrderState::Failed { + matching_fee: Some(matching_fee), + .. + } => Some(matching_fee), _ => None, } } diff --git a/mobile/native/src/trade/position/handler.rs b/mobile/native/src/trade/position/handler.rs index b581a5a55..b77bf64e2 100644 --- a/mobile/native/src/trade/position/handler.rs +++ b/mobile/native/src/trade/position/handler.rs @@ -147,7 +147,7 @@ pub fn update_position_after_dlc_channel_creation_or_update( } /// Delete a position after closing a DLC channel. -pub fn update_position_after_dlc_closure(filled_order: Option) -> Result<()> { +pub fn update_position_after_dlc_closure(filled_order: Order) -> Result<()> { tracing::debug!(?filled_order, "Removing position after DLC channel closure"); let position = match db::get_positions()?.as_slice() { @@ -162,29 +162,27 @@ pub fn update_position_after_dlc_closure(filled_order: Option) -> Result< } }; - if let Some(filled_order) = filled_order { - tracing::debug!( - ?position, - ?filled_order, - "Calculating closing trades for position" - ); + tracing::debug!( + ?position, + ?filled_order, + "Calculating closing trades for position" + ); - // After closing the DLC channel we do not need to update the position's expiry anymore. - let expiry = position.expiry; - let (new_position, trades) = position.apply_order(filled_order, expiry)?; + // After closing the DLC channel we do not need to update the position's expiry anymore. + let expiry = position.expiry; + let (new_position, trades) = position.apply_order(filled_order, expiry)?; - tracing::debug!(?trades, "Calculated closing trades"); + tracing::debug!(?trades, "Calculated closing trades"); - if let Some(new_position) = new_position { - tracing::warn!( - ?new_position, - "Expected computed position to vanish after applying closing order" - ); - } + if let Some(new_position) = new_position { + tracing::warn!( + ?new_position, + "Expected computed position to vanish after applying closing order" + ); + } - for trade in trades { - db::insert_trade(trade)?; - } + for trade in trades { + db::insert_trade(trade)?; } db::delete_positions()?; From 5efc04b8263458ff9d123c9baf8e932a207203ba Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 13:03:24 +0200 Subject: [PATCH 25/32] chore: Delay websocket connection retry at most 1 second --- mobile/native/src/orderbook.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mobile/native/src/orderbook.rs b/mobile/native/src/orderbook.rs index 9d60c4398..d8f752201 100644 --- a/mobile/native/src/orderbook.rs +++ b/mobile/native/src/orderbook.rs @@ -17,6 +17,7 @@ use futures::SinkExt; use futures::TryStreamExt; use parking_lot::Mutex; use rust_decimal::Decimal; +use std::cmp::min; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; @@ -141,7 +142,14 @@ pub fn subscribe( tracing::warn!("Cannot update orderbook status: {e:#}"); }; - let retry_interval = WS_RECONNECT_TIMEOUT.mul_f32(round as f32); + // Retry at least every second. We do this as it the p2p connection is not debouncing, + // thus it could happen after a restart that the p2p connection is established, but the + // websocket connection is still waiting to retry. This could have implications when the + // coordinator returns an error on the websocket which the app is not ready to process. + // + // Note, this is the same issue for why we originally moved to 10101 Messages, we should + // think about a similar way to return protocol erros via the p2p connection. + let retry_interval = min(Duration::from_secs(1), WS_RECONNECT_TIMEOUT.mul_f32(round as f32)); tracing::debug!( ?retry_interval, "Reconnecting to orderbook WS after timeout" From 760d805c75d2ccbb67e1aa5c90d6c3f4110980da Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 13:07:25 +0200 Subject: [PATCH 26/32] chore: Rename xxi screen to background task dialog screen --- ...xxi_screen.dart => background_task_dialog_screen.dart} | 8 ++++---- mobile/lib/common/routes.dart | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) rename mobile/lib/common/{xxi_screen.dart => background_task_dialog_screen.dart} (96%) diff --git a/mobile/lib/common/xxi_screen.dart b/mobile/lib/common/background_task_dialog_screen.dart similarity index 96% rename from mobile/lib/common/xxi_screen.dart rename to mobile/lib/common/background_task_dialog_screen.dart index e9ab92fd6..6fa8e4dcb 100644 --- a/mobile/lib/common/xxi_screen.dart +++ b/mobile/lib/common/background_task_dialog_screen.dart @@ -12,16 +12,16 @@ import 'package:http/http.dart' as http; import 'package:provider/provider.dart'; import 'package:version/version.dart'; -class XXIScreen extends StatefulWidget { +class BackgroundTaskDialogScreen extends StatefulWidget { final Widget child; - const XXIScreen({super.key, required this.child}); + const BackgroundTaskDialogScreen({super.key, required this.child}); @override - State createState() => _XXIScreenState(); + State createState() => _BackgroundTaskDialogScreenState(); } -class _XXIScreenState extends State { +class _BackgroundTaskDialogScreenState extends State { BackgroundTask? activeTask; @override diff --git a/mobile/lib/common/routes.dart b/mobile/lib/common/routes.dart index 176aa4c34..955e6508c 100644 --- a/mobile/lib/common/routes.dart +++ b/mobile/lib/common/routes.dart @@ -5,7 +5,7 @@ import 'package:get_10101/common/settings/emergency_kit_screen.dart'; import 'package:get_10101/common/settings/user_screen.dart'; import 'package:get_10101/common/settings/wallet_settings.dart'; import 'package:get_10101/common/status_screen.dart'; -import 'package:get_10101/common/xxi_screen.dart'; +import 'package:get_10101/common/background_task_dialog_screen.dart'; import 'package:get_10101/features/wallet/domain/destination.dart'; import 'package:get_10101/features/wallet/send/send_onchain_screen.dart'; import 'package:get_10101/features/welcome/error_screen.dart'; @@ -67,7 +67,7 @@ GoRouter createRoutes() { )), ShellRoute( builder: (BuildContext context, GoRouterState state, Widget child) { - return XXIScreen( + return BackgroundTaskDialogScreen( child: child, ); }, From 5fbb258f93b8a5380e11fbe068ce3b4c22b04783 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 16:07:15 +0200 Subject: [PATCH 27/32] chore: Don't wrap original error message in another error message --- mobile/native/src/orderbook.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mobile/native/src/orderbook.rs b/mobile/native/src/orderbook.rs index d8f752201..7a22e4358 100644 --- a/mobile/native/src/orderbook.rs +++ b/mobile/native/src/orderbook.rs @@ -8,7 +8,6 @@ use crate::health::ServiceStatus; use crate::state; use crate::trade::order; use crate::trade::order::FailureReason; -use anyhow::anyhow; use anyhow::Context; use anyhow::Result; use bitcoin::secp256k1::SecretKey; @@ -280,7 +279,7 @@ async fn handle_orderbook_message( order::handler::order_failed( Some(order_id), FailureReason::TradeResponse(error.to_string()), - anyhow!("Coordinator failed to execute trade: {error}"), + error.into(), ) .context("Could not set order to failed")?; } From da4d8b1f9c1bf96916017f03d3f793458a2e893a Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 16:09:57 +0200 Subject: [PATCH 28/32] chore: Add try catch around pop events This is useful during development when we reload the dart files to automatically re-render the dialog. However, the logic is only intended to get executed when there is an actual event, so this will fail if we reload manually. Adding this catch makes development a bit easier. --- .../common/background_task_dialog_screen.dart | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/mobile/lib/common/background_task_dialog_screen.dart b/mobile/lib/common/background_task_dialog_screen.dart index 6fa8e4dcb..b71b3c2e0 100644 --- a/mobile/lib/common/background_task_dialog_screen.dart +++ b/mobile/lib/common/background_task_dialog_screen.dart @@ -61,13 +61,19 @@ class _BackgroundTaskDialogScreenState extends State }, pageBuilder: (context, _, __) { // watch task updates from within the dialog. - final task = context.watch().events.pop(); - if (activeTask != null && task.type != activeTask!.type) { - logger.w("Received another task event $task while $activeTask is still active!"); + try { + final task = context.watch().events.pop(); + if (activeTask != null && task.type != activeTask!.type) { + logger.w("Received another task event $task while $activeTask is still active!"); + } + + // update the active task to the last event received on the stack. + activeTask = task; + } catch (error) { + logger.w("Re-rendered the dialog with nothing on the events stack. This should " + "only happen if the screen is manually re-rendered in development mode."); } - // update the active task to the last event received on the stack. - activeTask = task; return getTaskStatusDialog(activeTask)!; }); } From eb0b1a7ecdda0d8a41bf8f3c61eddd77f22ee8c2 Mon Sep 17 00:00:00 2001 From: Richard Holzeis Date: Mon, 6 May 2024 16:13:00 +0200 Subject: [PATCH 29/32] feat: Add dedicated background tasks for expiry and liquidation --- coordinator/src/emergency_kit.rs | 15 +- coordinator/src/node.rs | 4 +- coordinator/src/orderbook/db/orders.rs | 1 + crates/xxi-node/src/message_handler.rs | 151 ++++++++++++------ crates/xxi-node/src/node/dlc_channel.rs | 2 + crates/xxi-node/src/node/dlc_manager.rs | 14 +- crates/xxi-node/src/tests/dlc_channel.rs | 6 +- mobile/assets/info.gif | Bin 0 -> 514172 bytes .../background_task_change_notifier.dart | 10 ++ .../common/background_task_dialog_screen.dart | 40 ++++- mobile/lib/common/domain/background_task.dart | 17 +- mobile/lib/common/task_status_dialog.dart | 49 +++--- mobile/native/src/dlc/node.rs | 60 ++++--- mobile/native/src/emergency_kit.rs | 10 +- mobile/native/src/event/api.rs | 6 + mobile/native/src/event/mod.rs | 2 + mobile/native/src/trade/order/handler.rs | 27 +++- 17 files changed, 291 insertions(+), 123 deletions(-) create mode 100644 mobile/assets/info.gif diff --git a/coordinator/src/emergency_kit.rs b/coordinator/src/emergency_kit.rs index 4c8dcea1b..b83cc988a 100644 --- a/coordinator/src/emergency_kit.rs +++ b/coordinator/src/emergency_kit.rs @@ -1,11 +1,13 @@ use crate::node::Node; +use crate::orderbook::db; +use anyhow::Context; use anyhow::Result; use bitcoin::secp256k1::PublicKey; use bitcoin_old::secp256k1::SecretKey; use dlc_manager::Signer; use dlc_messages::channel::RenewRevoke; use lightning::ln::chan_utils::build_commitment_secret; -use uuid::Uuid; +use xxi_node::commons::OrderState; use xxi_node::message_handler::TenTenOneMessage; use xxi_node::message_handler::TenTenOneRenewRevoke; use xxi_node::node::event::NodeEvent; @@ -26,10 +28,15 @@ impl Node { signed_channel.update_idx + 1, ))?; + let mut conn = self.pool.clone().get()?; + // We assume the last taken order to be the relevant order. + let order = db::orders::get_by_trader_id_and_state(&mut conn, trader, OrderState::Taken)? + .with_context(|| { + format!("Couldn't find last order in state taken. trader_id={trader}") + })?; + let msg = TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { - // this is not ideal, but the app should be able to handle the scenario where the order - // is not known. - order_id: Uuid::default(), + order_id: order.id, renew_revoke: RenewRevoke { channel_id: signed_channel.channel_id, per_update_secret: prev_per_update_secret, diff --git a/coordinator/src/node.rs b/coordinator/src/node.rs index db83a2150..2750902a9 100644 --- a/coordinator/src/node.rs +++ b/coordinator/src/node.rs @@ -141,7 +141,9 @@ impl Node { let error = TradingError::Other(format!("{e:#}")); async move { let message = match msg.get_tentenone_message_type() { - TenTenOneMessageType::Trade => { + TenTenOneMessageType::Trade + | TenTenOneMessageType::Expire + | TenTenOneMessageType::Liquidate => { if let Some(order_id) = msg.get_order_id() { OrderbookMessage::TraderMessage { trader_id: to_secp_pk_30(node_id), diff --git a/coordinator/src/orderbook/db/orders.rs b/coordinator/src/orderbook/db/orders.rs index f0f1ff6d7..698223560 100644 --- a/coordinator/src/orderbook/db/orders.rs +++ b/coordinator/src/orderbook/db/orders.rs @@ -458,6 +458,7 @@ pub fn get_by_trader_id_and_state( orders::table .filter(orders::trader_id.eq(trader_id.to_string())) .filter(orders::order_state.eq(OrderState::from(order_state))) + .order_by(orders::timestamp.desc()) .first::(conn) .map(OrderbookOrder::from) .optional() diff --git a/crates/xxi-node/src/message_handler.rs b/crates/xxi-node/src/message_handler.rs index 6e217f466..f418be614 100644 --- a/crates/xxi-node/src/message_handler.rs +++ b/crates/xxi-node/src/message_handler.rs @@ -1,6 +1,7 @@ use crate::bitcoin_conversion::to_secp_pk_30; use crate::commons::FilledWith; use crate::commons::Order; +use crate::commons::OrderReason; use crate::node::event::NodeEvent; use crate::node::event::NodeEventHandler; use anyhow::Result; @@ -149,7 +150,11 @@ pub enum TenTenOneMessage { pub enum TenTenOneMessageType { /// open channel, open, close or resize a position Trade, - /// rollover + // expired position + Expire, + // liquidated position + Liquidate, + /// rollover position Rollover, /// reject or close channel Other, @@ -165,11 +170,22 @@ impl TenTenOneMessage { | TenTenOneMessage::RenewAccept(_) | TenTenOneMessage::RenewConfirm(_) | TenTenOneMessage::RenewFinalize(_) - | TenTenOneMessage::RenewRevoke(_) - | TenTenOneMessage::SettleOffer(_) - | TenTenOneMessage::SettleAccept(_) - | TenTenOneMessage::SettleConfirm(_) - | TenTenOneMessage::SettleFinalize(_) => TenTenOneMessageType::Trade, + | TenTenOneMessage::RenewRevoke(_) => TenTenOneMessageType::Trade, + TenTenOneMessage::SettleOffer(TenTenOneSettleOffer { + order: Order { order_reason, .. }, + .. + }) + | TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { order_reason, .. }) + | TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { order_reason, .. }) + | TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { order_reason, .. }) => { + match order_reason { + OrderReason::Manual => TenTenOneMessageType::Trade, + OrderReason::Expired => TenTenOneMessageType::Expire, + OrderReason::CoordinatorLiquidated | OrderReason::TraderLiquidated => { + TenTenOneMessageType::Liquidate + } + } + } TenTenOneMessage::RolloverOffer(_) | TenTenOneMessage::RolloverAccept(_) | TenTenOneMessage::RolloverConfirm(_) @@ -210,20 +226,23 @@ pub struct TenTenOneSettleOffer { pub settle_offer: SettleOffer, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct TenTenOneSettleAccept { + pub order_reason: OrderReason, pub order_id: Uuid, pub settle_accept: SettleAccept, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct TenTenOneSettleConfirm { + pub order_reason: OrderReason, pub order_id: Uuid, pub settle_confirm: SettleConfirm, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct TenTenOneSettleFinalize { + pub order_reason: OrderReason, pub order_id: Uuid, pub settle_finalize: SettleFinalize, } @@ -476,92 +495,98 @@ impl TenTenOneMessage { /// an offer so if an offer is passed the function will panic. This is most likely not a future /// proof solution as we'd might want to enrich the response with 10101 metadata as well. If /// that happens we will have to rework this part. - pub fn build_from_response(message: Message, order_id: Option) -> Self { - match message { - Message::Channel(ChannelMessage::Accept(accept_channel)) => { + pub fn build_from_response( + message: Message, + order_id: Option, + order_reason: Option, + ) -> Result { + let msg = match (message, order_id) { + (Message::Channel(ChannelMessage::Accept(accept_channel)), Some(order_id)) => { TenTenOneMessage::Accept(TenTenOneAcceptChannel { accept_channel, - order_id: order_id.expect("to be some"), + order_id, }) } - Message::Channel(ChannelMessage::Sign(sign_channel)) => { + (Message::Channel(ChannelMessage::Sign(sign_channel)), Some(order_id)) => { TenTenOneMessage::Sign(TenTenOneSignChannel { sign_channel, - order_id: order_id.expect("to be some"), + order_id, }) } - Message::Channel(ChannelMessage::SettleAccept(settle_accept)) => { + (Message::Channel(ChannelMessage::SettleAccept(settle_accept)), Some(order_id)) => { TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { settle_accept, - order_id: order_id.expect("to be some"), + order_id, + order_reason: order_reason.expect("to be some"), }) } - Message::Channel(ChannelMessage::SettleConfirm(settle_confirm)) => { + (Message::Channel(ChannelMessage::SettleConfirm(settle_confirm)), Some(order_id)) => { TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { settle_confirm, - order_id: order_id.expect("to be some"), + order_id, + order_reason: order_reason.expect("to be some"), }) } - Message::Channel(ChannelMessage::SettleFinalize(settle_finalize)) => { + (Message::Channel(ChannelMessage::SettleFinalize(settle_finalize)), Some(order_id)) => { TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { settle_finalize, - order_id: order_id.expect("to be some"), + order_id, + order_reason: order_reason.expect("to be some"), }) } - Message::Channel(ChannelMessage::RenewAccept(renew_accept)) if order_id.is_none() => { + (Message::Channel(ChannelMessage::RenewAccept(renew_accept)), None) => { TenTenOneMessage::RolloverAccept(TenTenOneRolloverAccept { renew_accept }) } - Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)) if order_id.is_none() => { + (Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)), None) => { TenTenOneMessage::RolloverConfirm(TenTenOneRolloverConfirm { renew_confirm }) } - Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)) - if order_id.is_none() => - { + (Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)), None) => { TenTenOneMessage::RolloverFinalize(TenTenOneRolloverFinalize { renew_finalize }) } - Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)) if order_id.is_none() => { + (Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)), None) => { TenTenOneMessage::RolloverRevoke(TenTenOneRolloverRevoke { renew_revoke }) } - Message::Channel(ChannelMessage::RenewAccept(renew_accept)) => { + (Message::Channel(ChannelMessage::RenewAccept(renew_accept)), Some(order_id)) => { TenTenOneMessage::RenewAccept(TenTenOneRenewAccept { renew_accept, - order_id: order_id.expect("to be some"), + order_id, }) } - Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)) => { + (Message::Channel(ChannelMessage::RenewConfirm(renew_confirm)), Some(order_id)) => { TenTenOneMessage::RenewConfirm(TenTenOneRenewConfirm { renew_confirm, - order_id: order_id.expect("to be some"), + order_id, }) } - Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)) => { + (Message::Channel(ChannelMessage::RenewFinalize(renew_finalize)), Some(order_id)) => { TenTenOneMessage::RenewFinalize(TenTenOneRenewFinalize { renew_finalize, - order_id: order_id.expect("to be some"), + order_id, }) } - Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)) => { + (Message::Channel(ChannelMessage::RenewRevoke(renew_revoke)), Some(order_id)) => { TenTenOneMessage::RenewRevoke(TenTenOneRenewRevoke { renew_revoke, - order_id: order_id.expect("to be some"), + order_id, }) } - Message::Channel(ChannelMessage::CollaborativeCloseOffer( - collaborative_close_offer, - )) => TenTenOneMessage::CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer { + ( + Message::Channel(ChannelMessage::CollaborativeCloseOffer( + collaborative_close_offer, + )), + None, + ) => TenTenOneMessage::CollaborativeCloseOffer(TenTenOneCollaborativeCloseOffer { collaborative_close_offer, }), - Message::Channel(ChannelMessage::Reject(reject)) => { + (Message::Channel(ChannelMessage::Reject(reject)), None) => { TenTenOneMessage::Reject(TenTenOneReject { reject }) } - Message::OnChain(_) - | Message::SubChannel(_) - | Message::Channel(ChannelMessage::RenewOffer(_)) - | Message::Channel(ChannelMessage::SettleOffer(_)) - | Message::Channel(ChannelMessage::Offer(_)) => { + (_, _) => { unreachable!() } - } + }; + + Ok(msg) } pub fn get_order_id(&self) -> Option { @@ -601,6 +626,35 @@ impl TenTenOneMessage { } } + pub fn get_order_reason(&self) -> Option { + match self { + TenTenOneMessage::SettleOffer(TenTenOneSettleOffer { + order: Order { order_reason, .. }, + .. + }) + | TenTenOneMessage::SettleAccept(TenTenOneSettleAccept { order_reason, .. }) + | TenTenOneMessage::SettleConfirm(TenTenOneSettleConfirm { order_reason, .. }) + | TenTenOneMessage::SettleFinalize(TenTenOneSettleFinalize { order_reason, .. }) => { + Some(order_reason.clone()) + } + TenTenOneMessage::Offer(_) + | TenTenOneMessage::Accept(_) + | TenTenOneMessage::Sign(_) + | TenTenOneMessage::RenewOffer(_) + | TenTenOneMessage::RenewAccept(_) + | TenTenOneMessage::RenewConfirm(_) + | TenTenOneMessage::RenewFinalize(_) + | TenTenOneMessage::RenewRevoke(_) + | TenTenOneMessage::RolloverOffer(_) + | TenTenOneMessage::RolloverAccept(_) + | TenTenOneMessage::RolloverConfirm(_) + | TenTenOneMessage::RolloverFinalize(_) + | TenTenOneMessage::RolloverRevoke(_) + | TenTenOneMessage::CollaborativeCloseOffer(_) + | TenTenOneMessage::Reject(_) => None, + } + } + pub fn get_reference_id(&self) -> Option { match self { TenTenOneMessage::Offer(TenTenOneOfferChannel { @@ -851,9 +905,9 @@ impl_dlc_writeable!(TenTenOneOfferChannel, { (filled_with, writeable), (offer_ch impl_dlc_writeable!(TenTenOneAcceptChannel, { (order_id, {cb_writeable, write_uuid, read_uuid}), (accept_channel, writeable) }); impl_dlc_writeable!(TenTenOneSignChannel, { (order_id, {cb_writeable, write_uuid, read_uuid}), (sign_channel, writeable) }); impl_dlc_writeable!(TenTenOneSettleOffer, { (order, writeable), (filled_with, writeable), (settle_offer, writeable) }); -impl_dlc_writeable!(TenTenOneSettleAccept, { (order_id, {cb_writeable, write_uuid, read_uuid}), (settle_accept, writeable) }); -impl_dlc_writeable!(TenTenOneSettleConfirm, { (order_id, {cb_writeable, write_uuid, read_uuid}), (settle_confirm, writeable) }); -impl_dlc_writeable!(TenTenOneSettleFinalize, { (order_id, {cb_writeable, write_uuid, read_uuid}), (settle_finalize, writeable) }); +impl_dlc_writeable!(TenTenOneSettleAccept, { (order_id, {cb_writeable, write_uuid, read_uuid}), (order_reason, writeable), (settle_accept, writeable) }); +impl_dlc_writeable!(TenTenOneSettleConfirm, { (order_id, {cb_writeable, write_uuid, read_uuid}), (order_reason, writeable), (settle_confirm, writeable) }); +impl_dlc_writeable!(TenTenOneSettleFinalize, { (order_id, {cb_writeable, write_uuid, read_uuid}), (order_reason, writeable), (settle_finalize, writeable) }); impl_dlc_writeable!(TenTenOneRenewOffer, { (filled_with, writeable), (renew_offer, writeable) }); impl_dlc_writeable!(TenTenOneRenewAccept, { (order_id, {cb_writeable, write_uuid, read_uuid}), (renew_accept, writeable) }); impl_dlc_writeable!(TenTenOneRenewConfirm, { (order_id, {cb_writeable, write_uuid, read_uuid}), (renew_confirm, writeable) }); @@ -902,6 +956,7 @@ impl_type!( impl_serde_writeable!(Order); impl_serde_writeable!(FilledWith); +impl_serde_writeable!(OrderReason); fn read_tentenone_message( msg_type: u16, diff --git a/crates/xxi-node/src/node/dlc_channel.rs b/crates/xxi-node/src/node/dlc_channel.rs index beee90151..ab15d95ca 100644 --- a/crates/xxi-node/src/node/dlc_channel.rs +++ b/crates/xxi-node/src/node/dlc_channel.rs @@ -282,6 +282,7 @@ impl Result<()> { let channel_id_hex = hex::encode(channel_id); @@ -296,6 +297,7 @@ impl Some(TenTenOneMessage::build_from_response( + resp, + message.get_order_id(), + message.get_order_reason(), + )?), + None => None, + }; + + Ok(response) } } diff --git a/crates/xxi-node/src/tests/dlc_channel.rs b/crates/xxi-node/src/tests/dlc_channel.rs index 7be755797..1101adb4b 100644 --- a/crates/xxi-node/src/tests/dlc_channel.rs +++ b/crates/xxi-node/src/tests/dlc_channel.rs @@ -583,10 +583,11 @@ async fn open_channel_and_position_and_settle_position( tracing::info!("DLC channel is on-chain"); + let order = dummy_order(); coordinator .propose_dlc_channel_collaborative_settlement( - dummy_order(), - dummy_filled_with(), + order.clone(), + filled_with.clone(), &coordinator_signed_channel.channel_id, coordinator_dlc_collateral.to_sat() / 2, new_reference_id(), @@ -620,6 +621,7 @@ async fn open_channel_and_position_and_settle_position( tracing::debug!("Accepting settle offer and waiting for being settled..."); app.accept_dlc_channel_collaborative_settlement( filled_with.order_id, + order.order_reason, &app_signed_channel.channel_id, ) .unwrap(); diff --git a/mobile/assets/info.gif b/mobile/assets/info.gif new file mode 100644 index 0000000000000000000000000000000000000000..dc61bdbdcb07b4fc5f61807381c9c024bcf5b7e3 GIT binary patch literal 514172 zcmeF&_fM3;A183yE(^Ph4{d3pfFd0iq>3WFqf3)6U63XqRZv)9>Agvl-i!3!d+&V# zS$b6|7DU`Vzu(JU?k~9Hl6x{g%p{Xc=95e^dC%)nR#lRav|uAOAlY9h(pES()jDxA z-$UDO1leu`+iwIr;o{#c$9rMpy|EeI)7gQu*+H|}!E@P|x$Kbn?2v_0%t&_lQcXx# zM#NTj#BzN|cSiJHcJx|C+);KMt}(i^F{Udc@mpP7Uq;etM$%bE^1pVTk$jPna?y~` zmyz;4BjrcNho5yxqjgDReF+tHA13P3r|Uj0)MYQ#WiR(+x7FpY*5$3$<*(NjY}6It z>IyeU@@q!&YwL=(>q-ym%8u&Fj_b-#wu*e~D!$ZJoYqyI&z6_fRee9Ki@-Ie9d$;0 z>w10E6?xq)chnt4=tUm&#vS#>AN3_3^(7w-rk@T5UkzE{hhANdIQ$v2#gCa?PuTt) z_qv{RB21ZFO?eQeUtCW6T~EIu%vj*3{0TFTgjt)*+2FskUW8d!!kisp&i-hwjWF+Y zINyCaA3<1f{kf2cUwC`H5Qv`-CoH=ET>3y*@+2(#{8^4AEF}_F-W{$?;a9?bVY3KW z^dD?8VKtbr8iHSqC9H-2T}vmdNB>>VCwz|oy;1sSqmY10KHS_RY^Ggq))6*y@SCNC zt;|1LRrsxf!|mh4?JxMPPlWC4!<|#YPTt|}>EZ4a}s;PUX`>hR#tuY(c7LCy6+$Kl~M{-Ed2VK3pZfpFAJ zIBF*xw-Jtpu8)TaC!K^ZJ%q0Vgs)SCZzF`$3BuVl;e3v8zDBrMBwQ>LzON9zZxVj2 z6Mo_dzqSd#4hWZfgx`mR-zS8tZ-lG!zgJg;Kc|F0=Y;F;gzF!K>tBTH--PQc!rvc+ zzds3oFA0Bt6aN0e|0NLcmjwJ30e?;S&*1;k$4-DgRn*mymqjTG3nEF0iHL~Uf0I#= z5)p{_|MiLfb4-XJcp_5BO_l1Lo*)PuuGt=nyQ7|^(NeoRmioZq^LR_${#1^91ik&Vz4>f=IFZk6vc2VEe>z`1`)Nn(kK^S! zhmFaOwqM_HefY@R&pO+GUmVPpn@x3g{P}gdJ(m5ftMl)l%ZuZUsje;pfe6fv3m`+- z;n0wKCAdJC*a0pGP~zSUrh9I;iD7(MvKeyI^I$WSErfe3>~4zPRycQ2$yNk^*1@c~vk8%Sm-VKK;0+_&)bd~mcN#MDOvN(*l%hR;}gu

+7#;#st+*?h8iDA;~BDfzAS$EeTi&I3Uf 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

7A9#DO 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