From cb39460219ec6468f9f838299331da7f2dcecb05 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 5 Jun 2026 13:13:36 +0200 Subject: [PATCH] New epub reader (cosmo ereader) + integtration tests for api + many small fixes --- .gitignore | 4 +- .../main/res/xml/network_security_config.xml | 8 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- lib/core/services/api_service.dart | 76 ++--- .../book_details/bloc/book_details_bloc.dart | 4 +- .../book_details/bloc/book_details_state.dart | 11 +- .../book_details_remote_datasource.dart | 5 +- .../reading_progress_repository.dart | 30 +- .../presentation/pages/book_details_page.dart | 137 +++++--- .../widgets/add_to_shelf_widget.dart | 5 +- .../widgets/metadata_search_dialog.dart | 10 +- .../widgets/send_to_ereader_widget.dart | 15 +- .../presentation/widgets/search_dialog.dart | 8 +- .../widgets/book_card_widget.dart | 13 +- .../widgets/login_form_widget.dart | 13 +- .../pages/login_settings_page.dart | 5 +- .../me/presentation/pages/me_page.dart | 36 +-- lib/features/settings/bloc/settings_bloc.dart | 19 -- .../settings/bloc/settings_event.dart | 9 - .../settings/bloc/settings_state.dart | 5 - .../settings_local_datasource.dart | 9 - .../settings/data/models/settings_model.dart | 4 - .../repositories/settings_repository.dart | 8 - .../presentation/pages/settings_page.dart | 77 +---- .../widgets/download_options_widget.dart | 5 +- .../presentation/widgets/feedback_widget.dart | 18 +- .../widgets/sync_settings_widget.dart | 11 +- .../shelf_details_remote_datasource.dart | 5 +- .../pages/shelf_details_page.dart | 12 +- .../widgets/edit_shelf_dialog_widget.dart | 24 +- .../shelf_view_remote_datasource.dart | 12 +- .../widgets/create_shelf_dialog_widget.dart | 24 +- lib/l10n/app_de.arb | 4 + lib/l10n/app_en.arb | 4 + lib/main.dart | 13 + lib/shared/utils/status_colors.dart | 30 ++ lib/shared/widgets/app_dialog_button.dart | 82 +++++ lib/shared/widgets/coming_soon_widget.dart | 10 +- packages/vocsy_epub_viewer/LICENSE | 201 ------------ packages/vocsy_epub_viewer/README.md | 186 ----------- packages/vocsy_epub_viewer/android/.gitignore | 8 - .../vocsy_epub_viewer/android/build.gradle | 47 --- .../android/gradle.properties | 4 - .../gradle/wrapper/gradle-wrapper.properties | 5 - .../vocsy_epub_viewer/android/settings.gradle | 1 - .../android/src/main/AndroidManifest.xml | 4 - .../android/src/main/assets/3.epub | Bin 220751 -> 0 bytes .../assets/highlights/highlights_data.json | 1 - .../vocsy/epub_viewer/EpubViewerPlugin.java | 121 -------- .../com/vocsy/epub_viewer/HighlightData.java | 86 ----- .../java/com/vocsy/epub_viewer/Reader.java | 189 ----------- .../com/vocsy/epub_viewer/ReaderConfig.java | 39 --- .../ios/Classes/EpubConfig.swift | 190 ------------ .../ios/Classes/EpubViewerPlugin.h | 4 - .../ios/Classes/EpubViewerPlugin.m | 8 - .../ios/Classes/SwiftEpubKittyPlugin.swift | 97 ------ .../ios/vocsy_epub_viewer.podspec | 25 -- .../vocsy_epub_viewer/lib/epub_viewer.dart | 85 ----- .../lib/model/enum/epub_scroll_direction.dart | 4 - .../lib/model/epub_locator.dart | 48 --- .../vocsy_epub_viewer/lib/utils/util.dart | 34 -- packages/vocsy_epub_viewer/pubspec.lock | 293 ------------------ packages/vocsy_epub_viewer/pubspec.yaml | 66 ---- pubspec.lock | 181 ++++++++++- pubspec.yaml | 3 +- .../book_details_integration_test.dart | 139 +++++++++ .../book_view/book_view_integration_test.dart | 80 +++++ .../discover_details_integration_test.dart | 101 ++++++ .../download_service_integration_test.dart | 86 +++++ .../login/login_integration_test.dart | 38 +++ test/features/me/me_integration_test.dart | 39 +++ .../shelf_details_integration_test.dart | 108 +++++++ .../shelf_view_integration_test.dart | 86 +++++ test/features/sync/sync_integration_test.dart | 57 ++++ test/helpers/test_setup.dart | 67 ++++ test/integration_check_test.dart | 14 + 76 files changed, 1376 insertions(+), 2136 deletions(-) create mode 100644 android/app/src/main/res/xml/network_security_config.xml create mode 100644 lib/shared/utils/status_colors.dart create mode 100644 lib/shared/widgets/app_dialog_button.dart delete mode 100644 packages/vocsy_epub_viewer/LICENSE delete mode 100644 packages/vocsy_epub_viewer/README.md delete mode 100644 packages/vocsy_epub_viewer/android/.gitignore delete mode 100644 packages/vocsy_epub_viewer/android/build.gradle delete mode 100644 packages/vocsy_epub_viewer/android/gradle.properties delete mode 100644 packages/vocsy_epub_viewer/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 packages/vocsy_epub_viewer/android/settings.gradle delete mode 100644 packages/vocsy_epub_viewer/android/src/main/AndroidManifest.xml delete mode 100644 packages/vocsy_epub_viewer/android/src/main/assets/3.epub delete mode 100644 packages/vocsy_epub_viewer/android/src/main/assets/highlights/highlights_data.json delete mode 100644 packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/EpubViewerPlugin.java delete mode 100644 packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/HighlightData.java delete mode 100644 packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/Reader.java delete mode 100644 packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/ReaderConfig.java delete mode 100644 packages/vocsy_epub_viewer/ios/Classes/EpubConfig.swift delete mode 100644 packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.h delete mode 100644 packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.m delete mode 100644 packages/vocsy_epub_viewer/ios/Classes/SwiftEpubKittyPlugin.swift delete mode 100644 packages/vocsy_epub_viewer/ios/vocsy_epub_viewer.podspec delete mode 100644 packages/vocsy_epub_viewer/lib/epub_viewer.dart delete mode 100644 packages/vocsy_epub_viewer/lib/model/enum/epub_scroll_direction.dart delete mode 100644 packages/vocsy_epub_viewer/lib/model/epub_locator.dart delete mode 100644 packages/vocsy_epub_viewer/lib/utils/util.dart delete mode 100644 packages/vocsy_epub_viewer/pubspec.lock delete mode 100644 packages/vocsy_epub_viewer/pubspec.yaml create mode 100644 test/features/book_details/book_details_integration_test.dart create mode 100644 test/features/book_view/book_view_integration_test.dart create mode 100644 test/features/discover_details/discover_details_integration_test.dart create mode 100644 test/features/download_service/download_service_integration_test.dart create mode 100644 test/features/login/login_integration_test.dart create mode 100644 test/features/me/me_integration_test.dart create mode 100644 test/features/shelf_details/shelf_details_integration_test.dart create mode 100644 test/features/shelf_view/shelf_view_integration_test.dart create mode 100644 test/features/sync/sync_integration_test.dart create mode 100644 test/helpers/test_setup.dart create mode 100644 test/integration_check_test.dart diff --git a/.gitignore b/.gitignore index 8eb4d37..55bec42 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,6 @@ app.*.map.json de.doen1el.calibreWebCompanion.yml # Don't track generated localization files -lib/l10n/app_localizations*.dart \ No newline at end of file +lib/l10n/app_localizations*.dart +lib/l10n/app_localizations*.darttest/test_env.dart +test/test_env.dart \ No newline at end of file diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..d7b4192 --- /dev/null +++ b/android/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index efdcc4a..74b269f 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 306b414..1145e49 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -35,7 +35,6 @@ class ApiService { /// Returns the base URL with base path if available String getBaseUrl() { if (_basePath == null || _basePath!.isEmpty) { - _logger.d('Base URL (no path): $_baseUrl'); return _baseUrl!; } else { final normalizedBasePath = _basePath!.trim(); @@ -228,12 +227,6 @@ class ApiService { queryParams: queryParams, ); try { - if (response.body.length > 50) { - _logger.d('Response body: ${response.body.substring(0, 50)}...'); - } else { - _logger.d('Response body: ${response.body}'); - } - return _sanitizeJsonResponse(response.body); } catch (e) { _logger.e('Failed to parse JSON response: $e'); @@ -287,12 +280,6 @@ class ApiService { queryParams: queryParams, ); try { - if (response.body.length > 50) { - _logger.d('Response body: ${response.body.substring(0, 50)}...'); - } else { - _logger.d('Response body: ${response.body}'); - } - transformer.parse(response.body); String jsonString = transformer.toParkerWithAttrs(); @@ -333,12 +320,9 @@ class ApiService { headers.addAll(customHeaders); if (followRedirects) { - _logger.d('GET request to: $uri'); - _logger.d('Headers: $headers'); - try { final response = await _client!.get(uri, headers: headers); - _logger.i('Response status: ${response.statusCode}'); + _logger.d('GET $uri -> ${response.statusCode}'); if (response.headers.containsKey('set-cookie')) { final prefs = await SharedPreferences.getInstance(); @@ -625,12 +609,6 @@ class ApiService { } request.files.addAll(files); - _logger.d('Multipart POST request headers: ${request.headers}'); - _logger.d('Multipart POST request fields: ${request.fields}'); - _logger.d( - 'Multipart POST request files: ${request.files.length} files', - ); - try { final streamedResponse = await request.send(); final response = await http.Response.fromStream(streamedResponse); @@ -694,9 +672,6 @@ class ApiService { contentType: contentType, ); - _logger.d('CSRF-protected POST headers: $postHeaders'); - _logger.d('CSRF-protected POST body: $encodedBody'); - try { final response = await _client!.post( uri, @@ -749,13 +724,10 @@ class ApiService { request.files.addAll(files); - _logger.d('Multipart POST request to: $uri'); - _logger.d('Multipart headers: ${request.headers}'); - try { final streamedResponse = await request.send(); final response = await http.Response.fromStream(streamedResponse); - _logger.i('Multipart POST response status: ${response.statusCode}'); + _logger.d('Multipart POST $uri -> ${response.statusCode}'); if (response.headers.containsKey('set-cookie')) { final prefs = await SharedPreferences.getInstance(); @@ -785,9 +757,6 @@ class ApiService { headers.addAll(customHeaders); - _logger.d('POST request to: $uri'); - _logger.d('Headers: $headers'); - final encodedBody = _encodeBody(body: body, contentType: contentType); try { @@ -796,7 +765,7 @@ class ApiService { headers: headers, body: encodedBody ?? "", ); - _logger.i('POST response status: ${response.statusCode}'); + _logger.d('POST $uri -> ${response.statusCode}'); if (response.headers.containsKey('set-cookie')) { final prefs = await SharedPreferences.getInstance(); @@ -847,12 +816,9 @@ class ApiService { request.headers.addAll(headers); - _logger.d('GET stream request to: ${uri.toString()}'); - _logger.d('Headers: $headers'); - try { final response = await _client!.send(request); - _logger.i('Stream response status: ${response.statusCode}'); + _logger.d('GET (stream) $uri -> ${response.statusCode}'); _checkResponseStatus(statusCode: response.statusCode); return response; } catch (e) { @@ -945,7 +911,6 @@ class ApiService { fullPath = '/$endpoint'; } - _logger.d('Built URL: $_baseUrl$fullPath'); return Uri.parse( '$_baseUrl$fullPath', ).replace(queryParameters: queryParams); @@ -996,13 +961,10 @@ class ApiService { if (resolvedAuthMethod == AuthMethod.auto) { if (_username != null && _username!.isNotEmpty && _password != null) { resolvedAuthMethod = AuthMethod.basic; - _logger.d('Auto-Auth: Resolved to Basic (Credentials available)'); } else if (_cookie != null && _cookie!.isNotEmpty) { resolvedAuthMethod = AuthMethod.cookie; - _logger.d('Auto-Auth: Resolved to Cookie (No credentials)'); } else { resolvedAuthMethod = AuthMethod.none; - _logger.d('Auto-Auth: Resolved to None'); } } @@ -1104,10 +1066,21 @@ class ApiService { throw Exception('Failed to get CSRF token for upload'); } + // Start with the stored session cookie and merge any new cookies from the + // CSRF GET response. Without this, the upload POST sends an empty Cookie + // header whenever the server doesn't re-issue cookies on the CSRF fetch + // (i.e. when the session is already valid), causing a 400. + String sessionCookie = _cookie ?? ''; + final rawSetCookie = csrfResult['cookies']; + if (rawSetCookie != null && rawSetCookie.isNotEmpty) { + final newCookie = buildCookieHeaderFromSetCookie(rawSetCookie); + sessionCookie = _mergeCookieHeaders(sessionCookie, newCookie); + } + final uri = _buildUri(endpoint: endpoint); final request = http.MultipartRequest('POST', uri); - request.headers['Cookie'] = csrfResult['cookies'] ?? ''; + request.headers['Cookie'] = sessionCookie; request.fields['csrf_token'] = csrfToken; @@ -1118,7 +1091,22 @@ class ApiService { final customHeaders = await _processCustomHeaders(); request.headers.addAll(customHeaders); - final fileName = file.path.split('/').last; + final rawFileName = file.path.split('/').last; + // Sanitize filename to match werkzeug secure_filename behavior: calibre-web + // rejects filenames with parentheses, brackets, spaces, and other special + // characters, returning a 400. Strip to ASCII alphanumeric + hyphens + dots. + final dotIndex = rawFileName.lastIndexOf('.'); + final rawName = + dotIndex != -1 ? rawFileName.substring(0, dotIndex) : rawFileName; + final ext = dotIndex != -1 ? rawFileName.substring(dotIndex) : ''; + final sanitizedName = rawName + .replaceAll(RegExp(r'[^a-zA-Z0-9_\-]'), '_') + .replaceAll(RegExp(r'_+'), '_') + .replaceAll(RegExp(r'^_+|_+$'), ''); + final fileName = '${sanitizedName.isEmpty ? 'upload' : sanitizedName}$ext'; + if (fileName != rawFileName) { + _logger.i('Sanitized filename: $rawFileName → $fileName'); + } final fileExtension = fileName.split('.').last.toLowerCase(); String contentType = 'application/octet-stream'; diff --git a/lib/features/book_details/bloc/book_details_bloc.dart b/lib/features/book_details/bloc/book_details_bloc.dart index 4eff6c8..e1c62de 100644 --- a/lib/features/book_details/bloc/book_details_bloc.dart +++ b/lib/features/book_details/bloc/book_details_bloc.dart @@ -779,9 +779,9 @@ class BookDetailsBloc extends Bloc { LoadReadingProgress event, Emitter emit, ) async { - final location = await progressRepository.getBestLocation(event.bookUuid); + final cfi = await progressRepository.getBestLocation(event.bookUuid); - emit(state.copyWith(startLocation: location)); + emit(state.copyWith(startCfi: cfi)); } Future _onSyncReadingProgress( diff --git a/lib/features/book_details/bloc/book_details_state.dart b/lib/features/book_details/bloc/book_details_state.dart index b302321..08a7190 100644 --- a/lib/features/book_details/bloc/book_details_state.dart +++ b/lib/features/book_details/bloc/book_details_state.dart @@ -2,7 +2,6 @@ import 'package:equatable/equatable.dart'; import 'package:calibre_web_companion/features/book_details/data/models/book_details_model.dart'; import 'package:calibre_web_companion/features/book_view/data/models/book_view_model.dart'; -import 'package:vocsy_epub_viewer/epub_viewer.dart'; enum BookDetailsStatus { initial, loading, loaded, error } @@ -64,7 +63,7 @@ class BookDetailsState extends Equatable { final BookViewModel? bookViewModel; final SeriesNavigationStatus seriesNavigationStatus; final String? seriesNavigationPath; - final EpubLocator? startLocation; + final String? startCfi; final bool isDownloaded; const BookDetailsState({ @@ -90,7 +89,7 @@ class BookDetailsState extends Equatable { this.bookViewModel, this.seriesNavigationStatus = SeriesNavigationStatus.initial, this.seriesNavigationPath, - this.startLocation, + this.startCfi, this.isDownloaded = false, }); @@ -117,7 +116,7 @@ class BookDetailsState extends Equatable { BookViewModel? bookViewModel, SeriesNavigationStatus? seriesNavigationStatus, String? seriesNavigationPath, - EpubLocator? startLocation, + String? startCfi, bool? isDownloaded, }) { return BookDetailsState( @@ -146,7 +145,7 @@ class BookDetailsState extends Equatable { seriesNavigationStatus: seriesNavigationStatus ?? this.seriesNavigationStatus, seriesNavigationPath: seriesNavigationPath ?? this.seriesNavigationPath, - startLocation: startLocation ?? this.startLocation, + startCfi: startCfi ?? this.startCfi, isDownloaded: isDownloaded ?? this.isDownloaded, ); } @@ -175,7 +174,7 @@ class BookDetailsState extends Equatable { bookViewModel, seriesNavigationStatus, seriesNavigationPath, - startLocation, + startCfi, isDownloaded, ]; } diff --git a/lib/features/book_details/data/datasources/book_details_remote_datasource.dart b/lib/features/book_details/data/datasources/book_details_remote_datasource.dart index 3a1eaa5..b8b25b0 100644 --- a/lib/features/book_details/data/datasources/book_details_remote_datasource.dart +++ b/lib/features/book_details/data/datasources/book_details_remote_datasource.dart @@ -293,6 +293,7 @@ class BookDetailsRemoteDatasource { body: body, authMethod: AuthMethod.cookie, useCsrf: true, + csrfTokenUrl: '/me', csrfOnlyInHeader: true, contentType: 'application/x-www-form-urlencoded', ); @@ -726,7 +727,9 @@ class BookDetailsRemoteDatasource { selectedDirectory: selectedDirectory, schema: schema, format: selectedFormat, - reuseExistingFile: false, + // Reuse an already-downloaded file instead of fetching it again every + // time the reader is opened. + reuseExistingFile: true, progressCallback: progressCallback, ); diff --git a/lib/features/book_details/data/repositories/reading_progress_repository.dart b/lib/features/book_details/data/repositories/reading_progress_repository.dart index 997d86c..afcd781 100644 --- a/lib/features/book_details/data/repositories/reading_progress_repository.dart +++ b/lib/features/book_details/data/repositories/reading_progress_repository.dart @@ -1,14 +1,13 @@ import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:calibre_web_companion/core/services/webdav_sync_service.dart'; -import 'package:vocsy_epub_viewer/epub_viewer.dart'; class ReadingProgressRepository { final WebDavSyncService webDavService; ReadingProgressRepository({required this.webDavService}); - Future getBestLocation(String bookUuid) async { + Future getBestLocation(String bookUuid) async { final prefs = await SharedPreferences.getInstance(); final String progressKey = 'book_progress_$bookUuid'; final String timestampKey = 'book_timestamp_$bookUuid'; @@ -45,16 +44,31 @@ class ReadingProgressRepository { } if (locationJsonToUse != null && locationJsonToUse.isNotEmpty) { - try { - final Map decodedMap = jsonDecode(locationJsonToUse); - return EpubLocator.fromJson(decodedMap); - } catch (e) { - return null; - } + return _extractCfi(locationJsonToUse); } return null; } + String? _extractCfi(String stored) { + final trimmed = stored.trim(); + + if (!trimmed.startsWith('{')) { + return trimmed.isEmpty ? null : trimmed; + } + + try { + final decoded = jsonDecode(trimmed); + if (decoded is Map) { + final locations = decoded['locations']; + if (locations is Map && locations['cfi'] is String) { + final cfi = locations['cfi'] as String; + return cfi.isEmpty ? null : cfi; + } + } + } catch (_) {} + return null; + } + Future saveProgress(String bookUuid, String locatorJson) async { final prefs = await SharedPreferences.getInstance(); final String progressKey = 'book_progress_$bookUuid'; diff --git a/lib/features/book_details/presentation/pages/book_details_page.dart b/lib/features/book_details/presentation/pages/book_details_page.dart index 7840140..4f3c0b2 100644 --- a/lib/features/book_details/presentation/pages/book_details_page.dart +++ b/lib/features/book_details/presentation/pages/book_details_page.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:docman/docman.dart'; import 'package:flutter/material.dart'; @@ -32,7 +33,10 @@ import 'package:calibre_web_companion/features/settings/presentation/pages/setti import 'package:calibre_web_companion/features/book_details/data/models/book_details_model.dart'; import 'package:calibre_web_companion/shared/widgets/book_cover_widget.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; -import 'package:vocsy_epub_viewer/epub_viewer.dart'; +import 'package:cosmos_epub/cosmos_epub.dart'; +// Exposes cosmos_epub's `bookProgress` singleton for cross-device WebDAV sync. +import 'package:cosmos_epub/show_epub.dart' as cosmos_reader; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/core/services/webdav_sync_service.dart'; class BookDetailsPage extends StatefulWidget { @@ -51,7 +55,6 @@ class BookDetailsPage extends StatefulWidget { class _BookDetailsPageState extends State { bool _didUpdateMetadata = false; - StreamSubscription? _locatorSubscription; late final WebDavSyncService _webDavService; bool _isInternalReaderSupportedFormat(String format) { @@ -184,23 +187,13 @@ class _BookDetailsPageState extends State { } } - @override - void dispose() { - _locatorSubscription?.cancel(); - VocsyEpub.closeReader(); - super.dispose(); - } - Future _openInternalReader( BuildContext context, String filePath, BookDetailsModel bookDetailsModel, ) async { - final lastLocation = context.read().state.startLocation; - final settingsState = context.read().state; - + final localization = AppLocalizations.of(context)!; if (!filePath.toLowerCase().endsWith('.epub')) { - final localization = AppLocalizations.of(context)!; context.showSnackBar( localization.errorOpeningBookInInternalReaderPdf, isError: true, @@ -209,28 +202,88 @@ class _BookDetailsPageState extends State { return; } - VocsyEpub.setConfig( - themeColor: Theme.of(context).primaryColor, - identifier: "book_${bookDetailsModel.uuid}", - scrollDirection: - settingsState.epubScrollDirection == 'horizontal' - ? EpubScrollDirection.HORIZONTAL - : EpubScrollDirection.VERTICAL, - allowSharing: true, - enableTts: true, - nightMode: Theme.of(context).brightness == Brightness.dark, - ); + final bookUuid = bookDetailsModel.uuid; - await _locatorSubscription?.cancel(); + await _restoreReaderProgressFromCloud(bookUuid); + if (!context.mounted) return; - _locatorSubscription = VocsyEpub.locatorStream.listen((locator) { - // ignore: use_build_context_synchronously - context.read().add( - SyncReadingProgress(bookDetailsModel.uuid, locator), + try { + await CosmosEpub.openLocalBook( + context: context, + localPath: filePath, + bookId: bookUuid, + accentColor: Theme.of(context).colorScheme.primary, ); - }); + } catch (e) { + if (context.mounted) { + context.showSnackBar( + '${localization.errorOpeningBookInInternalReader} $e', + isError: true, + ); + } + return; + } - VocsyEpub.open(filePath, lastLocation: lastLocation); + await _saveReaderProgressToCloud(bookUuid); + } + + Future _restoreReaderProgressFromCloud(String bookUuid) async { + final prefs = await SharedPreferences.getInstance(); + if (!(prefs.getBool('webdav_enabled') ?? false)) return; + final url = prefs.getString('webdav_url') ?? ''; + if (url.isEmpty) return; + try { + _webDavService.init( + url, + prefs.getString('webdav_username') ?? '', + prefs.getString('webdav_password') ?? '', + ); + + final localTs = prefs.getInt('reader_progress_ts_$bookUuid') ?? 0; + final serverData = await _webDavService.fetchProgress(); + final entry = serverData[bookUuid]; + if (entry is! Map) return; + final serverTs = (entry['timestamp'] as int?) ?? 0; + if (serverTs <= localTs) return; + + final decoded = jsonDecode(entry['locator'] as String); + if (decoded is! Map) return; + final chapter = decoded['chapter'] as int?; + final page = decoded['page'] as int?; + if (chapter != null) { + await cosmos_reader.bookProgress.setCurrentChapterIndex( + bookUuid, + chapter, + ); + } + if (page != null) { + await cosmos_reader.bookProgress.setCurrentPageIndex(bookUuid, page); + } + await prefs.setInt('reader_progress_ts_$bookUuid', serverTs); + } catch (_) {} + } + + Future _saveReaderProgressToCloud(String bookUuid) async { + final prefs = await SharedPreferences.getInstance(); + if (!(prefs.getBool('webdav_enabled') ?? false)) return; + final url = prefs.getString('webdav_url') ?? ''; + if (url.isEmpty) return; + try { + _webDavService.init( + url, + prefs.getString('webdav_username') ?? '', + prefs.getString('webdav_password') ?? '', + ); + + final progress = cosmos_reader.bookProgress.getBookProgress(bookUuid); + final now = DateTime.now().millisecondsSinceEpoch; + final locator = jsonEncode({ + 'chapter': progress.currentChapterIndex ?? 0, + 'page': progress.currentPageIndex ?? 0, + }); + await _webDavService.saveProgress(bookUuid, locator, now); + await prefs.setInt('reader_progress_ts_$bookUuid', now); + } catch (_) {} } @override @@ -1139,26 +1192,16 @@ class _BookDetailsPageState extends State { title: Text(localizations.deleteBook), content: Text(localizations.deleteBookConfirmation), actions: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.error, - ), - onPressed: - () => Navigator.of(context).pop(true), - child: Text( - localizations.delete, - style: TextStyle( - color: - Theme.of(context).colorScheme.onError, - ), - ), - ), - ElevatedButton( + TextButton( onPressed: () => Navigator.of(context).pop(false), child: Text(localizations.cancel), ), + AppDialogButton.destructive( + onPressed: + () => Navigator.of(context).pop(true), + label: localizations.delete, + ), ], ); }, diff --git a/lib/features/book_details/presentation/widgets/add_to_shelf_widget.dart b/lib/features/book_details/presentation/widgets/add_to_shelf_widget.dart index 3ffe6fb..2b6a051 100644 --- a/lib/features/book_details/presentation/widgets/add_to_shelf_widget.dart +++ b/lib/features/book_details/presentation/widgets/add_to_shelf_widget.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:calibre_web_companion/shared/widgets/app_skeletonizer.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; import 'package:calibre_web_companion/features/book_details/data/models/book_details_model.dart'; @@ -275,9 +276,9 @@ class _AddToShelfWidgetState extends State { ), ), actions: [ - ElevatedButton( + AppDialogButton( onPressed: () => Navigator.pop(context), - child: Text(localizations.close), + label: localizations.close, ), ], ); diff --git a/lib/features/book_details/presentation/widgets/metadata_search_dialog.dart b/lib/features/book_details/presentation/widgets/metadata_search_dialog.dart index 08f9faf..e68d257 100644 --- a/lib/features/book_details/presentation/widgets/metadata_search_dialog.dart +++ b/lib/features/book_details/presentation/widgets/metadata_search_dialog.dart @@ -5,6 +5,7 @@ import 'package:calibre_web_companion/core/di/injection_container.dart'; import 'package:calibre_web_companion/features/book_details/data/datasources/book_details_remote_datasource.dart'; import 'package:calibre_web_companion/features/book_details/data/models/metadata_models.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; class MetadataSearchDialog extends StatefulWidget { final String initialQuery; @@ -242,8 +243,9 @@ class _MetadataMergeDialogState extends State<_MetadataMergeDialog> { @override Widget build(BuildContext context) { + final localizations = AppLocalizations.of(context)!; return AlertDialog( - title: const Text("Select Metadata to Import"), + title: Text(localizations.selectMetadataToImport), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, @@ -305,11 +307,11 @@ class _MetadataMergeDialogState extends State<_MetadataMergeDialog> { actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), - child: const Text("Cancel"), + child: Text(localizations.cancel), ), - ElevatedButton( + AppDialogButton( onPressed: () => Navigator.of(context).pop(_selection), - child: const Text("Apply"), + label: localizations.apply, ), ], ); diff --git a/lib/features/book_details/presentation/widgets/send_to_ereader_widget.dart b/lib/features/book_details/presentation/widgets/send_to_ereader_widget.dart index f8af219..badd7e0 100644 --- a/lib/features/book_details/presentation/widgets/send_to_ereader_widget.dart +++ b/lib/features/book_details/presentation/widgets/send_to_ereader_widget.dart @@ -8,6 +8,7 @@ import 'package:calibre_web_companion/features/book_details/bloc/book_details_st import 'package:calibre_web_companion/l10n/app_localizations.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/features/book_details/data/models/book_details_model.dart'; import 'package:calibre_web_companion/features/settings/bloc/settings_bloc.dart'; import 'package:calibre_web_companion/features/settings/bloc/settings_state.dart'; @@ -181,11 +182,7 @@ class SendToEreaderWidget extends StatelessWidget { onPressed: () => Navigator.pop(context), child: Text(localizations.cancel), ), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primaryContainer, - ), + AppDialogButton( onPressed: () => _handleSendAction( parentContext, @@ -195,13 +192,7 @@ class SendToEreaderWidget extends StatelessWidget { codeController, isKindle, ), - child: Text( - localizations.send, - style: TextStyle( - color: - Theme.of(context).colorScheme.onPrimaryContainer, - ), - ), + label: localizations.send, ), ], ), diff --git a/lib/features/book_view/presentation/widgets/search_dialog.dart b/lib/features/book_view/presentation/widgets/search_dialog.dart index ec62db4..fed4c67 100644 --- a/lib/features/book_view/presentation/widgets/search_dialog.dart +++ b/lib/features/book_view/presentation/widgets/search_dialog.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; class SearchDialog extends StatefulWidget { const SearchDialog({super.key}); @@ -47,14 +48,11 @@ class SearchDialogState extends State { onPressed: () => Navigator.of(context).pop(), child: Text(localizations.cancel), ), - ElevatedButton( + AppDialogButton( onPressed: () { Navigator.of(context).pop(_controller.text); }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [Text(localizations.search)], - ), + label: localizations.search, ), ], ); diff --git a/lib/features/download_service/presentation/widgets/book_card_widget.dart b/lib/features/download_service/presentation/widgets/book_card_widget.dart index 86be67a..f46c3e7 100644 --- a/lib/features/download_service/presentation/widgets/book_card_widget.dart +++ b/lib/features/download_service/presentation/widgets/book_card_widget.dart @@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:calibre_web_companion/shared/widgets/app_skeletonizer.dart'; +import 'package:calibre_web_companion/shared/utils/status_colors.dart'; import 'package:calibre_web_companion/features/download_service/bloc/download_service_bloc.dart'; import 'package:calibre_web_companion/features/download_service/bloc/download_service_event.dart'; @@ -317,32 +318,32 @@ class _BookCardWidgetState extends State { switch (widget.book.status) { case DownloaderStatus.available: - statusColor = Colors.blue; + statusColor = StatusColors.info(context); statusIcon = Icons.download_rounded; statusText = localizations.available; break; case DownloaderStatus.downloading: - statusColor = Colors.amber; + statusColor = StatusColors.warning(context); statusIcon = Icons.downloading_rounded; statusText = localizations.downloading; break; case DownloaderStatus.done: - statusColor = Colors.green; + statusColor = StatusColors.success(context); statusIcon = Icons.check_circle_outline_rounded; statusText = localizations.completed; break; case DownloaderStatus.error: - statusColor = Colors.red; + statusColor = StatusColors.error(context); statusIcon = Icons.error_outline_rounded; statusText = localizations.failed; break; case DownloaderStatus.queued: - statusColor = Colors.purple; + statusColor = StatusColors.pending(context); statusIcon = Icons.queue_rounded; statusText = localizations.queued; break; case DownloaderStatus.notDownloaded: - statusColor = Colors.grey; + statusColor = StatusColors.neutral(context); statusIcon = Icons.download_rounded; statusText = localizations.notDownloaded; break; diff --git a/lib/features/login/presentation/widgets/login_form_widget.dart b/lib/features/login/presentation/widgets/login_form_widget.dart index 008beac..834dc25 100644 --- a/lib/features/login/presentation/widgets/login_form_widget.dart +++ b/lib/features/login/presentation/widgets/login_form_widget.dart @@ -8,6 +8,7 @@ import 'package:calibre_web_companion/features/login/bloc/login_state.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/features/login/presentation/widgets/login_text_field.dart'; import 'package:calibre_web_companion/core/services/app_transition.dart'; import 'package:calibre_web_companion/features/login_settings/presentation/pages/login_settings_page.dart'; @@ -517,20 +518,12 @@ class _LoginFormState extends State { title: Text(localizations.credentialsRequiredForSSO), content: Text(localizations.enterUsernamePasswordForSSO), actions: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.primary, - ), + AppDialogButton( onPressed: () { Navigator.of(context).pop(); if (_usernameController.text.isEmpty) {} }, - child: Text( - localizations.ok, - style: TextStyle( - color: Theme.of(context).colorScheme.onPrimary, - ), - ), + label: localizations.ok, ), ], ), diff --git a/lib/features/login_settings/presentation/pages/login_settings_page.dart b/lib/features/login_settings/presentation/pages/login_settings_page.dart index dd92daf..c2e6189 100644 --- a/lib/features/login_settings/presentation/pages/login_settings_page.dart +++ b/lib/features/login_settings/presentation/pages/login_settings_page.dart @@ -7,6 +7,7 @@ import 'package:calibre_web_companion/features/login_settings/bloc/login_setting import 'package:calibre_web_companion/l10n/app_localizations.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/features/login_settings/presentation/widgets/header_section_widget.dart'; class LoginSettingsPage extends StatefulWidget { @@ -177,8 +178,8 @@ class _LoginSettingsPage extends State { child: Text(localizations.cancel), onPressed: () => Navigator.of(ctx).pop(false), ), - ElevatedButton( - child: Text(localizations.ok), + AppDialogButton( + label: localizations.ok, onPressed: () => Navigator.of(ctx).pop(true), ), ], diff --git a/lib/features/me/presentation/pages/me_page.dart b/lib/features/me/presentation/pages/me_page.dart index 2c78884..554cda3 100644 --- a/lib/features/me/presentation/pages/me_page.dart +++ b/lib/features/me/presentation/pages/me_page.dart @@ -16,6 +16,7 @@ import 'package:calibre_web_companion/core/services/app_transition.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; import 'package:calibre_web_companion/features/me/presentation/widgets/stats_card_widget.dart'; import 'package:calibre_web_companion/shared/widgets/long_button_widget.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/features/login/presentation/pages/login_page.dart'; import 'package:calibre_web_companion/features/settings/presentation/pages/settings_page.dart'; import 'package:calibre_web_companion/features/shelf_view.dart/presentation/pages/shelf_view_page.dart'; @@ -358,23 +359,14 @@ class MePage extends StatelessWidget { onPressed: () => Navigator.of(dialogContext).pop(), child: Text(localizations.cancel), ), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primaryContainer, - ), + AppDialogButton( onPressed: () { Navigator.of(dialogContext).pop(); Navigator.of(sheetContext).pop(); context.read().add(SwitchAccount(account)); }, - child: Text( - localizations.switchAccount, - style: TextStyle( - color: Theme.of(context).colorScheme.onPrimaryContainer, - ), - ), + label: localizations.switchAccount, ), ], ), @@ -397,17 +389,12 @@ class MePage extends StatelessWidget { onPressed: () => Navigator.of(dialogContext).pop(), child: Text(localizations.cancel), ), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.errorContainer, - foregroundColor: - Theme.of(context).colorScheme.onErrorContainer, - ), + AppDialogButton.destructive( onPressed: () { Navigator.of(dialogContext).pop(); context.read().add(DeleteAccount(account)); }, - child: Text(localizations.delete), + label: localizations.delete, ), ], ), @@ -431,21 +418,12 @@ class MePage extends StatelessWidget { onPressed: () => Navigator.of(dialogContext).pop(), child: Text(localizations.cancel), ), - ElevatedButton( + AppDialogButton( onPressed: () { Navigator.of(dialogContext).pop(); _performLogout(context); }, - style: ElevatedButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primaryContainer, - ), - child: Text( - localizations.logout, - style: TextStyle( - color: Theme.of(context).colorScheme.onPrimaryContainer, - ), - ), + label: localizations.logout, ), ], ), diff --git a/lib/features/settings/bloc/settings_bloc.dart b/lib/features/settings/bloc/settings_bloc.dart index 6b75b45..9741df4 100644 --- a/lib/features/settings/bloc/settings_bloc.dart +++ b/lib/features/settings/bloc/settings_bloc.dart @@ -36,7 +36,6 @@ class SettingsBloc extends Bloc { on(_onSetWebDavCredentials); on(_onTestDownloaderConnection); on(_onTestWebDavConnection); - on(_onSetEpubScrollDirection); on(_onResetConnectionTestStatus); on(_onSetShowSendToEReaderButton); on(_onSetEInkMode); @@ -92,7 +91,6 @@ class SettingsBloc extends Bloc { webDavUsername: settings.webDavUsername, webDavPassword: settings.webDavPassword, isWebDavSyncEnabled: settings.isWebDavSyncEnabled, - epubScrollDirection: settings.epubScrollDirection, isEInkMode: settings.isEInkMode, bookActionsOrder: settings.bookActionsOrder, enabledBookActions: settings.enabledBookActions, @@ -499,23 +497,6 @@ class SettingsBloc extends Bloc { } } - Future _onSetEpubScrollDirection( - SetEpubScrollDirection event, - Emitter emit, - ) async { - try { - await repository.setEpubScrollDirection(event.direction); - emit(state.copyWith(epubScrollDirection: event.direction)); - } catch (e) { - emit( - state.copyWith( - status: SettingsStatus.error, - errorMessage: e.toString(), - ), - ); - } - } - void _onResetConnectionTestStatus( ResetConnectionTestStatus event, Emitter emit, diff --git a/lib/features/settings/bloc/settings_event.dart b/lib/features/settings/bloc/settings_event.dart index ff2884a..0e60226 100644 --- a/lib/features/settings/bloc/settings_event.dart +++ b/lib/features/settings/bloc/settings_event.dart @@ -200,15 +200,6 @@ class TestWebDavConnection extends SettingsEvent { List get props => [url, username, password]; } -class SetEpubScrollDirection extends SettingsEvent { - final String direction; - - const SetEpubScrollDirection(this.direction); - - @override - List get props => [direction]; -} - class ResetConnectionTestStatus extends SettingsEvent {} class SetShowSendToEReaderButton extends SettingsEvent { diff --git a/lib/features/settings/bloc/settings_state.dart b/lib/features/settings/bloc/settings_state.dart index b072498..d7e09db 100644 --- a/lib/features/settings/bloc/settings_state.dart +++ b/lib/features/settings/bloc/settings_state.dart @@ -36,7 +36,6 @@ class SettingsState extends Equatable { final String webDavUrl; final String webDavUsername; final String webDavPassword; - final String epubScrollDirection; final bool isEInkMode; final List bookActionsOrder; final List enabledBookActions; @@ -78,7 +77,6 @@ class SettingsState extends Equatable { this.webDavUrl = '', this.webDavUsername = '', this.webDavPassword = '', - this.epubScrollDirection = 'vertical', this.isEInkMode = false, this.bookActionsOrder = const [], this.enabledBookActions = const [], @@ -123,7 +121,6 @@ class SettingsState extends Equatable { String? webDavUrl, String? webDavUsername, String? webDavPassword, - String? epubScrollDirection, bool? isEInkMode, List? bookActionsOrder, List? enabledBookActions, @@ -168,7 +165,6 @@ class SettingsState extends Equatable { webDavUrl: webDavUrl ?? this.webDavUrl, webDavUsername: webDavUsername ?? this.webDavUsername, webDavPassword: webDavPassword ?? this.webDavPassword, - epubScrollDirection: epubScrollDirection ?? this.epubScrollDirection, isEInkMode: isEInkMode ?? this.isEInkMode, bookActionsOrder: bookActionsOrder ?? this.bookActionsOrder, enabledBookActions: enabledBookActions ?? this.enabledBookActions, @@ -216,7 +212,6 @@ class SettingsState extends Equatable { webDavUrl, webDavUsername, webDavPassword, - epubScrollDirection, isEInkMode, bookActionsOrder, enabledBookActions, diff --git a/lib/features/settings/data/datasources/settings_local_datasource.dart b/lib/features/settings/data/datasources/settings_local_datasource.dart index 739d8b1..5013429 100644 --- a/lib/features/settings/data/datasources/settings_local_datasource.dart +++ b/lib/features/settings/data/datasources/settings_local_datasource.dart @@ -310,15 +310,6 @@ class SettingsLocalDataSource { } } - Future saveEpubScrollDirection(String direction) async { - try { - await sharedPreferences.setString('epub_scroll_direction', direction); - } catch (e) { - logger.e('Error saving epub scroll direction: $e'); - throw Exception('Failed to save epub scroll direction: $e'); - } - } - Future saveShowSendToEReaderButton(bool enabled) async { try { await sharedPreferences.setBool('show_send_to_ereader_button', enabled); diff --git a/lib/features/settings/data/models/settings_model.dart b/lib/features/settings/data/models/settings_model.dart index 4053fa7..cab1ec2 100644 --- a/lib/features/settings/data/models/settings_model.dart +++ b/lib/features/settings/data/models/settings_model.dart @@ -27,7 +27,6 @@ class SettingsModel extends Equatable { final String webDavUsername; final String webDavPassword; final bool isWebDavSyncEnabled; - final String epubScrollDirection; final bool isEInkMode; final List bookActionsOrder; final List enabledBookActions; @@ -60,7 +59,6 @@ class SettingsModel extends Equatable { required this.webDavUsername, required this.webDavPassword, required this.isWebDavSyncEnabled, - required this.epubScrollDirection, required this.isEInkMode, required this.bookActionsOrder, required this.enabledBookActions, @@ -96,7 +94,6 @@ class SettingsModel extends Equatable { webDavUsername: json['webdav_username'] ?? '', webDavPassword: json['webdav_password'] ?? '', isWebDavSyncEnabled: json['webdav_enabled'] ?? false, - epubScrollDirection: json['epub_scroll_direction'] ?? 'vertical', isEInkMode: json['is_eink_mode'] ?? false, bookActionsOrder: BookDetailsActionConfig.normalizeOrder( List.from( @@ -182,7 +179,6 @@ class SettingsModel extends Equatable { webDavUsername, webDavPassword, isWebDavSyncEnabled, - epubScrollDirection, isEInkMode, bookActionsOrder, enabledBookActions, diff --git a/lib/features/settings/data/repositories/settings_repository.dart b/lib/features/settings/data/repositories/settings_repository.dart index 53bf544..57ecf59 100644 --- a/lib/features/settings/data/repositories/settings_repository.dart +++ b/lib/features/settings/data/repositories/settings_repository.dart @@ -235,14 +235,6 @@ class SettingsRepository { } } - Future setEpubScrollDirection(String direction) async { - try { - await dataSource.saveEpubScrollDirection(direction); - } catch (e) { - rethrow; - } - } - Future setEInkMode(bool enabled) async { try { await dataSource.saveEInkMode(enabled); diff --git a/lib/features/settings/presentation/pages/settings_page.dart b/lib/features/settings/presentation/pages/settings_page.dart index 1aaa2f6..fca30b7 100644 --- a/lib/features/settings/presentation/pages/settings_page.dart +++ b/lib/features/settings/presentation/pages/settings_page.dart @@ -143,7 +143,7 @@ class _SettingsPageState extends State { _buildSettingsCategoryNavCard( context, title: localizations.readerSettings, - subtitle: localizations.scrollDirection, + subtitle: localizations.webDavSync, icon: Icons.chrome_reader_mode_rounded, onTap: () => _openReaderSettingsSubPage(context), ), @@ -334,8 +334,7 @@ class _SettingsPageState extends State { title: localizations.readerSettings, bodyBuilder: (context, state, localizations) => [ - _buildSectionTitle(context, localizations.readerSettings), - _buildReaderSettings(context, state, localizations), + _buildSectionTitle(context, localizations.webDavSync), _buildWebDavSettings(context, state, localizations), ], ); @@ -2131,76 +2130,4 @@ class _SettingsPageState extends State { ); } - Widget _buildReaderSettings( - BuildContext context, - SettingsState state, - AppLocalizations localizations, - ) { - return Card( - margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - elevation: 3, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - Row( - children: [ - Icon( - Icons.chrome_reader_mode_rounded, - color: Theme.of(context).colorScheme.secondary, - ), - const SizedBox(width: 16), - Expanded( - child: Text( - localizations.scrollDirection, - style: Theme.of(context).textTheme.titleMedium, - ), - ), - ], - ), - const SizedBox(height: 16), - DropdownButtonFormField( - decoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8.0), - borderSide: BorderSide( - color: Theme.of(context).colorScheme.outline, - ), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), - ), - initialValue: state.epubScrollDirection, - icon: const Icon(Icons.arrow_drop_down), - elevation: 16, - style: TextStyle( - color: Theme.of(context).colorScheme.onSurface, - fontSize: 16, - ), - onChanged: (String? newValue) { - if (newValue != null) { - context.read().add( - SetEpubScrollDirection(newValue), - ); - } - }, - items: [ - DropdownMenuItem( - value: 'vertical', - child: Text(localizations.vertical), - ), - DropdownMenuItem( - value: 'horizontal', - child: Text(localizations.horizontal), - ), - ], - ), - ], - ), - ), - ); - } } diff --git a/lib/features/settings/presentation/widgets/download_options_widget.dart b/lib/features/settings/presentation/widgets/download_options_widget.dart index c3ed344..6665901 100644 --- a/lib/features/settings/presentation/widgets/download_options_widget.dart +++ b/lib/features/settings/presentation/widgets/download_options_widget.dart @@ -9,6 +9,7 @@ import 'package:calibre_web_companion/features/settings/bloc/settings_event.dart import 'package:calibre_web_companion/features/settings/bloc/settings_state.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/features/settings/data/models/download_schema.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; @@ -329,11 +330,11 @@ class DownloadOptionsWidget extends StatelessWidget { ), ), actions: [ - ElevatedButton( - child: Text(localizations.cancel), + AppDialogButton( onPressed: () { Navigator.of(context).pop(); }, + label: localizations.cancel, ), ], ); diff --git a/lib/features/settings/presentation/widgets/feedback_widget.dart b/lib/features/settings/presentation/widgets/feedback_widget.dart index a8029d1..9bae8aa 100644 --- a/lib/features/settings/presentation/widgets/feedback_widget.dart +++ b/lib/features/settings/presentation/widgets/feedback_widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/features/settings/bloc/settings_bloc.dart'; import 'package:calibre_web_companion/features/settings/bloc/settings_event.dart'; @@ -141,7 +142,9 @@ class FeedbackWidget extends StatelessWidget { final isSubmitting = state.feedbackStatus == SettingsFeedbackStatus.loading; - return ElevatedButton( + return AppDialogButton( + isLoading: isSubmitting, + label: localizations.submit, onPressed: isSubmitting ? null @@ -172,19 +175,6 @@ class FeedbackWidget extends StatelessWidget { Navigator.pop(context); }, - child: - isSubmitting - ? SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - valueColor: AlwaysStoppedAnimation( - Theme.of(context).colorScheme.onPrimary, - ), - ), - ) - : Text(localizations.submit), ); }, ), diff --git a/lib/features/settings/presentation/widgets/sync_settings_widget.dart b/lib/features/settings/presentation/widgets/sync_settings_widget.dart index 0e05626..6f40633 100644 --- a/lib/features/settings/presentation/widgets/sync_settings_widget.dart +++ b/lib/features/settings/presentation/widgets/sync_settings_widget.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; +import 'package:calibre_web_companion/shared/utils/status_colors.dart'; import 'package:calibre_web_companion/features/sync/data/models/sync_filter.dart'; import 'package:calibre_web_companion/features/sync/bloc/sync_bloc.dart'; import 'package:calibre_web_companion/features/sync/bloc/sync_event.dart'; @@ -44,7 +45,7 @@ class _SyncSettingsWidgetState extends State { content: Text( state.errorMessage ?? localization.syncError, ), - backgroundColor: Colors.red, + backgroundColor: Theme.of(context).colorScheme.error, ), ); } else if (state.status == SyncStatus.completed) { @@ -59,7 +60,7 @@ class _SyncSettingsWidgetState extends State { content: Text( localization.syncFinishedWithXErrors(errorCount), ), - backgroundColor: Colors.red, + backgroundColor: Theme.of(context).colorScheme.error, duration: const Duration(seconds: 5), ), ); @@ -319,7 +320,7 @@ class _SyncSettingsWidgetState extends State { switch (item.status) { case 'done': icon = Icons.check_circle; - color = Colors.green; + color = StatusColors.success(context); break; case 'downloading': icon = Icons.downloading; @@ -332,12 +333,12 @@ class _SyncSettingsWidgetState extends State { break; case 'error': icon = Icons.error_outline; - color = Colors.red; + color = StatusColors.error(context); break; case 'pending': default: icon = Icons.hourglass_empty; - color = Colors.grey; + color = StatusColors.neutral(context); break; } diff --git a/lib/features/shelf_details/data/datasources/shelf_details_remote_datasource.dart b/lib/features/shelf_details/data/datasources/shelf_details_remote_datasource.dart index 2131518..8c39c04 100644 --- a/lib/features/shelf_details/data/datasources/shelf_details_remote_datasource.dart +++ b/lib/features/shelf_details/data/datasources/shelf_details_remote_datasource.dart @@ -53,10 +53,13 @@ class ShelfDetailsRemoteDataSource { endpoint: '/shelf/remove/$shelfId/$bookId', authMethod: AuthMethod.cookie, useCsrf: true, + csrfTokenUrl: '/me', contentType: 'application/x-www-form-urlencoded', ); - return response.statusCode == 204; + return response.statusCode == 200 || + response.statusCode == 204 || + response.statusCode == 302; } catch (e) { logger.e('Error removing from shelf: $e'); throw Exception('Failed to remove from shelf: $e'); diff --git a/lib/features/shelf_details/presentation/pages/shelf_details_page.dart b/lib/features/shelf_details/presentation/pages/shelf_details_page.dart index 0048ff6..9f1803f 100644 --- a/lib/features/shelf_details/presentation/pages/shelf_details_page.dart +++ b/lib/features/shelf_details/presentation/pages/shelf_details_page.dart @@ -15,6 +15,8 @@ import 'package:calibre_web_companion/features/shelf_view.dart/bloc/shelf_view_b import 'package:calibre_web_companion/features/shelf_view.dart/bloc/shelf_view_event.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; +import 'package:calibre_web_companion/core/services/image_cache_manager.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; import 'package:calibre_web_companion/main.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; import 'package:calibre_web_companion/features/shelf_details/data/models/shelf_book_item_model.dart'; @@ -515,7 +517,7 @@ class ShelfDetailsPage extends StatelessWidget { onPressed: () => Navigator.of(dialogContext).pop(), child: Text(localizations.cancel), ), - ElevatedButton( + AppDialogButton.destructive( onPressed: () { Navigator.of(dialogContext).pop(); context.read().add(DeleteShelf(shelfId)); @@ -526,11 +528,7 @@ class ShelfDetailsPage extends StatelessWidget { ); } }, - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).colorScheme.error, - foregroundColor: Theme.of(context).colorScheme.onError, - ), - child: Text(localizations.delete), + label: localizations.delete, ), ], ); @@ -606,6 +604,8 @@ class ShelfDetailsPage extends StatelessWidget { builder: (context, snapshot) { final headers = snapshot.data ?? const {}; return CachedNetworkImage( + cacheManager: CustomCacheManager(), + key: ValueKey('${bookId}_$imageUrl'), imageUrl: imageUrl, httpHeaders: headers, fit: BoxFit.cover, diff --git a/lib/features/shelf_details/presentation/widgets/edit_shelf_dialog_widget.dart b/lib/features/shelf_details/presentation/widgets/edit_shelf_dialog_widget.dart index 3d9479a..d6819da 100644 --- a/lib/features/shelf_details/presentation/widgets/edit_shelf_dialog_widget.dart +++ b/lib/features/shelf_details/presentation/widgets/edit_shelf_dialog_widget.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; class EditShelfDialog extends StatefulWidget { final String currentName; @@ -60,7 +61,7 @@ class _EditShelfDialogState extends State { ), const SizedBox(height: 16), SwitchListTile( - title: const Text('Public'), + title: Text(localizations.public), value: _isPublic, onChanged: _isEditing @@ -80,24 +81,11 @@ class _EditShelfDialogState extends State { onPressed: _isEditing ? null : () => Navigator.of(context).pop(), child: Text(localizations.cancel), ), - ElevatedButton( + AppDialogButton( onPressed: _isEditing ? null : _editShelf, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (_isEditing) - SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Theme.of(context).colorScheme.onPrimary, - ), - ), - if (_isEditing) const SizedBox(width: 8), - Text(_isEditing ? localizations.editing : localizations.edit), - ], - ), + isLoading: _isEditing, + loadingLabel: localizations.editing, + label: localizations.edit, ), ], ); diff --git a/lib/features/shelf_view.dart/data/datasources/shelf_view_remote_datasource.dart b/lib/features/shelf_view.dart/data/datasources/shelf_view_remote_datasource.dart index f9827b7..e81844f 100644 --- a/lib/features/shelf_view.dart/data/datasources/shelf_view_remote_datasource.dart +++ b/lib/features/shelf_view.dart/data/datasources/shelf_view_remote_datasource.dart @@ -87,9 +87,13 @@ class ShelfViewRemoteDataSource { endpoint: '/shelf/remove/$shelfId/$bookId', authMethod: AuthMethod.cookie, useCsrf: true, + csrfTokenUrl: '/me', + contentType: 'application/x-www-form-urlencoded', ); - if (response.statusCode != 204) { + if (response.statusCode != 200 && + response.statusCode != 204 && + response.statusCode != 302) { logger.e('Failed to remove book from shelf: ${response.body}'); throw Exception('Failed to remove book from shelf: ${response.body}'); } @@ -108,9 +112,13 @@ class ShelfViewRemoteDataSource { endpoint: '/shelf/add/$shelfId/$bookId', authMethod: AuthMethod.cookie, useCsrf: true, + csrfTokenUrl: '/me', + contentType: 'application/x-www-form-urlencoded', ); - if (response.statusCode != 204) { + if (response.statusCode != 200 && + response.statusCode != 204 && + response.statusCode != 302) { logger.e('Failed to add book to shelf: ${response.body}'); throw Exception('Failed to add book to shelf: ${response.body}'); } diff --git a/lib/features/shelf_view.dart/presentation/widgets/create_shelf_dialog_widget.dart b/lib/features/shelf_view.dart/presentation/widgets/create_shelf_dialog_widget.dart index 4552d9e..f0e3b66 100644 --- a/lib/features/shelf_view.dart/presentation/widgets/create_shelf_dialog_widget.dart +++ b/lib/features/shelf_view.dart/presentation/widgets/create_shelf_dialog_widget.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:calibre_web_companion/l10n/app_localizations.dart'; import 'package:calibre_web_companion/core/services/snackbar.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; class CreateShelfDialog extends StatefulWidget { final Function(String, bool) onCreateShelf; @@ -46,7 +47,7 @@ class _CreateShelfDialogState extends State { ), const SizedBox(height: 16), SwitchListTile( - title: const Text('Public'), + title: Text(localizations.public), value: _isPublic, onChanged: _isCreating @@ -66,24 +67,11 @@ class _CreateShelfDialogState extends State { onPressed: _isCreating ? null : () => Navigator.of(context).pop(), child: Text(localizations.cancel), ), - ElevatedButton( + AppDialogButton( onPressed: _isCreating ? null : _createShelf, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (_isCreating) - SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Theme.of(context).colorScheme.onPrimary, - ), - ), - if (_isCreating) const SizedBox(width: 8), - Text(_isCreating ? localizations.creating : localizations.create), - ], - ), + isLoading: _isCreating, + loadingLabel: localizations.creating, + label: localizations.create, ), ], ); diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 6eee7e5..7ff9921 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -94,6 +94,10 @@ "libraryStatistics": "Bibliotheksstatistiken", "cancel": "Abbrechen", "close": "Schließen", + "public": "Öffentlich", + "apply": "Übernehmen", + "comingSoon": "Demnächst!", + "selectMetadataToImport": "Metadaten zum Importieren auswählen", "retry": "Wiederholen", "tryAgain": "Erneut versuchen", "error": "Fehler", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ecd1871..f8a1c15 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -94,6 +94,10 @@ "libraryStatistics": "Library statistics", "cancel": "Cancel", "close": "Close", + "public": "Public", + "apply": "Apply", + "comingSoon": "Coming Soon!", + "selectMetadataToImport": "Select Metadata to Import", "retry": "Retry", "tryAgain": "Try again", "error": "Error", diff --git a/lib/main.dart b/lib/main.dart index 730d469..1bbbbd9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,8 @@ import 'package:get_it/get_it.dart'; import 'package:logger/web.dart'; import 'package:skeletonizer/skeletonizer.dart'; +import 'package:cosmos_epub/cosmos_epub.dart'; + import 'package:calibre_web_companion/l10n/app_localizations.dart'; import 'package:calibre_web_companion/core/di/injection_container.dart' as di; import 'package:calibre_web_companion/core/services/download_manager.dart'; // Import @@ -61,6 +63,9 @@ void main() async { await di.getIt().initialize(); + // Initialize the in-app EPUB reader (cosmos_epub) once before it is used. + await CosmosEpub.initialize(); + final savedThemeMode = await AdaptiveTheme.getThemeMode(); runZonedGuarded( @@ -192,11 +197,19 @@ class _MyAppState extends State { final lightTheme = ThemeData( useMaterial3: true, colorScheme: lightScheme, + cardTheme: CardThemeData( + color: lightScheme.surfaceContainerHigh, + surfaceTintColor: Colors.transparent, + ), ); final darkTheme = ThemeData( useMaterial3: true, colorScheme: darkScheme, + cardTheme: CardThemeData( + color: darkScheme.surfaceContainerHigh, + surfaceTintColor: Colors.transparent, + ), ); return SkeletonizerConfig( diff --git a/lib/shared/utils/status_colors.dart b/lib/shared/utils/status_colors.dart new file mode 100644 index 0000000..c15742a --- /dev/null +++ b/lib/shared/utils/status_colors.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class StatusColors { + const StatusColors._(); + + /// Success / completed (green). + static Color success(BuildContext context) => _shade(context, Colors.green); + + /// In-progress / warning (amber). + static Color warning(BuildContext context) => _shade(context, Colors.amber); + + /// Informational / available (blue). + static Color info(BuildContext context) => _shade(context, Colors.blue); + + /// Queued / waiting (purple). + static Color pending(BuildContext context) => _shade(context, Colors.purple); + + /// Error / failed + static Color error(BuildContext context) => + Theme.of(context).colorScheme.error; + + /// Neutral / inactive + static Color neutral(BuildContext context) => + Theme.of(context).colorScheme.onSurfaceVariant; + + static Color _shade(BuildContext context, MaterialColor base) { + final isDark = Theme.of(context).brightness == Brightness.dark; + return isDark ? base.shade300 : base.shade700; + } +} diff --git a/lib/shared/widgets/app_dialog_button.dart b/lib/shared/widgets/app_dialog_button.dart new file mode 100644 index 0000000..faa072b --- /dev/null +++ b/lib/shared/widgets/app_dialog_button.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class AppDialogButton extends StatelessWidget { + final String label; + final VoidCallback? onPressed; + + final bool isLoading; + final String? loadingLabel; + + final IconData? icon; + + final bool isDestructive; + + const AppDialogButton({ + super.key, + required this.label, + required this.onPressed, + this.isLoading = false, + this.loadingLabel, + this.icon, + this.isDestructive = false, + }); + + const AppDialogButton.destructive({ + super.key, + required this.label, + required this.onPressed, + this.isLoading = false, + this.loadingLabel, + this.icon, + }) : isDestructive = true; + + @override + Widget build(BuildContext context) { + final scheme = Theme.of(context).colorScheme; + + final Color background = + isDestructive ? scheme.errorContainer : scheme.primaryContainer; + final Color foreground = + isDestructive ? scheme.onErrorContainer : scheme.onPrimaryContainer; + + final style = FilledButton.styleFrom( + backgroundColor: background, + foregroundColor: foreground, + disabledBackgroundColor: background.withValues(alpha: 0.5), + disabledForegroundColor: foreground.withValues(alpha: 0.5), + ); + + if (isLoading) { + return FilledButton( + onPressed: null, + style: style, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator( + strokeWidth: 2, + color: foreground, + ), + ), + const SizedBox(width: 8), + Text(loadingLabel ?? label), + ], + ), + ); + } + + if (icon != null) { + return FilledButton.icon( + onPressed: onPressed, + style: style, + icon: Icon(icon), + label: Text(label), + ); + } + + return FilledButton(onPressed: onPressed, style: style, child: Text(label)); + } +} diff --git a/lib/shared/widgets/coming_soon_widget.dart b/lib/shared/widgets/coming_soon_widget.dart index 0cc4772..102531a 100644 --- a/lib/shared/widgets/coming_soon_widget.dart +++ b/lib/shared/widgets/coming_soon_widget.dart @@ -1,23 +1,27 @@ import 'package:flutter/material.dart'; +import 'package:calibre_web_companion/l10n/app_localizations.dart'; +import 'package:calibre_web_companion/shared/widgets/app_dialog_button.dart'; + Future showComingSoonDialog( BuildContext context, String contentText, ) async { + final localizations = AppLocalizations.of(context)!; return showDialog( context: context, barrierDismissible: true, builder: (BuildContext dialogContext) { return AlertDialog( - title: const Text('Coming Soon!'), + title: Text(localizations.comingSoon), content: Text(contentText), actions: [ - TextButton( - child: const Text('OK'), + AppDialogButton( onPressed: () { Navigator.of(dialogContext).pop(); }, + label: localizations.ok, ), ], ); diff --git a/packages/vocsy_epub_viewer/LICENSE b/packages/vocsy_epub_viewer/LICENSE deleted file mode 100644 index 0bdbd9f..0000000 --- a/packages/vocsy_epub_viewer/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [2020] [vocsy] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/packages/vocsy_epub_viewer/README.md b/packages/vocsy_epub_viewer/README.md deleted file mode 100644 index 4b2da39..0000000 --- a/packages/vocsy_epub_viewer/README.md +++ /dev/null @@ -1,186 +0,0 @@ -# Vocsy Epub Viewer [![pub package](https://img.shields.io/pub/v/vocsy_epub_viewer.svg)](https://pub.dartlang.org/packages/vocsy_epub_viewer) - -originally a fork of [epub_kitty](https://github.com/451518849/epub_kitty) with few more features. i -made this out of epub_kitty because the author was inactive(he isn't merging PRs or attending to -issues) and i started having alot of issues with the plugin - -vocsy_epub_viewer is an epub ebook reader that encapsulates -the [folioreader](https://folioreader.github.io/FolioReaderKit/) framework. It supports iOS and -android. - -## Features - -| Name | Android | iOS | -|------|-------|------| -| Reading Time Left / Pages left | ✅ | ✅ | -| Last Read Locator | ✅ | ✅ | -| Distraction Free Reading | ✅ | ❌ | -| Load E-Pub from Asset | ✅ | ✅ | -| Copy and Share Text | ✅ | ✅ | -| Highlight Text | ✅ | ✅ | -| Multiple Theme [Light / Dark] | ✅ | ❌ | -| Support Multiple Device Language | ✅ | ✅ | -| Change FontStyle | ✅ | ❌ | -| Android 13 Supported | ✅ | ❌ | - -## ScreenShots - -+ Light - - -   - - -   - - -   - - -   - - -   - - -   - -+ Dark - - - - -   - - -   - - -   - - -   - - -   - -## Install - -This plugin requires `Swift` to work on iOS. Also, the minimum deployment target is 9.0 - -``` -platform :ios, '9.0' -``` - -Import into pubspec.yaml - -``` -dependencies: - vocsy_epub_viewer: latest_version -``` - -**NOTE** Please add this to the release build type in your app build.gradle to avoid crashes on android -release builds - -``` -minifyEnabled false -shrinkResources false -``` - -**NOTE** Add These Lines In manifest - - - -   - -+ 1 -```java - -``` -+ 2 - ```java - xmlns:tools="http://schemas.android.com/tools" - ``` -+ 3 - ```java - android:usesCleartextTraffic="true" - android:requestLegacyExternalStorage="true" - android:networkSecurityConfig="@xml/network_security_config" -``` -+ 4 - ```java - android:exported="true" -``` - -**NOTE** `android` -> `app` -> `src` -> `main` -> `res` -> `xml` Inside xml Folder create xml file [network_security_config.xml](https://github.com/kaushikgodhani/vocsy_epub_viewer/tree/main/example/android/app/src/main/res/xml) -## Usage - -```dart -VocsyEpub.setConfig( - themeColor: Theme.of(context).primaryColor, - identifier: "iosBook", - scrollDirection: EpubScrollDirection.ALLDIRECTIONS, - allowSharing: true, - enableTts: true, - nightMode: true, - ); - -/** - * @bookPath - * @lastLocation (optional and only android) - */ -VocsyEpub.open( - 'bookPath', - lastLocation: EpubLocator.fromJson({ - "bookId": "2239", - "href": "/OEBPS/ch06.xhtml", - "created": 1539934158390, - "locations": { - "cfi": "epubcfi(/0!/4/4[simple_book]/2/2/6)" - } - }), // first page will open up if the value is null - ); - -// Get locator which you can save in your database - -VocsyEpub.locatorStream.listen((locator) { - print('LOCATOR: ${EpubLocator.fromJson(jsonDecode(locator))}'); - // convert locator from string to json and save to your database to be retrieved later -}); - -``` -You can also load epub from your assets using `EpubViewer.openAsset()` - -```dart -await VocsyEpub.openAsset('assets/3.epub', -lastLocation: EpubLocator.fromJson({ - "bookId": "2239", - "href": "/OEBPS/ch06.xhtml", - "created": 1539934158390, - "locations": { - "cfi": "epubcfi(/0!/4/4[simple_book]/2/2/6)" - } - }), // first page will open up if the value is null - ); - -// Get locator which you can save in your database - -VocsyEpub.locatorStream.listen((locator) { - print('LOCATOR: ${EpubLocator.fromJson(jsonDecode(locator))}'); - // convert locator from string to json and save to your database to be retrieved later -}); - - ``` -Check the [Example](https://github.com/kaushikgodhani/vocsy_epub_viewer/blob/main/example/lib/main.dart) for implementation - -## Issues - -If you encounter any problems feel free to open an issue. If you feel the library is missing a -feature, please raise a ticket on Github and I'll look into it. Pull request are also welcome. - -For help getting started with Flutter, view the online -[documentation](https://flutter.io/). - -For help on editing plugin code, view -the [documentation](https://flutter.io/platform-plugins/#edit-code). - diff --git a/packages/vocsy_epub_viewer/android/.gitignore b/packages/vocsy_epub_viewer/android/.gitignore deleted file mode 100644 index c6cbe56..0000000 --- a/packages/vocsy_epub_viewer/android/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures diff --git a/packages/vocsy_epub_viewer/android/build.gradle b/packages/vocsy_epub_viewer/android/build.gradle deleted file mode 100644 index 8ab8fbf..0000000 --- a/packages/vocsy_epub_viewer/android/build.gradle +++ /dev/null @@ -1,47 +0,0 @@ - -buildscript { - ext.kotlin_version = '1.8.22' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -rootProject.allprojects { - repositories { - google() - jcenter() - maven { url "https://jitpack.io" } - } -} - -apply plugin: 'com.android.library' - -android { - namespace 'com.vocsy.epub_viewer' - compileSdkVersion 33 - - defaultConfig { - minSdkVersion 21 - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - } - lintOptions { - disable 'InvalidPackage' - } -} - -dependencies { - implementation 'com.github.kaushikgodhani:vocsy_epub_viewer_android_folioreader:V4' - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.8' - implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.7' - implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'com.github.kittinunf.fuel:fuel-android:2.3.1' - implementation 'com.github.kittinunf.fuel:fuel:2.3.1' -} - - diff --git a/packages/vocsy_epub_viewer/android/gradle.properties b/packages/vocsy_epub_viewer/android/gradle.properties deleted file mode 100644 index 40fb6b7..0000000 --- a/packages/vocsy_epub_viewer/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableR8=true -android.enableJetifier=true \ No newline at end of file diff --git a/packages/vocsy_epub_viewer/android/gradle/wrapper/gradle-wrapper.properties b/packages/vocsy_epub_viewer/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 3c472b9..0000000 --- a/packages/vocsy_epub_viewer/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/packages/vocsy_epub_viewer/android/settings.gradle b/packages/vocsy_epub_viewer/android/settings.gradle deleted file mode 100644 index b305c68..0000000 --- a/packages/vocsy_epub_viewer/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'epub_viewer' diff --git a/packages/vocsy_epub_viewer/android/src/main/AndroidManifest.xml b/packages/vocsy_epub_viewer/android/src/main/AndroidManifest.xml deleted file mode 100644 index 08a5125..0000000 --- a/packages/vocsy_epub_viewer/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/packages/vocsy_epub_viewer/android/src/main/assets/3.epub b/packages/vocsy_epub_viewer/android/src/main/assets/3.epub deleted file mode 100644 index d4f2aeb43e79a95d5a71b1ee3320ade4e93c0cf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 220751 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
FgIB8 zt0a#X3Ydp<;X?Ekke|FIqsMB0>sc^KQMUAN4f|TI-BQRc7kQBP&Dimk+ABhko2Q0F zcBbW3) z`J#*RcKpBzE}L+3f>e2`fik|@XBL&3OsAYRYIJECrR6%N!h z_%?mSIiW5r@0VtQtZ9P;DP%ALI=MOn7?_xs+B<|=x5~?GGZ7;rHbHIY&}yxJ35w3= z*{m=0js;j*}U4!xCPjrB9ulm8*wI-dVL^n^~T8>4b3399!SHX6W0JBFg)9 z@iFH%AL_uc6$4^v!zCZN9WYlr*Bqi4qGV};e~3h5eh*W~pk1o&P>;+sIHL0pty&}e zOk?$IzRIS~rRrO29Rg{9-%nF3ujh0uF@g|t5F#gk@+N}49-=8)J~)-8Z!l$1YL0XW zLDM43NgnIn;3XNFADk;R+%ZQItrob*Omo`&BH0?tWGH0nS9j!hi2;s$%2T6_7EJX0 z;$?R_NaN&cEmX*_DZf$`bp}$C^*meh(q3jT!n~csth%qE!E@odh0B=VbwwIzq5ZyXO9KQH000080It53MKd@bidP)~00lZNBQFl4vJ(k$#HW|Kw5EDE#bv7Q`RKvn@m00|*cMAtm&A8h}i zzQpI;dlNvhn~v}co2&vdZ{GFXCHv)@cU_x5_%Sx2f3UtbFTcEg$7go>&{uvq?Ju5es^K8d{_gqn&#%J})05p33x09^qnm2^@#7Ea z;i3KD{#f((*Uw*E4`b+0ec8APhyAqm@0v37>D?H+_KBBYT)%jJ9nbw#``9d$#fRe) z&*R~T;|^T$u6q4)YNpn|{_T{yH^0ICE`+W4+HBRT&$J+a8mrv&bY@YnP z>AH;AtRDU0)vgNVK7{*E$+#htHH z{o!B!@cCz-|L%8Re(@aQtD1+jqAWDHqt}n^NB!dB``v|*>ldJQ^XzBo*?8L9<1c;p z`p-?<=1t81wR!M;?((-T-oL!Y7g*u5w8Hl1@cNf#s>5l*!^hV3rO(}z%QDc&5!QE=dj@%WK7w<4f9o=zpZ^=~y({nYrpKNn;t)n3r>mFO1L@t}PI-5VQ@#hO zc{O_1$(sCZ{RM8uHI*GCtkH!IT6(q1^KZZhtT4OS zKf_`|9|)+L3V*Kz?c*#;ne0s>q@^RMkvUtfc0>I zw!ypkT{*&>^84P;*zyc|MjUM)l$fb@eadzxNs}vO({;eJM5BdHSo8HGr0`?=E zZ4P2^W-q+wLbDrt`+TllI%U>2_a5usPR}CN0q@TF!JXQPdmKD?7kIXbZG5%J%`%rfl%`*c@wNEEPjoIr`3bdr$`HA05~a0cWwK6m=V8 z1`l==C7$`Jk)tBnpGJsZ)x*0nCc%6=o_R#@f7zP?7R_^KEY!4~2dBoyE0y*+oUqq} zh%QcH$YQ{8#ypI8jK;?eCz8M?<3xQ*&sV-|D&r^rq=bIKqnT(OR~vj)$gvOMWV!^d zFX{n(hq~Y}XS{i5;@o>|*779T0m_4A=N{6l^z40@Wf@o(^jA$T-#23w<>k`52-ZRy zj${Si$R^bTY&-bz0M~|ZTTesx?@B*RG%qpa*pY1mgLkCc&Z7_wwv}}jJp@u`|9P;thiDZ0Bla}o>7Q(LA7 z&B#ChZh-zLn=GArY`E7jz~&JCu&29r2bcvI z)ca@rXoRKGER>bCNC1+C4Nz^4weBDbL-Qwb4Rkmish~O_)Phx>vg&*^?P$_@_MTy} z*u*DLg^+|#=`G|O6+*$i2_A$&43vV1Kw`8oW$`%{l*O;gF$#^`q@{zRBivCi2X=J}LL{rfi52L(z*f15|^}HaAq%F6Te7xWVBC>pRO*E{)&!#yD zAb|D`ZjQM`$(~H^g^|rvNK{)EkNo=W=nk$ux-q}|`w7}&Owo`_I!nK3B^d&H?h#+d zLad4V`ZHu;t_MeO7F`Tm$YXA!d=fLVgma(<|NO^)D=xwgvMt%F?qp`56?v%~!7{+v z?o`%1P`!G>9b)e-mCs;OGXcv;tUZY4_${6R>QF_S7T`gdLF%`37Xd)+77~3<$Ttf@B3>MAjH-v?+Rb_Hy_hvz4ZWv`lt|*bzH12p*IOmU?fsA6%hhB z!I*ek(_6TeY{vIqkmOv4%@zjoWzC1slwP5&V7VfWz$NbQ)&TSppg&)Hry@_pdHBJDI)c ze%lODv|Ck^9=OPiJ$CLCyhIxvA;hz&QAr@4_XFL>+_V+{B@%;)LD~IyLkWa&QtNgP zAmAAASg$MVBJc&OpUH9vQII&t>>$xdAeQ6?7fw8dg}o*ZYcN?~YWfWMxhyG>7i{lI z^m)+VP=ack?E^w57B9e%@$x%5n(_RhFI;~d&$>FXnmXF%qRIi@ao6`8_!DMJp3Rh7 z)%f?#{5?DVxrVB`@uSUpMS}RQSEo)P<|af|P7r*Dfyvjc)_{&7yU2Ui_pG9Th_%}g z$-Gmt!tG;EQ3%dxZ6}oFX&g2EO%)}izNvnb-h)kW<=(F`Q(z|1?Mr@ac%A8#1Ut!Mba?@Z+i=*h09_>yntqTXBA1HqMJ)TcvMnc<91069~T zO<_Y*Gy!1Ql6eUd(VT7elaeg_B7#Yp{cW&%-v_+MCQ$mkMnjF%ML{ApLOqly z4apRC5TAsDl1Ta`KiOn@IOcHr?Ki$FF-5Ca@PQKOSdi~nUA?!eJ-3WdEQS}VYay5< zvlRd8La`aR#o2pn;|R#5t17G}phaoAf6?NYsS86&t0wN&7Dk7V1W}z7(OS7_VaXkn zspOu8lnbqSGWe@jE?FkxAR@YV{etVYX3BJ%)}*ZPZ|L(?s(oPBE;H^MK+(KWvuj%S znvcyIlnr596`NaJWtMCTowL=1lcfvL#UFQgocrM~t6OTj6Y`&v>*IzN&w=i0H>lG} zuUeF7!QvBZQf5H2HgndR(VV&ke7OoN&JSA@!}z(DFGQh@2?D~Cpl;V7SgJ4K_h3x1 z%RVfU1;bH$64g%|!)@-m)d@&pVzozB8r-;)KE3AZY!+(nuU2fmiMDwV2%NhkPH~@# z4&n!@#f-(Uqoxj0{$TdpM7AD-oE^F%?`km&b_gQ=w7gXNW_1ZmmKR|cL^JTct?!Lq zSgEJfp$2E5-$oCmpZkZGNVgN>~s)bKxQrR%gU}i>r(Q^=i=p9^bErL zOz;Ghvy%e$l>And@FP_+#%$XO*zL9N`d&^XNcnSe^qt*b;eR7F|WdCq5Fj#s% z&?*72YNR?K7|~4=l9Xxv^2o!lec3168pB|b58_gv&>Hd7;+d$7Pq+!VK&T_Obyf>w z7bh|)*LIXGb38F0=E<90NdjVw(u83Ux{-Q!V1mB@i2Qrx4U9$6PZ7Kd(<;(}GLeNl zZFA=UxSIKR(Pre@m1>n{A0r;i6zs@%37g)eHZA)rYhEO+QL$KwvbArC?C+!)caur| zg3JCIST;VV2x97H&2S`gSY%3B`Py~{GCeiDub5JvQ?Bp&vY|R28)WrSig(Re-Kb7U z?f1|~d1D?MDQ1#aTK&&bc}LWjI|*Foe@1-LM)4uD_B!r`xeCb`PZWpa zh3+hFyh#2@d^&jdb%du{wEF9~M$xqqDjTN^p-3|mYHd<3(0({__H5ac;toqOflBUr z37;3?|CYO~Hg#blLRq1O{v$-&vH>auNht;z&_7F*5!`FBNH|ah2^v`4S`Su!;=jV7 zS{p{+Xou98ElD^bc*s(r7SH^fAG|icjelX3N~cb2Kn`NE%PEvSYkR<;3K0k1=!_m6 z7!W2c94`ZMZ?^5U&B$s>s%nl#0~gS70zv#bSkPDxwoGD>=Q8VpOQYB@xbS{(lbDL- z6V$($0KCi~Sl}mmEVS&m>Bnw*u~4_K9)ru8&A<+VWv|vxE0A4r`p=?`d%&)#{*XU3 zmq##c9?#5v_A#{(Gx5fh<}Dudb8>d8F5QXI6SYo2uM7%JZ&=;%q6CUn_7LJ5Rfwhd zl93ZK!O}5IjA(gJ}u5f}&e z!5nurS{lltH&?aR3z#NzM#HuDRw&O`@A-bWO*#=0)|Vh^H3Pt;>MFb43@NzQjh)tfv@0VR z;VGULxrgw}1_Yfmw{fef-N9AXwlk|(dtWzNA_KVYG#~0iDrsAJEgZCLk#Gj}RXU3% z=2QS-wFS^lLEEG3d2Q|JmLf1}8jA;$7HG7Qdb@U6^Nm@m<1Ey2ip5tJ`TM`En1-x2 z*JJ=)Ce_sC5E06#nuRAM-o4HBEDr!a>yQu?y>BD~yZD|9WNCp$k~tGeZ{Ak&5U8mX z>R9XPkKPhPX;LD74ANc91hO%OvGRuu4QSYv`lZ$`0!!lZ?dFth)N0?cJ+t-9=`OX; zG@K?5nVEAstaU$9sXg^LC6vk3M|=J%34qE2EnxRZ$`rzp1=(FLou#E!=nk0yQ8!mi z0LRXgKE6p2l4UGeI}`t#aAR6V!7U)FwMr?wBVD@8CoLle#D%0d13L~(NR}N<8Y|@0 zGQ$FNNKBvlwdvrQ_NgYZb0bt|T^7CK6UC|%f^YRZNrDLsfwjzoHsVXc#HJenHvt{F zL_%*J0UG^^4mu2uotd1GpqH^(2#EUPMoxxBK?;wR-pb8u`8+AfPo`E(IWmndaZNId zymE9;bfky;`v(~90c@og`{zIYXVXMCJ67ov zNLyXdQW{W4iI6G&!I4^cTF`FeN$er#k6QnnvbY#5j5f3&^JY*2IW2X(FYEOAp@~zP zXaT#%22cWNwo{nVYCTVZ$}&u6f6GR!kjuCn_X~zn70f3;Ol$R=?vxImH9gbx%w$T> zhh@rCP6U0c&5ejEY-6q}4N0L9Y9SK2Eshoe&V(oFPn>`=%o(&#suoLg@Ge!vHm!20 z5gaxn6E;D?Tv+xjQbVS#uwt();4p%AE+s-9=v8L%@oN2#Qi#Qs(rGP)|1_(i4J{~o z8(hlJHvBeEE~=rMX8zs8Fayew93E)Dke?L@*Ev*0#f%+6+dC4s zQ-)}D3{j>`3!U*Ye^WYfx7zu!obK6!&yvH!>EsAWJ7~0@m}#f7OhOr5kgl|4mJvBw zHV8R!bM#9MfG_OVDw?Q)v3c(~)hMH(h^1q<)&zUa{Ussw)NUE&*n7(jX_X%C9{Cmr zDwM|TVp9bnRvmh1_M_YdQ9S%-1+dosvTjuFvOOEdq2J5^=sdAyjvU$uQWU#ao4K)h z1V3$NVt+~V)X4`?cxg7+3aEw~o+!&x3|VY`Tfo2)Zj%(ilLt##MaNmHl>wczjy&1Z zA*)YElZ{&$TQZMI!~c<_NlT^lKykbMHk~kZO7CDpF_xak&3H=Fr&il2x$vXWwztNQ zZ1Krv-8X9|R86vOWc1Qq_N}xx7*11`s&?s>)$S-ptzS~Noc7eE{=vAhPIn6;&)nKc z|K^8rOBDiifKxxLzDscR>R|KR$jyl_k;YMM8V-^Z3N*fmR8 zu<+axYu)%xbKPf~;rU`6dr-?_osycC2Fz$>>rjCd#Svkh&5b&lZq-RIxd$Y-ES6T5 zjPuL1Naf3Rlh-}Ev!M+D8TZqXe2$qtv-Agnw)K9Ha&uq8J@Kzp$7&=qHO(cJaAG>0 zTS+B%vg`l}O|CaGl15IP!=qX9&P6SCJ4rt*6C1{`hg0Pv5mNnGbu*)*O2xZkZF23G zjdDppfAHioYcT0129-97#b*LrMSGX@^Owz2Y5Gx^-2=RY5tbMWjWm@Tk=V8;x@gz* z>m)oo%B+Dmtj%euoTCZF<5Bp1b3DqumYT(wlmVzW)(bkBjXcYwJJN1)E8WH^+i1R38XI8Z*R3ODlf4W^y5nXGYxG*2~hz%XG-?LP(m-YK_vzF0T&>8S{#`gr+u7Png4Iw77+~d;=P#nWp)t_}O z@3WQL`Ig%=2UA*3c=xLS4_Jqn)4qEARHo!7t5to6mFJ;^)j)ID7PRhw?4nhUPAA5F zx6KA5^R-!WMvJleO=&Q&<}@o;7YR-D#yj31$uwct+@B9H{0Gug-nRzZwbvqn)Jy2F zl+rTiWh82?nyw?;u1aR6r2vHs7io^XzF5g-YDcaLByOk5g18T!A+e59U2G_gkfr9U z=1?Ce97v#?kc4PBhu1%0H$jLK*Pn?i*BdgtRif#MCe5`L`E4pXNm^oG3l)vmr64@x@W`#~c1;i=pRAT?c0*GWWniknL(hc-$ zIN`KS=~+NGS7ZgJo0Xw|}KE~{I_R8kfMfAB4%7gzW=rP$IvL#F(jDN~&N za)}V<8>eW4;GtZHLCqzqe&Q(~Z_+gs2}e#wFwV=!cm))O(|q3_MeLtEI)TKM{9-cv zsEz9z?T)N1Q37TbUZd7}lPg_2WTK$O8jDq0>I+l)Dlkl|O_C6k>8jW|>m#V}G!A1* zmFSsp{xuK#iCGk4&tHe!u7~-RcC!lWOoz#}>HcCG%DYH#G8xs^x25#0JyRQhR+o~J z#8OAE@HxEv5eed^)RaM^6#aI(`;>lP#;Cn}eAUpVR4l?Wi&j(DNtC-(2AYErB2~DA zl{;6aS@Sqp>-P{`#~IhtkjC`H@vXjF{mWQ!ltJ$4be!@@?|K7);_ z02&it1=+*dPNAE+xTSU%Q{+lV^aTB1rMkioO`nsI0nQG{2|AjKbkb$nD5gqJ>&L;} z0P@Hik2UJMcmQ`-YUTETLJku*xgGnKwbMV(ir9sG_lv##{-f3a2#z~V#BhVwj~B1* zjQu9(mIo`Ymd#WA$?H{!7}o|?vI!Z`@+0_aYV71kR=N2RI?m^o3J6?TnHcevQR`uO zRkL_fpZ1{?@-K-ZhP)y*o|RJxggeq)po^ zOOM8|$Ny5Rx0@F)h3Oo}Jci*0R)zH;Bf#B(>PV66FvWMBlGlP9ScHa-C^o=Aq5JDsOR4m4S!94* z(5z z1};9bAEVKhZzR%{`<<1~{{`np{2(jP5rcr}%l@2^%bK_F z7;6oG757QWHM7;3TLu)-`Ai7%k^Gk*A+IO=Z-#zO z)L@m>u$F4jXX>Xl+;-GzGvDc>r`CIaPq~uE+jBiLWgqUtRa4!&^E3Y7{_5KssBB2p z5|MRo5# zzM;>*R3z~}+t-ff8sAu-pO3h`gT#5ILa9H5y{~)7pywLMc79Vee0 zjBB4eh#BifsJj**H@Q;hrRv%lJN7_a_@1IM9B5al}m zF`GE9@Y>_snSw2nrs)W1OSaDGt@-ei5udgT=YZqjGcp`~T(9PaFt9XEL^tJQuy4ss zf=<&gSYohCr7I32SAb1@`a=B1{NPjW!nJ_bii)f-Q8TiVQ{{_lFkRxVibgidOK93uhT$tdsVtXaz8WyTiE9W&FS^G38xBh zdhL0pJo#L(MpOXdhAM+0ZS$G$#@Sk9v(gG~M&+O{5QEI8s+awC*b@?Jn#Jy{?t=8N z>-x|-K>0byr(dXs%pE+Gq9k@l9x{w!C!!{FR@|ZC6?{WiPPA&uV(-ogL?g>&4^)#G z>&3JF(&3iFS4py&u$|aryzfb|IoF9yuIh_Z!1=R?NWhT0-l}=h84f53RNe%PxXBe< zLTPneRT6a&SB!*){tM*`7C)X7J=HE+lT|sz(jQk3vB56F)VcJ!tg-9_Yid)T#?70l z-{yN}(}$>TDZOzIWWjyKdtiK|T@8GOLCGdpn{FEnq|qYXQb~?T%YNj%cAdXU%q$aP zPl13*bA&x8D1@T(0!gU2>c{<=GXM|dsyC^ zb2l2nyD1f-@{_gR`XTegK!h2BO_VSs85qA=`~O3@CuCKm0R)&Pq82QqS}n!!f5h1lly>o+x~udw(z9#^yk4Vozo}dQPZid zd`X&|m+J5;V_fF0N67A5m8s$SGqNvCe)dSqGh7WsM;`)xjqr8nJuWEqv6Tofve`Tt z+CofFU-+>p?!hGQIrFE=)j!D?z>rsNsHC|u*W(j5t>&z|F$w}OX>E`|I55>0^Sr73 zd-&kgzErGyvNvLjyGBm*3d(?=C4OT%H*y6Eiik#C$ECnE6GhDDo%OJ}~D(Ls#|owT}H@nip6Cg82`2s%uW zgTI4CCRBdtq{uB7!?b2umEuUgZ8_GMw#9Ttu-9FsJDM~q+Og${JKCruPfQUMQDd2g z+cb(l>E16ojBu0VcK{vRB9Eny*_12j5QaNA0e;!# zS4Df_U1^+Y;~9W@UaEem2#TG<>1@i>8l6AS$@AV>)}=`krSBk}-8y$b{W^ulKf#B( z9&uPWa}D#)e!Se;dI4!jsM22k%YC+gK59OS#-`+jBN8QO#A7nr{u z<{~9Mib(-U_0dasp|KL_`FIUM1WxePua+iwMzD}Fl^%==A#~^<4j0}o;3_t-{2O9g z%ZPIj*H53;Cd&!Q3bZ2lfqfA{WLxm;3p=3y$ZA-@^)BMI(C&JIA6V92cojGRqU)Np zbJv*?BHw+8*j@F$JI@dOWG7ng+iH)LF~AMSIOPJ7`~szZGvU);ulYo!(ybBjk&Si% zYj`=OYh8;IIYgfvu4g@%VAm84T8NPC0K!>g;=tIzRX2ks#a)qP|E5L7(>1mh3$GWH z%jP96VFBhoz41_@o6P4&Yqpr3WBCuGbmm2MBBTK0KxRSSpHqI%0U)qP5;?@dHBQ;0 z#ybZ5VAoSvcji5^5eej&$$Iz5H^|4-G;FNxR(3Ze;6UJb-Oqo&#wob>cN$T_=SJVc zUZ3oRoDeZ)LroZVUFnnG(tSnDCjVU-1F1z>|9azz2uTja*~34y2yy`%bMsq5GLv9P;gl+%P0eG^r?5xi$^OHjCu z1-$QGLq$-bFqDIBsrKH`?t_}(7_+uI>5+jd70Wyi(SLwihG%uv_C2$0JZCZg>CPUN6sNLge}zes*L*qFZm!vxU?D zG!f(walcGY1&Ca@xy}1ncWQpi8^FM16VWYd!E?xR8-a~m5@O0F@{qsJvlaJ$SRyi>v1EQhAu0^U2Mi0bS* z#g_*0X4bUym3VYVSwzd%8+0a~8;G%*b|D50NeOe3-i_29BEB+$%#sYYNcAGC8k?yD zu|86}TAE5soi1@K_^0aBkDg=`@HL7(qjnicU-7OMgI4*f=pySKjKc{Dy?oTy#%@Q= zW@v59f*>l!0ts~D<25PYUYK3eSfuEPQ;2d#B)||9oAhHUDW+;+=PhtCwETOxW6D0d zVwYXtxb$C@oSa9XfC)ac-bpcn4!JRqH|ERj`@ftp1YGldxLKGq2ltVZ=nz9=@X&+X z!?s>j2h#wncO+`<8GMbqUONmJmapw09)q*O%jkfomf|O+#lwtS{$lV;C87g=r{nyF zbf#hlc|aefhDnvlxqyH;7(C18@yKe=Usf5OwN_CY>bal)JQ#Gr(Mc(gzuem z;K}$Viuh5wU%%3Lhi`<#+yPU2=cd!Rys`M2T@-@+eRmv~Bx3I}#^aGK8TIs+oc3Sks>tBSVvm>$lpzb`rzh z=M<{iMtQ4srqptP+;NGnm8ou-Mw1#}0lC{w#4SG^pXd)j&?!`6ED5$5yl=3qOncR& z>+-MOEe?SPR5-flJ>6BuY0gz&3BXF0X`-1{9f%3%YxIzaecd=PNLW*09W3mjsGG!l zAt%#bv?PJ2)}<%MgoNY>mkkoGKBqdIPy1Ef`n8N>FH6Q3PfkiIL2x&oiz#XE?Rm<& z{6^{dg;38|F5~L8*Co1#NZ&*AIvitWB#voK3kYrMe3jS_locU7MJM`Z;Dut5hDs@ z2k|%ZATft9!1M&%mBuqoZV!2Gd>{JA*!>v_|CZ7fOFT;Xz0?@s6LA#0HSrj55{SY~ zC%$$IQ7mV$Iu88(>SP{}_@`@TPKZ2@$S~%Ij?VgP_6Ua8Nl;`a_Kcjc7;YFn(7c|; zLQW~HcK=~1`xgwZx0~0W4DGv9cp_Yp zhwE1^E|xt}Sw?nb-M`F+rdWJ+6=#-L5RuEEbwLw$8m;yaCdBc z@Cjf;4|v+=cYKFi$sC^+@rs3>|%SUsRJ`4X#Hrs_f*IHljDR8nza z1Gkxr{z6W(^ZFD8SV>D0e&S5TpBz;nNn)_xc_lv{z1Z32`Mo*vuiao_7~HYU+=t0( zBEM3cI15?Ul8@z%dAS7g*6VqTVQM)Hq%izQj`k2gBPWMqAK9wSNymB z9o~TwnA71XW=F^vD(Pi6fy6142u98wkVHi#m(K98RK(j$)MaxvIKu60d;?I4Gs=#( zo(0D(t;;NO~t8|ZR)1Vxff1i#nCZ%j1nhPxEfIOFbP@LJ|J01M*R zKJkdB#D~G6@v3vGHanZQk+d+z5NU07%tU~-S`Xfz56X0M5HpV z^1Ar2q6K%EH0M=_-mrmtx>$=_%t(RQ;1DV3HQN8t)?Tnvz&#KCOd3PI+xT=|osO44 z#V`!g5iK-IZ?im zg4Zl_=qEPA>?K8Z{x@ zr^M8k8pM#9oV2xi))9|aZLrzH>yOIJc8K5_?IaICG|GR3%Vv-{CFsnngT0QkevM&% zPvE+6J*@qGLu)#FF)cC*CAVq)@n&2hlOt|tgQjCjR0pqj83sGOdon| zQW!gp0Xa|vhZ{wu-0<}9Ss=g1ImaG%Y>Rv(8Oq8aTGEf@_X@)i%oD3cBW|nxFU3y+?!(3%! zd{~AJ2=y9vR##JDs-84Tp7#v;aqaf)3&nqnyI$?)^pq*o=iG2qEbn31RzDJ**?6n3m+xAs_7NsAGIJykd5&uek4Gg+hU%!5~H_$@KU2>sIS8<7@cY;%c8R=}O$*yy0ifO$x3)QA zFvOC9H{lb^%N7Ax)0k(|BdFdYyT?!M3K~2tSutsUm(TNTEPnaoQVN0HnYN|!}8(v7yQx(vXa|r61<`?k>E2)9;0=uw{GC}Qg;u6ff;5onR6#T?$ zhh4*_1Bq4YQ-TGw(}pa$vb@Nu;pU{K3(<(B0s-y79ZLbZc+-dsS;babR*uKCLZ`jfv4| zq#O=T*4WjO|4vonrs>ei&4dOC@Yd3$Qyp5ZNR}_%Ih(auTwtWWzQyq4c_wUXw%r( z%QfEf!}vS*S&GGsO}`Ymg9=~HCnc86498cLlH{4QL0xqbbxDQae8P(va@EDsMhup# zQ9hHP+QhG3uCEmtm2X(0LXs@Ihbkn2VfttnQ_Pd0vVp`?(cSr&3CmG)ImZB9_xGT@ zWa-*pu@UNr2_YxF47DR@y7mQ~6Q*lJF{_(FUXbh+OVn3jR zsupjc7A`lti^r@iQqU?*&Kfc9S#f&wcqVx!9JnbuM3gzj+Aq|9eraD6I8GD95EX9M zheAzmG?K41-F+89k-$1$bu^ADjcJ|@&&J4(AK>rWDn%Spx;|*N^=i}%kIN7R|GqIw zi$t9vAD=Y?YbL3YRGs)3-o41`|eWeg};qec&#%HjI%TB z`w`U^kzXI=_S;qL{sDbnl<2fMY^f?Hf~~3$1~5vrGoF8g6ihD(1SkZLF(xaSgeXs8 zb7u_|vkli&T|zz0FaG{CZ7{d-2wEM*eqSGd_sPb4h{4J1_Bhr~cV2V~8b9+Rco#yk zu`OeI)7B0hbuCQ$19smh4z-=?1S2c7?rFh$)76)^=FY0G%0M+_9BkDKS&$vlvXEj3 zuu#+g18>5&Wj;s4QgqgZz{i0{BEcpk1MXny?mnBs?~zVtK=@AvPlm5_gi#i80k`)A zA|!hNe)j~GY|&QR@Xa!wF;h=u#1(>&$BZHTm@Cc(yOn-G0^9#*&gHs6bereplp<{u{-#JZ)D zurq<(&&#EfpQe_Ic*CV&*%dkGen(2tRWFHdb3I5gMGN19lr$@9sGMf-l{Z@4c8x!K*t2aGyYrPE#DLV6XYKv#!9HHF!nb(YvzxgT0aeV}#F z-6ltmpYoF^yJbjAjf{sOudnZ3b+3Z)9Y9)B+i_;X(FY9WKQ0Y_bx56V>?7f)(QFIR z7w1bd+~tbLPa^`&T2;@Sp9d0YlAiy|EP{r0Tm#(*?mdKH1X1swwaANVuGf0=2M8AZ ztR2vk5F#y4+M%FZ%YW&L>K4((rbN9P^;ay%nf#N+O6~)S@9;ydTs$3GpR0N#!iGrHjE087u8o0qxb5A^d)U`IAeZzwkbR&Y*E9RW_kTnxnU~ zK%SXNFDlk*{jN9F#kJ(qGD$0Jc^Tu%f`yx*Nz7`{VQaji9*FzY(9VwNiodOCy0?5= z!NGjZgE+5=6lxe@!BQA&J+|C)HfUTXGBy#P3oA)k!_M!_e@2x()~ot%NOJy z9OT?~Ez=2_RvM3vtE`{q?}ubcDo}sN6^9;t8siLDqzmIgJ+wRaw})=1>zndK9P;PL zrMg~sh7~ap{+kq8jG0A|N=7|IRRI>X=|#h)E)#j_l=6cEayw2ZPcf`#FDO%AH-a)y zu>cVkSe*1Te7P6_!1=S%oLL9!fwzUliU)_{n2jD2NZ#c)A)Et($j>#5KD2Q)*Yt$ZwI$IP_@T%+dBeHcrazB^XtqE9Ow4)zm|D?g93sIpHl+IKD4mFKpM z+NZSsZ>awt?^Y~(?N%ZJ0fCYJU(Ev6|JN)?JQzvw{txedomYa`;?u05^WvQ!Qg6J} zm1$gNp{>bdj}%P^#)Z&FUq$~q^jqB`dQ7u6%>{t0vN#Tjuhv+grd2wPC7mdJ-7m=l zOTGVlXm>t0ElIS^sF_%|>8P}Q%&7j{Jy+>{TB?*XHLI9+u=}=Jb}m)TM5WF2d@f+w z{oHTej1Rh7^ZSkEk>@U!&ZvetTU%#2_Fx#>K=xD9=2Z&GV=aYi=WmKbv!THUN9Oq z^_uU?KebvtbW;;#<+Z;Rb;jlHl*sT98djF2lmNeGwBw?PUT7uBL(d=5jQIX5KrkQ{ z5FIFN`~BQc^LwlB8eE2|z<5MA5C~}btl9WQO-%gPEO2=<_4K6a zmA5%vD8T!$a64 z%c0}K^fm&TSNg9+dcp=xX{$IDC;fK@P`RVIidMqrieto!w=)`Kl;vlUz8aShuwi8lNQ4sD* z*QxVX=9Hwny$8p;_utma(aiV5M?*CL=d>lw(amy0hKq2w?iEM;Gu*_|@Y0Iza6V_8 zaj1nq1pMZ!iHUcJ)VgCq{rZ6O{J3^==$yku)+acMb*iM=?G4n#X`Nr&AAZZiZ?`1u z7P}!>hi~XVX~miXqK;b^{e)jtR_W%jDV+gJeK`Qo!eN9%WF$j|GjhMEDk2+U$JfGG zGejE|Jgm0WPJh=$z^k&q+wqp@xPsumQ%d+|g?pE~Vx!`E#eU8frjX(;*bi0xB&BlE za^eqV(7$TxaXwLxZK4snAdWpR4^?hz*UvLOs_XPWi=tJMrLfZ_)zpH1o?gfK;3(wsa~HZhka6Ow874h8f_C#n{33n z`#RyI_}+|5<(9nu5AdwVMQF)sO9!dE787^=91nzzKcs(u>V>}OX;oW4=gGa#=%xO) zfs^RmAf4UNzy63LS<2j!E_cQp3+V^A^TRWjHr3n_n;7FP=1sM8b+s?DGKrbQom8se zPxz~*jOlqE$v425s4!o+Rl{nksCg(1^t-XB`rBSQjIB5uarS!yEj38ZMg9G8Cgr1M z2fE#FO|jWi!afIM$597@iDai;WRc0e$Q$Y(S}=o~fYaW;)8jd9beXyiwW_Y%m5$MP z^cU~{(l-(*{wHjak8!o6zq<^gF;3dN)@XKW!)mK8a8rtTBD^C9znEM2ykoF`9e7@z z+axc#1u*!Z>yzOeX;!zlqazdMM(XRRmi6}$Wd^LkOzM~nLMGxCRaCKW5!Sy*4fTep z=5^B!w_WRr3^}e(XT#w6r;2m;>-{qcFu;$pN5o=L*MJh0R4&!D(+BgH`Ex8AbBnM= z1E`~9bU^7@o-kmRS*F7BVqCA25 zhZWI3wG{o_N(|2r=?K)Q?`Pp^peLLOnjW%SLL9|1LK(Dt_-CFAkx@n@l~2+k_4v!S z_5JVANG!pjgS4U?G7TqtH@${8_xurEtSSLjz?vW^g5dE9Vmav$R(cCaNWo<*G^)s? z!+FT_m1c~9jZFsFCL$<2L%C-6?^2sngx5(+h`|vQbXoXR**+CaL~RTn1oZCevsnZq zFk8G|&?*yOFm;2DMC+bdEbi9W?|jZ1Iw2bMSL%@?l_Y6f75(5Cx0R7h@V~sL+oYq$ z`p9IO&G&65wQ?DQJJ+=7XqH5b{+Tf@vud^(Gyg%TNko<;q0 zL8d7nEi3nYBMKg}n0U*Gc zis?*N`-<=wma~J#;cDRTG0Q)2Kn}iC<;Kwyt_ZDznG`O8=WtwW6)a{vD<{wf+P{X< zhn)CNDOF*wMv;&TH4A+l21B3eFX!`g=mV;5Ql=m);a?ZX8mJfbQOW>UC>DFhmBW3> zNbUb@W|?at=G`IeQhXt{cgE6%$&D@n1mG$+b z0Nccrp=q!=Kln9JkhDCuw0@7s$MFCaze8Y zRNe@|8cYl%s#T=~u`kF5ljYMyce=zm=HJ4x;k4uR<2v}zizyHBL#e@Asd@K|>M+{C zsImAg>im%An>z=P`>!)1&&cob9xfs9kR-Env;Wx53t79OF;vyy;UEH>iXFCaN~~}~ zB^oLgg(%h?!(U*R+9K4<dTNZ-EtoKEPL2U^u&Alj__$S0y`;Uxq=6*5pD-E} z`hR+DzycoanWFx)h$1i77pOlQ3<322nf)RwwsH~C_J5y2zR=*_+mgT)uoGBJdH#1s z`1BXFTtJ1Iwk!58{a&Vh;J$y;|`|KJh0dU9cmM5!7EX zThY5Qi>3tm5P#-j^Ib>5coFRZo*L%^xI0xnb~LDQE;(=cp$^zeE9LkWwJ z3+sGS7&Cv==PRir08>+IiMFTq;bbYJjaj9MK31DkxrUa#DECY?2fr6855l)!^k9&J zV8?^~u{L2j+*yF1bLSTRAhyG^s>WG?f31&vhZDmT9OrudTDq29AUNKcSAqeoYLY!c z^_08JMD_RR=$O0Sc(oP+;?pY=$?)E}tufs>G60 zE5L%?ZSq)zT_Tq8E1&RP`=@{YHZu`7^+#=oxeL1BT$s!hx*s13oW=U-Xvz7)1jy-Sd;)PgfT0=PvUD3W$UcTf+ z#8$8AFe5q}!v4u5L*wJUY$yepIeVX!fResfDz=8TD&j}E9UVXx$;Vn-*`AE1uJ4>R zwoyNI92mAjpzN4F_u@;lE4(wzwg%aV>bdf8Q8VCQ^JN+<^og(Z9w}xV0wf=xs1s7M zq`}4)o*_${Q9n3}URaq(>3gvGSF&3p9aTIm;5erjytvZ8Kd)u|O8k%fZ4lwL2Nnwx zRCr6BS>AVG{4f4GbL$d%b!S0E@_zg%&LWQ+zvk*7oZn^oqmJ%rR^X2PiJz%$FQipH z>K2D!3+F;+U1tGJFFrC%U`h7ope*h++*Q~ZDGCB6gmcS#%H{T}FA>iW&kWqlZHCfZ z9?x(hEPc=97c|96MVx4zG2~7qZMR)K1s2jlOV0#1#)wbL(nnTNt~k!1WNZN&+X_!r zVwct4c~Wy4DNB8>dQY{}kK*bW6wyGDiUgLp&3x@n+WMcWc(@rYI{6!-PB&Sn`v{`R z9AeXL97hL-%HNsYf77b2H(REL=L6gd`tZXUJF;3nPyUqw$A)@DlQ-uo;=aIn5TNG2 zDh3bU+$kyO>io*)$LOTbZ3~Z@EID_({lYm^-UO`<%2J)!2oiZJPe9ix%m!g8xxRB# z%r5KkfMzQjCVS{Jj7^0f8P^Y$C3A)l7KEL97}hS8bq*YaHGfkdA?;0n=B5UT`eGe2?J!% z_sr;>%yvJI;5ULl+dzC#3iWby!UEA#*L9eZM6xjsM?4j!x!9O8)G9?dn4^st>d#iO z-HBdRFb1dH{p2rpRa;{D1E&zMW)xeaxbZ(|BAL)KFmE*t+zy-*F{N6LnMEe{oiD`( zcvl@lnwV8qv!I8AERqQYuAx-ptvrBVi`^)v5wPb(|H^kuUp_Xp zKa$i)_MC$WjQr1j(7gCYO1c9vD}BF)K^U3e<&S_&e4QG9sjX|`0n0#7c!)YkY#b7o zd(YUYMr1hLPlJG-`g)Br@a%763_Q=~aYSA2{^u-M))kFc=7vI3$}l7k=)OL8X0_EU zmN0^9MfWbg^6KJ?@;pNxs)P9S;5nU?HF?JhnlsVHW1hV;*(kW=*uS1I5DJHD3xa%4*$sk#*B25{a>t~D zcl*M~Psc!)toFc$lmYcgG8}Rbq;Q5KJ$bfEGAMGF>ki+0wYFCTG?ZJa$SGh3vOa79 zbImMF^!~`3zHydUDFLB6p|wgwa#s=WS8}6Bc!H z?0@{Iempz`;tbaBHe&KecCtjt0DlY4JHKdL0W)mx{~ZRVo_59(MH2%SXX|*5J-gRmFKv|p+b7SOqU@&2timCt|R{bQRh>W-k|cR8P2~@DPG_VeoZsE4B9^ zLpTUZXwnh~xB~MN52-|-a*b8nl$zO>@P=N%FTkxq8%h-{Tje*nfMdom>wxF#(7nbU zv;(hleuDr0wlORQV>B-?p||g&03Fl7D6w~;gl8uh&L@}cpitLU&QpxEYh0FT1Mh)Qa6BaC%=0!NoWdVVonD$Ix9e7xbq)Lv zw#6G`N+Fkqzx6B+TgzV%Pff2rP1KsH9)k$3uMsG{&nNnis!EZgZh{rAy6(eR3IoR} zT?r4)7S`V}10F;coR(frIj@EdpaEbG93%Zji`RE@u5AT8m7- zF+c`*V?@-tK0BO+>jecH9uV1#xX_$RVv3l%PB+%MCTjB9O0jqhnpdQLF{W@OKJ9L6 zYdV#W3re=C`*}1 z#A#8^_7aTPPLd%80@b*-zU!pG$OU)G4nlJ88cgC2w|$hlWbazFGf}DK1XI~l*ga79F-X3&QL$H**Z}sYy!V<+v7|Mr#LS~QWWf}@ZY}sJpS01TPRXlM z=dhzCJ!c%Vy)IsBObtwiugtG4raT*02Xd``wTB|Kurw$7wIrLsq*P@%6u}H7^`c-| z70$pGn9n-&Cq%&JyB+ug!gV>Lex~?5* zWL61fXRmV0oR{@+V4Q=m8`fM(6%Tbpui=7a%PD6HiHTPZvymAC$V$D4P@52k&I-U? zS0Y9FJqHd|L<*Hzfj_zXXtqIICq}uE-J(7TLQSH7=rEXIu++aEbHKE0llx)Mim!oV zLTdVKSHk$OVW9F%+WC~O^GZlIhLX8koa3T40YA(vqWg>yGl&b=m`VEDz0 zP+QtY_Q@+XE0$jqBx@S28Y`j94m#O&V&ML&M8^!Htk+OAD7D&3DpI1IuH&&o8IwHq zEb#;*l(H8J$m25d1r%GZ>vFpCLz(N)BjB%Oqf8{7Pf%oL1f@lAWVl@gYN$0JbgPSA zuVtX=sKJ}RvcRBKje^{ksSbOH$5&XT%~VaU>sF1h>eGG%b?j!QEV2?iT?+r^i#H*( zPwxKvUfylu5Lq%gwVM@vH`yc|K?uJ|WBnkKZPn8;TH5~K?4}u`tt9}NkTjd~LkSMA zuoV$*`D+R?wJ+erivefVA;u(RxTvvFsnpJ<-xraH=ZR?{sLeWFzqSSjb3}VP8^-b6 zc^rXpQgasrrgS3FkBWLSN;6rCLg<6rBm*@pUotAU6l!8PgKj+#_!yqu+P*HqdoL||uI#KIRPy&9a z-c)i32a`Qf9z8RKx`YN;uba~p@xZCoc0wqDKf7H+By&mLso6<>R^Uv*1cP zm$~n2PB1RF0W$Mu*Bb%cCn#Z>OU1Q53GxniX%-&*hVJK(Eg3fa4Y;Ap^G3GLX;1ua zjoytDHctc095F|Sb9veIt9Ze_sR>CUw)@WoRtIRiRHYh4K?{Ia#GRHs94hYQ7KRS; z7B^R>Upz$0U2&(mP3i98W*BS2Z3eq?8MdM z;V$4+G@5Ss)I1^Sac0$&kl|i5iUl-&EGNpYROZJc#ek3n>LSNc@ypS0fv5+lCvQjD zqS5sZyUR@izP0eUCuP4WxG^YxOo={3hvq>C-2#iN(fIO<(-0RP0i}P>(M=j0GvfYy zZbm;NaJ+P|Hr~at6?n)&1+&ZeDE=-t$ny zz~BpI0J6T~n)sRuPD|!|e?PePEu;EMEk1r5SvSsL7wq7E3?9dSqUF zXEF4yx$I0$fd=+5Q>A>o>PjBDpVlPeR|J^`(iY8N`Rz=3Iukz6TgKR$e5=qi4Bw+g zX38w6aXFZ9EH6fc(oi;>yts-CkK(h%+!^F9WE}`L0n10O|4e^D$0HrWzjVeB8B;P( zk}TtfwIlBd4#{oAo}HOfn{ta}$v)B3Djq919vNznLzxv-pih?2*ib~t1BzM$ky;nX zgbkGOntiy};*lC|Ti8v2Xdo9BF>ot{tfgiW)72=N8)HB&sw!aeSnX7Zxl*JA2qM?wr5GL&?$-gruf)x+Jg0KJf>JifvW!WOhbw~%7%2fds;>S+Q zMQ+TO=%({dT%O5VcDc?E3z1F=FdjQha!sZH?k^XKv^K+$9`M^W^BAyxitCHzL9@4@ zUxz{~`o!|ICOb6OSxa}PzX*Eo2K}jL6q=6g!j6%+?esL}xU`n4t(F78c629y3zdG; zZ`!18EIKKfboi(d%!BIr2&BEOQMYo!C_j>V!pyX$5(&#AQBTt+3*7Qs{UVLBmhrduqTb4}WZ&BBgBF6t! z$DGQc^hs7LE!pL6E9)REuA0W33z|ve1!z#qa{vh_`Dm9+)oMC$#5AtFoB`;-a!o8p zObKo(I~|N59v}0kstoVE^{l=kcOtGyeEbhr=fIo^v}Mt#W1C-+j%~AJ+qP}nw%M_5 z+qP}n$@ILMs;QYjaq8T=&e~fN?mFSb3lJ#S8>x#4oX*U&@3$t->C&&1x!~ky+;vrG zLWSiiy|P}nykOj4+UNeE385I0JFq-Ns-N>o=s!e#?i31_h}*+G_7d^Ms)UW!OoqW1*Z$%jC`$QISPi)vgQM%6$@9f7w9X;EY11XHtFKFhok-E zmIFSV0Y$KBOE7{5viSYS-xQHbAD6-BNSU$=7Cj!U$+`5~xf8ur89t{4GDF^&Hwke+ zmlpZf$P}Lm##A`b<3&0%N^Z(?`>(O?l0JF-wM%s0``xCWWRPrV@2Bekin$8^8175K z%cVyA4dIIyDa4((ozb_?qnNrZUzU^U?}+K_@1TVr;Q!0tal-p3r~dJG%Ky*bS^k&5 zZ-^xPi&yXUGUp0dps6t(#u!r>O|A17!59*=toaXqA7u91&+{v0m;Daidi&!$mg86t z4WyZ1$ktEjn#iwR&nTPIsl@00-flhaxiiA)lv~5w>C;H*-2$h)b;YOqHB!;@xtFMn z1+k)B4VC@lwG_OxKo>!FC+&{8ejG{m*)k}m{psb58FFCC#`dpw`~7jw z`SgVi-{<|TgstXnavbnJi9a$ml<4fddA8>3`FMJeX&3c2_KXMWf2a+y$rY!#3RPJ~Dy7?e%&}n$xkjYsgbYy?wKD z#|`M-sUbkSDW}VUeVTox>*j1d*!{RKA!B>)ODw*=9^W>cXV1dHN7zQFaA3zLJnHKK z*fb+K;(7FZcqs>8kp^|}$=R%Yejfk4@a`M{G4yP{_a$dr-d%3HcDo9ms*(&cyxRPe z`khyO!bkq0_c!e~2W*}czM*Nn147uJr!%tL&oc+Kk?oz6x8_h$-%c5_f9Sn?9HjN@ z?7j*9zpefg*Usk!8r=?tcpCv{*1LB=u1L>Oc*@4`(5U?5c%~qK6Jh9#l+c2r^V3^- zHLuU(T<*{7Ni5&{YoaWl`y*ti>e7olf3%~Mr!9VoFFd}ESC0nZZcnh%`R-KoZI0b$ zenHmjV<@t&9J|MM_<0P@XUG%(=;c2$|4Y01cw%HxWc16(Mg1o@tLAX~#yhfwdWa%Q z&3M5@CU)pL+|lrjw(9=scwohC=1oKcmoxnZvgPH4v?Hzlk}-zNf}%2hjHqt1e#-zX z-5o{AWxpKf=L+*s-5u>d@W>s<;@H;RN>@ckQ^){YM>~;65`G!eq!s|D<;k+tAaV^n)>x&wN3wv;I!v(c)rL)g-YxP& zw{mUgqdI7Ln33+y=~f&U0OL2gDaUVTYV8GS{FvpfdJQs&tr2_Tsryd)zT@+SkFw|| zj7w+`*1}QqW>j~F);+xK2F{n0Q4ywXb5otWiR*4vfse2bH4Sm^j)ZMx#bk3ce%A_K z+1^g6YvY+ly4`{Bv}_1dVai2`G}uLZkzZ-(@92ca${f|zqjQvRTceT1H{5?+Qey~E zfo`}GjGE%83F$98x6lUkLxG&PHPR}m*Zx>5w%|~s@cBgIy8?R8KN|59dBI@fgL$Jq zK!t2g`2Z6y6ig6ME73oBn^`1LNG{$%+WYa=X5}%a{>k@LsxQGYpnNyjzLW#(NhKca za>jXBY9RO*=U@7M{5pFlto*|YbDaCIc0o!V)%!^MX)>QBFiuK5OS^Q{p&EF3Vb}>H z-EfAAdr1sDQzkpF^?P95lrnDcDt7mX=^H_w4W&HKYs#?`l)Xk}5|)%SUV7WZKormG zi>jM*Fe@FNJ9^I>`Bwf?8Q3z8vUfI}U}J=(9>zy3T#FdGeb)jVw1#ZgFx-9!%W>DW zJfj*EMeQvo6NMIJrJ~C(M1><|@NuF+oBrXye0Ny;w$}QdWL)5!vDu;FWit;fn|0P< zxeG4ZnN%flC_)v<3zOzlu8hODdBSSTARvQBfNg+a9mrgLvXayt0q0@`i*u-fme&?2 zV82fFBw3%%Iffy5T~t9UVl;SDeJ8p{jQ;-JZ>^LJx~rocFD7Nx^dB; z>7hPR--`pf1XR1wOJ&0IgAE#^JV(2fmA-Lue zF0y$``}y+Q)dn(`%Wq`oUFmb8i573N>=IhPnJ}XLcjJitKp<#7!R{)oFyaPf-kVuB z2w8VC*%v$Tz=>pNi<1ej>jlg))K;qda7~2L9@U|&ZNjjd2*umX`@<9J8g5Sv>MfZt z+#xwY!{agiQEnICmn!aBbbmgaAoaE3-$q_kh8(1`3?iisp}X&x3dI*`Oj9N0S4&Jl zmDJAM@9;*!j5$Ea^3>R1`FGjuP2JUVgpO6*)@~AJ?P%U%fpkBUKlzO#$kyePJ15;M6G*(C za=ZzKDn4JenPtJ_D6oFDsM2Q)j0N|e_+IuwZUT7s%~SlGLJzR9`&OGF6w_6n$`*uG~3x3sCr0iXHg7JA81QRyIdBlJ{L|u?YKa`SR2;Nn)Fd8R? zSGWGvn|dE8V`7Lb1(R#&DA}X40FaP%n`!#)IJwt}MxaFTk*4GrrCs9wMZ*R9{%$ML zykOt1r;$GeHIa}fVRU&}^c?NZ@Ph8d?9J(QWrhiXH-q$ff5~>mdSPpMnFgx8`1~65 z^llwnfp^V5dqwC05V90`B%%qYw+l9iV0!u1`{u>9$i>#~+0HM?R>!y^S^rdrQ~&G{~wEU51Nk&IPFeQN5U+32xGk1#Z;_2xu zTYLP%481Y`vfGvi<|;zXy2-Fz9{O)$u1G-W8cl5=B}N~lj;Y?EC6ayx6TH9Yvmk3y zwUUj3B+9`^geb3i?~uR)W9WT92@t~Iov%;UoX>=x+~Ed>g}uUQ<#LgX%Rmz-k(OfA zLabbguDW2w=s5bP&3NrmXQlaFnBwt@fKLMNWR-3#pt(pXKxLowKUnRqD`RX~-}0MU{akOm>!@=MQsge+CcOr>T-BRSdr z(BI`fV(oqa#U0`mvwluo#MM2Stcy}JAhu&A#Y&+D zJZsA`$;`($e|jfDg#M-4?w7)QDg+d_MxXABnSsir;x2>J0-&!%Iiz+aq&L(A;qAEr zf{z$?LYo4)nD*HyIwXGn2I$qm$I7Oo264H@wc-FAgxQanS;rrXhw zvJX#b4dVbz@Y5j?LWjlh;^NS?_XVSkba%UITD-FzTe*%AUSi@)Q3qqAhNH6!t|VDc z-BAYw8v?=|f)<0`M3PcEI z(8&MOTLs9H_mTb=+M|Dm7G5ZDdruv1OW2Y>1O80NGqMIzJ!TR$;!;nb z3_QR}_;*VYiLW0dL~CR%tFgsdjb6VU_zD5<4C7JKlC55D+KW=>x<+Y?BE1cI zV@1K73(8LQHk@fI?r%&cq?MruVU1k^Md*~zy@9TjI%mU2V;P5lc;+=u4S88|%XlG+ zW7EC$M~#065A@_Z^C_3?gq2jhGLVyCgukyRu!4&Wi&Qemt^|aAR68?>|2E{_)9k*z z=tsG?o6Z?Q&~Oy3+Git+e8g|g^)pbyCLT3In*5Xp9YrX>SiqK=Ml?P^4UnF;`Llh~ zG6qbw6}VxF)A(C|qQZCcq2sj)NRTJqh#}-;TFJgD$MZgSjc|SbzQd2&Gu*-I4=?z8Wm|=<26;SD}AxyvTHu?98ZF6Np^_mzZ$zN~(bOG~8 zcvO#(XnvCjXMs_+#mY{W-Jg>lLfHWT6FWD8{K__`l)lZUyA=_>*J>QB*671%y-zav z+b`eeSx?HK?o2J5-`J~u&qfSEq%^M1~05g!eOEyf&tDU)onRmx;$F0gUw@VAE6LW<4ZP?ut z8oju{Kz^FYWXhe%lcX@2xy_hqFs4s^+IxJmi)z#$1sjt-lV(2-Wq8a%*yNFaKCH1n zD~=e=VNtWcO_Crh!FbYJEAtA)n}Nv#Pc7PBh2qjTT$-}W!HrF#Z-Z48cn4|@%)gnq z@9xlRZjJ#TC6{h!lAcz|b?7n*?%gbq#6{E49&8*O@ONA|#uZR177< zpZAI*c9(S(<#+(mo(KpRnNvB&IgGM_9=H#cl=xO@wb&H;*A&d}{$>9<$O;sYJbT1UQVzlGdx)7A@>UT*ndNtyPZwpOIL6sR6p5{gVJS-s zg4DYPpeL^!)8f#ss%fBJwZC$c55E*`APL_sZ|F6HV}y#!b`()wQ%Xn~+B~w}yfslv zzq6)g;FSMQWFfc2darHSA`w-nMCOxqTEO@+*^zI^4WqQ0=3GT94PN#c>xva=ac)#7 zmdk)MZU6~dI8a+7XvX5NUH)8zvww@14PLHOCSZSg%}P_ zN9=4^YaeTa`s_OtJn3z@i9@8vsQP=;p%lJnm|SMKOoN*tJulrfTbCiNX2ysSh8}|G z>n>n;Zjz)Rtl3-6z8~`tI#NagqWMbfxh-pbBL{`3iOGSeGzg@6-hYj>r&d0Ev=#zm zX=HZi+Nog9-g?ixHZ6HTCQFL9mrm0dj}mXd z{V}*>nECPaX4a!{G5dXllFV1LVUH+Ad{2v-t{l0jm{(I+p(hDv7x zl#0R;ZFU!ecz(xHS84VKcvPb%Ln)v8j62M!Fe|z=WckArqb&b!s~R^{jBpc^!Ya1( z5K!hzF4EogOkUjCkKR+bpsiCb_Zk5*yT$UCW>}mKjExxk)|(h?dg>HNnHUr^P&2hj z>y`|!a1+g|h@fD82=6B)C`D2X`4jxH0EFDM6>{&LopVG4jm&&E+3Zt=QUcwl=tVzNnE3m^&%S!8KMiXH17ka%in%)TO-NTdZzotj0W1LX9CatJys-jZ_q9qRRV#c>-`(6#X);4=hNJ8|+UZ37Um^VL>b z9lKMO5Yy&wO5Va5U0|fP&_LT5Y8yQl)~6&ok0+e3DjSOx9&N@h2o)H_P9`v=$^yuG zTnk5L3M0;-;X=ame<*kKBjeq9ETy3?Xh;21-(iv#&knU&U|3Gp%Ff| zq8>p3)kLW!$1gwI zOJ8)xaTn=TrZG-9F;6dP+KRCjLbiwzhL^@6G&WHB`3tvhoUZ#wE=NGEUh*wDyW<>f94p zA0)cz&V+7KGX6Vj#=rfBT5t|`G-fko0 zY(vRi7a4gu{4d%kf9K_!;6J)ghMqwqDUsa?xRD|zNC0N5kV*-pktC#a5DM7CAM(3mH?L0$!DT<=`<+9tvnvlH>~ z=k0~e6wAN?ZXQp|a@u(>(?-I7QF`Sw)+m|Wl{x=PU~y9ygfv=+Lz3A6AF}q;psV|q ztzd&K z)%Ha-9`Zngv0v&8S|VY2h*+g;Hy@#NI2@EweaKhZYa&?n_;mfs26CZ>DlGk69;iWvO$|o_opZmF-N_;Ul#$Xae@Hh@eCu&X zrl|6jZ>WXap$QFfNQEHaI3vPDt$F;u_U#o>~U0HGqU zWY{wlWiq99C^!EvnUJ@MQ$Z4wYTnFr?FbfkPwbB>$57>Ea!);MBF)HO>A?&s@D1>7 z|M(X4k|W%F562mVeT-qA=g zHslHiP`lbvncntg&E~CYn{-v99KxjlL0$4ID|{U%(k>F4brfBP3vyB%>U($l+maXB z0JIA|gIS?Cqnl$?M!2?*x%EgKr2NC&GK^zbGV%2(=C7QAwm|9)6HxM0ZA7i$_HMLHy32u!ca?t;7RB5Z0;Cei%aRpe8dKE5F!9DbEl2|_ zOJDZ8MMXw^9w{E(R2>GV)2AeT%Fi?+4dNpeW(?L%rNEM=%p>Z}(%Lu$mB$g=W%4`R zlk~J*K>dXhmL&f)C>kck^kM zbmjAnYMi3d)M9pO)Iv(uR5eU=>tSAwo0<%XGs%N(&0=>!i+!qSh@D#JL~B27svupQd=SQf-K$q_SPHtBRq7l<+4bvi0X)$e!g zuWR(GEycCLN52$pR1i&-nE~!;?98dP2;=Q_z?RwlvxzMq9*$y93EFg*kE$S>gS6R3 z<&@IhRw+ESWzinxUj5b2%5!cV_75WMi_pmuhGeP&?DA|&xRNBXvb}YhQG)FXuPSWx zC7xl*Dzy~N-KJWJoay0FA8{7_*k~J2yM15uF0kszZ}roseGXU30{W>@)3HpmazIw5V?4BSijL05cuC1UvRDo4?S{)k1G3rV zf~c-}dwW|I!dVW^43q7hjITj_8jC;uPIXQwtl;|NBhhc7E{sR0-CJ%h^`^`HLvtT<}Nf+t-ozsdgQze0ac`bNCWJ}YI&?5)559y)YL z5cj`aBry6LS0UHEMk~f6wkGC~y@kfTYQ3#9wV{@fgqV`*v7^{wxQxKoQZx9+nCC9? zK#7f90l7b&^MqAMB&tAzeX&HoqQxBnCYc$YA~bhV@GDOEI&|_SGR<^+_%LaMd&3%; z{}f2j%3DUosob*9nS=EMxK1fZUSf$+N6|SlUbx$~cGOq;g;!%)HCb4a=ciMpUDaVcCe1M9NPhg={Q{kCe)&w zaKlpdm_4>oBw$^y3Vcm)?KXm(L0)S_k75%O@Qb4l+VQ*15|JmBgdW-DF?yX;9Rc4| z3nmE_Fja58`poF2+MrgqaFBU5e8XT&{T}2XS6mS@{+(e8UR2hT`0K`%05~E(H zc;rmHa(21wc$Y5S-vys*jTLVw`wk*3e9x9Y16nsxN~8OZ;^J$}y9CUTxQ(F_B_Trb zRUG<8z5;%4v`9+N7Q)-?BrzxGRUk@{G)xcxX4Z`@_hl)?ie?t4;tjxTMlZUwvngoJ z@o}nG&EWNOvb&f~t??Jd&721~afLKqi=m2H#QmQMiEfP+T=^sHj+adu8(l|>31}CW z9>OMJq|>+iu}rXa_th8YGyAy>gD>1rM95!51C}GpDSeutWpzATtl#{GT8lpgp>a+x zaa#Z!7bBhWY#k)X^INW;)=3%{-c-U(`qW1!Pu?Ldw3`$CN%q{RuRyU(y(~Lo{oWVQ(jYy8;db&!Iy(j8=WSJI~ctk!pcOgfU(tg$v|tI#GGf zKC`@P<)Vy9*D!u+LCw`DbsrpfDX?tcQqNL))aUNeUxrV5au~lT0t2i#jQQU;9a=l9 z<4(PyiB26Cv{TX~nwPh=4?*Bo-F8lTpyGPn_nIfADHsg*W*Y>%qk5&{jSY{5kQB!Y zdVR;B9Ng@7X^v!CB#t*8S1R_=Ocg|g$qckVM50ToorZV?jvq%zS_K9|A|aI&Pc)wA z)s1@$5Yrq4lnUQ$1=ts|He-7R(U$HboNgMmzUreuSAA1|21TzKWbiyU z72frwvPn0j62H<3aWBQF6vz{5q|6s8ozHXB3RfI|)u^A{So8aezMrfX-Fk^BV^An| zr{qd%HusM5`2fW?p4XetN0TpLzr#}p2B#)zsDe_|lod;L$hNd7uz4^%_H*Y9mQI+v z*sz_|oO<1X(K^oVEVb43G&mOY+&%XEU-U1CpQ&T`8whA$?*FOxtpAJtH;3c@p?|*z z#_cfHP>r?aXym{IYxCvyDhkbulIU|0XEx^6M)_W5P1$b^sE-_^camRbMd3)+)bJ(0+RpF6rr4Ne2&oB?%lw(p+{+ahH2UE0r z#v_E+eBI^mTg^8&KGJjNdGLJScxM+U+Dpd_H#&{(1f_2&(qj``$h~*RPi?vf4-M*CVP8V1Vr<{i2GF z?T@w&8(a6C=rN}aRg6Si+*|VquJXoB7D5tUk(bUREP5NreZj;zFLiBiFJ;vm9?uuo zp0_Q}o9>^>mLB(K*z=0>k53_#~SHS1@xqm|Jjb2lQ<<8VfvH3+RU+fjx z4xZtg_mBVB z%40`If&k5iPj4v1Kjv0f_`#a$po?EjSX^I)FjB`I@}Xv9co`9de^j=;wT4#*7!Fd-LIm*BJ!qe0{&H7z z@y@1&Bo&0c3VBJs1JHfdw3|Dbufz^vud!{~Gf z+f?CZ!O*nq2{lb(iLTtfSy(t>BOCuYZtv7O?!wP15UtkS>6#?0Y@_HQVxl zUV7uhiHk9p3ISFOiRH~1{fq8{67~$zIQwECKb~~&e1tPOX|jw& zhe!*G6Egs?x1KZ>C2Cz8B6SyK9gQKUEL-Dswlk;p`~`Lve7_i^O)c$F|5ux@Z)e^H zl4i=CGd&<*w4*jjsxR6Be2|A1E(EUb zdZ4#w`6FualTBN{CQe-*7<69<4xbA)357NuKf_2=(VR=)QB%AsYRSJn$Vh-InVbS)yy*II@NYQ;%#ykf)c8p7+A+5oF2SR8x(w)b*DG|sET`1K zzr=e1^}b4i1w}vXnOmIoiA9!13=y!@0brO4J-{k;^_gmS^(=q>ZUF(#jA2Wo$t~ zoSRQ$W1=UUhu*^_LKbqrJnGtzL^`hJ5S<|L(wF?e#92_Ehbik{{hB56Q?*NrC+var zJSN2~442g>dur(L#ZQKBw=DieUD}b9%5KBW+l9q?AH5?;78eDWu6TZm6A9nd{dpC) z$#H?Cm)>^oc8P@BN{$1;?fgSb?Q?ntlltjdXzEBQ;zzruk7vlVNRjAzlykPc0ckFx z`sZJjRs}4?=A}Vk@G=)iCKsdkZi2KYT3+qXUu=-ymJnAX{=-J_6`BcMP5D!onLsmx z%a~%|&^ab(lZepJ31`V~wFREB70QyV)#pfkUUK^Nv;mFGoeWR!6N0 zdvfXg{>dEerBj~y?>t(LtsAHCjzq7@Tl7$~qgQVw*vONb%YiVOsN2sZpys#iV5Y<# z?0ggxJyZYc12+by&slN9yiBrL6+Ht!7{$1N$5Yy&5rtspIJlzcy?Vi9sEwKDwEl4nm2~kx$ex!QxYxEGU5* z=!Z;Klnk+4`K0>!q8()ua5p=DPBMtk2G9j;2$+{(yPptmeW8r8Y!hnGQ#cx43)9-Z z`HPz<(mxsV-8tVwJhJLw?gdHk3?jbo%SSv2`hJ&Qw!Ap=6&)*-P9GP?S;k-?BLbeX zGf&w2x$uK1A&^@cSvS73piNNM{=G+a1ndU!m3HnQI(EEhq z({D#X9=sux4 z-t3EOQpg{I;7dp@zOQP+kt}G|&KV3j#r5mM_({|gIQNp4qJfc>`UK0|HOL@4;reM* zeDjYr*ua4Po{!rXM5)*n%HBi%DLLb;Qu&?tD=39TgP;aJiltVHx}x3}inq@t4`Ko< z)(gJxaCS=n`7bWV4fc4qXrTbKXFLCG%-*Hi&npq(z(9|$#3YN|jA!f6GlZT1I~iYk zNZnnA@?8ohcKi%t0VNxw+C_-c#_z4hV^y< zS$vtWEyd^FarnTiX9V2CxNh-Qd$wuL6yuwZY?>Hs_4eZop-i5y(uG9cM;A?A#~k*@ zzY4qi;)Ty^eLI>uq=HtKjmqw@L}2Fh69Ofn&?|#?t<9Yj9-JWtly3~J>77{{74|EZ zQxAwFP4Jcg%M;G$121J;K&>}Qt*0RsVrB4N2T`W;9_&&A2;T`Rp)<;j!NZ8TDlW8A5Fc0TE5pA% z!ItCQGwjasuE@gZ<|8*tG6!b$AUt*bm`r#q5nciT!LwjIEAi~D=Hh5xL&*kX`;P`i z!*xfaOhBFDOnZj~l;s*6i5BI7Ot1u*z#NxgQH`vWR$`Zsq>IAJfwM`B+A1N5Hc(AY zq4``fF2qphfvK%R9&(LgO%>=Biz2(|NT6XMn=<^iu2L}U=Np{B(&4MczKn0CMGy-R z;ssN+)?!&S9)F@fdS$w$d3vTC-a(xnw}O?b{3E^OaD?WWPetwt6>Moiie2{8vijVA z=1m73c}!+0K)ubl9pRvP?s>96EX=Vp!2O1|vb-enTUZ6{=)_=H8G|Wv>#Xzn|7L|w}e<(?`n&VU#X6A2cz!^ROA=& z_U7vYF7~b?Jfiwj>rk9LGjVINGSgy(gY7N?(RnnnLPE?!0(*IXa60X#C!7EN%L`i* zZ_wpFfa}ar>ZnfLURVGXOe8Ss=MwlzdOAgDGK5fii+7Q#PV|`h7%+ogWV9FR zxoS5TqB1->NDv`f7;icVrq+)x7AdSVj{ja&bhy7LHOwZL)uF|yGAWwyP72|LMQr;Q z;^Nl;?oOmEUW0mPot+nYQ>vjkjwlC`RB#B3>9Z|oD3&8Eb8j5*?kohUep#OU)(r?*Q9`Ir-AlNT@ zRX1OQZ(gE1rY^yA&b*8#c2jbi0@7g7>B05a1=l9aHkK5*J$jANnDlkHi>N)VH$U6a zpRbB4-HR9TqY4+S7EeipAa+bAd0#>k+iGYnoN`K)3ZK!_)7qwfe`P3FA{gdwJfEzo zQ6*S$o0MvE`K9E{tM%67`T(J_9UGJUQrmI@z+XcQrr+jQBDN9<%Xk>|frasX+Jy&0 zDq66=&}@>77!8;XbqNz;pvn+Vc=G%Y1GrtzO9gisOEa225&b}_8s!N#51L}0k6t$6 zJp&N@n~u(k5Y$RrUh+2D@S@-yg(>E{)JIHp@Wx(o9dQh?BWRHgaQDf-r3G?=+Zl}P zW6E9BK_sJ6RDhCawzNo56F#-lbi8ZqD&-z+7k}sgkI96BY04w~yliPDiLMD#pz;j$ zY-R>dVG^wutcG|*pheMhYB?J;f@pV7;Z;2Fz@Mn(V-hqclWWOu4RAE?V-ZI@G6GGM z9TD`SKR(Q+&v-}bhr^A4GF1{73sznFis5USZTW!h zN^aj@@?JQ_$DC-+8e4{V7e$sXjim{mMf%q<>n@JIx#=F=XE@E@3VfFYt$UpAKVhRd z*zX+Mr@ZBf=`fDcT#sN>QY=L3k|p#sBv2zLYjZr37aeW`xQH=umm3D(N#p{B9ERj$ z&SS`BzKz@zXjHU#Qt z^FMPMWP*K;@F`6bZ$Ti6pG-ra20jlrp8l8{*o1=BISykk*=HI9BQiTK;`+{9_UL4& zCR?-v^xbZX6c?>@=vynSv5TkbL`3;Z*v)s_V~$}Zl(};-nuyIB5B91HI06nEt;yYXwfF7&3iso6piR!pWp3M&Qy7s zIUmal(lWL}fD6)8%;-zyIYAye`5-fmI0&8pHmS~9o$T4`$kC$NV^6D#cv`RjH5mbw zxtg@|EbV1PlXU2zM@S#%4X#T2ehtUCV@fL(qn*R+j@tl0z*`cS_~qr&XpVUTrnsYr zH(cS4T(5T=l?xS&_wlaxr&u<=bDioNyXKBI2EE6OB7V02z#Q|Cay`yt{$neKP${nG zl$y*lx)!H$68$$mDSV4kcb>Hwsf!V1g__D>R!EP_VJMRZz#?-`FFl17M$!D%5V3+? zNCs@^pTsJ(oH+;yvj>S|zL0@sZRyudUuPKRy+n=R;^qrS0O(TkD+-0i>SljLGhEI< z$5cOd^XG(5LP_4U!w)9eOudyRhLKcovF!?0G5M{pJji(6vav*-hAaY)>e!7)SV$S- z4Q;vC&`yJ@w@_|pFRa*D*d+r_!q(`3*1=Tb1xdDDvMr)-U|g$lz!(|@-ZM(2k#SX$ zBnsNa0nC5A^y`5!e38FkBN9-19qwi`qS|S>#A-s?xT77>a1L3a!|3i8oy}IEpc}AM?Z@jS3dLekFIrD&n+cJG{g{3bJX{(sa(keJ!ugH> z-+#`_N*hP<$~ar=L|tP!YIh$3%L?a^^(WHqtYe1-a>ote(u|E}0z>w4;aMShwz7Y$ zOc$-He=)D<Yas1~2yDvju~ zBxSKu?4H)R>`bZsaC;H$gjRf7#NcH!m+(27k-&H;jiS7N(3A;lxqtz>pWrh4E*lsA zN)ytRIL?}7Z;YN;q7-~P5%^%5uGPDP|1LN&_411IV*>k`h$*H&vqrg7lqC6$gjEb1 z=J9nah2K4l=_5&oUIyWFd8byH_20cd4t~68)bn_BQ)hzPB{;UqtDVOiu7g%r;1W9X zaZCvLxPO!a&EGI>Se5Yw|Ao*3ha|@r6oa7)+xMu9VMq5&N z9}Vrn`K}ZCxmZ38!%*Qpkt?98WYDN__=Yy0>gMt=>`tRwzBVrDNafC&u5}DO72hb8 zv}tBFDlq7;P-EJ+N=sxMt!?(jWkZA4HzwZdzsGRunT(=ZUH9+)_ksyDw`^QL&Vn%_ zLSQAplQ7g0xg2j_k8p_t$3$tL6>|4nq!cgS;r=9>j@liOkGRAiFd) zh4|RzAiMm13j?aK#*}b30ivfb(*@|7dF9>XO~$4vfX81xFI0P&g&bTJDD}ipsjNO2 zr+aT2iLat)4&2qSk53gL6QVzak=xe+X67v@ymTr_^NX+!_zj=(17V7>rf5j>k3B-U z^CXXD!Vs40;3JcqhUKpX7C(wR_m}!BAt{{|T+73)$@qQK(iSj*&%i1e8!xyfhOo^T z>g$q?x7{H|u+;D3DKc^*HBFbFxu^4b*Ox7{ch-@u1ai~YWFdoCd26pY@gir;Zhb?b zK;_ckFu$a8(wBY@BrP!$4^Av&l)pV?^etwtjF&}gxU_ktfhWKSQQMhK)anN5<72W$ zxs(rjFtp-^b>q*Rf>oesKw{rl-&}+|h$ylwbXo;QAyJJO2kV1$8ZG%jWpE1qNl^2( z3=y+Vvr`LbcEF1&TTSR}m@{orT}`N2op+sm#QrhxY1a9BD*|Bhh-6QF7lV^XukzAR zmReAS$OK03p@&Tc*@%N=U*~A4G?R)*zBii)E)`y7d@Mv}L6%*E;2qMfm`;=uho6Lk zB}yTxB*kOdNH*n6c^WH041%+=9dKLB8qT5TYGKU6LA~WF4z>y)WY_);i|z2Mcz^v~ z{CkJ}5&N2n$tAC57=Shq^kPfMheK&DTbGaG{NI&RSieGlNb&jXu2}uCaB? zY+`&9fiB^!Ssg?3b#&%Cfwnpqfwu22FR;qJPYIBt3Q}F!x4S{Sh5prK=iY~cd!c4# z)FOnZDt?XQ%&>)%wjq!@UH-?Bc8r=Tlx-`V4};{h#KZ3b6^f*4CbN+`;Vz;xT8MY# zSS4uxIV;;cn7yKTVpIKCjRyb20h=tSk}qPyr&ljtv8{n@=4TO@Fo48Ga|L;R0zcZ{ z+^esjsKlDpb}V(rX+nxZ)yYA7T%%;a>09&lOfjZsVwqA(DU*JOu99xhFgh*KgxBuc<An@`)J2HlLG<+ zWSG$`eoV0zlZNizJ)8=|K_7=zO-olzpf^vS1bZCXQx21KkC1UK`0xj4yrXm`JeU_l z-(WQZFtDZGTbhH?mpl`|gO8Tv1Lqz6iifavs{E{X7En4tg!cUp!6L5cCoQnHR= z$JDR#sSym-(H|w4%IxhoaiMf6r^90R6F_7W^P#ahMy-t}1e(&+sV7YU#AFZe%g6IH z4Lk8_H`Rd)>%eTzke%9H*YI2K{uE@2SkbXA4-S9=C&mcWKHgbX=-bm3g1lrDLKx^+1l0O-P|_*6vhnl+ z9VR5p7LP06g+39e(8r2o+2r`GjcQJ8V5`9Yv!cN?<6>O4P|QIk7FD{-bn@ZWBuK=j z9?x)rbJ4yZE)Mn9SG^y@fo%$<%bbx(Bi`_~a-n}%0Yr{2cT7?HZ^kc;Kj`D4^Wvh8rAr5yyLJ5x(P4Rz3}ATs)*f}$_T#2Lq%~HtDzomGgc^7gZFg26O&_aj6u?uq%;)w900;2x(7V^$r2gfJE^zBeLeF_Wb zItArE_E;V=g3cJC?UQ1;I?;2vhp&8|Kl74r%(YfG&a3e>mMKEfbtgEP@sJyf4Ho_? z%oM4Yr(D|W^vj?F%`u5g%a%X1g`#)$cJeYgHcPQB_7XUa=j9$8rq-S^%LdG!t5cEs zL|s)~U9}X}t0CCBjeF%l1%lcKtcP_$~7B;g!tr7iZ_(9_qJECm2(Lhb)V?X zu@3t)&IbhvA-S~8hzdfC4!Snifv%fx0|!vg@Cw$B7;>dsvDfhu%*WxNY^4Y%`kcRe z9~E$R-2q#dUQ(FEPSNGH;Sd?r5xNO^Yb=kJ9F59+k+qP}n?y_y$x^-VBV&*5D zhZC_QbLF?vV||cq(SmiDOnSMsIBmPb7ZW?_Hqun zI7zQM6bj-`>S{~FOdCXX0CcjI>V`GA2$oMQ`jZ=#dwk|6;1{T<=u{(<5?ie%-lQOs zB0Y={SM`h$CA%2P?N-UM<4B6G3UxFVyvg!a4XMGfmdRgu+NZKq^iMceU!WT+R*-oa zMM0UcD_k#2)@bCCx{B0j{W;)LH|fmlXFYRm{@KD;y-dX=m(!tHrjxnO`ov>m7I8e4SND%^-UMV#2+F`gGjYs`vSv+u(5=1BCvT zyPoi)oiAcN7`A+tXHmEI8(!p3_2li|eXSEzy7PB}e!3XL#<`?r&|5tQ!(M`%a*K`B ze|GqjKUV|$)h^>Tfg$gtj0UReh7?VEH3g|8I5p~xwc~aNa};;V{?bSkP@yV>NRj) zLNN+z1Nn2RA6?r^T1~jBNp_K5tyF(Qs=-k!n{6w@1GxJFHi~~!>V_5ltZpzhdyC~g z78eM_keFiDB?&a8T}%pYk4nQHUB!6%I|f`B@J9!4P@JCLZ}HI}ukzGV5z>=bsu!C{ zVcO@EVifKe^lS$P8LB(%A!;N0Ghyh%@17&~94&8CNr0A!eD^|b{pXrMJuNNR zFit!~lZK%D1nvFTLQ-W5VscfNfImu>PNG*My`NW!Cs~~HEB#xmD}!67osd8H{~btK zuPN26{Iw{U|JR~m`%fSx zoyC!}I55pzV1J&)!=p`|{5nefuwm!*`mEIbI^V;sU0W5I7390Jsi~Uy&a?bED~$Dd z`}f44z4kc<%;){uf+6>Qcg1$L-}Bx7bT{Se{(5>4>T|kYzNI=GHu&8IcT?fLQsQZ7 zb&lWub`ToN=MlEz!X2zO%@r9tirvN}v z-(6PuoCOa!IdZ2F>IS91d3ewqnl*ZBA;rGcZnm4!ef$#VE zg51xM3;GuV-h#)+f>>{xYxYH3t~DCs=Jv8dW#tC%*W8BA#Rxd^MGbW=**^X50><;A zMNe%c#v9JoqY%8mzYyB2wDg0s%G+8AmG9dedGG6q?&p1?T>h}G7YJ&~lA%XY&LaA# z9{xw{!YJF0tqrR8JI05$_NPP#yDV4lw}=_9uP4-7Wkt=yb==?>!EL@-ETJz~AG*F1 z9iAQHZ>5&U`n&1uMrfQWgKcLQ%oS=+rmCS2rGd_2r~FVnJnel$+xE#D{_Yh@rZ0Xe z+C;QEw{ELD6E2)H#Y05EWeKAJ7iiAV$wAJjrBC^Y65hu3J$J4~*!Mr@gOtg|;qNTm z5Zaj8yWHym87DO;uDzF6Uvqe_AdjhfC+B};o#i9w!yJbzHdyy=HS1MeICXP3viZgA zHE;FU4-K77t1GJ#g5KK7-$(hG^M#|xLI2Q!XEW~_fVSZrXF_LYH>5w5ww>5#=vA!Q z&irU~v~pbA1MYKG?6@a>UB#oa)EYP>&_Z5viYv z;zm0gW3DM`RoHs3Ft=ihoK)(k?Pd>Y#n{6&t?Ddj&x=KQtvzWl4I z8j6c0MGauauxE9SAgS#T!G@7F+PCmDeX(diGCem6%1W|OV%BkmXTTMChK_2^9J}OC z#Q6kgbnnCk$0We%-3x1Km=CvimtkCkB`aRq%gf@K7A!&#u&5gXg!5E<+$yhD=y}CvA=FJ4XJq`k0?-E89P@vexlWf{g(kt6cPSuD zR2l=H!}MYJoki;pfYq@1(Vh#2aU(%W6Nvdy@#Pm)-MpI)pr{GMfleWwk}sO`6$bgK z`kc_b9pm_UTt@lFt;{JyVo{mhvnPA{}Pc{c!AXhy0h0Wy;^y|%21!6P{0_vp#UdL#R zt}O%DJ2ZLF?8IAn0`O3=u_6(dM#VO51S(u^P-ZrqB%g2Rja(g!H`uh(73 z!YE)hgQR3HFHSJEhLk*_7;r47h=liOQbNClu-Y=ho&-&+1F&ZIQDmN6@BXlF0YXbM z7c%vELEb;dxU+y10^Z%7#}OLu>NwC32slkDweB^aU_D)}mAH*Cu8Vn-ElbSlNQe6x z;5-;U-^=Ft10qNcj8%tI$I)-i6vDYRf<31R~TJ#CDf7l!2EG%$;CvKRTWDPc~FEnnTrvGfOvuT4vuN^|iV( zF-Bl;yUv&Z4NRP>k_7UY^zg zGj8$xpuW`QA7S^9^fS|UsvDG_V&Bs+G;BG>i)UH}+(09GoK|HJJ0A%c<_s0LRVsCEn zdZoju`gC)0@hVeY*sKOzCf@2ki*S`~JB%t|g>IzKS*2Iy@4oDXgsk@P`XiFpj9aP4N2tmQvOoH)jj94PH=**XdwtcH!U63yqbebRCu=x3w})vx_tx;reBoHhPZ(O_w#czL zs?&cf6|oOMd~~oWLo{{}>3MAXfoz|pS&Fau2Dtlf&dU{UwHUh;j@ikf_Ze&yGgF1= zUEoUUr+-$L_99_j{1f%TpKssR(d+4s*QLxn)WlJ%Tkc4A`!3MCP8|_tX46~WEP3iv zG_^U8WjBoDjW^5*_h1WNf&T7gO9GCAC32p14ImNk20eAoUpibeBB^BKTuhn1#=NK+ zVE&Ff3e^SZ@%!c?-F$v_YsE^2A8q7>5}uQcG!ft9zNg zgHMhJ7s;rS_%D4Dm%pG538S7|nO%BUT0=U`car(?v$*fQ01OTopA7^0Tq=^wc<(`b z_}siivtV6?Gl%2cr9Am70+Qrm#L!5N-E+HRW(1)7p4pKR$kUHUbf+?XjWLwi0&J zCHKTJ8iu)YC;eRZ`mAXD7vs-1^D&fT{ITc1{Ro8QUeSeGKc`hCz_N=V&?>N){j!bI zZIT(c(ul1rOFSU3)J$Fxg+6(Tv`NQFOw$S*F~Hn`_~nP@{qGbR2ru@ULGO|0yu2JNs;xJZpFGCl#bU=)CO|Daq?Nt9DN z8Y0TXX@?s@kF3IhQtQK=G>N6mp}@nXMoa4h-mq^g>9Ps|^v={@D4e%b^G~bZY7+9Q z=)X0U@_~gX{)2=+qkLVDT;8q05Sl#IEMQx2MeL*c+lD#Of|k``d4IztK{rO8gkK^~ zQ}e_dHMTY}L#3K;#sn}UNANYhyd2lt*QJKD!UK$_H}Qt82w!#aq%C)>0?-~EkKcgd zQM^HU=#ssJSd&uVGK3-Mubwl!OSGe681f64L`jv?{&tG(M5e@r2X*BVQH$_M1>C0% zNNYUqqGUZ9*CQBUYD|7AkBM>~iU!EdShr1K*b^)whu%0#kK8E37&!-`aDu_hT{iur zsxDhP8nx4W?|*WvM|3{}$kLJ=(wq#~d;eEK!5e7624SEmacE#{2aYU6jXDU?S5@NG=kGDgt?LduCj~3g!snbvOqGSY@_KpvydPHfXAyyxEKaJd&E4{Lgp;`7 zt@_G3UbfC5*KES;z+-U3%di`AZ3!-DGXgJdEh~_7TMDWO);7>&?KBQ zpT<=6+dH*$EC%A1nlUBwZCQG}zKeC}9?*rxRlc}_pmjDXoKv)li$>_ytmRSt`2G$@ zRyd?F9T)SbtD2UVk`^tf1HX#qIgtfANw)eFSTacj?LmM41y;mQe0T z4UrY=Ez2nCX$22<57kdhn+1R{a$l|~W!MJO^ry$AwvL>yik^HoA+=YvLD{oUQ96mn zOzsb{qSus~{_Hh1BYz1mo~}EW0Z4q!2bIcKJ>g<=tJ!Xo%vkBs!A*ZLkC46&PeObW zbo51Hc%cYxspkp{0@V}{I!_JZUGw^xM~VIuwq=vz`I`WgsKp>)2)hi>0Z1~~5~B!h70qShHD0BqgIm=HAilFSu4_MG3e=JW*1vV? z+cZqO^EljA|GpGgUoMyybFCtA7sw?1Fgn-|9jB94uhhVvkS?-ST$8O}R$F30ZgL*U zu{~U@soZ4kDv}^4(izsGbHk`A8(eZlRoJ+nwsQ_(hzeu8vPfbsf^@-_Op$@Vh+IC? zq%))f!q-kXn+(lc+}!t-f>1)LjxAbbZ2XJPc3x#YD!Dr-5@RQ8Sjg;=GBww-%2j9H zolQ?M-t)rj-ZC^^B{6S;61|NjFbpcCp%f*-YqE*8{)2b@#=7qa zOvpUPeR=aCv*8zUi;rifx)H*m+Aw`r0riMQ+>1dAGLtV~o@4;jbNb<(3;HSpd&FSu zNJMA(zI*vm-xK|oVe`5TLb0ka!>0JtQf}R&Q9zM7(V2Cr?h{`>+b1tE)iu~Sb2;?S zNTQZM+Qv>2#qG;+aKMSeR5mSA2b7iGC$p^#RBCClAw5r21aTlq1_}pmTrVk96Lf}a zCG5IclCLhjd{(&tMJ%loy>6@B-@bVr91=fE`MbjB+8R665n5KfYpX)mu+`JZUmSFz zpjl7f2_%D`;w5iv9Nf~tVl<}{r=z{IkgB9Lw*L)l-cSFUT(c>ES_mcmh?bPV_{MTl zoxi_x#1q$<0mt{!2N-F@?&2~_nLF_$Fc8FKbXYH2!jgirHDj`bz>f#>^hK$;*Q6fH z!c4w9;^CYu{M|<-Q%@hY1$~=PM`ikh1;4bWN&})MoMHptiGKuJ2C%CItB{^=u(owX zHZD^wRPDrZnP_fz=(v;MM?s%6*g=+|j#=<|@H40;i44k0!9VYqD8eE+F%ZxmOIWL& zoG4;}z9&@r0rC-!xM9dgeU8-3N&h=Ii=nRV9@)RUYCvWS9&wUBAapuw7}Z8U1%1Fu zwHPl#g@#_`aIn*WFTrdLS99-+B`OXRLaUyPcUEbd&hW(qz6&VWDw#+U%`ZWBfeY|2 zc5TH2pnX<`_7yOPMRZ!QkzRrw4N}t@b+y!Zf669RUlJ8`W=ae}Dz>tOO_ZF8-0EEx z#C?J(-l2CIVKj_ZPLnm};WOT*7lipRVmrB1`-rhm5E0U?Mlp!G5gB(GoYb>DWs*?T zmKOR+S-1$XPb*2BP#Q3o_Px2%Kz2=#P)@i0a5Z5Z`m&=XPU+Tg+LKAu*9TM8m`r2Z zh_kD`h3o3qx`eKfD$hY-G6Vt4GIs##0ft@|TjAp1eZ$NqWiIws81`R%wTx}StTdRkncvpb7dtYXnbQO<<5-4RC0py*kCo``a7E%9NvGw%|(*sC9SGv!QXpv}GprkLP7{@lR~X95X|0#X2vS5lDvDipH3g}}AdPjr z6&|(U*~wDU4?G~Rj1r0e=4FS(XX~CsugNRVo#^L<`%CsUn(#7|Ue)sKk0;8BJ7y`y zhZrd?07@6p@Jv^E+nJ~)A6dMf9kIKX4|IsY&O&sDSkDXS5qS}H7E~L?@snQ=Dp9S4 z5-N34?#WYqHc5JPM{`$;+EqPd6<>H?DvBh9ljcRP?-MOQfM7O=T0%|Qw`?DlD0uC} zYgdCYDM8uY>oX!3qZh?8BTZw|MAup+!+19O+I$sRM0wqrO#JrP$grLAhkF!@_DvAP z44)42>4gopnFCq#B$!lIS60V!_y4unLMNohMq6z~5%X?hBq3MYB;TT`^4}=tK1^ zUI$QSFNXv>I!IW zMOnh*2yWCjWPxQ^v9?j{(|H=QL{Jk1|0!fx6?)vR*{D&i|E4IS*}BM|I~KJuG$ml? zRB=c;G?-M9egD-t-agaz0day`Sahg$XG)OjWtRKVqY;kj-`B7W3iGm;_;}ZoP`$+; zG`k@zM6JJ;bUK*a>om~NbzW0hmIP9-s}TbiO&h9R1Rhk281jHuA~;H9y&wo%0XGba zS}yeFdd6vx>1vw`>4Sn4Yp2gP*|9ZKP4;&WI#Fs&`>CqU1=>OL;YWOf)G5aKqAoTB z3KF>roaIJH$^>(+YV3pp7R}z%_OL24@!I=*@UJgbm}{8wUd|p>RTQ1o7C&vFsKBZ# zXOXSeW7yjO=iKExP|&(hTV4NovItV+1nhD;Z2mJ=Uj$QN?NC%(pUN~_iO+?d6m+_s zi?`Y(t+ZA?3f?d{l+a9f<2d)g>^Idh54ExUJIjO2JV0bcs!h@|D+*nH7Yn1U*tvYM zeNg^3&bZlAh-fhhGqu3W@5M_C`k@w9d3g5tz4TXItAJJ7{>PAuZIm#67%S zCyudB3hppIQVKa9nnXQW?0TVh%T%GTuu4ZxB4+)Ks!P@$YG|&wOS@G5tPOoW%tq5P z>6V?VgW6aeFpMUfO2x&U(7sSXdbp5#jtl^^*m?$b+%LHvw_haj#_Plbp8oR8QS&Or zMr!l|kDDDH+&_2oqz$~iZ7~*JM>{ll*Gtng8m;f&+ z?1&AeTl(kxQmM%i4isg}72t`G^k(^^5hmM_SQSgRLbZ_;f7M&s@t8IrZ7zURYUE#m zih6vj8a5`j#f$2VkelV2(x9SS1C@`=nQ^GWEo2LBtdU__Sd^TpQjZc^tt{!ViP*Rg z5rpQG2X1KU(hlQ_gZA1g(P+~pX=2gM??~BvH)-$L`=XxB*=D`6wW1gI{eDC-V19_7 z1ylInv6SE?9zKoQt~@2%lYhXR*mCn}A6{P-H-YD6R|D<3npV}6)BUFRlBPjG22kCp zLe*;g;bP?Wr+HRR%krnN%aGfl>7Dj{BK%OP?Y2uj;3MI}ZZ0Wm6x^H@!rX(c4v>`4 zCoOW`OSxw6O@aR?Z6OQ45bJ71l!J}WzGT30eoN0g=aY!?TJD?7s9!*u*d5vUCC|q_ zx(31fn>Uc%+q|U@qG{}M`fk`(1+2&11~CLup-lAFdQe+Kd$62Z9L97(=nGObQ)z}p zJI8wiy9AbLu?V=|D3mLGHcD-!O>y=d{Odr366ZEo$)>`P#7(bNNcpsC;K?zc%)eLI z>R9M*11eb<4|ChUFo4`bzda05kE`ZfGGJ==gz9}(POC{`bG+>J!??li_ka5FN(b}X ztZ1yIPI^#pRDlQ1oOYXT|-bh&-79tw4-*|pkj4*aDEe;$xyLh;mX7bg~bZ^k^54F!}U(tm1Nz3T8vSn*^w6 zss81N&EckH(%-wB@y76F_dSWP)UWRY`Us~*-~R@>h&^7H&eKd zqK;?5_35N@8Di#4u>@1B+OxNcY6Fi>`6ru6(Kzm$Vcr5`e`)cMe<*|QXPD#%TMlw6 zk2DN)k>9LEfG`lxmOUU!jWkJfu)Ds6U=_?EhkYM`>9=eGN&Sj}v+|c^P}lEv6;Wo@-{!1NeWO!H=-v2{EB?=dk?5ZyTp?0(>k1iZ(g|@+xYET8DW=N!ffT~*S(Qyb!6w*pW=_#ohjP|JNH6$ zLiEwA_(bwGhQt&WS`p+DlN#D6Dv#_QPTD}%wJOOTuad5joxD=E{#rYG=dwrIFx4@o zTuIkj4aAEyPblZ~ib@?(undvdjWd->$KvO@B^q_8{j@b+7-FkXTLZ*$bRYUj^BJ(R z3amtBe5C#B69Mry zM9c)?u@DxQ__?a2m+K=XkLb|HK)Fa!QxW~n{!xFAM14o2-m(S{;iFhiA1z$`j}}LK zj#pe`=rK*n)b@9?hw@q2KT_Zvn2!^WrP*tWd|1erQ+4)FzpQ){=@q!T5x||t9-mp| zVO*ZMA2?9EsVU?fg$*+5H9R;f-Q*0-JUlnx3%U>S@hbCM1jD}E0Uy+`8N`_J zh!eLMK4{WTmoe`{?KI4>fX|k zpVnS*uj+2N|I_t+=lk!){tiBVECwL}0JqHlNE7V;S?nhqw*0>|VRv3^N;I*R(A-kg zZYG#AqIh#|Vs5o2hh0WgA&x5X4}_z5z4QzG1NuekIco}J{2Y@~5FX1})t?}4Y;rs? z+~@oLq=j-jh;XUiv)=vZxmyOY!~4(0^{c_d%8KvzmRKfHbPu&Ra_6nV!tnH@+~$K= zuJ6a%g|F93McGKp+abpf4ZTvTj#Y*IW$yM?_Uy^V19+=F`*!!w-6;Of*AxRb?j!T# z!nK8w_A@x<$H&X|$1UwMWvrF2{y^+?&$A)vkJpz9-X`0P7vJ&c;IFQ*^CWaxVx#+k znE9oR>{IhnKRH{n$l7~*`{8=i>zYctr53C_OD$y^(@T#RxP$Y%(!V_-pB?qE8X(VA z>A@eA|GfJC{(j5$dG0FjRAK<>Vv9~CE20XrSBgr-3&0zkJ=o&ib6!G#qhmGRyfNVZ ziYe$kI&tm2a_1d|RPR4`F<^o{kH3l@PV+s|9D>V#NS@epLEf+`peknQ!}WcI_v!jJ-hXj9lKSo z=33uX7B=W7r?mQ@9O-?awEyRRtW(Du9yat(PDR?Wzw?`cQYwDWOF#b4K`g${?HoSu z`njkGSDdNZ&xUWq8xdOl2HMUrnN=hsS}Hqi-O`!es!fEWN+~Z){vV%J zc=orA6IY(x_t_5f2%)Tw1`KLGG}OQABj!~RjdCIpA{<(e*ja2%`W6${V7-t1xlp=U z2lCq;__r$PlSqx^KVV4aw4ga{J_{F6C(vw)QT1i#tii`|y5Z*ZwsWBDcz;aTmu&;8 z4()LwZb}-g2I|u_&@Iw7Z;gHteVJ~)z3f#ipGzgc)*xepr&qi4H=-!I??^hH90p2WWtmB5AQVgWzbPvwsu{M%_ zexY1TJj-09)_n5YGiF(9)lbY?EL*ll`T$x9)zS8E#ye+NE11eqwSXN}k;9Ny^|myh zr}CP-YHTkhS8f_|Q$I#YsoKdk3Q9VK90!Fxvy zzG0I?tImZf-A0jw`e z3umSjTIOE&$`bWEJ5G6U*mg!3kUve~f6yn68&snEGGgU_OAPO3%kh9?Ya>1utdMv9 zYF@${=9X^H#xON`A7LI1(cHaG!P@^L=MDrrS>#zSqp5m2xjXKp?|UQdh{+_`xdXsq zyMSNhCGrOpPS>3a6kVJE|{U-8+;JXo8AmE*b?sw(e&k}5m zwYF>eivc?wC&szIL3gT2KwU3W=9O+z7&IVMIM`Ne$7{^(O7ug#X!i$<11Bcb*EaoJ{-#D=VJk2N04Gu{qjNIC<{1MZ&_J z)q>p3bhJ;acywk^kvB=J-23La{h8vUmj(7IA3Wkk@L20zvX0_*7`Ep%0&kr$`>k{h zWE!jVp1e>>R{fjq0R!uDA=TW9;CLIhpS^j*D+A1Mk61PzoatI$ZKhi$r}9$mR}- zN8)t8n-Xxl{w{Gg#}cN?$D(bPQOOI$yrNq#)cak+04nNpXFC9KyOJnbhxlY4mXOJbQ`1N1r-)67~X| z;8h0x+^c{%6nDvFd^j}Vkt7f$-WR(Ah~BM_jbWV#RKItojr4|!DHvRI49t{5_yu69 zq9bcwVOS95#&V`i)hNY}h=xO_`LnvjcmTou?%-gtObJ+PUz9;Q-1r4z0nvxSJ48c* z1)5f^sBVzSeayAf?Z0@eY(rrZJX`~!y;F7&ZfhXoyplJX<{#D8)kR|e`FgyJ&n9sW zRtU$jUA>OCMx@;0>P+98N~wyM3&d?@XS%eY6LfgHE^p~@iBMtgu1-AE(5tULl?!xO zg20_60blHcVCpX|Y4C_{Z8|4S3Q0!`buKPuynZjq6P!hOVLLBtHNlWH+-BvbHL0PB zSX}>X)w(g3&01MZx_&Qpnmm*-MKfisQW&(ouoN2_Mp{NK+s)enS#Ln01TOG9sH_e= zCkJPOMQ*vG#qko;-{EIvxW4i(t)+FgWY!*$At-=RE7^%159 z&orZ{3wVyRh->|jGSg|w`RMR;n)IKvwEm*&fGJNAkqC``wXrN(b80uZiV8Srhaih; z54nxCVvsCZVneZeK0bM7XDNiUR4(#9n8$f|Lb#Il1Q{s&+(J=OAcw-M_^k_2jrhq3CT;M~ zMY(m+f`Hg}KD3cds3+Btj|(GCnv!A!yv4Q$9d5MofPlcxA|)*bpwP{FV*R19;vIMf*D%~Ssl;FL+}xqI=n zX}vKvprS=`jj)s#abU+~icc72(++oE_Y=usYJEN1nh6nAvtM!Ng0R ziu#3UrHPh-g^5oghvr~^z11RdzR1G~=q>Q8UfQM+i6SGi0T_0y5BcWww z9|T72?dPWooA8uVaFovN%D9t&+0l+rB%!f;AM>Hf0P-d!?s(ogYKt{9IW~`To#OLo z-o|W#k@uH+wy8Mk%0QH6NYX!HL7W*QY_^q{vjrqD%r^` z7hR)}U4bpVqNV{*FqvY3K@18J#txl5vPelQTp8-$liiyL?dSnJb|1Gb3H8%Eo@dOV{qx%X8f&A6OQ zUdk{t1D3fTVG&^XM{%(Xdt04?s+K`n)(vruhYb@d>5Ggknwn8_42ira6)D7;(oxEp zEp=9pR3&DtARjEdebMO{hBrw&3^tLB4sb;GxF=#tj$lD0<{>+DrA}o?z)Flu{`A-S zLK(XQ>cAK&&py7~!szRcQmWf|H<6jS3Q$T9v~eIM0HNy2X)~kq3UGXbVkaiXBO?<< zhX)5dq6AbBwgO+M7Yw5;FMoHk5 zlY_kuIYo()Wz6+o(%oA`eOzno3%WoouSuvSF?%Xf0rLI;=>hr^iU}z9Ws(XzP9Kn* z1)Ne54Nr|=4{j=4w=xA2Nkh*toV*!la|afMkPDjn*jFG66_BDl%)G*-9^|WmY=)dS z9YPVY3t$e=EaOsxwo;2=arYJ(mTLaF5EU+Tfs6f3-~0K9rzjKX{`Pp-zY*uK)y57A z1x>s{!2OAqQA@90mZu^-vp>}$PFaZ!bIK?8URnTUBKhY!2Op95rVm|-T3#L}rjgDr z-cx3zPZM23BwUy3iuD-0%P=1EM4uMibhr*1tK6O>vQoMRvcsqW80H8C(DWj*6`6{} zUpa?Gwn(L=U%(Ow?;DbSxN@t-Oe*ipK5GY$=OY+qod;^UzPYr;E$qiHDhE`ChTju5 zk{}$^xhH%Fyu;f-)9C+HP`@#KNh0Cv?9CgDFNxCh-K_UM0s zD?+Hii(sV0Df3M*#QQ3Zgu?}$BZx=)v?#66P=Pthpe6}azT2kqLwbRlOsphhB9}Bt zkSFoDuqbYWFW0ar@d@kK@-aS$&8_n+d+4E!ctpoFqdR^EO-Tq^MgLc><~8184|H*M z>>&U@X<~5Wz=$5XqE9+c5Q7ONU;mPOu|cj%&UFdm&D$8ffFT$$`^+gGmi>5JE1TU? zpjHkIVph_T>id2Aq_&5y$48_br^g`3Ke`#E;YM#8Pi^R7bj@ zvR9B%F_R^QAKI_b&Z-|4kvMQpgLjVA)C*vt&P;NKE~VU-t_sckn)q0^H)>@k+_AP=!%&<1L`CzTXWV!PZNPdda`CL z%0_t=2}91pn>==&s+4i+{wz!s`#Cc+QH&?1LI9x(gU?0Flt`tPs^TXe$ht_xv`4#D zWJI6K)cYfmZFpC1g@dFVr&NAsZ6x9O8Lrn1Q>-WxAO^!+53TkuTtGFfuW;gnT@x%m zQ-U$Z&Z3~}tmCVTy8;SgDZ#&;G{5!;3exV7psKnPs&w~s{hgM?h0M)P5Ghsvc5sJy zK+s#Za=mi z?wYH~WmWT#w-P>FizO%!)Cs#o_EW-B=^ly&0 zk+I^(snzen-B=VaByVNM!BMW<0K}G|6Tn?ab${`e=)O(h9gw1BP)+&}93hXgu2sd( zNqHidj7Q;yk8)b3Tb84rR-!MI^dKmSng~i69@U4=*5g?pQ4EaCY!Vr`1PJYvntl%t z8=*PYNMAdeP2kE-tzsO;Bqa}tG)oxr$i;p3ziFt7LSYR&MxbD;%`W-i{_aQ7BTx+> z7K6kHS8>~Gn?o!F*p@VUwvMI{@x%0-&(-0{nrTR}KCAYO-?B#Yort3aI+D6ggfH z7X9%#Yf72{pp81hKHFy3{6WYqZ<;mGou=ns#IIL|Vzm{>bG#l58}=wTv=4~9GFFv*{mmpr2G zMrR6Se?M+=KCw#-T(ttV6H9lhbN#`fu%*fSvzAgYa|7o7^5P6^+cxiWhNi-iyGQ58 zvBL-qVNF~A+H_sUt?98lR@PA0A^l0*+rjo(;Vpt(nyS|hHl4)-*}yg1L}^d#p0I`u zEauCFF;cEV46`BSQ{`Z+ZQz2F3kg7a_hu`BbLZ03ps5w@YKw87^w$?m&|BQ^F<0s9FeXSiF(+UbhlT4eR|`4HW)MSXuy-!>Au#w7CDTh%u<6YHV(qb@e~0GPGAE{y=#yc zNo{igr}!`!-m`u6*W_cKTm+_-9!WI3*&3MXNOirJg$;_a+An@rQJrr`&eP$nE;j#H zaGYM;2QqW924>iFjmvsku>v}7X zwW)GT@HMfb%G^lbJ_x#~Xol`mbN6Me!&7T0gC}-g-!^zas@5r>@U{A2mm_aOfd9)c;Z`~xD?BecL zvSPfcoFaPn%#Pjm9K_9ea9^QxK?FmYDyy0C39pPxkMX!axK1X1lKW36b>5m>L~fcQ z@E?jn4D=Eb&Xd=~r8JNjWZzvu`;Uq&N?KElZUAG=tBG;tRx2h_Mqv`rBrBrw+iQxi zCPt)#{g=RB6KJ6TmcdC6iN+C%LSBGPrm(-bH5M9O0GZ4eSuH5AnpEkd5ZvolQdepe zE*QGhO}KF+NbW)lvNJa6&%?85jI>dnX}B*s5Qy1g(&C8iU;c#9Iu&WT6Z)r2dUq-G z=?}b31t)Gsn}UQWJGdb0%;az&+HF1mp)c`TvmiGM$M!z1xo$PfFmnY@i4uAra+Jf> zmd6iik?lh4aIW;BDJFX-+@GXZ^%=@!x=DqzFf1!>n2w%FS*5_JN&3W!g zElIJAh#fK%ZP_t_TFOR;$?W7vRSq~8#d4b8?<-E*fmltk^LYJxN=@A0_##}HyrM2# z1R&>_QBphKo*aDcqy%Pe$mYy_$CW1Rl2CXb+0*|uJw$lX-KC?&UP8) zO7kUhp4ck8nb&ZM0swt7QDVx?_fUM^G;9U4m3HjrvMw?AUc4vA0?OYJM}72_r#&9yV3|@O1_IA|IzY1%|~>%ORM7>Ca1Q z>&%1kMCwsb_`T)Y)IW~0A<4Wlp;j&ngh|`_7o8T(ikn_rSSWul5?8@oKjxXmjEYx; zHAy_fS}+YPQBzul&;#ks5t|V&ES0`qm2(p;j=LSx)1nDvE0-j*>v*2q=;LJ$ruP|7 zdoA*ZtD4AMVrD*AH=I9h?_DP~_Z}6aHMK`aonacY+$Nsz_xEiZ=Y|!W?T2@Kf*#rW z(64$?IsoSY1{)cDaqyK5quoeC{B3YiqISK~M27|;0FpGYJj3=s}o7I zH$k6ML^coMEStl16pYF$Rl@Fc*(}#7{Dra?WW_rUen3=Uf0sUcjzjoIB<#ellIB=z z9>}sPAw)-4q`tAr+6m2JqOUYSD&DiHfqJk;0Wm^3aT z$Rg9+{_>{mu5ET>hME39OIw#mqQ#gtBJTBkN2i&1Tngky)K#A zPgd%jWQrc*8B9gcmX8ODuuXMC7dG5lCHu2kDm4Gc)j22$0&PpSY}>YN+qP}nUAAr8 zwr$(Cy6k#==S{@Koxj-UWae5m^9}vwDZDf|UAk#m*SSo*INI!LFgs-(VTtU`Ungd_ zqZE5?mV5OF_OLJ@oeVIwi%sj)lvyAE3>Sg>PVuQ*Le#bGEbb7vbH%k87X_2RL zsu%&Qlhd>AFX%RdQzLI$oKGjWfYN0}Ozr#>4Vi$9@P@jbXQX_UzA6m>S8Tvje3 zO+C;bjUJ!D`L(V_FYVFlN1EHJb~-Irp`P?ExNsZkD1Rb=KexcE_(KPzPz5l zfoO?cMB|j25M~f+X!Nzc2e#cQF#8?C554js8Jg{LN_ ze9)>b-}zK5K)##ppGJsbHK23>mi!S2eH!6_8y~dl04DycQoHi^F2yD%Wz9Kj;8|B> ziTkG1=WR{rsZP53*CONxHBH>hSYSHIy`|$^U)sZeZxu6cSH`$10~PxTEqg^uuNKoZ z0%<Dc5vd|=_l`x+8b zdAEFQM--l3-Oc0py{?WLdZYeat&CL6$BomkNc0XzVAa0vQjX>Gddf6+4X&C|VdYlN zw`_%c?h@#fen#g~AD1inpXcje!2fPhXdLVKp5Xxiw2A+JEeg*6ZBdlyY$g7$ucQB) zNlC;zwAm+tA`xn{u{c3;g4&7p!m_ASafbrlKk%QhV@v)Ee5-FC{wVF5GeZ*~vyjbb zi2hiHole!0)AK>;@vUjiR(bc6Fl3!~gQwfCp3=81PW3!ip6&PhGD_dCn{w&AbCR{; zQJzhA+vla(<11>e?|Y~U|MzRG5pV1C!uUt~P*T^cv0|*@kBhT2S5B=wzV6t8$K!pH zJYR?Bj5V9r0`Z=FR}{7I3jXn?KCj1pSJrx&kLf2f{MXxQ2)6b6*~p`h<6igcx5ufy z9Uf2jMcDd3ByIb@9);v!+}x;j?lYOi&otmAqggRqb4DGB2i+>erG&K!Teb@YDjA3Wck z{-f$h@e`~$r0`PUPhODzjcJI69@h$8Nd6d?N4M`G9nvS@uI3N zhB(gzZhdwVcBM*e3-(l<@KSP1)nv}Au4g3fv3ok!ccatU)uASpaxew%-Tg^kJ5+n$ z7tR$r>HD&gPu3gw8O}q@AJ{}wCb*Y9&@wJqiuB6W?Mmgc$N0qVBH19M5V9#c0 zrD}n-B&)6j1y3qSf=M0?O zppm%Rj>i?^+lK1{)^%ahERN74ME;|{^nX>MhiI_Nk?kqo_nFn+US{|keh)c@*Nu{r zMd81N3_qY#Q+%$3O#9etq4;`yALHf^@{*uY-q@^*?qQR|N^pa&#JZ!ULT#1`u_;jS z2a5AcST+|8{LFBSgEKvLbR{NQ7rK!DY>HYKxR<_7+F7|%$#^D>wP+Yj)!k$6t_uzJ zj@VMd4R!Dg3z|%g-4uxW4Cu4Nb&aUY=Fdwt*n5;;76y4hwZyeP)qReJz`f>NK5FIX zR>Ia&!VBNywqft%qO9Z^grK9X9EyJ7)Rlc{O=c)@aioL!in!iRHs{p~Rd*h4%DMWt zu=>$h03;7+z&8r;!Sos9lZyjOD%!@asTK@^892#3_uv~L-BB6{-NR`pM1%>0Un-9c z9L*MC_gLU?ci$XGburvpzm;I6fupEv%63nvo3HTQ9?w$P8!!#0z5p9+r1qtT-NwnO zs`NsRX+6Wq8dV?w?|yqhh(9U8{1AtEN@P2SP@?GpO=m1=dST6|}2g=h? z3!xfrygt;bG(%9V<)4;!-imOus*}8h!=g;v)i0a`Mk3AP@GA1#MM9;0y-+O`i&IXgO{?_<# zi)2t=uZWA<;N7*rs{F?j-zV`(gnDh{^q+gvw7trb*a+7Rb@XxTpLS?HOYasOfpTLh zudLGQt0804DeMyz)J2|KKFS=18_XgODv^|6^57&)NceL$E*RNo=>YHyWa#^-XD!bY zdfL%f@+wq?8Ac*o((`JLz`2gZIA>ol6Y`&TD7WWF6a2f$u1IjsK&E-qHKB=g^Ac2yvcONj?L z1YHvD1i-Lez>zM@gg=Yvpd<5VM z^d~nIm6!nZmMy26g3Hm9NRe*+QbImlM!cp z(?7pD05M`_z0lT}->xrPl#nkl z$b}wGl`WcpzJ!ea7c11hh)R@H`amxV%W~O(*b`KpTK;1`cUpEYIh$yOcMAs1kap{O zs7}6MWICU|zCY8sgTDRR5+mGRQ>cUemsRg*TClmsBpHZxEHQWg7<*bJowTai?#=0F zqmJGyiS_u_JSSrusO0ZhW_+ zM!C|-@6j|fiKtB|5ec!p7F0>NmSHR=DX-k44@eL5`havK<&5zTC&wz>oyE?#dfjAp zNzc4Mk@}96yKgJX4cPM4S#D%V=eE&F3BG3gz(Q129F))K}2 zakZTsmG%nA4(A2VBl$8IteFtNSwWdLWZ(hFg+*}AnZUA04;>o`Dq~Q%=Sx*0KlHfz z!bx1J(6K?vNpL$z2J~VoSO)g7`~pE2kx9#`j&=iQS&Jx$aRTf3PFSB(Q$>LFKStxR zLK$II$_p#YD^i1*9dsQhmu+L$wk79gOGwrwX*`<(p^HFO}jyNQ+5Qc!6&4>5=)kqNiWzr zxdK|xV1ZB~qYIT+gN+G=H-J5o7x1~^GwnK+?n^OS89)|E9W3oWABXoGtENf`B5>0e zo_{&O6R|X9MlcYK!hjn+fI&g>O>To!yk(z5Obu(@qcrMlMDr1QS1Ljt29gysmnSz}7z2hoMbdUm!4MQs4-?ZAp{1c&gJmTy z4zfV8m>a=;h>gvkaNUQ+rvsp>ol`i&C1Tv(oAQ#w{)yrK>t7>bES_RaTQ+}24Rwle zNn#THu1hin@mgTPqPCE0+m=F3Zp zR@R>kT0}=1oL$I~*!+SBIc1SSXN!$z5P^SVjVP;r-8Zz5@vl9GK*aH!$ay+R4bBM)8Q*Bvx(;HfVQOD08+IwUonzV%~4;M zz-E$_#)8KfRRZhiOYG_y(w3ULhqzxKsSR7od;l=n{|Mmi{)o30!Lj1&O)*?NlI{k3 zSb4ZsDWENy_a-qwfk@GaE_hBVSKeiKQUNcFAu8cQS^b&ZCe;WoS9{K0Cr#`sjH?zR zF^G#exaXd=nvfya-Imy$&S{@Ajp?0{2v+C$%v@nkl642D*}_EEB0>GZ88JifTG6ga zE~t^;#Q{+hf@weXlKpK{^T@n52je~))~_DAXbsg`d8A1=H94+eY85CUVLZvbYmk5C z^p^^UPK_2M3_#F0>%-O%C1X`|vYLJiHfg^Y2wX)-y~V|Hm^(cSNljizeKGh8e@&l~ zL$IHYb@w$s(^SmQje_S?nrN&D+2k0h%puX3NwEGNI3m0FV|^URlEqf7UiRjJZm!s#3UHip^V>}8AlEMH4v zTVmrNEU+_aqe<}`H$T{m^K2Z`+5v7NK~oU)FWI0*fzP~DWh;HZf;ZPx`D|?2QHTBB z*CYSRDZ6G;Z-H_QG`Qh<<-}Q`NmKox_nM5}B2rnT`{$!;KuN!s<~^xkEl?0jIJ>YS z*rWLpM~m+J$l_Q(G_n)u+>;lN=bok{*@|=7Q{8ld#)7NDbChY*T}w{2kSo2>*X#rK z=2x~}2EGQVox!Q~xF;g9+^rn0EMY4CuC?fK{<4jHl8S6Nt_$*f0~Otr@uY)r8dCm zSli=xh2}u^Bcx$!@aZoGQ?K_sD#OF)7JZ-3kN9nX;kfL*i2{k+IM}Z`z3fPTFmW>j z{#x|k@*8T8g=NM2V$@7--3F+f($+L0mZUjK&4Y9&OoI3(oxnH1id@nY6W^z3kK6b{ zGllv+2pw&xIqAu^rVnr7TqRkN6bFybQ+KTt1-<;OMUSI&8q>L;!H!(v}~Gq%BE z35)kd9%075Bjw;NtCjYad`ve+97vrM&tN*sBPN*P$t39uQmW!fZ`*yEqTUs(**?V4 z{f&6G`r%bFl-K+zr+SwTrlz0~ax}w-mUd>5Nnvz zg5tZqX2pSzq2nOhGyNv4p%FbrWdGs`{dG(tz_vgEx@yTzoE_YT&s}G*p~Geqxy@S^ zf#ulwvWG`}pu!_}<#PnllFpHcm~3mtK)kPrZSz3IWNBo188YMmLM|m@y7J>W(c3}o z5Fr>*D;^s<5TR% zU4w4XTKsw<40Tz`$?L-NlEQk871iCj8|~R#nZ)a9$EqCTRjstGY4XDZ0*caN(aVEj z7HKOB)Okmr?~7|K8X7V7dSfPseLZ zO4{OSZY;@gf`Ci~yYB||!Ynh-Z`W_RM@s`8R|4*{>NjrzOJ)?)PkcOE(sfq))RU=zN+~gtFI?xlT z_qn+$Sh>n6QV&xUoguki#L!`iSdPr&j7TQkN~4aT3Go;w=IEy6Y?5#daQ>i!EyYh| zJNFpsrh2#m2EqZJ6sKs}=A=o-nW=J)Q(DqxMd=DEsGS+!=x9$3W3N`JjW~yl)Sx<7 zU)PAyJ+d)v=6|m+Hc4@9>f~qZ%G6dD>kqO_SU4K?*5b%vXkVF2dvit-K%7$t=xipV zk&rAHQ?%37fO-aYRzwY+Dv%h1?<2dKEK;2srWzX6d~_5?Cf;Pjh-V}>>Jv#BLi0B2 zWL8mW>p`Uw%viy@B3!mB;wC3#eWoi3a8b+Tub=o`QYVBZB8)iMM!fI|#p}d3bGT9o zUQwfBH&;z2B!jRB4d)5i&8At@d7cl=Q=rG^^O5XH@H}Akj3A=vx|_e-56A&pUtMcc z(fPuukEaLNS{8hXr+FDlOJ6Mp`X`f>V3ua?S?#rt`?_sT9pdO~^46K@-|?mt`{1JU zQ7eBcdCYyno@QBuRB7YtG8ShRXa?OLsqT7bCnymWX#kDI802N7&Ip{hI-ZyZiK@)#jcVWyNX=%0hIwF0mq*w zXxI#t#7=;nV-2@VRg`%%nzSG(?{PHOo&brM8-w+^MnR^t$&o;2Pk3^x1B$7xBalj!HCx$8vGP)^chkK^TB>P9`E5Lw=MfnVu0I z{T$d^B0kOB;Q)#*_V4fJUVl0G9y~%e2V8M~>ke!&)J`xFC6YMd>kQ_jU@~*MRL0n` z06q+qe4YJhAXCcVU8pa>bUcdr7)rvzwAP)HJpGFFR1ir=( z&;c!!hertHUJ`=UlyZ(XE<+X>DGeE-8u=0@{`i20G^kid2(rlbDAYKX6orj;u9P+h z7EiK8x{U3q9o|s6Mu-J1j#6E7wqwN&3^p;(Ha2BI5m<>48vm5)0{4RW*gd|3DQ7QL zgX1-RKeqwVhQpw8WtD3x&|S6Uhhkl>88*4$t*ZZL>V0}Of;72H|lVGHb4;b zJ;M_VyDqWdy5vDDLe8eK^uptbDUI7+fWsIS#oDz~HqNYP1xBPE9ae$Gp z#R#r#pxMyem`5P2)VRw7#N|r5_Bmv02N#u`6;x+V+2tfF{E{LMkoU_(N;}A7crZ*Y zc}&j;!mG3QkQdFBf6dgA)j5wkin@$OWgOS^;w-Wwv55I`&YVogVDa^($g5=U(ztfW zKrG|s@Z4%~8fQ8?_*&sd_SK$pBf2Se1-=^wCzHPj%?laMWfhNdO}sg243=`-BnnQw~)FpLR;v; z7MwZGewf6MK>~4*$BbY}YkdZH$x2o=M?IHlt?QLSyTkYc#aK?q;Y3kOCHQYt%EoUO zry@K@?|)aJ>HEzEI+G^o^HEsZa>PQYHzZV>I&EzhxGjyo;<(PN6^&>dX@^ll43Gbk zQoh-f2xelHfZpE)#j&YbFDL)B^9&JA6f;Q3G-|Oj2P44}0Wf7q=Bz*a#Uv5faoneK z!>G^by7*(VC=kVHMoWCDw&S@7_wrh^f6g{TIL0Yx4_UU6DHjM~Yzg7(lk#3zZUu!p zI-2h#1<+06;ioh%9Qu+a9BffMbWg2GQIn~#vnAoTd9P+Ym1G-a^wQ75KPBbpVT52x zn*A7ujE`8AfaW9gcgx3cBYsj=D&=$ucafYr^rtvGf>yFwv(M7=X*YQKo$3Lk+G#`} zWXoH@0Mz1>y%t%n|NV+hr0GO> zi9(L<0-R7GKV#7}=#!XYqWe7;=ge(69@C&ucx?0xskwwq-(d(z&QXulUBvYN&B4Tk z56ecjz$1dpJ$=)G2Qu8v#LJtVYf%zyjn?`w{6Hei9iq`Ue2rO+2#v-*0k8gLXlw#D zXlaI@ntCS)4J?x3Hv32pipuq%a5~Yvn-XW?R>R(~dHDC@kWYGrTW) z^PGWhK{m#T+;W16n+8Qid|yQpEiC57y( zepJkmJk0|wgmUK^#q-U?5{p4A*svmiH|;h9P5yLfVaqdFmOyhZg`7_*@<^LZc&=w0fX7 z_4sgU1S87l*j&{V$z{{ZR-Dc#Mv}{9ONK7>Hq6Axs9T#CtJ_>sP#Wx#`e8q6$#Tyc zq>I^&u-aLkE{Y-1N#zsmhoY;IZZhUuFsUpK-pMZc&zs2a@kGqmK+Z4de~03KaR@x_ z2><}bW&S%9XJq()XaVf81mC(ki-Qn15FX*$RrH8rj6xFnu~eHHQSH?wF+d7{nhWUd zG{6J$@1UN(di+xQ4QDwsS9S@>uGsic=9t^d%IfK)4DzP?>yfNZDmM=vo(^tq-hFyG`~EDsg>8}J``i!QVDC0HX7S0CIXb(VcW~dh-u3bNeO+z6 zET3^-;bY#jx9JZbl;i9B1Q6Ke>i1o{yMxRd^$c38G=?6w||~*D8Q+HoF^Icz*bQId|a>6@l;Ko z_MRi@ZNjHfJ&z@asxs=x#XrRF!nAGS-Ep~D{`$07w`H~V{DPji4PCYUZa(_N0zbVU zaKScM7{z$QS4isOY}%;`;0RlVo>j?j-AHfieLYvrMb(uqd>+#KBFld_;Qm|%?R}l5 ztu=ADUJ&-#d;5G1#N4%~e)^<X;d@@!x%*tNiga4Kqa)j2I<&}Z z-&!=(80|Tu@IKrkDEw2R2qQ1JsCRhxQn~l}ef`w^e5?2Q{RWNQ{XVG2HF$PC5W<%` z%KeSMZv5ro>-g|#**-i%o_2M-`g~vY+kV@bQ~F-GqT?&Br0=B*Gv@wBfU178vdP^! zWQKY0!!vn*d|J4?GX5+-o6+?GygDwjEDHl4N91R<0WIqFbn{*$b{DO79b0SIDk-&i z{kV!+w=G!ydYpp|)*P5$1NB2Om#HXE+VDdha zujcvi59mIJ=zh~d$(BZB*G7uQxWD5|<35shWT##t%(`k_?TZup*)XWByc8RDL=s4E zt`V^UX{0z0w-AAk;~m?0rqR;mPbyyUU02 znm*W-Gz``qh?Of%gDP|ylfD|dmEeU11-2J0Y{7n!=(d#I%a^K3MFE6gJ2t#&ca|9{ z`2xyNMC;f?MHr&-bmK>{n5De3=&MjzP<_=5JV<6E5NuP4YsZHZ=IVI9ID&@hXz7oL zl4T{c{f2~pSJk?cffYvk)Mi~DAJ-6U>|N+3${hETTo0`47_9*kqH}v+DvRCFcnUBx zNV>DSTjmeTAq1r9UQqYeVP93rJH!#GI}!D78j-kpM^Wz^mBlEuR%V6IHcS~SZ5lx7 z^5NSLmH#JxsMUIoo9E+WyhTyUgH*Me{x{c)rqcRqKZ=({A-Q+GAA%&yH!6lxh;17; znl|BPYH0nSmT=Lp;~LCrWgA4w2)nB`Io#l6@6RjzM-%W*sZ2diQ+{G&!GqOoHuM>) z+p=a;lyddrmnFZztpexQ;PX`)hk!E04|26`)I3=A5JL?zwo3rOtM}IejC=vqyr119 zf;0h^xP1ltVqc3djI9))6#$?e!_m%)t&due+cqGNqA;I0#&v4ob~3o!4a+L|wfG-o zy)3y0aG<22PL38+VGNs1zW2i$V9JWx%*_|pG}vs5+fUbhU%ryc9UD3~^3@;JK^vnI z&*ycwO|dOj&1q3xB$xWVf#BY;!}ElcyPy(4s(Nnii(2Ve`?&0hFww=p4w3Cy z$M9sI1nO!TIBcXA!G+uHR%6kfKBcbS6J5bBmEmuK9YC8@U49hs{0%g1I#6(!miEvK zJTimu&sa8l57oWkx>%v@fqu!mr1Nk$2oM%G-RQC`%z~=R9((~~A`DqEHHn&J_kI1h zyDh}WcdRL@CX>T z7KH?%-`NY%1R(t9GH;v>5<+pR>@NkQ9>97aOCRQ28#UX5K6|fw-><=YzX@Q~e*7?~^ zC7o#IV-c|aLZIpV8_SKq5J2=CNRsr?`@faL=^?1_vlS{b4^i z0j;fO#~x7dT^NzJM`o+KS-PIwcKSE)LlTEUqIUO@Z&Krmcca}c$tqaOk_F;|J8Q&G z9J308;5G#Tb&U)tFsa)I>lA2f55XK$1{396C@`e~iQ7W;1^w+*mT?KKhGfasneS{= zgj3SpXLmsxH+ql>tl-U4JonSI{rW(?f~VZfI+l2NJzmFnn#qd8Fbv z1@$CX$=}d=B4S=vpoS<%b88x4g_Ho3jc{G-a8!vr{Y+^hzgnS-nU(PrF$1uFiPahB zXY43bGrS9yw=Vk342d4iT}%S_UE!kac_@M~h<7lC=Zf$?d#~ifC7J{>d2h#)Y>b<) z(H9*~FjbqQ`n%io+w&)jM5i@dc4YMu0?%RQJd%%=Vs<$E~nfl#RS`5<=)F?9$yq}dBjB~=cdY_$uVq2`-&`vU> z<|yQy0Qiddeljt!wSvx2pN~PtCO(Ir%-JT4axGnmMrV)24!ls$@@*C!H%!3Bcu;Zm z_8|T~FQa`P8uJ|1c&Rwj@p_{s^uf^XK*BPhONThxbVjn8(TH8g=GTDuHCPFp35Z@; z>M?I|%?W~6=O9&bQi;Zo**J28%cnwyeR|92!2>_Os|=8cUxjD0jjeTBpZT~J02~w6 z%Y;{yI4(Wi1rcE4*r)z0zISgMW3Nm=WFgZCmIMk5^lz;>RuQ-Rd8dggGQvaohNRv7 zS?Z4p7n%RC(2#$Bbe<861q?H2O&{JT@t5Aip0k4K zDg#^B3?#QUd1j4v3GBozvlcwIATT%uFa-hk7aXexe zGmlJVu2m;5jg)Y^l+}fZ1UK61LvbJ-H-}|kYE2|MK7_MUIK6r!F-q{g+SJ5MKeG{& zbCL;_oyRvnHmhT_h6$#kZ{y%c>9B@Pv}iDB)li7eikE-&on{eQu20AZiOT7Arm{^P z(fUiwBG(YnRhTcHD~l0hgQJf)Oq93(`IgBf-}^iln6#5GqAh~viP-=$H||}on^83v z5L@RB5eB}D0+WbtDD*T6IBJOSFfuRz;z=5L?x-*`8tbZCxjW4=yy7JRxxH_rVVO;{ z5u}W3iJZyWTPe94MTQQ0^TXa}nTu-M#54GI98REm$+{h{ph_v(k;~FEF*gzxwxj%o zlP|8J?uj-?ws|Lhvx_+4iV0rD7Q#tTKC+>Wz+7W7+eG7i$`g)g$S&{g0()HZhkWv> zgU2?8vyUjO{jD5MwTVm7Q~mNMU2ji@HZVV6StNr)4{OgS7Q|j*!G>;yX?4$WWFj&R zCyD10E?1 zzCMb2Bu@sWxle;lR}&rq55rZf^wUnZf&b`6qq)pAl>`y?1oV&H;0Jinmlkrwpg`E% z1yBO*n7(N)0hwkjJtrtsW*ZHFe`V|7ATRzc_Gru9psp($HYD1sQ_A>kPX{1^$D?|I-1_pi{Ai|CkTyS%RqUEpqC(T zIvE~M69`buD3bae{q6U{t%N9PxY^n=Ivrr@{O@d*e}DN4q7d`; z$3mVY?-B*uN6e)_npHJZ<1;*jx5H3#mH z#Bu!9?pSh(0GUOPo@l7JOoqYZN>##rgDgN)G2aD)ojA za?4Vx+h|q2736T7?&i_Mx@pM|&uk>nzwNTF6W1^)6Dm|;4$w05FQ8*^#%yBSoJQVP zPGi2U?X?;V@xo~AF*bu|1SRXm!pm;U=~lBrzE89>Dbt;#qnXA}-KXQj2mrpw8b^qP z9EimH!6MCWRkXFRtso>2wJ0)R!tJtqYDfJ*uG_oJd)=Byp)yOwUk^H2#oeIZC5PW4 z+JNH)LjUl^QJdfR`#CW-B*p5M47(Nl2creA*X9#Yz0$io!7Eo8pwGC26mfXb1Vcbv z*XBKle1182t}+y@ubh?$4`3pRg(bZ&(ftT^P~(yOG5=CJC9~M`Y`@6M;7W$3tipNSrD1m+7 zJi03}Gmo6r>cI}fJY7DOk}^l@KB8GeCH5sluzA|5te`nU2RO7Q6_;Wsl%W;WNvE33 z&10n*Fpj_V^HDlC#){??sVbdeoezsDixW%<@k(3;+gDto*A0pxu$!{mZ0Mb>28>iw zE1BE7+VIiBZv6gwQ`qY;i+gFe02z&&uBR2VFmTL0Qfdi~SA{She<>-snQ{PeaJP~~ zb~tYiM(nhyU540`KC?Gg2MU*(4r1;`!@Ts}|3+PPxLqdF1?--Y=`(B51vz`P={-0$fXei=Jvj8bMyYyB>%}fy3+|_h`*2!wdy2WS zIpmWOpnM5|>m?e{WD5HD} z(9wC5%=x5~v3E7ij3`BU#tJrqH!hd$GBA3XLla55K?CCOnl%`TNVYjwMfT8u9icRf z3aMEkysV9*RYMdce*aY&xyqKZMS$m6h$Ip1ih*Elz{>IJN?};KS&dqJfz+OJDze=6 z;LwP)TgD=SL5qB!1>7w?WLRw#nb*`#{@(wY6aof%%XGnK&N8qXby&f&V(Gz&tB$gl zT+c)*n<#Z6&6Lp=(u030VKVCkLudA>k*iNowP{ z@vS2%NRB}|YPf2(86~-ru$oesMKoW`^6@GkgZp*tT@5~?N!^}|J&7K*+AYj@x?0jX z&+(S8@AI|(#Hevy_S>0%^rY>JQWCM8f2WwYr$cJh1`7(@pOGv)TU(N*tlG8y;S-$G z(n^^Fh@BrfDonnVtcG4&WLX``RyN*yA9&;ne?H71c+1L8Rqxod%xZ`iqZBs@Pd^1i zViaH|9BkPRmM^AUyIj~0b++!&TAdu$>ms%lue)!}-?T(rV%tqjF|=w6?+WokVyd}E znHeCY!ADXd3+Z_k?M5jeYndM5+pcp7gN2YA;y9^vd1eM3g5n)iAyu+gm-k&MHG!H6 zG-k|-RL0(jXZ$$377+^N_0GJ!Lw4rVT@Dy{&unVe-A#Txb2S3_r{p~2K+hqBwMZTM+$ zG63FW^x4we9kPc;E68ZKR~oQvqevhePVZzS-=3e$v!WAstLc}czZ{|PE@f<(A~iLF z=^9yQQq6-Rb=I(mOAck5vpd<(q!?2^Rk0b6IIhUqxn9|$g2^aGoleRru{x4$o*;uY zA9XoJ28ng%&PMMh4>2o6EzKO7XZrAj#m;e-QPoE^>Pe9}qts$eqZCu;5^*kF>+#B9 zO3DSIg`rL_%hM)@MGSyAsJ0#9;zrGHF#i~${s}rR|EnI$dD+re%BIdgA}w=sj<(9u zgXOmC*TWFrOe+6~L-sR^p?i2_>11f7k|POT=dw2?!S_Po5vvRul)BpQHx-&;K_d#E zj-lqRhGH7dbo}xv&Wn?GUW=Def-K|F6lr>hw@r8G2mf8Kvb@>(*Nrtt;xvHQyQ>M< zdjsON-Yk`w*}lpN<`n#!!R)EcUYbbIjvF z){$LzE_D|!qMHGA6hN%3ZkXtZ1_SqkHAJPewBnH3lofgDz+|pWG~ouEvSsP&nx#?n zp^_O0IRKnYbhcDBzG_u5E;9g@ehZg;NC@?;?!=&qL~@&swdrXJPq`0br4CsoSJ{uaik}jM{gT%P|>q;Y{2(2XzqnujNp}k;qAj97x=0UX?&eQv{ z#LAZW3Rd|u_+;cJS#q0l?QV~|5)X98mm41o$w3)W^&^F4)Qa)hoSu`0C2z#vE}R&V z2Odiyk31PJ0B?_H(i>DGS+F2xatB`?K-e4ZoKGCS`D z)RO^T->$F04pvMvFdkvxE~;qYXS6_I=swx0WTh1lFED8RjK1`^3nyaMj#w|LumXrK z;RiVZh+gI5+49_-*kWI9W3Su#s4ks?fua7exue@bGG>eODA7L_f4|*-jZfNiFU6kB9W| z<-gO^SX$HGI!a_@kr*Z(8$Ri)^}Lc=!QmA}QF)nLi2b&Z@HB50{*r_?5|ehQi(u0L zoDJ6~3)q*IsrVwc%{RpLjK!LWSy=;0I&V;fv$a1aUsjs1+V@lcFft#|lYZ`XUC(?R z2+URb?cJQkD0OLHiQyzvyXi`%cx~uaAF1awN4>Q6jNOH{zkR?w${`IJ|3-k(v zyvymda^aForWVUkg)o5feYxjj$9c%PM%^g}*vCZelSD7I68bZ3e#dh6>@(1g15_?@ z%_66f4WxqXpm@J8XF2xd#gQUid(NMX8|R`aHH(~hFW0=p3N#uDJNLHY#gwSnGVOP0 zXhgiiRgi0;)_*-6yK60}N>FY(SHnzvSy3jZptq>k65)DreX`WzY_^KN5!_xi6}v8d zjJ2|_7HySSE zteV?hA@=?+Pd;5gnXV4pDYzsn)+e|BHZA*!=TAYc4$8U@TW2-xwlcwptqi+lu^gG@ zne(tbz!N4KWQ}SLavfL8^TKnIq7}+gn1W-IVO7?Z+Xh^_WINQ$LJyI@ z9kJs2>Nvp^wJFOveU95nu8El2GR;R6Ts21UQ2B)0n=Lv)yPF(L?vw{tCg=ceW)$yL zPz`}azT$kxV~&?xsy*M_p0zB~p%WWDrP0w!N)$Grgi;7$H&(2WgFx5ce~^Ark%X%2 z`l4QZ-AL!YQ|Jb6oG{bY`e37MU6@8dz*Dj-rmj(rop7l^0Qs>dW!Dvzp=~o(yP=5n zrZ{aC;#Xllh{qQ)^+K&SOFW^I9oU|=Izxpy^$5@&1V~myJaUcp?BJ5*#m&aWNPwvk z0%lxsI9q?D_`PVrlML#nCi>Pu9j5yM0JTRID%yG+IN<+1SepA$@%g(k(+G4MnK6=} zQL2dFJlLWX!jCa?{OJm2=+xWIe7(rlaM+xy;>PD-WM6uORhn4`Xf;;bpj?&yp}Gya z(y9TR*!7I7PcL^W(Nq&_;>utKb_p}s%P?Wn#XzH%*<}hYo=FGf(KlsFgIh1eFGXKiYqp#WiX!!TdvLUnAKA*%M z&I7Zy_e%i%-XrYSeH|6FNUiaEx-%9;L4p3j-)r)g!2h{Pdpiz)=jon(0xj5cTNBrT zmT;Y;Srxm@4A=Z0{DZkn>MNCCA1Gm2PIbCOSak7!xH^X*L4a+Ec2C>3ZQItgZQHhO z+qP}nwr$&g-sb&?x2i=gE2`pF-n=J85w|?i;?1xVH&b$b9iOmk18>78R`lGFO4~U@l^8 zWl7>4)Z&&VYGIHW($atH01#@wOoVotksfti1a!^!N@Y>C2IC_8L!8o2x5-TrluvaD z>dk6qc`%&Ib5=h_Wt#8ree)6i?BMrGg*uJWVv9N?#O;mpbd}3<Tw?XP@t zm@{p9LkN4PExBihww2ZlPxRyt+!@- zT2(UV)XYjPsgkT0P3817*4{)OgQ!Wr-7nuc&1Q@zirB_1j&vYoo*GORcn`%KKzW9! z`}x-6k`4{~N%QaTf8PEGu>I8Jt!!l`vUiB&S>$jYRU{3MCgs$PZ7vbRT(0RIX~D{f z5x}K6f>yby^2QMmm|J2FpMmb#jv7FUf{IVluqiOYKdKXPoUUyVnZcm8s|oKfS*`1> zj%iql%SJjsIt+$mxK9iDq7T5>e*0|kkyONM&X%~iQWNWx4)T0@ zD{JV+<9I2OMI{EOr_x5H^3L{&m9Yy13d?-Dw(AA!eiS>;nQV2Z8O#Coc8GjGo-c4- zv{8qzld-b|KRqio8pJrQH9spOx#r`|i0f&;st8M75Z5Q$*L;)&7LqXLn@~n}s||es zaZzAkwd~~dxSpHS8I&rN`$kL5y{j0G>n5+Oo|wRKGb6MkX}_E*mh9q{LqrZT37Wvu z$vtX`OI(tcJ0|P^` z!AM?5Ll$c}`U2F&jtMeNN2DxH}MK&kU{o$*$ zWXARzzM{sv!`DR6olN$kqI(=Hwlw5k>r>8y&*tHNOK7U_*Su>3jJpc^YyZ6D?4`4&^Bo4nb$qt= z$M^M-mll3uIvP)Vrvr2q*ZUHT&1H}@lv{K+MwX4P^E&5YU734ZX&4XB=OJ|Wdp|bU>*M_P=kAVRNmZ%U zT!dz+v#>SxkngyVYuEOMyxl8k`yVWTSR1QEyX!05Hb=XaV~W!EJS6ig80zh79EEq} zJGba__4j3VCuPURysPptR>ruQ?lBR{T^EPPXin7!if2Vcr^6%@OtsS>bI|{>yYqhE z&`ZmRD^|oshz)0QzQ@UV+V;V~j;vZ2h67j$h9LLD>*{H2{@S8;()EYEc{2*{r@gu^ zLaNk)OxNq@sNz(Vjn74KM@oOH6xBije*Gjg|G^reMQt|v-Pvc+rL^mM1QC$z7WTdT z>W*SIaIz5zw)6E(4^DErQsuKOApFvrZE4sz#ujY%%>=B!^{rfAu(|Qz$Wm(4>=Gl-JE zqq8(F=hu;KWd=i&)Ad?kx|9y7rB-?}N)Gp3{#Wj=`7KYObZ4@gcK63A_4U#&Yr zi>4}DPmSH;%}3s$3`IBm;h^T<+RkT)+PVXOvp(?P3h3XefX^s9Vs#%$Rr}4npSowRZ6r z{EGWE`c$NWlTn1wI5w@{a{HQEtTIBGS93!U${>`B$D{p=lwWf~mzz~t8;5ow-~_kb zY;=R75gMF6iZGhkM7Nf=f26{w2Keli$sYe9F!&dzrfT2qs4K<#P|J?lHikIx@+r#t zbMjp7pfm)uuA%l3cvR}!@y2GvaZ%i&{w-cm3SBCK0trZ84S25v{t16#IZQrL0%Kx=}f3>oXNsw#^S+c|=F z*>AFg)?-SCtDW~|t|od$;T&Is#;3FI1x`ulk+r_G%nTO2f7>WqAbqy#sd?3 zwJfZ0&*^=Jd>vyi;Thcunv1BEt?9|Hj*UW9h(wLgZC$8(_%jr!OwLN};GZ3{V8U%p$Qx2xm-wuxpbO-$Xvv#jbZTP{6v-tav zUnmNjUix&1FgTXI<+dBjam&BEq}s2B0|y$}JFn32RV^ZFgo{Cr$Ej>$@b`!N3Hj}? z%8ZTjrQ>_rrR5Ot)##4k0!0-XChMw?Za@inA`Kpf2He7evO}*-9|}TR>Bo3Ky(6@zTCuW`@IPO2HS*e@kqS_H8XuGY6OXUyg;#Six}L2XFyE5 zM+iCr`@v&l_ekD1>?^-J?~z+9`mln~w-FB@k#2FDPmhIzX}gx5kK5V0-|b(>JcIHl z)>-Ndyz7(RpqCC8Kl~%jpy=Es=(=U5*y@$WRe}P^o<)2>D7QWoh}Or@jL;0^6h=Z@ zu`hlPs%*#B9N8o08+I%N3!Xd?dIrs?u49WWD2|= z#cS>AIuOl@7scs0%XU&wHV{^ztSSU*0JguBqcZm(7#i_^Nb55Ni-D`?i6v0Mb*8gK zfO!hP@lkGg9Fbcz&_L2PSet*mJ;$n}%O^1b@csQ#kdpfYMw@oCW#2vBZ9+)`o_P&ji7+yj7Zo z-DP(1w8-U8&4~p3OIVrb?g(K2+yKqcDOrQXJdQ z>=7@5FSW&=S6AnyzX2D@tnek#kTYlme+Iz=pH$hry?IeLts?H@2FHn}*gj8CoD3JV$mv#8( zQ_MnYBa#wN1Ul5(X9Vq+rCN_HBE^!NIkj$S7EcF|Kr_N25C&C+-isQ1uwEiS1&rg) z3JMP}pr^Q_EEs5)VYj@c#*zFv-|5TqUzv=u7nIN40gGo=rrvCagunt8O$38eLzKYJ~yOP zP`aZ6Xj)f>$rnpBKIO{`5OaY!MmbpIDgx67(C#Gf%FS*w*PVh zaF@|@`)9y#fRb-6RC#cK7{u94e>ezN68*6VD#OSdX+PMQ6j3m=q8eXisG|JV+2E%1 zWdm+d{Go%!5kLUmJ7|HO(;jM$Tq(K@Fn>_h4A{@{6nI$*t4>q&zNRu#JJ1h9VKIsBXealzvKd6=fYVL4Wgub*-|I96_~eQ^9nR_uiqw5L6nGoFy;aWjCVbYDVeeeNcJ@E5FVq{67ASM zLe%-%`iw8Fd;}7Hq~p#`A!AM9DQZr0zxzIN+U=c42+!>#${bmKeK*jdc{v(<|F|F` zA$*Xb0gq;M13Q-mwSqsO?2bgPjZ}Fy{e_=(eGi>dIe{E;aIQ3?a9|ur;_4$gt4BJA zE+0l)zcsrpA3kaegA3t5P%g_>T23lT5nDATV>TnvVNUB$LERNMdvO{)XEBwPeL*DW@qNyXyqvcIfgkv5uW69!3N@sk_dJ!R=ZTne~G%1zSjl;70w?H<-~TbfaU ziAeAQzdEHXDz=iZMVBhO_>_3-;D6C~nJuhBasaA*c15H5k-fGH2+ z@9Lf*li+`!iT`@M<_kwWtDld00=R_-nZX#)NgL{f|8j_g?if{(GI7Y`=7jIZ)F#Pc zyLjYex^m>X4IZX>EMJREw~__{dRB#C`6`zz_CU=p<=21U-~n}3M~HG9nt|3}&m&N` zQERvZID9@xVRCgyo^VCgit1}@hm?}3M(B?A&1$6n*UL5|+aKwVJT$To0(O+m4+QT3 zxgTGG!|5JGqlAV!!e%iP6n+VacIrqA4S`J|jz}kqf}lMnI1iMkm}~3UX^lv%TN&C@ z-{+kg+Ig?ewrWO z1Ex)4x*6Liocb6*!z1!o95WjxQz28C7Y?Fp8i|du`kqUdYtFQqIYtmbMDs8_htNmi1Hic!fkl&2jZF1rC=00TNLPX-LSeO%TIc*@5 zl9#AEF!3n;!fS9O{gLDU(ISLm-z(LHR$7K~l4T)9fy5h=P=%V&fLS9Ltk{19K0t#k z>cGkKOt+l^u9&n0$&4YsueeJ&CIHNSwuIFm`B0CA>Fh-WaZ=pDjhpNpRfwlJ0KKSZ zMylda@dLA_mVngk-16f`5}MA?80Wm`;^h@aow(dMcDEu04!Sok6*MXJu4^}nPA~ct z!hq3ZfD)YZH>dzF$Ts@Mz|#*(l(8rRxMc#oA4NS~<#Bj`v^%=g6f9`C0daplWfocK z+{yJjb1Fk!w&2PHY(Xa`1pGq+KmnMXCliVR4CvEH6t^LvGqr%II2pckFV5LOMT&Tq zTz?pUWO)gGspP~aig0qgK|g}*p~N6KK?0?T;Yp1NzC=7la&A_H6@V;jNzngjB=MEX z=RM0_`_RzNZuw}WaaRo}Y7*2>70*1%+e(38e2Y}B$+)Y5L=wo)@lrZ^?4^VhY$z9D zXd$*|2QYYTmTWIN?Qo8Twe{FyDkgoCYWPx zp-Edn_McHfRzDmx_@gw3_D#qfCzrBF&gLpj;fT!&rJ4Gal8|O($`ZUF=B=rf91O5N zRkJgxEnL$WSwSox^HW&M(OO&lcKtP~9d`F8nad;Yw3YyIQS176Tm5jrtXkF5Wu5@h zDYi4F6U83iZK*8XzBCue%D78;`H97_<-$IkzU3@okg#+S(d@v=-Sz1wk5{8bCj|%oS1yHRSb6tW)1+ryAeRBCny6f^yl1C<1IL8ld#7$Zx|a50;*Sf(^Nc<%Z^CN^&kBF4))onwLq^Hkl69cFLuP|**Y({fHxK&}}9d~rch_C$sub5Sh~*(RsI z*MJJE8bh}2{rJ>(e(rC|&>h`ZN4#u>T}GmN=vDzbo@R~Yj-)+Gi|7X3b2GV@##)47 zM=n3@QgHySP`ZSfPt%OUpa8&$xTi{(+@%bN!Q31^evmKQ%6U|U$mq?P^KDj%>N+eN zN0vu76BLo0SlxuzdQ?9$|G>K zhb+-;&Yp z7K1XukIn|9(8&yy@t|I4NI9Rg7TzgT>VgI(C1+a*Qk7;E1D&jrXAEs1Y}CF1ERQeX z7d^-=eqtbg^tMNY1@I$GE~7ALHqj_tRVYjeAEFTmh!F=eC~m;(oYEPHK06E5PK6h& z7wd*U0!Bh=UoIRR=m%HC!*!0roF5duhhlw5V3CBj!uv&CDXd92y6OK=yh-_cFY{n3 zJ08YC#}HxB-ii*oBi}EnUmEeZHyrKZtUQlla|;#(VgB~SAP!9Px(pBL?OR}_{JFDW zE^N+U6xB(vv2P$~L4X!A8-{|~XnqwMF$5*8!iad?} z$9+u;&Z&6-t?>f`e%69%=L6W*UL$Ywg@+X1CUG$?BF}{kDBztJV0BOZr4%(UKK3u_ zz~;)dA)#U4sBK~8b^gWRZB(!?Ra)UW>h;CO#Y4cR>aty~TG1Qfxyww!00rtnp`22<06J}qNKjlYxu&6R|#h>Ul zCNh;i?PaXwhVKecLzYs;KW&Ev@P(qA`(|5afgO^$X2Z|gJCBjNB7qcbfA~gh^o^MB z+KqWo{^kee!~e0;A(O+OZhtg>DgFD`WDUG%TD^D_k08mmx<$xquFQ6!<%pOHd(83A z^?<%fhv>scX2+I2ZEH(T;WR7G4v>3_eGav7zX2)el%3&MT{Tf){5*5v z)@+jU;rN|#&>K#{vCAtTmS^^9{g!vvD_mD=3-h6(TuvBF_?_LQos2sgr@E4J6GJt# z>KHP=?1)5Mw58r6^bw;*#F!%5Bn9F;YQY@*#o%{!UZOuFYvBN=s)SPVD3{=g>qkpw zL`k}s*kQz#&*t8Q`pZTvr%5>SYYZK5D-Y$LX_t#dB^mChfiuqn}lH| zuAT#SX8vtL?BVso;medA6VtQ)YnFU!OErLqD#2}z{{FGZT&q@Au|!ZHmd?WRG#wr$ zoksYumx9!4L{p|0)=LSKY`y80+>sPBnNm1xTEpu_(v&O>2=mYbfOGN{TSD>8;e1i< zLovRQ05Mhyr%X~2tDa!Air$@@DpnpLFMh=GR8|6dRZp+H^rpUv=)0C^flh)euY58k z!>VXG`QxknzX)OA^lCu>ldGrH#zgb0EY#Ap0E zX^%YQw@_Fg#B^65#F6Na>@Y0mab(hsB5?63Pjjc`#B8OJ&^hm>*nd5(2I#UNa#PJ< zVnkz)aqP5)7aotC$G~ohN*97k%h=}w@JfnU>9{}`FX&Rlx|~JmX%~r5+pLiD^AbiQ z&RgF3BN?WPFPxK#z}b5ETIl)8J}viQ-$k(r&pk<$Gf(T}>D|K;8pj2TwbM(|k2DRA zIT-TlW2vQ0D=Zc+!Rjzr-h=~nfDyoN5sMui9I;(q2@+a5P&gY}-Zv6&TDF;0`5es1 zo#VH0G?w>7rND`44l-e69%Zw}lQTE=*ovP-21G2oXA3_O@EjiG=#q?rN;0I*AdgnI z(+@$EsWw& zF8MEP=18iYIF&0?W8WB4m7c^HUaHqx`e5&t=Gj%)^Rj4*wjcJ7v?vYxOJjap@Eb2T zN!jGDONH2aMlTWU42mP2ee1VhmbnHm@hzGG?J7JB&;RXZZzyg3iOP+vC1o30EGvYSj8U?Wn&0m+q-MhhI6X}g zTK0urDj{!`8WNRUs+qn~-MBtSjhW$$b%Hd)@oOZk$;0=@uT%fSI2E0)5e#)+a@wmhJKhl^W|C@}+Qj=Mte^K+&Vc$7>S_ z(iabNtIMH^uQRhpvoR(GPw&e0`HSGVR~AR(sTDNc8)VRw8Y3VTP-78GX3BK1X$IL zF)h@jjT|W}M8mpQy#BiEm)N2D5)yFMoK^sdYdO~-^Z9*a;3dmwif$7n% z%CFuBP=gj9nl{}+|9;N`O`kKEr|uEVrgaH zsLFe-T1yrQCVAr(Atlnl+;ct9O1?9_wSF?m9GnSktZuy9Ow6BZV9qM#Ow-YkMq&4+ zi|VcyQe=A&*``rahDeaTJ75=Eneme>&i4#5+`;)LSJjRH>wii(#n3G8)jT2+$pLE^G4kC5^=Yi;{@j6X-qerl6`#APIuOHpXEG-ln+BFc+cuoVtE0cG1#mQ-#dFBU&>b&vG)=7xfT%S!g?=D z!_@;fV@ldq^-HT|KsHRJ)iSR=F1VHFjBtfyLsXp@uV~7jXwVEaePoW6H!(aD1&{3` z?sY$o1P@i&!n7xwol1iC3|mdJkW|p+QqgtgFGq^m96KFdU;g8XpS+3WpN!f6h4!(V5?k^8(O0W5{&Q^Rq9&X=1 z$|(O_?JL(mhn2nEZx3vEI?CpE*DGxGFnGGn_ZRDmum8|7zYpt?zFxl~&ge1Ii)3Go z1LD>nZx{5?+l85#i|0<>AA6iHpP8X}-cR$>lDv+_a6FLPZ9Q%cJ1$&2pPR3{zlYLS z3hobYP(VIzkJWgvABUT^6NB21Bkv3+x3)XJZi~xx5$``4F;vTyHku-p{X_n`CS+^NA%k zw-vm48_Zdmaj*o?{|ew6{8NH1Y#UaHMx2kj&o>J!w#$D2f1&aJ0Q_}dd3O&1%DcRv z18X&WhZ;ZULU!Qldn@qc2$}{*RdYwDOWnFYJ|Ar>P8ZM0KW3LcXmJkibn(33_HXG_ z=b!g`rdm0;z1*^AwKl)sEKvK8Eoo9Z+^z$4y{=X0cGA>V?LAo$LUD6T>h{Z3GDk{> z?4K4gLHz@SP-CT}79F2o4l6xAM_>8g2LE;8N8xxsuK%r_ul7NkA3f0J@tnPIFZMr& zcXtP$m6L(I+(RB{aK3W5GKZXezr@(NJ?udjwT9r34rEPNS$vRM zzTVRW9q|-EuttBC?=ppwFRb^_z09!;dn@Y7EO2DqjIjh)vuZ0ZKt?(AZ!FLM*81x=neU18Wx;rf1H?^1RUulYi4d&D*c!0+`Z}}el zga~23f@OWnW!KqNN!FfKC4h@$iSbJWF=5O0Zr?n|kIN`Rlix9IhQg zH_)k!k)!EQ)gG&2K2%$r>UsE1k^sa$(ZVsp+8+9No@oHVg>)P zxdbk+xi3k~*iymTWu~HSdTeHf`pb-6Q`?kfvHRB}d)KBOA5OXA0COWoo2^9IX5(v? z@B1@XVb-aS!oF5|Yb(850-o-0fbqz2#JApCMVSwK26g6LjbuLdnlt8FMOSq6-`wKhIP047 zz$kJWOo?JB%)g0)Yl-q^0!62@jgvhYCy={jV#^TUM$c-zDj5ip-CkoXUxn ze>X)eGZ0V?gxwXZQnARL?*P-HybOvr`#Q)IobJYj5p%cic;9yB`W&U4F3?GVY7l9T zNwzm+@RgQjYYcWFz(**iM^^n-MNQ()^(l){M)%s2ToA>@%|lK3T?;pv=xfEcyIt9W zN!c8y?ZI%UcN4zlWYEkPS!pL@rUHBk1|bK0^sEvHHb@Y|!eSGUi#fDX@$w=c)#G=XQa@Q-O&0;g|s+Pd)=c2fdR}O`%pi(r4sLO9hGIBX$jsS(18mU*N&AGzHuH! z)^8;&_lSD|;Y1<0CzeqQhm(gjra4g3-<$m=v!IaNbWlcMgZHTr8@gmDPQ5y#3USoW z)RxNkr~*4=6zV|)#oG6rx2T!S0?0&Si`zA;O9?o#!$o(+8*{Ig0NLhhIao0DvU{o< z3ydcDR4?aB&cGb%lARJ=+MZ1$ahIkEavt`xtFl1Q?uFO4UuAF6zHZS%6;}RU{I=n+ zT>uuB(wCbE_?FUq>nclg7$dXr*u2kBp8f`yx^vWL%G_jq0N{RL?Nii-*jy&4>iUc4 zI=CYCcB?}m?%z~-6|o$^AcjDcLjmql_V&H0<__fV)(9k_VBK)$rO*}5?yV4%a-g~p zA3dudNQ-N%P~Yxp)s>$a{h^pkLDFlcg z(=rtLlRhJPfSUUJyoAZq-m!Z01NR#av(bW)jf=8zBui?5;q^#Qq>^NAmiHMJHeJtp z43HNWtP|8%Xj+D-n{SQPD$s;@a!-f`+ zHR-U@y`b%nigK{GyogH~{WLuk*{FEvQ6oW;ziZ3h@PgXr|D@u8B_UR?0mh7tm=x*U za9LMFBFW-L*y_sz^UT=p89i9J>m+^f-K0=FOAXAkX0{ z@=A-SI7fi{h!}R2u27<_j;%-r?8QV)LLRa}X=S8&ea~q%RTaK5EIQq>YvaI=Q-eI6 z!p`qPpq#(_?-<&u~&HY2$Wi+N00} zoY$fKUXY7%L))z{8)7%+*e1P>=#gwKV|ZrJGoF=kOO6ZjgQpo#~`$IzN;tY zUz(k3(okXs&b5OGlf@_BX4Y-;*Pw0Z)JoIPbUt9d3r(`npqqZI>NSe{--x4heXt<%%w})j!q;O95BX@_{Y-{jdKSgtT-qc0W z%LuFk){N?up~DoMFGC@E%yKDXy< z$n+_8d{8##{lgVxe8pDq1#2{3$ud7UpdjGkp^YICRd0#s+1DK?`gssHGmCxZR+F=^ z5-AQ4#9EBQV6RSSDIA;hJb);xviZKoH=S?we~TJxvKS%2`7 z+++Xdb7HvK{fP?gNrtwuI^N2smce7%HoRjX17WJ?UMb}=23Oj|#rUhW3m>~ zc=QB8l&?;U6Sc)2B}P3MrRawmNmFP#*K0@|QjYW8L%NV3C<7WlVA5#V0EE?#7jIdh!VF>P!5K!nBor~b89of)Q`j5*t)14MEo-C@VKON7wr+2} z`1fzzmIL|+74^>)u&=$G4JSDU<=`plN9x+)->Uxqlmh5%oM0b&<~N&QqY!*(sRLhp zu~Gz!j~|E7N%^46)va!WcmoSCkT_iZ;=2=dm8xA0USV5w_0iUGE?uXr_@bLi_Yk(Q zg*H-&zx+4tH1&bx?P+ zudjpq_2v8=&mda4A&yUXpLIbGnE+;nd&^k^NwnyIEK|0pS-#&kz$rYmAs?%B#bRd^5!E?eU>g@ zzqS%jQLLy!RXa~L+%E28aUJr!Thf9u5ok>VtI=Q1M&#NBR*+sD9*=5|GdkJv^<%(< z19?4nrL|L^FRmaisC2oLo=jfN&gxle2V6iDAuz$?pHtqsq}l$qT%c=bA6;>>GIe>* zJ@Kl!j@whMq_7ezkm;Nd>aNe_G|G1}?X}E?s*cggDWt^ljd}`zIN_#}Q;P0=*-dJP zPr~zv{+dl5+yWw0#M4Lk18I4CK!^m$g+zTpq`kwx;2*T#FhB$WmM?fC>4r)tCPrkz zQE_B&4?}_TK-6k#>fyM7T~Wj$Vg@;Vm6U?(hGn-70?PmtZJLtlHj>Zfa1Q@? z8V5;9_7QgtUf^A#{bOjd>;-0T)G|OzIHMSoV75oFCbq#vG2Vn$ww9;qKE7CG;1hEHT-TdZN#lA)#q=V_nX+f=Ks)Cq> zF>&n#5JkS**8?VX$lRV-R9FhWG;B~Dnd8L;ZfFi(&`9)i>uUY577m22t`Cw`N%?~G zBSkW|S_GkGgNQVXMJ4>-F*Ihh{6)@Xo{IGXVzwJF8+NG$%;+J&>r<} zwTz;+PF1V^nD+QKkEQI!D|4U0v_%-J9DAxpQ*kTZ(~Yi9k~f6Y z*J>rw?`F*4eyjszrL{z&<7ulg3gVpmIKHYlpRE233bu;QFej2{^C6)s&WNNJn58d> z*qs+WHpTCv#&=`sV#G}8rp_|1zJ`xuC01d<-jw{KCQ>MoIEFs1pZnKewpfa4_5@R6 zpZbFNl03DUF%lnAWj?WDXa?>Q=&addbXou8_(3PqVv=Mf@mH7L{GF?M!>v>c(Dz%b zbWNfL2BIk?Q&YAmEU;PN$c;ZC0wt6+JIKTHa9FvO&Pdy(;?5mxd2?)CeKSO!_VKYIuFx(aH108LseZ-G_&##Pnd6G&FPvncL5LusT|zRGEt-0r!G^y zgT(ulL{kb}idSn(N1;4xiHK+bQ|TGH5~=m1q+7f%b1kA$2II6Rwb0DA(3 zXa@c@zCP2?kC*qkw2iU4Re{0EfDcNlqkO&k%Hxh;n5x(5z_RT_S3h(_q&NA+bop??(gFw&0e8!FuG`wtpI- zF{!B!m!eFkLDm&qU#yB<*-8KS)9>$a4a*Uw^l5SkRqq6zaRi5vVT~us0Zpbo7mL?b zRR1Ildy@?Z^g6;~C+}fBo7IoX$FYM8Bbn_JvvP=t1WCE>442Qa&Tfi`G?W%>^y}`? z9aPcp%OCt|t@kc+8;qaHt)_cQZpLU5C*%wR6Yk}OkaCF#6dUuPG?DXLVPv%i=tC)? z3=dNog_G(CY2b?#oXN6Q(bnWY>M7Oc8??-U@@dQZTSzhYdjK(QaUqOh)lA|W<_!W^ z8CsS$N#ja`M%+M)1&E$ToOXFL=p)NUF0r&TXsC2j9eF12v!=DBTff+s)7o-2@PBs| z6OlxDSKJ46!ItMyl>r0@bjySiXl{)Vt*`<$a>Fc403MymX=geDddjQo>z5Y&2ptay z3)!1f!#!ulx097J;tZvVje`zFNz;p=sM&<6&-n+fZIxd@sXC}zx-jL)oK2sD``Evi~e&z;3}c0_4Wl-9BC{GiDTj zQY+ovL$zcIQ(bD*H+QFMh)>&~1dkq@Qn{1X0Pdb_<$7GvQ=4;8t>APM0{%mlx(8EX z>`hQ1l#c}#fvF|}tH{hsOVHzf*>Byv<45sn=HN0gtB$qLy*|gF2bw)r)}trXY|N)p zxi5}0?v+XfsDaWe({sld^wQnUr;vH^ZxCeu<&kR7CNVbFqV$82Bpb1py-HS(QE%zG zZ>JCzY~9NW{Z$q%s7i@=(MwBzX(UP&dRbHGYsby;CJi{SgBNF4Z#S$u{UWcOvxo{& zxd*~1szNb9hjkAv$QjWG?El+2c#MfHD?G>KQXs%^2>l)2F}0h<$3Q>xfhf_n1tC$; zcGMFrXyVm(2I?re)o{{*o*c!Ps^Ui~FoHwOR=irvT$^!eIz3{>R?qv1J7Wj(%F0$b zu;>#Y%p;Q|ly}B*Xm0e$4oRmXN9pO8v1puz+l?TH>L3s_a1(Jwn9s(haa#E(4j) z^;e0dv?tZ~t%;d2nE|)aU-13QP@ik^y1Fs%!lDD^Mekv-f_#vca5V@3cx^G*c0AvR z(m(gWt4HB43yAD?4d~68pISTc+Sp1LZ|j}!1S!H3$wEkV@Dg3*404X3UOL8)$4d2w!hdnBx`2O}!hB!(3V zl9_gMn-@acLuh!E2pj1*9h9`_IiJ-($taF07}+@9MF4>Gpe(WtB2j3-q=l`3|51>sBtW5QPton_)Y;JIqJeK#9pQR%m zEoEo=$*)I;@icM5Vyd+m)GAB)L}7{-NJxy05QCcn;#W$b!peF~&38AY1320A`bA4k ze9i#h=lf#R6g^D2m1`8#x#ZIRdLu#4Z1A#}lS^y1461jh^ZJ=<_898*xSC)!9hHYr zA4!2hI^t`=4`{6#-@8p61Ti}Anat83Gn=-n<>Rnj1gXV(e^TCabjm)efVO*UX2=eG z+IKBPjzH$BW)@>ED2asPaErGGMpH+E0}BJcf+}WDJ;B?p8M^9cGU;Y@5 zX-jD^_GF#d<3~(|Ic-PEa+O!GTAO4`7GIZ6sbVtHwKW;qp{%ezP3eNbJee5ZFua36 zkQ0pEmtHEaqlCeyT~%%aKmmCuYci-bmc}7%UyGuTRtN5;Wy8R@cHlFnJ*ToX zYExgTghtCq3vxhw{5oxi&awoT@gsMoD2I`;V05X>YS9=^tBEG@W$#c*%Q50Rrlog{ zVsJ#Ic04Des_s)gU8z+)p;gWC>Ioxm=OW1fZcC3HL{luskqitUqZnIfoTr6sA?ey5 z!I{b44l-!@{_{B(hE@r$qQ$n9HKSFsf$^$oCcnj@Y%jUt35W&5lt>Kp)Nu&H*{LV@ za84_#0|L1^^F||^bOQ*!`C>(-tG++&v0A0dy;#Y`^^G?Gl(iRYhzWnP(sl08l%v^l zR*qnj%UrNoEd(L-HBE?Nb?-2*YeC+P^Q8j)a#YQ($Rp z_UA)Gu0wHPJOHm%X(b7C8a!FZcgVZ`NZrV0(z$OM ztpVZ`W$e_NAKSggGVz0mn$CH)tt6r`wGB{Rd_I*`PZ$_0E+iz;-m}=)pWV-$uUE{t zNwQAZjCH#Udv{!{Sz`TZs_{VyVZQ`OZORr}77lUeNr-p%7M)^7NebdRDvek6xcTGG zw2bQ-)LQZiIv}%7UjHky!_IWODQ|9Q5N#Y*{R!I&MO{t1F;@{c^>VsIv-|fB(pKhY z)p*x-xB3aX1f}h$@9(8FyNMpr43=jO6~2aNZi*<4jOyh};1OlhS7)=Pk4;f+uKiI&p#! zIZM)#r~_2#rx~jTZN;MH0;2FM(I*%PONk-t+hY>W=NZrW9L?WJRONvkm~V2A!Eai0Zq8x;q785?NMx(i}Lda-6Yc8mrZ>P8|3=+z_Wu6pI%si@|uQ2 zm1!kw?P9~#%+3_M@%V?j9<;WrLr96$h4z{DSjG~;J1cVF>R9aB<0)xrvw1DBm`sLI z!&Ludmx6v9rA5-D%Cli!&tkzO8HUK`|F}A*_CTO)iN>~V8y!38*tTukwr$(!*tTuk zc5d#&Jk0!x^X;>$R$+TlgCC$VTF#Y{>u!B0QUc@z+!$C|%*GzIu!(W`jbyh0p7WRz z6ZXexWcXM^WyzI@jk9p;qqkn@(0=rhjFVbnb&*I^ljLuKlb&XZAmreB zcnXf-n~hH+pnDm6Kp!Ms;G~+8?v1Sx{7ep)@uvR`t*G0t` z>+j+(W8bQroCz&Jthxr!Qp($h9kQ>^O^GkB zXkn@4qPuRL70yX+H@|BlIoztugj9PA1 zs98$aD3>WXJ6%UspVEG=!n-T2B0v0GQB&Vo`AU(KtE!v{if6hkRQ$zR#>=hMY!?a9 zSCmc@pCM~KD_3~dH^T$z&-R2?bzrX2V2mA{;OGp^RDJ)^wv(r2+tZ57OuFn*8~une zoSQ6JH0#zv0}OeQWT_K!C2R~?g|JASfE1)247?y{2seHGZ_CuSS`M`6-_ea#`PA1y zxpa$N^lI;OD~QgDT9Oyv*p)vKv!85U;LOFhv~~d7TPh!qx1fe*58U~%56@z>56{{U z(0?x~I0$^UzTyG^*a!mvAOHXW$O;R}DbgF7F*5%rsj!yt>kRPzbp|}mEB$TDZ0a=I zLrS7h=gGG&p`7r@7zJvmP=F=SCz&0ZPyFd)<~yZNcf9U`%o{5qCNn76sseLpn`k?s zD>kLyX_j_B2}Ln@@p^c?A1is(M!lHD&9U|IczC+uT}v`|(!R=AeLKmdv(f3M$l>w$ z8c4PEdAqB;XK$X0H2qXJD5m4t!5OLlxja92;?&OJ?T#AQJ3lMU_3?O0nX!7zpYh_m zy5_+=_o1Kp{vJ!@(;ebHBH#EG28=Da+HjA@-gHmFzf1*w7*6r&@VI*{!Pox|JhURF zerX@Z6&QA1Jm<$dAuJ|Wp~`2DyGS%T*KkJ;lc0Vvc^TYK1G@uVqpL5PZVB= z@+J9pba(r>6zB3-3c6~-;eC|cZN54^`fMg0w1wu0{+^Y-$j9T4 zbYYjel2q*Bdi!4g#m?LH@-oF$!OJ@ot}5%Bl`FF_t>bpQfzIdLDgw+$?F)CnC}Rj| zN&Vw^-|guV++&y@`yhCc`xU7wt$6J{fS%RqOcz^2*M-fgn@aBErU)zNquy51Ct9<4 z2?jsXS4}^0KQ)KG+Q>O>DP3iA2g6oth$E3>78UJtpNu_hc+t@ixk{PhEOzkcQlhGf zR*|N)h+dX%&%eQC3s52KgQ>SDME_iv&y!~SpB^=2NC`NEP#e4uR^(Qa;ECcsk!H8% zkhz$T<~RG2^8x(SqE3+m8|+qCGLf$Dkm>vI#6q;Ic6^M!U-5P5>bMFYTz)0@&chRe zVaL!~Xv|1NZ!_WJYQzh-d)Pg|9Eli#OD7zjME-Dg9*Py0Lao=IHn9GP{Jt8`H4 zSiTsWmEBg_ss^W_?cjWl)KH9zhT&lQHsF}g2Sg^ESi*~mu66@^$X_ZN{kM8PO|{zxth=rveGm$B$=>FpuSZU@;E z(#DN$ed0Dbn{6iZ*|WmMg4TjG;q}8n&(^fsX*bWF4@0opAH(rRReeqmX^4!n z8WdlyKgUQKm-q~+9ao5)Tw`$ju|D>uFU_dC@upISs&_zJu_0YH1L+J=k7jtXT*N7qPk!4AHZ*S_#`;^&nesf$q2Xsy={9NtJ z#rlHUb3%Q9Hk`Ip%c!yzu^-B-U6; zCpI{D1S#)O8w+ZW1)x=%I65p)0S&-DS?=g}k%yUFqfyO`To?A>+Y(pF_v}dcKTokg zkRMNiL=5)gPsWWs*`?K`j6f9@OYqwV1HqjznwQ&%$BVdRYOxUe(2RR&FgTBGU%X0+ z%wV}p6;?GbM;tPLx*MK;-ba3H>h1v98}-;>LJ`dD&12xZb(ZsVt=XKYs|FTqFvjT; zB=RE(-%>N*&LX*L*SUlXaB3-M=Dd(ugpJ%ms4fJxzeUY5I_ENR=mFa_BT#2Si$^tf z(V7!hU@-w3x^^WLMG^a1s3I{biM(1p`ZZ3J*=vMo5g$@mT@)@`v{}ygV)Oey{O>L; z_j8H%I#Kf#y?3Ykt{`6-6l>|=g8R<8*m^}FsGN|}K53Xe_!_fXQ>BDh@zszKM{quK6B+ytvk&a+w zRbDT~SK{EPgr=u2nTT>|jHSiH!bbRPC~;^3FzgUyh9ceqOJs1wsE)KOU1BgCx!x3^ z6!9b$A}Mdu?q9NdI$D_-p7Pb1mPxiEfQ%Zr7xoYDpF0w_p|pRtNlR$sWRHse|d-`IDqMg4Ko+r=vVO&tm$2pCmE!HwMSy8qE6nTsxPMPI%XM& zgPrlgATl_S!mXkGFk6=vQ#-&AB+)tKlndYI(a&oQe3KJpk!il{n%Jk7>IVtZqx-4t zBxKM=O)=O}U*B8?Iy#BWTtWh$Ed;{kw;~#7vmzmqbO)ygL~fO+#Ho z|7JVmim5axR4%&^?em)sYm?C{gVQP1m&*>IkY&SFTAgry}p6-=n!RA`k-?0c5&Q`9lz$L$%r= zm#!m$+rO9)AP~vgw{UdtUPfnpNBQ$vb_SjZh(XI4Ke(B2f1hACo&+O(!=7(Q%+$n}XmdG@{j#|7yX&QHUj* z3*LZi=#5sq*{Z(RCZCtL(wxF=xGM;QlJvWWx+w(?)Hw5c~?c4W|y$8<rbj^H`h%9hJcDh0ukEM87UnM6UGtR=%_hX zE(#^^QcRHaLX+^C;y6E0dg_*iF;jVg)<{kTLi&@^N8H zy2;})%NgdpnUcZaiJqrx3Uz@Kj-s+y!p34WB(ZslsJAj1WN9GGuge2cAVGK94O!WJ`;xUqAaW0>+Upiru$F{-3+F4?LpCCiPARJ)-BijP z)8m|3n4d{R!CxxmM6E%*9x^O_1I^a$Q5lpdzu?-ilt&GJ{9KH7~)xUYF5! zg*iFm$gm#5Vs?d!+hHD^lvNzzauQUCz0IjpZ3ax88@#Yg$TB8 z$RVN8C*;+Maq-j$75154kXr41RP$Yp&^%+1<&?hJ1dHl?c08Po9w7Ythy4(-9PF$6 zUs5&?-bplVs4^RUWV|RX4qG7+L;LZd!}}AbSbK5Iw&_pyz;D;s`wxZyPDV$1C*>aY z3K(a1G*%#1;!r`>VuInkOiaCzS8*)2Ok5iI`Z$)E2bgn-O%8k#UPPtVy(^_fh=6V_ zsjt0O+k!(-L5C2%RXDD%KvPEeXANMojT;s+Ed!m5jtRF{U(i$WmWv0oA5$2;~=!l&3-| z!|>AD4lA7KRGkXTbsrkx-AovFPr2zGS$WuNWlJe9AP@OmObY%E&u*2FvWjmt*)Lui z3sCmYn8(m?n;!3~#y!AFP2P-T30o>~yxPw=j3V|jadob>hLz{SSNh!8LNn+a`2SXpn zxTJ0ol)5UAD%fQlen^0_ zv39$j_UEjns0Ad@&P~TCujj{si3g@p1PfG448-wdV%7k85PN9!lFePXsa(NLuzf}AG^qr8l&nuT~urAmFM0aLUwq`}5UW9%GiO;*ene`i41*zUmRY>`Y! zbbu|oj9#mM+=bpfW|zE~BOuy9#yj?Jdt;Y6$n)?sZ`W=Ay@2$hqeVFZ2MOkwA9;l< zREaKyGMFVr5;Us#MO=Zip6KHUanRQ&F*5slu;1pWq^Jw_*O@BThn>|DpthX6M>AIL zSx1{8+;jdRmSoR9Z>nKS=@2Mcqy-NLPx-b%N2LCBh31n$ZGu20HRx=1z=}6$UDB zNUPH%k!|H?=I_Y1cqsBEj1jhklc2@1Z+t`L7PD=lW44wL)z3l<`4QH|QJjMstqU9< z8gArYutYVZInE%3p(dr(p%B5Aes>kYe_1KeomD9w%B1oNAiJkUHccwH(^pfe)rmW4Q@2U6kl_|1DveAy;~yNG0JnuZz*-f0Cx zMlt>QULt(VJ)T8{$D%25s6^;bqTv*Gc1Ms2z=)9&p3S91T!QZ?O+d*k9sCs!2uUHD zU1-dN`?ArVG;k4K1tT_`sn>V(`tD4sm;++kg2Sp$MENEFa|1CGe~IyL9ZhNe38`l_ zB(89-EACMT@0l;03jiyhtF&AVNOUyWPQ0zUTR}8t5=CvcolB+#+a5;j1clwtetI7= zBp1@n5N|dS)FL{7Oa9>zbHMUGOOB~?B8b{5Q;9+$5$08ZzhxdI&07leTlFEIjQLlX|XAyFo8l)+R(%pgVR@ESYpHorJTysHjRFkyN1dFDS zq8|B}a;i$Hu9#9g(sn<^3JUXPknX0$%WIOEm%M!E1gTl0`E_6PuwjRw*Nzi}kWk>8 zZT@Q`#j#*&Wa_WLk#jNVTD9 zeVfQCzP;=VyPW!vGOjQezN^5=V0~;3C>h#sXGKGq!ibDOwK6ZT$Ks-1(MCz5JyU4K zb5(V6b)-3B*dh9pMw}G*uMuzJ;d0~fV`rqQ-%RX$;sRQ{%)OCc`%lZ#(JoY@HO8f8 z)`Hx*f9pJEgnh1+jUbW;G=)~g9&C`|V-!-SO1;GAN-$A55goAwCnlkzu^_+IeDBF2 zrD=m$I_v0*0NC~C7o8spPL)|PQzBdPG|Zq|W92;riNLyY7U_c_w~)rJ2MgGRj)ihM zfh9U}guzwSLRZp*~&{!9D&Sr zc~$z18>Jho<7Q$=vO%StkUx4WqNv+F^SDJTirYA&VHEe;S)z|mN@5<3q&C`4_L8Ze zlr_#VQ$SQ=r{V!3bv$?CJUS_}TAWk4m`29a*6$7%9;IQLKH_lk(^}Zr3A~KoT&_AAI^V;J}BZRWx;#`$p z+%t@f*n{Nwdyg-biA-|DlzS0ZtNQ zmPVgbu00}G5Fl_eSMj#n1#_wtA(#BYha{-rjOI&g-o ztAp;3gPdmv{VaCPGet^tJTTAWJ6}XoT&;P;<1YGSVWLdu8q=MW+n6?YOh`2{S|0lw zI|?G&_nnmTxOS}IM#y7>TOT~q%1f!Wt_DU9CBT9~atw>oXsu>E^X4B{eX}!NQ>Woz zoBs@hk5xn_E|k&~uxc%&jFO~w3Q(J%kBAWml9hhd2>b6I>S_x;%SklvuZv@rONaSL zp%@>|ip*q_#-{?J{r6bk+26PvF-Gap3m%L1F$ ze|>{D2ObeF32P_H7N;Zx-n9hfHuE;A5s1NqRLG$){b~#~Ia5qdNn*-ov8y{IcY4Qg zvwM?CRKnDAVN#a^Kfw#g8mMZMwD8%ZQZdpN7!Gd)a21h$!B{8jo(?oDL^^yugRVYL zDAgh#?o}dGi5yvyJ&HRFhnN2%yQOv=^4*_>se1c>%8ffG30r~zjqs4c&czU2@weYe zA@TV4)ynfUp5E-)HUIVqH_=?`i662|AEa{(Vq?OBj}5RGU<{6f1B9OKLa(VWI4?WS z2cssXmZp-s7`>psuu?p8w&yav5VzZ3u{()4urxU{9vSa4dJoM~_@i%6hm%f>nrbpT zu-{O7-B3#_4E=L3SL*F*`S!LsIRA7_x@Zi@T7U_8;g)IL_qaz&5Um>TA4ckIi;foT z#UzyhA`K0cpL3xsL32zrvE+_lTy)M}Csf-nBR1TxYI*N~$V;dCDt%7o5Wf6Z!ytOb zz0N9RMwd73Ts)aLh#4e(gx2Yus(1Tvdc+h+58GJ%^ym!aLs&~3o~~{fcT41CAZfJ% zsS)kkADUoba1Ed?a9I>xjw8nmWmd^QQn40JjRmi%S`V5oFnyHNnB0RB>%c`W3(vog zV-0#vL50GfWL#v^$tP+4VnTgir?EmbGRXRQL;MGKgP!V=`02h5X)MCE!;y(Vux9*_THL!5sdj+GM?%^9}D z=|88!1^qw!Gu3MJQz$CvEFUz3zB&_g4wSpo)C}$Zce?G2Bu6q>assA(8YNa%axtKi z+YEAy5G&Vu7Mwx<{?h+$uF zsdj)z!9B~onYBb?^s1=dTDUrhj6p-ivpvzw8{q|KHtF!q+T#f^n6qeT%APw^u5YyC zJ>mi#A$kdp*d~E9G@B}F7VEU`afeH+mS-8C1xu*BhbN3Hw`gq52S`xvkk-vlTcs#5 zl8@1jqMGl!IT@z)Xv*6f%PBA{(KA4XP#4B8Q>P#QS&ViPWdgPiE;Kp@GP2+R;7hx{ zUYctG$>=RvKlaRqFxYzdhatm~^<+un^SfS_Mt{pUVvb?FE-o@yMOcY1=t&=`%Bn`4 zHvKlbL3(sC(C2`iUF`u-`&WN7r_2K*(l^qGxaqrl2!x^=&L*jr&V0ojb9k&6NSy6H z)w)QG&xv^_YtA&0df2KHT?H~0Y(-(?{>(~-$5tO$b(!y^h4=Lds?y$EQf-Wcxi#=Z z`oz`9LbILr)wnpYA=hbEssx<$O&~2xx~@J$&W7j=y=5IhGH$<|kss3Yd8?Uwf5fIB z>K-}A3Gz!NFKTQr#qS(gr{P)(^~fS_tH#S}C@cTlEVE}dY_`-d>14|4B1eJ@m?fp( zBKNT?nFEOu>z0u|V2l*7H1TQPSK~qKEpky-4qZ7?}k zVroo-ZTqOUfr<8ohT1uYnH4+RHRt_`ySWfIrynIVU)KMgVBzM^EA@d5p_!c#_gN87 zIxZhdna0jgQ-HpR8b|Mp?YXRY!%NZ3Tm+%GuF@23H2J-Q!=R}xL&bTRPD2xow^)g~ zQo*GwYbv3|!bB>rF{!#Y`dcVt+?!$lK(BgY7$hjD;L7t;S$B=8NX5cwR$*57Pzss&?6Ox~pSvc@rpdG>12k+}HO9p%roxA+PtS2>5Y2yU zZ=&gFG&^(nNL$>@=54;Vfb@f?Jk7sI_R3d&Z1&+cYEG`|5~Ey-61`-V{nip1g6Zpw zmprz@gfQS6z*50qC|5YTT*u#`1NouqTuz>(SZ4ioyEe8vMqIuhQ~FeU@Is&Jn6vV( zP6i@O=p(0MA(lQpc5pzAU#B!71-gUa8@XYE*bt1r3jDl;>~SBr-4!qjSZSSYUI3vD zjiF~JZ5v5lu8q3$w5F(9Ov{aImOVU^z=u_b(?9I~>a&(rmh1OPS>K}^+veW31Z={W z!;gq-d_jF5vpoBh<7kEUT7K;&$M{wiQSXSIou_63k-5ipr!KO9IFrJ>k-c_-!OIbb z?B>RrR^wJJ$J2wM{2J}d9(>|6SIKt|-*tEtX5Bq2l6+cG|qzeFi?xDQBT zK20fW9{CjQNq@4Fet`d*60ejWa`yaE;>Z7`#DD%ni8p>Jas2;N;s-&>0v_TT8p#4T z$n)_vR8@_{l*>|Br^0qXSib=I-ai|%@8BDJW%O%~GAe+ldvb`_gz*bJ{MrpnvN@e7 zx!k@RtZ&uWf>#}-=&^Ks?W5W)55`-#IXa(5Q!T!)mqhS}bIHO7TrZCW59l+w#*zRW)Ai?20)AUBkq62@_5)Umz5Q# zqHKr0UEgP8$=**z>jcBM&{@-@Lv&v3U2n zf~t@C_Xj^d-@pF+tl9$nP3sI>Ri5`(rku9sk4FQ&cnzO|LR*z>uy8~SPZc8{Q^8oY0I9-IonxO| zp{e`auh}Honp-ZIdwVRSFVmmP{Uvemv=zdiX|_;Untx@IUB0JY7jzGw`@*WnEAW|Q z__*KfZ|0-A?{L1soxSKQYtkpNZns0rvW7ZN?n9yxfitmiKd>^fxZJk{^p7yUzK;V_ zwmsh$;-``7hc#D~0nhog$~IvWC(JXC!(<)P`J9T12KnTj_z_5o`-)rqXRNPi9h5-F z-fkE7NPdC3xel?oum5O9lX9{X&1$ z)t$IT@Ug+mFJC^7c1k@al=n|U;A5OGx<_M|&Im=SBknlR{GW=>>R>SX-h%j4$*0$4 z^cNT3mi0XWjw<}DQ&L&`M|oxjIy=rot-FKgz(T*S7;$3LFJ^6Bh8VKk3etG>@`c;- z)0n<%elJFws8Vo30^9)~EQ-UCb+JuZE$OpZTvV|309x3z2o0o&t?2AUmvf0K5x&@M zwuka52mI3f#vSkzC+<50@XOsr4>F_b`yoJFSA5}iGJ z0brrts7hH|u(D`O@YZPWU_`e(%M+!5nJjSMYB1H+RwtU{mgkPw-keHFt3G}#j@Z5~ zapRO9>utP0csD|euiLWzhF5z%x0{37M~bbTZVpQm%{>dpx;K7Mb(Sw^B4El?54L$| zL(|sxkwE7*61LBCdfcZkY6Cj;RBT4v$tMqCd`b)$R*u1dkc?q?AdxqO2ggY-uqF^n znlyW2g+x9|bO-n0a=Od;OOS$|E^BSov&gz{6ZyYdO5X>??d4FY_w^>c zXJVQ@8qHL;Ct7$&2()vg`-gxinwSveLRPJH47om70g3|M-!TBeMZJ;nFT(+s-t=b( zMc8%3X^02{eJfdaO`LOF<-}KVy|SWiT^W?VfdpM#yWyG%_C!J&)?&q?cM$|;E#{6H zp;{i;?+}C^=C}qrNVz6^F;{;ZDK`9xWyH83d^bZ;lw+>qQfuT8IBZ^e{_&LBJog%W zX;gl|`<#o5IzkJ?F59r-FkyVc03qgo{YYvdwz60^2*;|@`d7Q&cFaM#$hYo;Q|5?} zUUTsyn`mqxPr7xwbaQs-xfeo7B*F9hZk!+SX1-+gQZ6*mE=NQns{B;oZgu%^>oopw zk_(lZ{QR3(e|$t^&zJ()J23(I4gtLQgC8e@#s_#?=Lq5#Fw*Q4C}5FNNM3{p+$xUsqg z#X90@QJ(tf!f1gfTWdz`Hd4DLMv>*u-FW1np6BGRdF=zCvj>LhI^_+z??UlAN!mt* zHl-Z8x(fFOJi3w1MaMt%+Wv8--#Z$~AdbfH@9BqXXX#1!wx94^57+aDe<3o%avg=LqPKFaxsYTjbY}M@?1c|68;Eiia3WJla9;f|nooadjVRh)W}Jii09w z(GkNn88b+V<4z(9-ZT9y1p8Ye46L`Of&*hvwOx1d#y?x~VLGePKZ?7-&5d(9%Ib7J zQn9V9FtrHMt%pp3Vo1sG*KaDnjBE59{1k*^-GFGPb;swcw2==_i^0tf zwAzgoifYMO12qZwgnKdX=@x(~$g+$GgUz6#P~8OeAG8guqsUFz40}_IPm@sI3~_pZ zrluj--#oBUp1Z}OJsd=$3eh)HGXeFEGKokJ0u6T`fxqgllrG;ceH?}RgC|I*8rP-4 zM>Gj;jbv_xH__Z=HO>7{gJGynqlhl-@7VTZL}J(gNNf;y0-KRGfcadzV{ zIJxNSvEYO<0A64295qCsrea~HXni>5x~IhXl7hfvLn9c61zz8w#Soy>(~$S))RhAD zFt4*BkU0vQ&W@Y%WK)!;lRgOk_`6GrWdWht1$~f1!LulMoW&Lr$3JC~$?~$$-3mPfNkKvbftvgaC5d0`iT_LodtY3=i4znJ6!K!Ck z#U!#s6){(Sx5FMtXBmn+cZ45v!)T+8-F_mX(3F8ETn?Q`g{xS)K)Z ze)<;O1oOy@c$MHV*;?QgfK;I~7){UTW&IgX;I$iNZBsn$cf3Or19l8-!91UyqzQB# zN_2rEW6#>wWhXvaS~s)V42uVju{zXK<%lj%8%@L0`u*R;zos<#YrqO1+voWRC7cFd zjyeo8TjmS2rj5+H=6U)ZQXjMm3*P&nClKFO4IFC0Nq}a+T|gQ>`{<-g1j&BI^fQh= z)hv!UVY#}~O=+_kASoZoWHJB|M+bJN{}@I4Jdd`n=(HU%&aQH1)*1+EON@?X*FCwp zgdj1$b1_X6Q3!Z3hK3oxnjDH5f;u1mDe-B-B;0JIl7&qRJ|f$NJySm2*qd6A2MlkhH6gICw`i5!ui2;4nconK zTU0(m(@ZpsMl@AgyTE}AE+YGK9#54WpOj%&xP8Rn6t#J!5GCAW1+92b_cZH6RL~Cz zOf5TH@qqtrj|(F2*c2k=vGOS`d5G^D(Hbk$t~6TfiL zg-YzRcK_MZMZ}|X-0F0-J?f;*ybK5S@CzH^LVr5JVIZSSq(BD8v-eeonSN;BPDUz7 zoa`1Ff?O}AZLgo`b+fs}IcaA%?fA0MB^Ezm16-bzC@I5n5!nb~2>OP}e)@a`+v9yr z|d5EA?|g z1?pXs!Zl+c$$Gm{|7L@}0RrG^qaAVa`j*d)OW~`nlnTs(e>tE>KgC`d7WP?tKS=(- zcqwUsW>FFSm<0gV48BZfyeRr8E+ZInDdu32kC@JmA2=%e>fv0a{Zi) zdVFO8*^pQ1B`&R!QXXlfwYo*lB&FcHN%f?L%B}beUsU{A1BLOdq^ymeQ-L$%oT2`L zV?DTV5x{77?FmkdL2Y{^2hR?FW@!yR04$f^G}+DIry`TGGg{2Lt_dFuvsMjRQ*`eP zjG>Pv_^wO=!oC49=m5A0vEjBlXF-b_sWfto4Cr71a z>y)7;n2?75Mx<>7LX8>v3Ih!O^(wh^qZU6q;$W=>?frSv1e4}BTVp6?d7SV2oh>;gzPLfX-4(bz*zQ+(VO(Zu^1-Cd-lvqR$d37JG3LfJmcfHV|N1 zEDi%Rsk`}b8#qI-km4fOIC2iUa_S`olV>94hKvEp)KLX!H~DSSL_5{d{Ig?v|M<6y zEe7kB^;1o`Rt=+j(#ajnKNPdaoy=H&b0+{Lj<*k43e56Qr5*NvhO&K?gYaT}iFaoV zFzJi?b`__279`pKa3Y?jHq)kSY2BEQX;}re@^OLFYu9g%D0l8#SOW!DO@uSJGN{6u z<-@pux12n9Ij$*Iv>8)sr&Db@L(^_5tGtD=U^cF<-6mM#UmwaNXp5SrH;6{L2>d=y#`DaT<)Us1nAd9Rp-!j30e8 zW|-od0b~Go8Ocd}i93j2V{EdtIL>|Wy9L`L0;^PfGd9TT8*3Y5>!wdHCO0bwC{H)t zP^}rCH}ld6#sSMlk}SbbRJ-(C2^q{~$VUa+x)jx*ponL5kPCT8O=mAOUQDXp`@2!T zP*9I+=5?(2SsrE$xD5Y8vsQFy%TW)tn^`A;Yt~8kD|N=Ic?^GMtWr# zG8_+SA|le1i71Mj(2vPFGGCP~TaT|Cn7a?=F9f!n?lP8jtA&>%d%GmAYy+gLw7_u% zs6JpY|MuNR1}&@aPoOx$W5QT?G>z$Z*Rf7Cz1z`v*J670C#6vnNz&eRtiWGwtBji` zy|6g-Ac2}6OzBF$qUwU1Ej`%09IS*01n8^_d%OChchLehoWv8XgVHec(jF+%5(GpuPF&lFquv#HC(h4ui5`Tnl%BjnQYNfOgoAjq*gX z9_ae_toIZ)$Xnq3vfZ3_?X9d<400rkv2>d&@3ti1`y* zW&bh9UY#l%S1HA?SfxpRto$veakJf6kxQG|WAtO<;Uv30!yhaP!L$_0{iK2uxxn+U z+3EBm!Lg)3z_hL4$j)GLs`G&p+U6{k)DR|0uHi^+B-|QPGsq%}(8u(Q-k^XG?G`$t zG5KI%8eV0wP@=m!bg@0&TaU5h6|M4fu)^?n_M@vM0$ad{k`9%6|Bb<` z36M04$1i@#X6? zh1R3!65xa1_`__H_e88L*4Qp1N$L{mn(addZG+yaL8;u1MU?0}fPeBqHxfHGzVfl~ zzm9V35Rnfgzj~^q@qOwn(2yxOMf86=+A$Giam<l-G(xAjmj&2U3%-|s8_|w zX$Hl^N)({W{?e}Fy)OtMO|BO^IbDd6mg8ORaGZAI$BRdLT|jD*E$NC?$+G2@%J6uO zwrLJ}Xw-@wOI2x=r5qm55A3 z&i3OQV#0={v|Yq4o4=~j(Y@g$JMti95Mi1W6%u<5D&WFzwK(u3XG?co6|FU=mR-hE z#fVx-z0xPC+Fc(o7KpbmB{H&zRt?J~S{SmlByLLPlOtHxH5G3giK!yE+|?--IP!3T zO>N7>3pvk#WW)T`+X}}Vx+l2APmJ-IYf(K0*wEI-wC0t!tF#XZ7e>+@y{73LH?OD*LdR z!Orf6KQZs;)yN}$CRZ-D>a@IE@|qDX%Zue~O_TvigYQ}C8&Lo(3>s3N*f)gZtlt)| zy)v;<*+}QP+(5Y@>XJH4KyJ3tcS-mdJdfpq1}f1r^=9>9l5lMUdgLG=;|964GX8{1 zgvHj59w>oE3aRl#3Wy{wBI?B)*5n#qk&On+mUNofjCrT7^(?XC4a-n=kwm1&3`v({ z2OhCa85?bh%mwlG@&*dSgOoCf6I>pQ!&6%4jo*5ce<{Rxa7)#EHA}o91l=L#dQNu> z!c3{akRgY*qe~}-;M&Xb<(EZ|Sy#cp2EfClc%GJa8AwMX$5Ahg+O1M*UjPz~GE|Za z;Dj1V%p((yUMSU@QGAK4)G6$BsF@Sv9FUfs=J}#5wNJ!(Ig+r zH~k@~0G%Rn$bOb!gnOyPkQq8Pfvi=9tH{faH&| zh23bJ5i(7@3ux-;=g$8gQ`OJW(=3TD#mH)$4rFvbNf$S8+8ZW1l|H0f{~AjaQkBU^ zwdDF#=ogM=O<6w*)Kgn4`agAzn3wap*RK3Lt$OLe5prI4v!*Gr`wNm%X zrR*Q(9Vc<19;@|pWR&V{BFU;YWUBfN>%FajPd0-{B`1sSQXemdR?4Z8rqq4OmSa*p zn)En1U@BpIB_^dxW!9E=BTfK@t?V7k2Uyo2A~7K$RX$98dE_C-Z*43s!kpt>yWA}% zlou#4QQ+lB6NWUH@GtJ_4=z3RgNR-Mw#Ub1kW#p+-`kSDZDJ;Sx2?f)5;2#)BqhY% zBD9T_E)!gn=v2m5*(o!xlm7L=r6*?`8Pk8Ps@;Fe%*-R{S8Ah=9NHiQukaKnxelOQ zTf?WI@USr?=nKtz^OQm>t&Z*Lxgh52q6(F*{*%Xt+ecbYs!q3FO3}Eu0L-sUGDuV} z;d1V8)Y{GoDo4bU0_3lPxt(@ax>892uE%5Sc=r=B*!Mx(v|M7`J+Jd;Og_B6+3wul zfQ^npt2HTKrA}7Qon;}hV6xq+3q(UH5Lj_1Wc1H&o^I!ob?2K^U$aiNq3NeInUM$z zHi}H-G+_6Q>^q4GYK#h3`w{8STs@adNSx&Q@Q_%O>gX=vr#%i2YNq>FRu4AqlIUgr zE4b5q`lC)BToY%d=tnBa(ALA%JO0Gbm%Gw=KUaQ$Rp|o?n=N$WWrL=mJ?NDk;N1-S z?(MQIk8-@t%?dLwEhhCU$8@%_=$b)(in^zmE?##Ios9|SWTj#qtirxpB=}SBHZo8m z$Erx72^X9(i?RW;D6*%L=4l!PgFW|T5bED{Kg``$MJAa|AN8h$0x0arY#L)VR2fj= z<<<$Raz~foGu<2kef9A-99~;0zErCG+6mRkh|BHa7$uRrkS3#|ZH9=)uF@>qnTeIZ z^e;_UnLE@I0jT6>S?ELzbO=rDFCM$jdDdPpc^{}+&v#e*E4GGsMeZ%uH6diKtoO`< zAz9He#q_cGB!%4XqC&|GIG5%`ULlz{PD33mgXy0(0HQ%?L!%g&cpXs$7LybbuI*o$ zLt#mx*|@MuO<^;zR%%1Hy~^R-c%T>$oSR(j4E4B5B-%bS4svj`Iw%=R$pw18$i-I5 zROBCSR$P;rrUif?v%#2YE3@Xj%$B@mn8syjSSwUiV3lzOS5G(KK!rlQ?GraK*VXML zDv#c10P+e*o#TjZeuPEw@|sWk&X2EUBuO}qgu~}V_uOwr*m*&77UpUjr4-4}QcgX} z1TmgO|2gxXW@vEZ(DsP6k(9==3brHF^g&V%@~I1m0{vWtdDuvi=hIw7-vT*un>aG0y&N?ic=M71J!==@e~8e9b{VmsM5 zKa9QW!Mm_3JtDm`y?F)Axmbz~S#2|0Q#tAb1tF!Pt$wTXQFl}w8#oSzhFgD~c$L8_ z<;zZ=;!MzRGAGQt@{t#cTg7>6)TVp%#HPF#!{T}dlTgJaPe|G4X8$=mAR4WW5w>Sf z8KPd}nrf>{|FlLX!V1U9eC^CbbH1BPEr||N?54WW&OB^4Iy`T4mm$CHZ1p9YeyhI1jigEXXk#?p9$ zBhUV(TBt3GBH3es*G5Z<6?6Szfb=~?u^oKQp#r*E#XB9j_Gh^n+{to$g(RP}D1til z5VRsgl`wpIn34_m!*7VXd{s1v_Sah6x|w4Pd-v`MyB(35{hr{vOGrn#_Z7yPOWldq z`JUx_-~Wca6tV>326(^na*_Y31hf1H_D-by!rrX|>fUuZ&eBck7%TOHS9T;yb)J;J z({X5`l^p89RX~dXNFqSmG_{}bct3ePM%U3{QhDnMCzAn2uBdUNQ76&ZfV|#!`IZx0 ze8XgqGpw<-c-9iX-r1$c5z|b*u8(83TFZlRgu=$`$xOo&CK`iP3^&TB^FN?-thFqXQvf1^h^4J@6X3< zsi)!Px^COs-P3{S%H5{yzgX#Q^-iwu@u$|;>sEiI&dMCV?2PiK8Qo=@v`@9~l~~!@ zr^Hh0g`Jeb5yb;18}F*FT-GBeJc8pf-?W++MEFWkU$^G+ejoJyD_e?IY9F7kpN`xY zd;c_>>(9gSZRghKQ%}Bj%BW1F`!p}U-|Yd{y!#BgrErbh(ua}ct z@8^yQZJ5Fy$(fCnSYJ)EX=NHz1c|#OWR7&}>rh2w%s^35Qj1eX=w^bSX_FO{R<5nNw{Z{t)Fc$uB z2qR2m3gyvHxDr3`Ip4c6*8lkH-%ic(*!qXD+`0X&tnH?aSRU{lL9a@qoikX2iMjJ9ch-FkQD^&2;Ku{@04^W<@Y zC7$Jr=-Wf-j;`tBMCq0|;Z$F3o?Z{8wqB3k!ohr{daBA8f_)y{Nd&lSAu#CD4cR2H zf0}$@%gbe#HgIK+*}V5{`(mRjI_w-aF;D4nADS@7_M9)ip=2BnPr>eSJ+8C|-i2oG zA%e|~*#fmZ)nk~CHDp*ehw`R8Iow~g%>=V9clfl%X8f2>y?IZqS0Yqe&uRf|(nSj5 z>lqe^N2ObS2x`3DjPsp6wG~~X`_lcuWVYp-xvHS0cJ8)N&r}`*O@w-bOrZcg7dv;o z+BbBo>Z3f`iWW{uLZ}pB!~yt7RYixV$gPE`w>ztHA7K9Dj|l zygRPVO-wWbIhU9tp3DpO2*=nB&55gDX!$t$vv@78ZJis~)iceoL^?Yx?{s0|0fKH4x>__yHAq60nRly$<$B5I)|PhqUY#ZQzN zmWisKni0A8a5mLIq;@)Ny`L;X-iyBUfqm!(7@?;i+pstPMu3EOAV&onAZ#yuk<1`P zz+Dhw$33MbaWGEfjL6AziJ;RRg-XHf;4;dVM;8a&@ub}R$K331AC%>{z8$dNZ#Aw# zU=*Z8wc;%f15gJaALdpbM35-QPKOT^++jFsRsROZcJc70;R&(e2hGvnimft+k3m#ZROVR9rj5#$7 zSm&%{Jcp|21NIg1*d-*^XU%|+jPK)O3k*s%1AFaTwX_4!&I^k-_v6wH9E^9}_RJb@ z_amScV$*R94(76oM+{P5g|Rm?b!FGY17&ejX!PMKC)k8Y{Tqn4O8?p|Z-Qjb$^+(Z z%b&3k+P8$;;*hSxm*qRx-co^YCx-|#mEXGY;3SnJimEFyR7XA$(UAe-;N})F1~|Yo z2*959lD(Fg{jP4{)G@^$JTKBC=?9vz#xb09aSL^n;epwsX9%6+c2kH5xx$;V={1qO z_j+Z7D?uu|k-xMIuuTFFH69?b4j$MwJ{I!8$(=o;3cQp-1L`^W>AYKa?pkiCmQq<;rPv1HxJr0)6AHn1m%1WOdY{$2FeS$8(#2hAYR$ zhX*_i(sBfRJ*4F<5ilMhBzuXLrpk*$aAWBpmI5kwZt1^q?)x(nM_Uyd=y+2MxUV;- z#LAW>aN5gs1!Jk&vjoc=I*TQR46arG+O@M!(O3aii$^$UBvf2P@_iqgNF^z15jSzz zwx|hPn-HaUKO@`%sHLcIO^V5{FQz560c_lFm-oXP-^GM6)DOKJy zSmbsnvWibc*kg^lsAJl|uX8sD^z-m+e89-RWVCLM&7NN$vH4?f#t){>p1|I-nG+!sk%5_!rsy@OD zUp+7ww7Ov$QOQ{u@Qs^$lg_L0?5e1U5)wGTv-ijy)Kg9WIJChDg0t8z;Jf&Su&FfI zv@V%aut=3_M%HH(zF#PO6OVK!EdZ8FEdW;HFi;u`?tlFCf9xmSA(Yo)Ed_J15*R)! zfFa6R4$W~MeauO9B2OY^4g98@nobHrBI8m0p~<3ara~}&xbs>PNFC~EguEP?U?|gm zB@S#Q2(0j>ZXYg+f}9^Nma5JkC*VgbUx-K;nwR^^2*^TR6NVlN&G!#-h!F+WLIfZ{ z^Y2E(tg~7aK|D@a<@PK`U`n_uzO)TY%u#xs!RSSqDqTi>H4^W&s3!b%!dVo;Fwkc- zJQ)s{k*7wDw2V(km6PH;-nOT}muOZn0*D*^;Ksgj2~!??JFOy&fs{rfwdlL@B1^&K zMfQ4Fg~+wRJ@Ubp+X8MRxCgF;Z&CIrOcj{%V%Ro*Lj7BKKQ=Ukpc*>NTAoQf>)a7R z#VN3Q-=K(i$e$5EIsxGp(Ta4_&e=WKQs*k45Nb>Fqts>3D8h09C7%(wA?-y;2n>v7 znv+jOU&egdj-3Vt1nzMv(hZu+M3xp@UE75y={3-6cnuT8y7DysXj^E}`G9GLBtxp5 zv7&-1+@~@+$*(n(dbKIbuN2JFawF0S_17~*i;Wx*;cBfBdm{oiYYg+UfiqE-W3HU! zr{cmEne$4qaR}no36PoLia-kf9i=Yi78+rnh<*1h4;8;CczRmF-i^$CVnx^!!Wy2+ zpawN-v^XNmlkfq?^R0fgYmU4aFmejSIJ*!g172F9a`WDHyb4{ivj(P$?A)FOD*;3u z3p(`kvn!XGvgQ(2&ZJK(S#| z+J$pOjl)87=y~(3E!iG&>+r>9~3&jm8`$G0}OOVt|iDjvIbTJ3v zf?$|EX%SV>>s}mLWhwl3Uu4=Mo=y!5MT#_sNd9pYmq3zTzU#^p}nEf#<39J#Z z0q37^uvSq$k0>W$D96?zi=Kx80x(isPNp6(>5u0fEa_JG$Ws$*!5a%;Zlnq=jD5cI z@t^9xh)^>arz;1~wH*xMK&Ty!yVm(0)z=XbcR$#iVR~}%Sr;!z)*g+>d{L` zk)sq^0;)2zk>k;^sl3HXMa&06LMizFJUew&&2aNnUlnhK!IARLzEERC?yP|QPH@t5 z-dHpzWicnpsayv+6jH4W&Dc!2?pe4!nj(OtWE)n>!t0mZ36ricUibh|PC}z=Z#Di1 zt*qo{%G@iwMWMrHgxUn4<)KHnYf*y^C?oKxl734eG(h1>j_JpLo*BxaXSFY_c0cU# zA-A1zZpyp=)brUUJjSL748jl%xRequ+*KI-X+glMHPmkFY@Euok+?X5D!&>;R1pHoiin3UD`fVVB1U6nb{P0iqc&b!epOAeD ziN;H4+*)PerF^74{~SzH0}9661^r69M~VCtm$NdSVeypFGnY%<>g<>VQIG;qV{<1g z_Zt|lO07n*%!&)}cv}va9}8kT2zFumz?0heV8xoRp-<(cTjow~#gw14)Zn=WCJpH! zY~GXaoCj&OmEQ*=t^E0+g(6NqM5V5q<1sh=<$FyuE-DxUV6;6LG47U*u)qryu5pEW zg+$5=mw91Fa=mySZ~k_U^@B~h^aoU<{7P7*fXzX%ZH1~4QS2`kj*C8I3SE-vjub9} zbYyTAEU`)<0v3XgIm=OtEG8c&6|&Y$vjGD1^EnY3VXI#$VaMjtHXpILIGk0I5zBuiq*k{`V&g5VmX_4is<4TuHT@ZdI(|h4 zU08IUe5}RPWVu2JDbZ#s3Z%^T9v+oDcrYFVEK4m$44rm$({;XToOD5# zIGRYnLp$ffoQpdxhFM&@Om)I+)$Eih9u>Vx7-g}hZDV-AfqANA;e~{%DKR8$?)oC^ z0L=L@xkv=HFp>0ObK7-6BdCSCiOjl`f9sBlBvEz=7(SVhuqdd8KuN)`i3-d*P@TLN~QzA4aPw z)ss@w1aNGEqYh(W*CT-}#Teu!*E19{?joC5)*Ow#V5K&49xB$#6sv$lJ8Gk}0akD{ zXWkgO%2_A>d=bjdHsXD?9Gp1EpZIAyUFgjUVrK=#E*4><(|Syc0A$zSu? z!JlaSY(+>?mIc)U)P}K`6vMr7K9De^ZUbj4s(1NI%DUc=u52SSXuiyZG*HE%RBGL;mgZdNG zl91I5sy2L-f))jX=pAQQT}%l`;Al8}(6Bt-Nh4ZJd2|pMVp}1$rymYdi%_4^TgH*M zX>sHDSFD?vk~G*0AptLE`%ViXE_76r+NG(xaydOC!Y(A=hhR-_)X1 zXS;THt_5(eeJaumG0q_3mbhYu8^bnlVb!42s$2_^lh#o}l%(E})psOcs8o8zSY=SD z3jv95jiVE=u0^M^vC_7}!&7pArsQiI=lZKt5V%1q=%$MAx?zZhmrYG!F5gQ23@A++JhB05EUOLZS5PR)K7 zI7I>AGNN@EotQp07f6z2%|yRow-DjI;=PO!TC}o0C8+~h(?HUk%#`{|`n`rj;BpoLuYi)FL=-@J@NNNX%{;p1(Zhms(Y8s@^yCRRnTgGz(ChRcm<;)3e7-U{J; zw071-py-4r+LoIyQSb^r=6ukVbymdh>6kKCC}b%8O!`2rwWWASeM&mRw!A5SVHoMH zAmp6~cRu-lc8yn{p((mBzIR-*bAA1 z*XoOYn;xMfHA{a;D)~g=&qwQQ7pZq$eq;=yb-W3ViP=(PQ9s4ntjr~?f1JBb1-mL+ z(Zg91hK0wZUce+8ex5|q8V%^DK^ey}b-@bK5KHvKiao4_2-7i0ljdT@+ckBEJZa@U z0!({Gb{4Kursb$0B{W<3)md$fp;kIT18H*>)nei>r#qnzlm#jNB@5Enz)))=Cq{!< z9N?Ihj1EhOMw5u@N6k}EGexAmiV{`kVQv{4_E5SQI748z0)~eK9vnvwSB;s>V5v>( z$#Jkj^Nv&ONqK94S+hb4Bh`+zwY-qFsr|Rii!F#ZMGV1M2BRWg_6m<{+6R>BJJA*?1lFjIWdyPT#_AWfgU7T7a6+~;FcdviH=!Su({Ja)vF@* z=@ea|c4{aCA5IdwlX?FT#39z+BvbkL z=~juppTjQImqLKj{45GHqoxs8F?YQ!Bb6@_MD16DtXsQO!lA5FC=t?XT9WArT`4uC zMY;9RXR&&It_!0J$Cmy4>~s^<68e*pJu)0!bgTt znhV4(BO;@dyvm4J(TSRaNEv%cMRhOrXtr7`qzr_S!sL*76uvugJd)z#*jbC~{w6F> zns@r;dGm#*-%9x<_InC;d?nPki6vWAlt5}^^Ygq)T*I79g$Ra<>5YV0oJ4!nl;9KN zkz5uAW>!psMQo<%J5mYnMieo(Y~(ouZ@`w5a`T1uuVP+YCRM!D0YP|y z>VeJ3xHRiiH3lA)U81A)-iA51YEqm$B?0KQXCTbs{&s;8I!sz|(?&A$vEfvm;W=a1 zOaZdjkc2wiRh`I9tloMUI<8Bi!&-{@bta=s?}dXZ%sVkM8TGTtQ|Wd{*?4s^n+CIF zZx@#M6+6BPk&IPboLqj?Ov8mnMEh<>iAgP%bzZr1f;}>;3YpY=mmr1o^iZV{BMMhej?czd9N9{`dk$QZ|moZ$g8P*EeR7`43tn^yvmSR!{5*UUU2rLla2=2aJ zWdgNIb#JLK`!n=~%ip+`mA)i4dy1S`2c|o%Iz-48k6saRe@8gJU5z~zHV zjd8!{b5*E~et!2eB0#iR zUSb$*=;v^@FIgiYip1LK;RPx*kqm)aJ}hr^`y?3I5Z{WWM3!H$tY1aYOtnn}EXDH1 znZ4}C@p-j>sO`_QkJGB}7zoKzy~DRGqD-`g)eB~C1XMD!$}|LpN<-eR`aB$ni@DL5 z`dgdHrkb>6#njUclXU=f3N(Ry4amKW%M7C*R3{4qRCsxfH9diq8hao*>HGKPjYNID zO^WlAa8BQ-^R9bR`JELBX_gRZ0cVS6aP?kifBwL+JTJbCYY7NTnF41IjpR({_VV%u zy#wHHnjPl>IgX{nF4 zV9R?aoiG;#UzyMu1A8CO#!vKJo=NCSFD{@%swLT5nShiQdU^A(N+?L=W+SmSno7dh zlG`73zFay9&2Sn$=L%ksOW?EyPC6CD$MFS^L0lYDxOnMWWIx=vL*DiyE_gi}hg6O3 z7&w8lVo?fZQP}zTazzjtT` z6F`m}aA(VG>CoX|!ec8T!j8o#w63HZ)&SbeN=C92SO&Lj7DZm^ zazV{rXa<#s^3WB^U>d+8L59N7CKtXgWE5mC-9bD*hN|6T@z_2N8TGA?};om_p-iT9DO^Vn>v;0T!f$2Nf9Ph%3e z9a92;l^1xVzE`T!c^C_2dNhM(z?FoTssfdC29G>merISt+BmLo5@}@C*=r8Ua`Ckv z#*Ezd5}?rJcjgLx-V~(l@H~Wv@bESjRC70x*eBAKe-N z>ZQVBNt)ibBN}MoSRczanF0Xa3R`*IBwH8Vd@Jg&uJ!*1 zxt9N)=6?ZDO9KQH000080It53Mb3%`<1{4z0Qgn_01yBG08d3iP*X2sXfZY}cxZHO zY?XZ5lHA6X?K{2#suxlb+Us2j6`E^_#!^@NIb-yY|cH{IkTJ`t-%-G>+$I zx3`ze<>vCqO&pH5AAk1QXScubnvGrbES#s^qbr;Ge9*Q3=cA8)e;dy!U)lZ24L`ko zU5zLG@%m5s;&c1n=i{Egz5VFp+w&0nsoyu%h|T_{4Zk$|*yrD-)V06zNm{Kq{fCzkEJ6V;jEw`c$3AFqHrGpLfr1?W5;y)8Cgvz+=;R zZ9_VRFmB56dWM|G@XL6+Pk7pC2!}5=b=>b_y#Ea)cf-$b|Fz%qcf3K$KkmXpfeln}@m`tgg+H*xc+-t7EW_{g2bfkG|hL*4OD{tao+s zC;8$u?fm-Zq5Ja9DU`251%VvPcqm_0LzkZ4;tSm2lYEEupXV=sI)%RczfIegmv|q_ z9$G8AIP|;)oUS~?34fm8pP@aJOcu{gw`gmadsI1EjV-*-?U zzO6=GcBxXitM>Q&IZU|xj~=qV#G$Qk%JQpeEH79@!7KYXHv3RN{%L#Fe)#AezQe|# zE!<})FU@$ur-x}6u4PyC5JVAyC0y@T%TLvXD~9RdibFGmaz9`tlF(D!yE$OXm-bq= z&G?}`BaPTffkzCyd0%gNe?2Z94%=BcY3kbsn}@}A{I~WtP#)SNh4ds9U7W^~32O*l z=yqYi7AlCF7eU46YdH?M29kjGuK1|de^prr-TyGPMViiM?Fhfy5Ajmt9!)<+lauKK z&rj!O43y6H*rd3>H>C&2d8RE@Dl$8#2()Fw<2GLjl9HXu%PlXgb^yQ=UZTVFkVPfH{K0_ zyQOu+D{ZRki_na+nH{VVU$_}p3!$HN(3kMGRNA^D7DSNk z%WIs<>0DL^;7>8zYUJLq@pSY2_DtvyY9wrk*W!jP;F?R4g@;F`dd7u z+QVYFDD!D3t2k6cSzRi~dKYO*+-fDe&Cl7qYPMR_c!?i?3;=XSJV%cgAhmI-%ZG@) z;HjIJL+GE3`avKT93vk!#^M;b)EAq4+aFIc(lw**S~c_lcNpCa=FtU{VYP#=5LNhq zH%%8Pt{sdojH9rmj+Y+ay@D&^F2@*QTz!oH4W-tR|KZDTBG=VHZ@6TPa2I@ByqWNq zix!a=_R|T{xWkX|h_=Bdw!S`Yd0QUa3LF9trQ9Jb=$U@MgVbBO|Dl}@hih>#luZ17 ze=^q(gB$~{J;pPy#bO6&=U_g&Z==C9(HusDuw3Ax3~1YOvtCx&j89Ve$F}MGQOg$I z3=^&%`R9huABJF{@%;rmXq&?*%tSnAT*P1E^kk479AewX3;xDu{1LaIW~=Kz{`S9{>}c9$Q8x+xioilIIaW=d zE&QdHfV-uDAVCnDW6lZNr=DQEqs8Pa^n-AcLK(>hU>k~c1x;Q6c~3|5@LaWBq*sp60j0`diBMbqp_+Qr#0V%ejUp-)*<7-A z(y1EGu&ri)57B_Rz{VKG8wwLJi%mv^m}u-k@fS86<1iz@%hLxYao!Xt)4T111dZGB zn~I85fG)q4x9~P_7~0AYVL+Ho1@Pbr1v2u&3!RV;`_Y2j%ev}r<|j~q@^40bgP23O z6bSPG9)n~URQWYXP6hA>uHr`zWEc>0&A@s%D9+<1Z7?VTFT(A5%BC5_hLS*o*L+>! zqaUgPw`p%SKoQ8ewiqvT17a@l_WhyQM?5tcCNfwxiLO{eobUu{DxCw8j8-e1dQutM zBt;&3{MNy%qS@LiwYn$Zre+y)bkUf(aE&BUmn0f*T zLRKnYS3hIrS3EPFnlsc>gkPYT(G&}x*ijdBMI+26J3>G*k>`bBnPd4f0rvm#x4+*N zE6pG}2_>A_$zC2BqizGXvNwRj|M5%HP-$!rys2ri5`f^|7reJSEwDd_yU0&}ir-Oqdg3+G-OvQDO5BNxE| z9G|u#T_#~}>S&rP)?l?_9I_!U9GBub1WjfSBx2djfl)0)P<&1Puxkbqb$EK!k%q#~ zTbcpH_;l8+|Dt5BP?ejO8{2I8tirPZJ}pS-v?Xyr0B#)DNan$OwOHv*u;)+$C^a9`6tg*Fj+ry@rG1h!?@t=8~UQKv7;9B9Onrx`f+BNE)*kL2$-UIg|dMX zCRxTOqKV7Rzdu1z`PT~uDxdX-IQBSBDY5jUEx>OXABASRo*LuW0cn~3sQ|`nSTV&yMFMlkiLoboFFnTaU%C!7Wm>Z zv0t03TY?fUI;sktFV+|ZZ8NG9`u_*ar~~4N6;~{_q_BMIDW;Hv^uW?7A;uaae~cbh z<3XvNJQ0b3DmO>N-ZK=S)#zXM5MQ_^PdfKRc|HeeI=PepeJy;qoRb?lSHoz0u~QLhcV*7<-&B}!SzHH6#R2TqYF2U` z&yd{lnZ9;lxm#s*C1|JZ2>E}dVp*Dw)qr#iD|y0{>1x?cn)afwVNi8K88DYurTc|2 z&2Z@nLvaa#R5$b%aAXsYZ-EF3WSNcYrI*X*(iyXXi*%pF+C|<>;l`Fnq!L~i8T{|-ojogB)7fpoK;&ZEwV4I1K0HF*fq{Wk5Jdf=bv&rp z13)Ue>ex32@KxGg#hM#S7imjsk0dK|1Q!;(U}5N% z)%TD0whKy0DD&bRTVm;A6b32H3O-CZz+A+sD{lDbsI3Z|xr(gf!_+Z^G z1(vd+CT~?9;-YD3p?Hmzo>;(Wj>ncE(>T`V?nwuMaG{rwSrbtXsU`vntg63Xho>JS zuD^Rv0P>7XWS*kgv8;9&Ajdj01S=%Zw<4&hNTJO6BHkpLuZ$ayu+)khT7?Q$<)Dov zC#E+pR7yl+115WJo3N&C79@q@#Sr%Q@J4RkVrp|ApgX689dw2pK~NV0B^OhgMjZ+H z#KLkQko6OVS%L8EY1-A9{C!eFrAnBngRU`bK?2?%Uld=*9;P==%9nYF5CQbys#V$)bQ?#uQI_dj6|%wMowuy zgA~z|X8Oy_^fG))JC1w8^<6kM)^Wk(rr|swySMa9nx>f+h=2!{9hGUp8QJIY>JHNm z?h?e+f&1R-?E0p|60b_w#EJ`MhFl_2!KFS6eq>j}8R`|pUX4-=lVFrJ+l&Hp=$IqT zV_d*aV6R++l1kX7vZDYa90FLvy*PH^0UqhjPl2MlTM7x{gk;m5Q2}h)Di6-7zkSde zSNryM)B~mwBuCtlVE6}M{(N8l z_MvL0U@C8$gD2+&h|G~Fd7ivt2&c3hYPDI@6l7pZ8OSTFMVGAl*neIGFC$?)&0#Az z%SK|gCn=>@Sx6CVT}xusuqB;ZWjFFjZO!Ad^4{Yhj)MQG0mQ$>3+XP%8|!Igs_GAj zu6c!L4_@oFn5E}t1%@7Sh_zpr&LBEld70|KlQr*FL<30zj4iYOnMGLHfgf4BY-~bu z%iE>Gx-yZRhL<$`0h;Ldc8Pw32p96#c%&7H^tBaQxFRnGcA?^;X7AzOa|jX&dl~i= zFOqd)CdEsCjxBN|fi(#nkd^H>O4&0XtJbi%a-i+TodqPpXjylf%yPsHaBnSd%p~O8s;s+!2#tItM7u z3GT=>V7XrfAaC`do+wv2kj4>e_d`rx-8&#tr^DhAkSuq|tFF-e=j4QgS1;{5-Ql`| zVNz~Gn8yIkgeM{hm$~{Rw5mq>s*&e(vg)=33mj9I$SZmlf-gBt6fEgz$;P%}0FjWu zVxfsb8OjbEFh5G7x7>3G33$<73u`Pqu8y-agb0yyN0Y3@MN6FQe&oUs9q_R*6sWw2 zohr3Aq*xVYS0tRPPAVGD@y;^k6gc4kia76>Jvf8T>AYIM5E7~8MCHJ;xlHe#GAADk zX;nRxPCg6?Spm&kABZ?gV8%=4yL*^a8|JY3*QvS|kjW*qr0`Z9{<=!%Mp5zs@z-nvMV5cu4zdVEY0WR`13{!W$=P(29JR}AalAoscI473@ z;l2+vY;3C;Jc-TNU6{I+K??wP94uLJdljTJ;(Mzw#}R9HgNbY4VQT{*08T|983pBZ z2<@2X9N-yNSJAgsx({zrz2@M>t(it+cZ~&SQ~cZ!npG`jA9ACMXrnbI_B0R@ooaiRLQ{gJ5mW8wvrFd50iFRX(}8Dx~@SqpIOEL zvxwxjry+3chJo{QiYb*(-+-KR<^NtWD$Z3ZpKar<9v8Y#lL= zjlI=ns3BQrwqNcHn{`iyw~-*@>RlxHXP&p7o0wZcbEpkUkL1zvZH1;L2Y<8YxqS?_ zyt4rXY!`_6p_#Vs<&cWi7jJQ0bE_7QEF^yEMyP1NCMU2T9zrnpG-nVI zX66>W{eqONN>|a&o}+6+`JH$PmH{x+l#+yIUc_BnNyCz8#POCq(}i3>c{FY;?WZ{; zur}jrTeP&+__A24m7BB}Br)biJj<2vM{3U_Zd)hGl_Nh=dgsztwZw>rK5+78K`_(n z3Nn?kbjWJ=mOy&3s#sR{D16xX(31Iyc)=T!K1s26ugH=wG*!pddfsB?N{(6?=u1wz zXq#(&SK+JBQy{zOf0DQ>c^d#;&}hdZ$gSFFVz;|T&y{9c!l;xkIq@D^Kw~3d7vzU4mN~flfMy_> z8pP~pt5Z=^>}rU4zru#~6r_su4B{8{ZiSw^*jsXO3T>yqL{$&!l%4h7qgz+R1GMq? zoTy@d?No<3t4|g}2G+rm*V`JGlR>S z4m_ncN7l00UX-dmfOj9RTAR#=SOKY&L6F<6Yq2+PHPQQ6i({oK57wRL*-B0!8h1Lc z?ym%Jzq&0wBAk8n&8tvcRIYLRXh5E-W%Q5^=c-ML>zqkbl!jhI^g_*=!XO0Y93+y<6B zvRIAjMgkAAZgZ2WHeQlNexPU0+-To6oDNnd8ZSlu1?LtlT6EKav&Iz%Z}UuLYL309 z{kAawqTr1CdA3}zex}T=hA*9(h>rD{Kp^fcCHIX08CN*cvyY&{<+@!W)z#!_)G>3= zimABfHcZHg({^cFSi`P&r?kK@?Uzo<%rw&S%Mlu%LLR|x>Ss%c?1MW>4htCyMAIle4O zXirAiCm-d!8k7qd3om_uKJ;mX0dHyWJ~TMae2O(ymHtH>mZB^~To>jQOCgGD@nUW! z*ZKOzMdk+LoQ@jdXD+ndoyCzd-Cw;{>BgKwu4y6Ds743H+{Y`J-79gvXkkibQm3k& ztY<|4oJ6Tf?j!eJr7aA2dV&Fd-!-hVq^aw;pt)MZysL|ZXJ8qfwIeVo9lBb9C|kP` zdsuZt?!vKX!dR%fN9FK!u=BMM#|kC)o;tjaQ?H4WEO2Hh$TK(IZsT*c_&n$=cF6NfXi; z+F($#X#t^n-59+2FdU`ip>!eGxc1Pf0m%e~nC4srSiG(X_U;hQ7k|BLKDVG}lXz+V zFqn<4NY2r!R-T{x>6PWDq?6Z2O4$~*+&br3Ip+^XOCVSSQpPB63Secc09-ld{;|I8n#JDY4QYra& zD{Y;JplW`RkAIZk>O9R{kZBG}%D}WkjsBM0x}jU=_|>Zxg#C!i8QJAXquXC&$r~d&yDjOIeMWTO}80Y3dh{GLnlY_D?QrP-@vs?#g7DGi4hmfS3D^LHlS9Ah>J zX3Gg7V8i}C`015)+S}CGNakysQNL6)smWQAbH~BQdo?Wk&g^Cca^-Bo?&m61y;KEX z=W)Z?db>k)ZkAHW=9@w7vC$UWaqn!i{_4I?#s~4Ir#Yz~dmlMvW{B%gi}^5$xa?=v7XcOf)la&~=bdVnH{> z%Q-EzVjEeYFBreq84V;WQLWOt&IhXKvG}(Fo?^w^kFypL>&LA1ch!+hAoFDsL7>Iy zT@(|v6m!()smP2~-_7=KMZPYq#+1t3xffCw4xXz5H(*wg{^Z&BKc6h5g?XaJ&0>c{04v4tAo;BsP7of!^Be4fe2kuKw-@65X_SLMh= z@PX6s<~-Ui(=Ql;GoyZVH9h-gndwtUF!Qa&vQ_n?aVl*4DzewhWHg@1lQ7m5{TWJM z4Uv9OX4LuM(OH-Lq1q8d1oET7Li3ti2B(%b(_3j;=ciLXEkzhkVUHlpp#TN9OB_7> z@~*pqM}?z{EL7y$VSqC%qplegl`->7El+^Fonxv}!crp(X{}CyZSy#rC8vdE67n%3 zmGs%gV+~ew=fC8Ws8@cmW|Xg8SvpW4t5ej@DQs4p#rI?f4LM$Y3S1w}hkVxm+iIVwf3na_woq&APF= zQ5DBi%TfQjs{16pnlo6Cg%*^HTYvsQDzdI)|< zXUGpy^}BN2!*97NKQ)O>uuQT*>7Doe)>mR33|)m{u*!(}H2nJ9l|SrGCn91#$)?m`a+G>0h zY5HT!;z?Bwj(Ra^DV1pvI*Gz8_t-YwS%I?nSB_aM>dM0_8oykels%xT*I9H9;9tA~ z>J`1KpJAWR*3IONzDFS!V8Cyel{P--NVVu}RPX|v76YK5Xbz;)`Jm#zx+|8U`~aUI zgNG#hn0wK@y=G6NsIKqE82D(0=fx4TBY<;jWhf1CSPZ<(sr&kn5TU5B?oU>Gg9VjF+e}KzaM#cs;NKE!)W=~;c@^^hjuF?+aB@d<`r`*vX6_8-EqR;eDip`G}n>)Z9)6+6uyr(B&2Wu89)$#xwRPB4ys8^)J)@)FISZh1WT;E0Mj}^)? zL$*?>4s(JVUyCyf&|5E=*n1w{Hkze-z9QN;Yn$cE7x;ae^Ja$j42h1O>HeAr^@fqr zF03Y|0CVb0s#gBaW3IVsvEJRWI&Zz%pKGFNj|W0{r(xRd@(fnY2^*)!@)M8O&Rz>* z2j}Mmt>&47Y8t1m*Mi?S=d>)3^HMc}HS9Gc%hQ;_NhAwveaCIBK%gdzcR{7XcUlBW z&~04ctq#GeTFy$Cbr?G5HV{lcD5&!fd5E_1Wz1()(|jVu!QW-a^&M#U~g zvCvQp)x0vjKfm=iTwLI~M~OyG!p_P){n-32MuVGS>ic;lY*8;5mc||PW8E4^ukx!E zI6B~+TjD67{AC^5s{A4J{ng*hz@2=3iY;qnJXP?z`Z*5U^4prF%%4!WwyY+)|oZ}}(+woFWp_EjYp$!O#(6cpJntt&|6VecXsjhl_d*pDI z(bGIUXWeGx@g!<03@8>E=s!&bhk@Us5WAJ;7zyHDq@bFd>PumJ^(xxm~E zK0}*B>)JEzH|hbj981b$k%dK)e3M|2Fq9Y#N^wn^6`ng?eqgbS; zYcs%SvYsoF+}L)`xu2-ORqGVL#Tm$irhpIE0Z5qQsurY z2TxtV3-ro@cfpEsx#!SMeKj`wt*4xPserJ61M}CVTx+WvPmAd~ZsjXQyW$|PFLKWD zUKTx9oYx}=JmKwWKT}lBDYALSXW0pGjo##4Kzeo>FFhXp(GG2@m=v`T>b_EIEBT}> zYqvVjXa|I0PCRciMx8BGKs$u|f-#i^3jRLbyftm^O7NG(=?zOP#^`lEfn|znT-L0o z7J6d_<@rN3v`r;}Sd&xJOj0lLfhR9jPFJ1m?U9?^B&U$Uli6oGO<_OCz!`m=1z1!~ z+sBs@q(K@<1rb>~6$GTEV*vqaSVDG5=@6t8>2N_nN@6LIlI{?syAhCHK|-2uc@21Y ze7?D^vpd(G{oVhWGxyA%x%Zqi4ZNO$JTko%4PDb23*p+ZieSHj-6WCZxv#W5?#08x zG&x?~Ffg7a`Ms4#1*`YoLj%}`ndY`WuF;JIn>JIz#GiifP#B#KP_MS8GADA&dl}Ni zbI1Eb%I#eUr*E34-11Nyz-Q2-)TA5T^XX28|>!p+)<}lbg>BaP@gaL z@M}(rRgKI^n8pTIg(noNrf3=6zjt53V=i#mlTF?+`N^GRzp}XR`&B{zQgto3#l1^IziJrb(hSI8q`S6X#Hz{d4 zc#VAnHZRJ1(qPr&LY4`!?sGR-_DdAVl-~kNmUpNEY$=?A-wWv86zIx-fv0SHdXSQw zHp@Tx<^$B;v`M9EFeP`YbzSq8b#Cx_qu9FDnkpt*SWcn4kSjsQgS#4dKUN!aY;&xH zvNC*2>5cH+Tv2Ogg@CJ;zJ+bijpLpaDPlTNl&x_tsX0X)+`_4lsea$~6n<4S!3NHk zlX;ul`kT&&p|69_Ik`q*jsm;7-VsZ2-Ih1pN|y4ft+q9xxyPsfyuvEPA!_6k001CB z0RV`Q@5)jSRMa_4pij;0e_mq66ecpaBNGJ|J`SsJUs7K4 zSAK0C3_8Ol`qL}LE>@NKY3proRnc_8(dd+;9`DpLmh?1YJx#+s+4W}?v$`qqp0_um zF;{}DZMpT{+QbhNxUe2zhNP;y%0mP``QJm&d@nixdY!wd<|g>P&$=pO+aXC;KcxL4fJg0?O$5gLU+ktWDi;C2}}Th>`%o_p(e&qs5Q{c*2$RN#KECNqaHHO ziCcYm2WyRgz>?pvZUz;_jmmAAy%AB&RQZ5OHDdQJ+h$r7kjZs2##?7X_xM$Iac9Ec*Eo3QyLQBpxzhilNT(~aMl;*_QGHO`|5<)_n` z1+v$^wOZby<>Pvb=Nhg*7>tnUFUo|;Wz|)dPxEYKivF{cMDs1KK0*459U1^|?T@dV z`N)~GIGj0(XJm(3<5@S^$L7MN4sbc}!Dt^A42`F_-eCgo=~=Fw6STBEFr4#ubV|ST zh^07$cDJs4PLFDG1hvKRY9O0+97j*SzF48TpAtV-_m4qvj)-HQz}Qz(E_JOss!H)2 z4W$oRN5BB;qBocbJhHb!s2~^(vw~#$cHFj(4m-VL-)lWNa^j_eIF)&~f`nMGAGY5s z-dOEB=+0av^?1|G>7%UQ`3~N+lNLJO!!mWm3k%Y2S(}G+N?UWyn?AN4f7ATc<>NxE z$DHM=m|-4FxOjEII-RtTB}{(5#V8z=ZQtUM1pnYx{)*@3HeHpcqDwCPB*d$t$vEp( zbGo6+_YQ}2GWkvZiVC|Gjj3j`$Q%NVxeCatIrk)=oX+Y@$Qn)-Znm;ZPvVX4%@zq! zGnIqajF674&ti_UTCzm7Xx2q#9{JK}aqg8rR=Hzi#EHJ}UU`KtT-!Oy z+$DMk6te z)H3sWG0&(CIO^$`dO)mU@U<7Fau18{TY9G%Xo?kGcXxKM;JA+M63i|Dh}!d}+gG&H!KZBWP1yqluFB;Q0RzQh(xV@vm?Q@yQk z7DBVYJWjP`U;kZkl=f7>d)EY2^sW{Kx`irHsn{ze^f^X)5b8={C_-^JX=Y<_4o#SL zROD#3q_Bo}cHjJC)!ps~>YZHrn#{}F8ylVL8&%(dYh|Wg(z!F(3`CSz zq-Y)zztlE2fK`#Y@gmZS#{H@IA(PiRAZYn%w?2}k$$R~bWx&8m)Ime#lWMM!1zDlE3|EO@wFR9@=kd#!w^9cvm*%Tg2hNYtt>xeL7$^=sk!%_(`RIiw35_T61sSGo&~WC!2_7 zTo{iz26#A;j*lr_qvlzW*3ngN6`oK(uo~#=7d4_nBvEwjt086p52XmEx27yi@hvc7 zz|Q9d?aQHzP6~C^L0`m!_npA1o?h?+m1vzcZQN|?0Z*g6bfGMX0v<%3$);{A$a<(a zGU?PtJJ%!*Kkr6pqTH&f9^ux}P64YFtyE1dQ!iVB9xISmYa8?h+EQ%>ANaq@QUKfApjA(ImX9RPSre6icx8ktxdfz8;Vw&r=-^`UTn zlF4qZ@~L8w6aW)7I8rz}B8Pnn@=k5=a}=7=7s|rh{5(<0E6^$qxD75BOhFQ4&NFiV z$Hd&KI|uVB$2T(+eK{Ztn3|#s6$`7wMQPLyjoNiX4eNOmTPp_G6pb>_pp;-08_cmM z>r-TIjHaxnd1u<&-94eV>Tait=e8>0&HDxTg&29?b6Y`*k0}(A_S5N^jMVmK*|s^f zLK|pqdKJeEBMQV_x51UBa z9y&74M3Av!8#*@>^V@gE!{^ibhmIIG)hkl2(2PqbyWC1k@X>7u`3Ct?b2zn@YS=bk ze*8RDV>H`0wh@Tk(1sHc*l>&2pm~e*;RzMz(TuB`2}qGURh=rUpLvFq{MA?xKrjlA z{RIz;O8^eNrCgnIi2O!tKLRWUJ0ZZYVt_7=tTd2EYt|v8>mJy8G$n;*lrxvF5NU?C9uObHY z6c6IevmuCP&`wP{oN38*Y_#hkk%sgABzP&SBGYbNsemB1@?&N0Lv8V9IW0`p?%JGB zgoav%3>LdaG9r7-PXXnt#qV09NLcZ!?k0dYj_KZJ_$B=qbF#Ld{(?$9d+e+~@Ao(? z8@qQc8I*c^;g-%kpOGl`2DLfy%dHYaoa$i5Sf{}4NwSaZTxpn$=^3e!(aiqZyZH6l z%z=2(!U-^=Y-}Z`IEM^1N-dB$Pp*8k_YeDzT0sUHt%whm;JfWbDkPrz>Z$suxV2NW z{mcQKtRuDPDVb)kV^VP9BqN=d!4K-D-h-uqFGH&l&BpI;$wbZz_w%zW3uNrySF=nj z?E+5V=6)yAtx+7>Arc7i!=Pr#fF~jjK=p^2C6<-Obwmc^X8QxN;yvg(2N64|G=nn6`@{R@Wi>2_b{ zohcN^qcE@;wVVYXJ!WQkEZOl4adnj#ql3xbNm(<_u1du_qC@1-V|G=NE|aq4=TU=Z zRkEr3#)tv4J%d%X$K-FQ8+0_HvvGL3$Ebbh9t)|UvO|TjurZoT_G`AGXoqldOp$Aw zl)JkLmgsxm-%(;9^l9emb{}(U23R6Y>O9M6(GcU`SZs%tWw^`m?BAG=Z?^b%l@{7@ zKT)PC6CXE~rga|YYwE#>)v_iu;Z>@A%pjIr;|LNC{m@YCjm1=XsdcyE|*}&%r6%fLs9|6#y8y z3IO2!Ibn2!ny^DmTw;b4p$VK6m>Y-pF}_!C;&|m@iLCKj_A}?jmxJ(KnyI+3Cio{a z>DtN6dWK3I#Ko02l*8yw?CcyyoJZ3rZ;e+1>!{JW=T>UoBfM~EkGk(%Eo!$OUdnei z$I&Bzd?N6N6O10o3)qOS9^2y0_V@R{>wW4rwLK?tlz69|K|HAbBZ+SZajUx)MYNQ) zqdJ-UoYU8BFE7W*ZYg@W`{Jvu#c#H%{d>MJRL^)2$B<&T|C~asy6ex1nSXePqaZvEC8e_SxuoE)Gp_9=c1rhd;pxl27 z$ouM33k*UjB=Kp3z10RzV-W$Go}eld6G{c^m52qPbD>9!JlA8mO^!}_vx&lV?B@JY z^G!n%iWXMiw|!Hxw{KqSP^c?tnu8HC)Unvy5EOTud@jbWNp$EF<*Q2Ao~9vwgo4(&v69LcqHCU1VNSN<$ndrzFks6Z>iUOpJ_aW-}l8 zg;V5qHVHmUKgEoYxj&c*6yj)P2{{W1*gX0Fq_6zX!r9B2v;@-B&v?Q`-8`hOModN6 z336{0#?OkL5kGaoe;8wHPA=eCmvOOh{H=Ok@_BW!Aa_X=z$+OP0CIK8KPmlL9C9x3 zQ}t|e_PbzWU>fn0T&q$i}UvyLB1^U;cUoX=VbP4(<$iF(is9e^rox4E)x>4^kJ(i!T z3rA}6{!3fs3hMbW7x;UQ_$Va3bZx0x@{f`6yA=k+`nkq@~o`&WxWWiHS{ zf2TLE)4OaSTdeJ0E%w~}oaW;EJDoSMC8me0H;L@!lBWhhlui1+qmG2=v6(V(6d#LpS{U5$|c^z0}C;8P&jutM^|KV$wA1r)MFQcLTX>YFo z@U_dgfu7T@j2Gzt@U_b!&U1QP<_~=y@VxA*mji|8_<-zh{BqdvvW?3Dq;nep`QJAF z5l*^n;Bt`T+(4qjZvz)X9+&aUlcjS!TIDx>Vd``lzkE7#j&p&2 arguments = (Map) call.arguments; - String identifier = arguments.get("identifier").toString(); - String themeColor = arguments.get("themeColor").toString(); - String scrollDirection = arguments.get("scrollDirection").toString(); - Boolean nightMode = Boolean.parseBoolean(arguments.get("nightMode").toString()); - Boolean allowSharing = Boolean.parseBoolean(arguments.get("allowSharing").toString()); - Boolean enableTts = Boolean.parseBoolean(arguments.get("enableTts").toString()); - config = new ReaderConfig(context, identifier, themeColor, scrollDirection, allowSharing, enableTts, nightMode); - - result.success(null); - - } else if (call.method.equals("open")) { - Map arguments = (Map) call.arguments; - String bookPath = arguments.get("bookPath").toString(); - String lastLocation = arguments.get("lastLocation").toString(); - - reader = new Reader(context, messenger, config, sink); - reader.open(bookPath, lastLocation); - - result.success(null); - - } else if (call.method.equals("close")) { - if (reader != null) { - reader.close(); - } - result.success(null); - - } else { - result.notImplemented(); - } - } -} \ No newline at end of file diff --git a/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/HighlightData.java b/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/HighlightData.java deleted file mode 100644 index 0e96c6b..0000000 --- a/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/HighlightData.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.vocsy.epub_viewer; - -import com.folioreader.model.HighLight; - -import java.util.Date; - -/** - * Class contain data structure for highlight data. If user want to - * provide external highlight data to folio activity. class should implement to - * {@link HighLight} with contains required members. - *

- * Created by gautam chibde on 12/10/17. - */ - -public class HighlightData implements HighLight { - - private String bookId; - private String content; - private Date date; - private String type; - private int pageNumber; - private String pageId; - private String rangy; - private String uuid; - private String note; - - @Override - public String toString() { - return "HighlightData{" + - "bookId='" + bookId + '\'' + - ", content='" + content + '\'' + - ", date=" + date + - ", type='" + type + '\'' + - ", pageNumber=" + pageNumber + - ", pageId='" + pageId + '\'' + - ", rangy='" + rangy + '\'' + - ", uuid='" + uuid + '\'' + - ", note='" + note + '\'' + - '}'; - } - - @Override - public String getBookId() { - return bookId; - } - - @Override - public String getContent() { - return content; - } - - @Override - public Date getDate() { - return date; - } - - @Override - public String getType() { - return type; - } - - @Override - public int getPageNumber() { - return pageNumber; - } - - @Override - public String getPageId() { - return pageId; - } - - @Override - public String getRangy() { - return rangy; - } - - @Override - public String getUUID() { - return uuid; - } - - @Override - public String getNote() { - return note; - } -} diff --git a/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/Reader.java b/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/Reader.java deleted file mode 100644 index 4c4bdc9..0000000 --- a/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/Reader.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.vocsy.epub_viewer; - -import android.content.Context; -import android.util.Log; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.folioreader.Config; -import com.folioreader.FolioReader; -import com.folioreader.model.HighLight; -import com.folioreader.model.locators.ReadLocator; -import com.folioreader.ui.base.OnSaveHighlight; -import com.folioreader.util.OnHighlightListener; -import com.folioreader.util.ReadLocatorListener; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - -import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.EventChannel; -import io.flutter.plugin.common.MethodChannel; - -public class Reader implements OnHighlightListener, ReadLocatorListener, FolioReader.OnClosedListener { - - private ReaderConfig readerConfig; - public FolioReader folioReader; - private Context context; - public MethodChannel.Result result; - private EventChannel eventChannel; - private EventChannel.EventSink pageEventSink; - private BinaryMessenger messenger; - private ReadLocator read_locator; - private static final String PAGE_CHANNEL = "sage"; - - Reader(Context context, BinaryMessenger messenger, ReaderConfig config, EventChannel.EventSink sink) { - this.context = context; - readerConfig = config; - - getHighlightsAndSave(); - //setPageHandler(messenger); - - folioReader = FolioReader.get() - .setOnHighlightListener(this) - .setReadLocatorListener(this) - .setOnClosedListener(this); - pageEventSink = sink; - } - - public void open(String bookPath, String lastLocation) { - final String path = bookPath; - final String location = lastLocation; - new Thread(new Runnable() { - @Override - public void run() { - try { - Log.i("SavedLocation", "-> savedLocation -> " + location); - if (location != null && !location.isEmpty()) { - ReadLocator readLocator = ReadLocator.fromJson(location); - folioReader.setReadLocator(readLocator); - } - folioReader.setConfig(readerConfig.config, true) - .openBook(path); - } catch (Exception e) { - e.printStackTrace(); - } - } - }).start(); - - } - - public void close() { - folioReader.close(); - } - - private void setPageHandler(BinaryMessenger messenger) { -// final MethodChannel channel = new MethodChannel(registrar.messenger(), "page"); -// channel.setMethodCallHandler(new EpubKittyPlugin()); - Log.i("event sink is", "in set page handler:"); - eventChannel = new EventChannel(messenger, PAGE_CHANNEL); - - try { - - eventChannel.setStreamHandler(new EventChannel.StreamHandler() { - - @Override - public void onListen(Object o, EventChannel.EventSink eventSink) { - - Log.i("event sink is", "this is eveent sink:"); - - pageEventSink = eventSink; - if (pageEventSink == null) { - Log.i("empty", "Sink is empty"); - } - } - - @Override - public void onCancel(Object o) { - - } - }); - } catch (Error err) { - Log.i("and error", "error is " + err.toString()); - } - } - - private void getHighlightsAndSave() { - new Thread(new Runnable() { - @Override - public void run() { - ArrayList highlightList = null; - ObjectMapper objectMapper = new ObjectMapper(); - try { - highlightList = objectMapper.readValue( - loadAssetTextAsString("highlights/highlights_data.json"), - new TypeReference>() { - }); - } catch (IOException e) { - e.printStackTrace(); - } - - if (highlightList == null) { - folioReader.saveReceivedHighLights(highlightList, new OnSaveHighlight() { - @Override - public void onFinished() { - //You can do anything on successful saving highlight list - } - }); - } - } - }).start(); - } - - - private String loadAssetTextAsString(String name) { - BufferedReader in = null; - try { - StringBuilder buf = new StringBuilder(); - InputStream is = context.getAssets().open(name); - in = new BufferedReader(new InputStreamReader(is)); - - String str; - boolean isFirst = true; - while ((str = in.readLine()) != null) { - if (isFirst) - isFirst = false; - else - buf.append('\n'); - buf.append(str); - } - return buf.toString(); - } catch (IOException e) { - Log.e("Reader", "Error opening asset " + name); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - Log.e("Reader", "Error closing asset " + name); - } - } - } - return null; - } - - @Override - public void onFolioReaderClosed() { - Log.i("readLocator", "-> saveReadLocator -> " + read_locator.toJson()); - - if (pageEventSink != null) { - pageEventSink.success(read_locator.toJson()); - } - } - - @Override - public void onHighlight(HighLight highlight, HighLight.HighLightAction type) { - - } - - @Override - public void saveReadLocator(ReadLocator readLocator) { - read_locator = readLocator; - } - - -} diff --git a/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/ReaderConfig.java b/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/ReaderConfig.java deleted file mode 100644 index a77c8e2..0000000 --- a/packages/vocsy_epub_viewer/android/src/main/java/com/vocsy/epub_viewer/ReaderConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.vocsy.epub_viewer; - -import android.content.Context; -import android.graphics.Color; -import android.util.Log; - -import com.folioreader.Config; -import com.folioreader.util.AppUtil; - -public class ReaderConfig { - private String identifier; - private String themeColor; - private String scrollDirection; - private boolean allowSharing; - private boolean showTts; - private boolean nightMode; - - public Config config; - - public ReaderConfig(Context context, String identifier, String themeColor, - String scrollDirection, boolean allowSharing, boolean showTts , boolean nightMode){ - -// config = AppUtil.getSavedConfig(context); -// if (config == null) - config = new Config(); - if (scrollDirection.equals("vertical")){ - config.setAllowedDirection(Config.AllowedDirection.ONLY_VERTICAL); - }else if(scrollDirection.equals("horizontal")){ - config.setAllowedDirection(Config.AllowedDirection.ONLY_HORIZONTAL); - }else{ - config.setAllowedDirection(Config.AllowedDirection.VERTICAL_AND_HORIZONTAL); - } - config.setThemeColorInt(Color.parseColor(themeColor)); - config.setNightThemeColorInt(Color.parseColor(themeColor)); - config.setShowRemainingIndicator(true); - config.setShowTts(showTts); - config.setNightMode(nightMode); - } -} diff --git a/packages/vocsy_epub_viewer/ios/Classes/EpubConfig.swift b/packages/vocsy_epub_viewer/ios/Classes/EpubConfig.swift deleted file mode 100644 index fdb3555..0000000 --- a/packages/vocsy_epub_viewer/ios/Classes/EpubConfig.swift +++ /dev/null @@ -1,190 +0,0 @@ -// -// EpubConfig.swift -// AEXML -// -// Created by 小发工作室 on 2019/11/21. -// - -import UIKit -import EpubViewerKit - -class EpubConfig: NSObject { - - open var config: FolioReaderConfig! - - open var tintColor: UIColor = UIColor.init(rgba:"#fdd82c") - open var allowSharing: Bool = false - open var scrollDirection: FolioReaderScrollDirection = FolioReaderScrollDirection.vertical - - init(Identifier: String,tintColor: String, allowSharing: Bool, - scrollDirection: String, enableTts: Bool, nightMode: Bool) { - self.config = FolioReaderConfig(withIdentifier: Identifier) - self.tintColor = UIColor.init(rgba: tintColor) - self.allowSharing = allowSharing - self.config.canChangeScrollDirection = false - if scrollDirection == "vertical"{ - self.config.scrollDirection = FolioReaderScrollDirection.vertical - }else if (scrollDirection == "horizontal"){ - self.config.scrollDirection = FolioReaderScrollDirection.horizontal - }else{ - self.config.canChangeScrollDirection = true - } - self.config.enableTTS = enableTts - self.config.hidePageIndicator = false - super.init() - - self.readerConfiguration() - } - - private func readerConfiguration() { - self.config.shouldHideNavigationOnTap = false - self.config.scrollDirection = self.scrollDirection - self.config.enableTTS = false - self.config.displayTitle = true - self.config.allowSharing = self.allowSharing - self.config.tintColor = self.tintColor - self.config.canChangeFontStyle = false - self.config.hideBars = false - // Custom sharing quote background - self.config.quoteCustomBackgrounds = [] - if let image = UIImage(named: "demo-bg") { - let customImageQuote = QuoteImage(withImage: image, alpha: 0.6, backgroundColor: UIColor.black) - self.config.quoteCustomBackgrounds.append(customImageQuote) - } - - let textColor = UIColor(red:0.86, green:0.73, blue:0.70, alpha:1.0) - let customColor = UIColor(red:0.30, green:0.26, blue:0.20, alpha:1.0) - let customQuote = QuoteImage(withColor: customColor, alpha: 1.0, textColor: textColor) - self.config.quoteCustomBackgrounds.append(customQuote) - } - -} - - -internal extension UIColor { - convenience init(rgba: String) { - var red: CGFloat = 0.0 - var green: CGFloat = 0.0 - var blue: CGFloat = 0.0 - var alpha: CGFloat = 1.0 - - if rgba.hasPrefix("#") { - let index = rgba.index(rgba.startIndex, offsetBy: 1) - let hex = String(rgba[index...]) - let scanner = Scanner(string: hex) - var hexValue: CUnsignedLongLong = 0 - if scanner.scanHexInt64(&hexValue) { - switch (hex.count) { - case 3: - red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 - green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 - blue = CGFloat(hexValue & 0x00F) / 15.0 - break - case 4: - red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 - green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 - blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 - alpha = CGFloat(hexValue & 0x000F) / 15.0 - break - case 6: - red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 - green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 - blue = CGFloat(hexValue & 0x0000FF) / 255.0 - break - case 8: - red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 - green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 - blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 - alpha = CGFloat(hexValue & 0x000000FF) / 255.0 - break - default: - print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8", terminator: "") - break - } - } else { - print("Scan hex error") - } - } else { - print("Invalid RGB string, missing '#' as prefix", terminator: "") - } - self.init(red:red, green:green, blue:blue, alpha:alpha) - } - - // - /// Hex string of a UIColor instance. - /// - /// from: https://github.com/yeahdongcn/UIColor-Hex-Swift - /// - /// - Parameter includeAlpha: Whether the alpha should be included. - /// - Returns: Hexa string - func hexString(_ includeAlpha: Bool) -> String { - var r: CGFloat = 0 - var g: CGFloat = 0 - var b: CGFloat = 0 - var a: CGFloat = 0 - self.getRed(&r, green: &g, blue: &b, alpha: &a) - - if (includeAlpha == true) { - return String(format: "#%02X%02X%02X%02X", Int(r * 255), Int(g * 255), Int(b * 255), Int(a * 255)) - } else { - return String(format: "#%02X%02X%02X", Int(r * 255), Int(g * 255), Int(b * 255)) - } - } - - // MARK: - color shades - // https://gist.github.com/mbigatti/c6be210a6bbc0ff25972 - - func highlightColor() -> UIColor { - - var hue : CGFloat = 0 - var saturation : CGFloat = 0 - var brightness : CGFloat = 0 - var alpha : CGFloat = 0 - - if getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) { - return UIColor(hue: hue, saturation: 0.30, brightness: 1, alpha: alpha) - } else { - return self; - } - - } - - /** - Returns a lighter color by the provided percentage - - :param: lighting percent percentage - :returns: lighter UIColor - */ - func lighterColor(_ percent : Double) -> UIColor { - return colorWithBrightnessFactor(CGFloat(1 + percent)); - } - - /** - Returns a darker color by the provided percentage - - :param: darking percent percentage - :returns: darker UIColor - */ - func darkerColor(_ percent : Double) -> UIColor { - return colorWithBrightnessFactor(CGFloat(1 - percent)); - } - - /** - Return a modified color using the brightness factor provided - - :param: factor brightness factor - :returns: modified color - */ - func colorWithBrightnessFactor(_ factor: CGFloat) -> UIColor { - var hue : CGFloat = 0 - var saturation : CGFloat = 0 - var brightness : CGFloat = 0 - var alpha : CGFloat = 0 - - if getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) { - return UIColor(hue: hue, saturation: saturation, brightness: brightness * factor, alpha: alpha) - } else { - return self; - } - } -} diff --git a/packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.h b/packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.h deleted file mode 100644 index bafe728..0000000 --- a/packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface EpubViewerPlugin : NSObject -@end diff --git a/packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.m b/packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.m deleted file mode 100644 index 99d66e3..0000000 --- a/packages/vocsy_epub_viewer/ios/Classes/EpubViewerPlugin.m +++ /dev/null @@ -1,8 +0,0 @@ -#import "EpubViewerPlugin.h" -#import - -@implementation EpubViewerPlugin -+ (void)registerWithRegistrar:(NSObject*)registrar { - [SwiftEpubViewerPlugin registerWithRegistrar:registrar]; -} -@end diff --git a/packages/vocsy_epub_viewer/ios/Classes/SwiftEpubKittyPlugin.swift b/packages/vocsy_epub_viewer/ios/Classes/SwiftEpubKittyPlugin.swift deleted file mode 100644 index cff93e7..0000000 --- a/packages/vocsy_epub_viewer/ios/Classes/SwiftEpubKittyPlugin.swift +++ /dev/null @@ -1,97 +0,0 @@ -import Flutter -import UIKit -import EpubViewerKit - -public class SwiftEpubViewerPlugin: NSObject, FlutterPlugin,FolioReaderPageDelegate,FlutterStreamHandler { - - let folioReader = FolioReader() - static var pageResult: FlutterResult? = nil - static var pageChannel:FlutterEventChannel? = nil - - var config: EpubConfig? - - - //12.13 - public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "vocsy_epub_viewer", binaryMessenger: registrar.messenger()) - let instance = SwiftEpubViewerPlugin() - - pageChannel = FlutterEventChannel.init(name: "page", - binaryMessenger: registrar.messenger()); - - registrar.addMethodCallDelegate(instance, channel: channel) - } - - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - - - switch call.method { - case "setConfig": - let arguments = call.arguments as![String:Any] - let Identifier = arguments["identifier"] as! String - let scrollDirection = arguments["scrollDirection"] as! String - let color = arguments["themeColor"] as! String - let allowSharing = arguments["allowSharing"] as! Bool - let enableTts = arguments["enableTts"] as! Bool - let nightMode = arguments["nightMode"] as! Bool - - self.config = EpubConfig.init(Identifier: Identifier,tintColor: color,allowSharing: - allowSharing,scrollDirection: scrollDirection, enableTts: enableTts, nightMode: nightMode) - - break - case "open": - setPageHandler() - let arguments = call.arguments as![String:Any] - let bookPath = arguments["bookPath"] as! String - self.open(epubPath: bookPath) - - break - case "close": - self.close() - break - default: - break - } - // result("iOS " + UIDevice.current.systemVersion) - } - - private func setPageHandler(){ - SwiftEpubViewerPlugin.pageChannel?.setStreamHandler(self) - - } - - public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { - SwiftEpubViewerPlugin.pageResult = events - return nil - } - - public func onCancel(withArguments arguments: Any?) -> FlutterError? { - return nil - } - - - fileprivate func open(epubPath: String) { - if epubPath == "" { - return - } - - let readerVc = UIApplication.shared.keyWindow!.rootViewController ?? UIViewController() - folioReader.presentReader(parentViewController: readerVc, withEpubPath: epubPath, andConfig: self.config!.config, shouldRemoveEpub: false) - folioReader.readerCenter?.pageDelegate = self - } - - public func pageWillLoad(_ page: FolioReaderPage) { - - print("page.pageNumber:"+String(page.pageNumber)) - - if (SwiftEpubViewerPlugin.pageResult != nil){ - SwiftEpubViewerPlugin.pageResult!(String(page.pageNumber)) - } - - } - - private func close(){ - folioReader.readerContainer?.dismiss(animated: true, completion: nil) - } - - } diff --git a/packages/vocsy_epub_viewer/ios/vocsy_epub_viewer.podspec b/packages/vocsy_epub_viewer/ios/vocsy_epub_viewer.podspec deleted file mode 100644 index 329e653..0000000 --- a/packages/vocsy_epub_viewer/ios/vocsy_epub_viewer.podspec +++ /dev/null @@ -1,25 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'vocsy_epub_viewer' - s.version = '2.0.0' - s.summary = 'A Vocsy epub reader flutter plugin project.' - s.description = <<-DESC -A new flutter plugin project. - DESC - s.homepage = 'https://github.com/kaushikgodhani/vocsy_epub_viewer.git' - s.license = { :file => '../LICENSE' } - s.author = { 'dudecoder' => 'kaushik64494@gmail.com' } - s.source = { :path => '.' } - - - s.source_files = [ - 'Classes/**/*', - ] - - s.dependency 'Flutter' - - s.dependency 'EpubViewerKit', '~> 0.1.3' - s.ios.deployment_target = '9.0' - - s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } - s.swift_version = '5.0' -end \ No newline at end of file diff --git a/packages/vocsy_epub_viewer/lib/epub_viewer.dart b/packages/vocsy_epub_viewer/lib/epub_viewer.dart deleted file mode 100644 index 1a947a6..0000000 --- a/packages/vocsy_epub_viewer/lib/epub_viewer.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:path/path.dart'; -import 'package:path_provider/path_provider.dart'; - -part 'model/enum/epub_scroll_direction.dart'; -part 'model/epub_locator.dart'; -part 'utils/util.dart'; - -class VocsyEpub { - static const MethodChannel _channel = MethodChannel('vocsy_epub_viewer'); - static const EventChannel _pageChannel = EventChannel('page'); - - /// Configure Viewer's with available values - /// - /// themeColor is the color of the reader - /// scrollDirection uses the [EpubScrollDirection] enum - /// allowSharing - /// enableTts is an option to enable the inbuilt Text-to-Speech - static void setConfig( - {Color themeColor = Colors.blue, - String identifier = 'book', - bool nightMode = false, - EpubScrollDirection scrollDirection = EpubScrollDirection.ALLDIRECTIONS, - bool allowSharing = false, - bool enableTts = false}) async { - Map agrs = { - "identifier": identifier, - "themeColor": Util.getHexFromColor(themeColor), - "scrollDirection": Util.getDirection(scrollDirection), - "allowSharing": allowSharing, - 'enableTts': enableTts, - 'nightMode': nightMode - }; - await _channel.invokeMethod('setConfig', agrs); - } - - /// bookPath should be a local file. - /// Last location is only available for android. - static void open(String bookPath, {EpubLocator? lastLocation}) async { - Map agrs = { - "bookPath": bookPath, - 'lastLocation': - lastLocation == null ? '' : jsonEncode(lastLocation.toJson()), - }; - _channel.invokeMethod('setChannel'); - await _channel.invokeMethod('open', agrs); - } - - static void closeReader() async { - _channel.invokeMethod('setChannel'); - await _channel.invokeMethod('close'); - } - - /// bookPath should be an asset file path. - /// Last location is only available for android. - static Future openAsset(String bookPath, {EpubLocator? lastLocation}) async { - if (extension(bookPath) == '.epub') { - Map agrs = { - "bookPath": (await Util.getFileFromAsset(bookPath)).path, - 'lastLocation': - lastLocation == null ? '' : jsonEncode(lastLocation.toJson()), - }; - _channel.invokeMethod('setChannel'); - await _channel.invokeMethod('open', agrs); - } else { - throw ('${extension(bookPath)} cannot be opened, use an EPUB File'); - } - } - - static Future setChannel() async { - await _channel.invokeMethod('setChannel'); - } - - /// Stream to get EpubLocator for android and pageNumber for iOS - static Stream get locatorStream { - Stream pageStream = - _pageChannel.receiveBroadcastStream().map((value) => value); - - return pageStream; - } -} diff --git a/packages/vocsy_epub_viewer/lib/model/enum/epub_scroll_direction.dart b/packages/vocsy_epub_viewer/lib/model/enum/epub_scroll_direction.dart deleted file mode 100644 index 9004ac2..0000000 --- a/packages/vocsy_epub_viewer/lib/model/enum/epub_scroll_direction.dart +++ /dev/null @@ -1,4 +0,0 @@ -part of 'package:vocsy_epub_viewer/epub_viewer.dart'; - -/// enum from scrollDirection to make it easier for users -enum EpubScrollDirection { HORIZONTAL, VERTICAL, ALLDIRECTIONS } diff --git a/packages/vocsy_epub_viewer/lib/model/epub_locator.dart b/packages/vocsy_epub_viewer/lib/model/epub_locator.dart deleted file mode 100644 index b6581ae..0000000 --- a/packages/vocsy_epub_viewer/lib/model/epub_locator.dart +++ /dev/null @@ -1,48 +0,0 @@ -part of 'package:vocsy_epub_viewer/epub_viewer.dart'; - -/// Model for android EpubLocator -class EpubLocator { - String? bookId; - String? href; - int? created; - Locations? locations; - - EpubLocator({this.bookId, this.href, this.created, this.locations}); - - EpubLocator.fromJson(Map json) { - bookId = json['bookId']; - href = json['href']; - created = json['created']; - locations = json['locations'] != null - ? Locations.fromJson(json['locations']) - : null; - } - - Map toJson() { - final Map data = {}; - data['bookId'] = bookId; - data['href'] = href; - data['created'] = created; - if (locations != null) { - data['locations'] = locations!.toJson(); - } - return data; - } -} - -/// Model for Locations in [EpubLocator] -class Locations { - String? cfi; - - Locations({this.cfi}); - - Locations.fromJson(Map json) { - cfi = json['cfi']; - } - - Map toJson() { - final Map data = {}; - data['cfi'] = cfi; - return data; - } -} diff --git a/packages/vocsy_epub_viewer/lib/utils/util.dart b/packages/vocsy_epub_viewer/lib/utils/util.dart deleted file mode 100644 index 612876c..0000000 --- a/packages/vocsy_epub_viewer/lib/utils/util.dart +++ /dev/null @@ -1,34 +0,0 @@ -part of 'package:vocsy_epub_viewer/epub_viewer.dart'; - -class Util { - /// Get HEX code from [Colors], [MaterialColor], - /// [Color] and [MaterialAccentColor] - static String getHexFromColor(Color color) { - return '#${color.value.toRadixString(16).padLeft(8, '0').substring(2)}'; - } - - /// Convert [EpubScrollDirection] to FolioReader reader String - static String getDirection(EpubScrollDirection direction) { - switch (direction) { - case EpubScrollDirection.VERTICAL: - return 'vertical'; - case EpubScrollDirection.HORIZONTAL: - return 'horizontal'; - case EpubScrollDirection.ALLDIRECTIONS: - return 'alldirections'; - default: - return 'alldirections'; - } - } - - /// Create a temporary [File] from an asset epub - /// to be opened by [VocsyEpub] - static Future getFileFromAsset(String asset) async { - ByteData data = await rootBundle.load(asset); - String dir = (await getTemporaryDirectory()).path; - String path = '$dir/${basename(asset)}'; - final buffer = data.buffer; - return File(path).writeAsBytes( - buffer.asUint8List(data.offsetInBytes, data.lengthInBytes)); - } -} diff --git a/packages/vocsy_epub_viewer/pubspec.lock b/packages/vocsy_epub_viewer/pubspec.lock deleted file mode 100644 index b571491..0000000 --- a/packages/vocsy_epub_viewer/pubspec.lock +++ /dev/null @@ -1,293 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - file: - dependency: transitive - description: - name: file - sha256: "9fd2163d866769f60f4df8ac1dc59f52498d810c356fe78022e383dd3c57c0e1" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - path: - dependency: "direct main" - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" - url: "https://pub.dev" - source: hosted - version: "2.0.15" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "1dab723dd8feeb80afb39c7be894f09df1457243d930010f6f328fb8c660c5e1" - url: "https://pub.dev" - source: hosted - version: "2.0.21" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 - url: "https://pub.dev" - source: hosted - version: "2.1.7" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: c2af5a8a6369992d915f8933dfc23172071001359d17896e83db8be57db8a397 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c - url: "https://pub.dev" - source: hosted - version: "2.1.3" - platform: - dependency: transitive - description: - name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: c2c49e16d42fd6983eb55e44b7f197fdf16b4da7aab7f8e1d21da307cad3fb02 - url: "https://pub.dev" - source: hosted - version: "2.0.0" - process: - dependency: transitive - description: - name: process - sha256: dc3c073b5bc0db4e0f3dbc6b69f8e9cf2f336dafb3db996242ebdacf94c295dd - url: "https://pub.dev" - source: hosted - version: "4.2.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 - url: "https://pub.dev" - source: hosted - version: "13.0.0" - win32: - dependency: transitive - description: - name: win32 - sha256: d13ac5deea7327f027b3b97ee19ee210f68256ecf3f1a304bcfb992ee947637c - url: "https://pub.dev" - source: hosted - version: "3.1.1" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "0186b3f2d66be9a12b0295bddcf8b6f8c0b0cc2f85c6287344e2a6366bc28457" - url: "https://pub.dev" - source: hosted - version: "0.2.0" -sdks: - dart: ">=3.8.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/vocsy_epub_viewer/pubspec.yaml b/packages/vocsy_epub_viewer/pubspec.yaml deleted file mode 100644 index c07bda4..0000000 --- a/packages/vocsy_epub_viewer/pubspec.yaml +++ /dev/null @@ -1,66 +0,0 @@ -name: vocsy_epub_viewer -description: 'vocsy_epub_viewer is an epub ebook reader that encapsulates the folioreader framework.' -version: 3.0.0 -homepage: https://github.com/kaushikgodhani/vocsy_epub_viewer - -environment: - sdk: '>=2.12.0 <4.0.0' - flutter: '>=1.17.0' - -dependencies: - flutter: - sdk: flutter - path_provider: - path: - -dev_dependencies: - flutter_test: - sdk: flutter - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - # This section identifies this Flutter project as a plugin project. - # The androidPackage and pluginClass identifiers should not ordinarily - # be modified. They are used by the tooling to maintain consistency when - # adding or updating assets for this project. - plugin: - platforms: - android: - package: com.vocsy.epub_viewer - pluginClass: EpubViewerPlugin - ios: - pluginClass: EpubViewerPlugin - - # To add assets to your plugin package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your plugin package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages diff --git a/pubspec.lock b/pubspec.lock index bbd2d66..218e295 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -121,6 +121,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + cosmos_epub: + dependency: "direct main" + description: + name: cosmos_epub + sha256: "68603def7311cf2c79335aed7c0a2a2db172a36b60c7f3a44928ca3d0f499f0b" + url: "https://pub.dev" + source: hosted + version: "1.0.0+1" cross_file: dependency: transitive description: @@ -193,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.1" + epubx: + dependency: transitive + description: + name: epubx + sha256: "0ab9354efa177c4be52c46f857bc15bf83f83a92667fb673465c8f89fca26db3" + url: "https://pub.dev" + source: hosted + version: "4.0.0" equatable: dependency: "direct main" description: @@ -201,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.7" + fading_edge_scrollview: + dependency: transitive + description: + name: fading_edge_scrollview + sha256: "1f84fe3ea8e251d00d5735e27502a6a250e4aa3d3b330d3fdcb475af741464ef" + url: "https://pub.dev" + source: hosted + version: "4.1.1" fake_async: dependency: transitive description: @@ -395,6 +419,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + flutter_screenutil: + dependency: transitive + description: + name: flutter_screenutil + sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de" + url: "https://pub.dev" + source: hosted + version: "5.9.3" + flutter_svg: + dependency: transitive + description: + name: flutter_svg + sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" + url: "https://pub.dev" + source: hosted + version: "2.3.0" flutter_test: dependency: "direct dev" description: flutter @@ -409,10 +449,18 @@ packages: dependency: "direct main" description: name: fluttertoast - sha256: "144ddd74d49c865eba47abe31cbc746c7b311c82d6c32e571fd73c4264b740e2" + sha256: "90778fe0497fe3a09166e8cf2e0867310ff434b794526589e77ec03cf08ba8e8" url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "8.2.14" + get: + dependency: transitive + description: + name: get + sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a" + url: "https://pub.dev" + source: hosted + version: "4.7.3" get_it: dependency: "direct main" description: @@ -421,6 +469,14 @@ packages: url: "https://pub.dev" source: hosted version: "9.2.0" + get_storage: + dependency: transitive + description: + name: get_storage + sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" + url: "https://pub.dev" + source: hosted + version: "2.1.1" html: dependency: "direct main" description: @@ -533,6 +589,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.20.2" + isar_community: + dependency: transitive + description: + name: isar_community + sha256: "683fd093956eac3a660776afb70d65d50a3391b3587b40b89e3d12586b8cc47f" + url: "https://pub.dev" + source: hosted + version: "3.3.2" + isar_community_flutter_libs: + dependency: transitive + description: + name: isar_community_flutter_libs + sha256: c44340fa38c81ef16d924202d443bbe799cde4826be9a31a9dc92ee612e1966f + url: "https://pub.dev" + source: hosted + version: "3.3.2" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" json_annotation: dependency: transitive description: @@ -717,6 +797,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -797,6 +885,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.5+1" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" rxdart: dependency: transitive description: @@ -805,6 +901,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + screen_brightness: + dependency: transitive + description: + name: screen_brightness + sha256: "7d4ac84ae26b37c01d6f5db7123a72db7933e1f2a2a8c369a51e08f81b3178d8" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + screen_brightness_android: + dependency: transitive + description: + name: screen_brightness_android + sha256: "8c69d3ac475e4d625e7fa682a3a51a69ff59abe5b4a9e57f6ec7d830a6c69bd6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + screen_brightness_ios: + dependency: transitive + description: + name: screen_brightness_ios + sha256: f08f70ca1ac3e30719764b5cfb8b3fe1e28163065018a41b3e6f243ab146c2f1 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + screen_brightness_macos: + dependency: transitive + description: + name: screen_brightness_macos + sha256: "70c2efa4534e22b927e82693488f127dd4a0f008469fccf4f0eefe9061bbdd6a" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + screen_brightness_platform_interface: + dependency: transitive + description: + name: screen_brightness_platform_interface + sha256: "9f3ebf7f22d5487e7676fe9ddaf3fc55b6ff8057707cf6dc0121c7dfda346a16" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + screen_brightness_windows: + dependency: transitive + description: + name: screen_brightness_windows + sha256: c8e12a91cf6dd912a48bd41fcf749282a51afa17f536c3460d8d05702fb89ffa + url: "https://pub.dev" + source: hosted + version: "1.0.1" shared_preferences: dependency: "direct main" description: @@ -1050,6 +1194,30 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "2306c03da2ba81724afeb589c351ebbc0aa7d86005925be8f8735856dbe5e42d" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "7ee12e6dffe0fc8e755179d6d91b3b34f5924223fc104d85572ef9180d73d172" + url: "https://pub.dev" + source: hosted + version: "1.2.5" vector_math: dependency: transitive description: @@ -1066,13 +1234,6 @@ packages: url: "https://pub.dev" source: hosted version: "15.0.2" - vocsy_epub_viewer: - dependency: "direct main" - description: - path: "packages/vocsy_epub_viewer" - relative: true - source: path - version: "3.0.0" web: dependency: transitive description: @@ -1130,5 +1291,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.9.0 <4.0.0" + dart: ">=3.10.0 <4.0.0" flutter: ">=3.35.0" diff --git a/pubspec.yaml b/pubspec.yaml index 12e32f5..41d91df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,8 +63,7 @@ dependencies: flutter_rating: html_unescape: webdav_client: - vocsy_epub_viewer: - path: ./packages/vocsy_epub_viewer + cosmos_epub: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/test/features/book_details/book_details_integration_test.dart b/test/features/book_details/book_details_integration_test.dart new file mode 100644 index 0000000..cbad575 --- /dev/null +++ b/test/features/book_details/book_details_integration_test.dart @@ -0,0 +1,139 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; + +import 'package:calibre_web_companion/core/services/api_service.dart'; +import 'package:calibre_web_companion/core/services/tag_service.dart'; +import 'package:calibre_web_companion/features/book_details/data/datasources/book_details_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + late ApiService api; + late BookDetailsRemoteDatasource dataSource; + + Future setUpDataSource() async { + api = await setupIntegrationTest(); + final logger = Logger(level: Level.off); + dataSource = BookDetailsRemoteDatasource( + apiService: api, + logger: logger, + tagService: TagService(apiService: api, logger: logger), + ); + } + + test('fetchBookDetails() loads details for a real book', () async { + await setUpDataSource(); + final book = await fetchFirstBook(api); + + final details = await dataSource.fetchBookDetails(book, book.uuid); + + expect(details, isNotNull); + expect(details.title, isNotEmpty); + }); + + test('toggleReadStatus() flips and restores the read flag', () async { + await setUpDataSource(); + final book = await fetchFirstBook(api); + + final first = await dataSource.toggleReadStatus(book.id); + expect(first, isTrue); + + final second = await dataSource.toggleReadStatus(book.id); + expect(second, isTrue); + }); + + test('toggleArchiveStatus() flips and restores the archive flag', () async { + await setUpDataSource(); + final book = await fetchFirstBook(api); + + final first = await dataSource.toggleArchiveStatus(book.id); + expect(first, isTrue); + + final second = await dataSource.toggleArchiveStatus(book.id); + expect(second, isTrue); + }); + + test('getDownloadStream() returns a 200 stream for a real book', () async { + await setUpDataSource(); + final book = await fetchFirstBook(api); + + final details = await dataSource.fetchBookDetails(book, book.uuid); + if (details.formats.isEmpty) { + markTestSkipped( + 'Book "${book.title}" has no downloadable formats -> cannot test', + ); + return; + } + final format = details.formats.first; + + try { + final response = await dataSource.getDownloadStream( + book.id.toString(), + format, + ); + expect(response.statusCode, 200); + } catch (e) { + final msg = e.toString(); + if (msg.contains('Server error')) { + markTestSkipped('Server returned 5xx for /download/${book.id}/$format'); + return; + } + rethrow; + } + }); + + test('getMetadataProviders() returns the configured providers', () async { + await setUpDataSource(); + + final providers = await dataSource.getMetadataProviders(); + + expect(providers, isA()); + }); + + test('searchMetadata() returns results for a query', () async { + await setUpDataSource(); + + try { + final results = await dataSource.searchMetadata('Tolkien', const []); + expect(results, isA()); + } catch (e) { + final msg = e.toString(); + if (msg.contains('Server error')) { + markTestSkipped( + 'Server returned 5xx for /metadata/search -> likely no metadata', + ); + return; + } + rethrow; + } + }); + + test('getSeriesPath() resolves without throwing', () async { + await setUpDataSource(); + + final path = await dataSource.getSeriesPath('Harry Potter'); + + expect(path == null || path.isNotEmpty, isTrue); + }); + + test( + 'deleteBook() — POST /delete/{id}', + () async {}, + skip: 'Destructive: permanently deletes a book from the real library.', + ); + + test( + 'updateBookMetadata() — POST /admin/book/{id}', + () async {}, + skip: 'Destructive: overwrites metadata of a real book.', + ); + + test( + 'sendBookViaEmail() — POST /send/{id}/{format}/{conversion}', + () async {}, + skip: 'Destructive: triggers a real e-mail send from the server.', + ); +} diff --git a/test/features/book_view/book_view_integration_test.dart b/test/features/book_view/book_view_integration_test.dart new file mode 100644 index 0000000..3789d33 --- /dev/null +++ b/test/features/book_view/book_view_integration_test.dart @@ -0,0 +1,80 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; + +import 'package:calibre_web_companion/features/book_view/data/datasources/book_view_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + late BookViewRemoteDatasource dataSource; + + Future setUpDataSource() async { + final api = await setupIntegrationTest(); + dataSource = BookViewRemoteDatasource( + apiService: api, + logger: Logger(level: Level.off), + preferences: testPrefs(), + ); + } + + test('fetchBooks() returns books from the real library', () async { + await setUpDataSource(); + + final books = await dataSource.fetchBooks(offset: 0, limit: 10); + + expect(books, isNotEmpty); + expect(books.first.id, greaterThan(0)); + expect(books.first.title, isNotEmpty); + }); + + test('fetchBooks() respects the limit parameter', () async { + await setUpDataSource(); + + final books = await dataSource.fetchBooks(offset: 0, limit: 3); + + expect(books.length, lessThanOrEqualTo(3)); + }); + + test('fetchBooks() pagination via offset returns different pages', () async { + await setUpDataSource(); + + final firstPage = await dataSource.fetchBooks(offset: 0, limit: 5); + final secondPage = await dataSource.fetchBooks(offset: 5, limit: 5); + + if (firstPage.isNotEmpty && secondPage.isNotEmpty) { + expect(firstPage.first.id, isNot(equals(secondPage.first.id))); + } + }); + + test('fetchBooks() with sort parameters does not error', () async { + await setUpDataSource(); + + final books = await dataSource.fetchBooks( + offset: 0, + limit: 5, + sortBy: 'title', + sortOrder: 'asc', + ); + + expect(books, isA()); + }); + + test('fetchBooks() with a search query returns matching books', () async { + await setUpDataSource(); + + final sample = await dataSource.fetchBooks(offset: 0, limit: 1); + expect(sample, isNotEmpty); + final token = sample.first.title.split(' ').first; + + final results = await dataSource.fetchBooks( + offset: 0, + limit: 10, + searchQuery: token, + ); + + expect(results, isA()); + }); +} diff --git a/test/features/discover_details/discover_details_integration_test.dart b/test/features/discover_details/discover_details_integration_test.dart new file mode 100644 index 0000000..8e28459 --- /dev/null +++ b/test/features/discover_details/discover_details_integration_test.dart @@ -0,0 +1,101 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; + +import 'package:calibre_web_companion/features/discover/blocs/discover_event.dart'; +import 'package:calibre_web_companion/features/discover_details/data/datasources/discover_details_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + late DiscoverDetailsRemoteDatasource dataSource; + + Future setUpDataSource() async { + final api = await setupIntegrationTest(); + dataSource = DiscoverDetailsRemoteDatasource( + apiService: api, + logger: Logger(level: Level.off), + preferences: testPrefs(), + ); + } + + const optionalTypes = { + DiscoverType.hot, + DiscoverType.rated, + DiscoverType.readbooks, + DiscoverType.unreadbooks, + }; + for (final type in const [ + DiscoverType.discover, + DiscoverType.hot, + DiscoverType.newlyAdded, + DiscoverType.rated, + DiscoverType.readbooks, + DiscoverType.unreadbooks, + ]) { + test('loadBooks(${type.name}) returns a feed', () async { + await setUpDataSource(); + + try { + final feed = await dataSource.loadBooks(type); + expect(feed, isNotNull); + expect(feed.books, isA()); + } catch (e) { + if (optionalTypes.contains(type) && e.toString().contains('404')) { + return; + } + rethrow; + } + }); + } + + for (final type in const [ + CategoryType.author, + CategoryType.category, + CategoryType.series, + CategoryType.publisher, + CategoryType.language, + CategoryType.formats, + CategoryType.ratings, + ]) { + test('loadCategories(${type.name}) returns a feed', () async { + await setUpDataSource(); + + final feed = await dataSource.loadCategories(type); + + expect(feed, isNotNull); + expect(feed.categories, isA()); + }); + } + + test('loadCategories(libraries) hits /libraries', () async { + await setUpDataSource(); + + try { + final feed = await dataSource.loadCategories(CategoryType.libraries); + expect(feed.categories, isA()); + } catch (e) { + expect(e, isA()); + } + }); + + test('loadBooksFromPath() loads books from an explicit OPDS path', () async { + await setUpDataSource(); + + final feed = await dataSource.loadBooksFromPath('/opds/new'); + + expect(feed, isNotNull); + expect(feed.books, isA()); + }); + + test('loadCategoriesgeneric() parses a category path', () async { + await setUpDataSource(); + + final feed = await dataSource.loadCategoriesgeneric('/opds/category'); + + expect(feed, isNotNull); + expect(feed.categories, isA()); + }); +} diff --git a/test/features/download_service/download_service_integration_test.dart b/test/features/download_service/download_service_integration_test.dart new file mode 100644 index 0000000..20368e3 --- /dev/null +++ b/test/features/download_service/download_service_integration_test.dart @@ -0,0 +1,86 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart' as http; +import 'package:logger/logger.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:calibre_web_companion/core/services/api_service.dart'; +import 'package:calibre_web_companion/features/download_service/data/datasources/download_service_remote_datasource.dart'; +import 'package:calibre_web_companion/features/login_settings/data/datasources/login_settings_local_datasource.dart'; +import 'package:calibre_web_companion/features/login_settings/data/repositories/login_settings_repository.dart'; + +import '../../test_env.dart'; + +void main() { + late DownloadServiceRemoteDataSource dataSource; + + Future setUpDataSource() async { + SharedPreferences.setMockInitialValues({ + 'downloader_url': TestEnv.downloaderUrl, + 'downloader_username': TestEnv.downloaderUsername, + 'downloader_password': TestEnv.downloaderPassword, + }); + final prefs = await SharedPreferences.getInstance(); + final logger = Logger(level: Level.off); + + final loginSettingsRepository = LoginSettingsRepository( + loginSettingsLocalDataSource: LoginSettingsLocalDataSource( + preferences: prefs, + logger: logger, + apiService: ApiService(), + ), + logger: logger, + ); + + dataSource = DownloadServiceRemoteDataSource( + client: http.Client(), + sharedPreferences: prefs, + logger: logger, + loginSettingsRepository: loginSettingsRepository, + ); + } + + test( + 'searchBooks() returns results (GET /api/releases)', + () async { + await setUpDataSource(); + + final books = await dataSource.searchBooks('Tolkien'); + + expect(books, isA()); + }, + skip: TestEnv.hasDownloader ? false : 'TestEnv.downloaderUrl not set', + ); + + test( + 'getDownloadStatus() returns status (GET /api/status)', + () async { + await setUpDataSource(); + + final books = await dataSource.getDownloadStatus(); + + expect(books, isA()); + }, + skip: TestEnv.hasDownloader ? false : 'TestEnv.downloaderUrl not set', + ); + + test( + 'getConfig() returns the downloader config (GET /api/config)', + () async { + await setUpDataSource(); + + final config = await dataSource.getConfig(); + + expect(config, isNotNull); + }, + skip: TestEnv.hasDownloader ? false : 'TestEnv.downloaderUrl not set', + ); + + test( + 'downloadBook() — POST /api/releases/download', + () async {}, + skip: 'Destructive: queues a real download on the downloader service.', + ); +} diff --git a/test/features/login/login_integration_test.dart b/test/features/login/login_integration_test.dart new file mode 100644 index 0000000..606aee3 --- /dev/null +++ b/test/features/login/login_integration_test.dart @@ -0,0 +1,38 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; + +import 'package:calibre_web_companion/features/login/data/datasources/login_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + test('login() succeeds with valid credentials (POST /login)', () async { + final api = await setupIntegrationTest(); + expect(api, isNotNull); + }); + + test('canAccessWebsite() returns true for a valid session', () async { + final api = await setupIntegrationTest(); + final dataSource = LoginRemoteDataSource( + apiService: api, + logger: Logger(level: Level.off), + ); + + final canAccess = await dataSource.canAccessWebsite(); + expect(canAccess, isTrue); + }); + + test('getStoredServerType() reflects the stored server type', () async { + final api = await setupIntegrationTest(); + final dataSource = LoginRemoteDataSource( + apiService: api, + logger: Logger(level: Level.off), + ); + + final type = await dataSource.getStoredServerType(); + expect(type.name, 'calibreWeb'); + }); +} diff --git a/test/features/me/me_integration_test.dart b/test/features/me/me_integration_test.dart new file mode 100644 index 0000000..2310e51 --- /dev/null +++ b/test/features/me/me_integration_test.dart @@ -0,0 +1,39 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:calibre_web_companion/features/me/data/datasources/me_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + test('getStats() returns library statistics', () async { + final api = await setupIntegrationTest(); + final dataSource = MeRemoteDataSource( + apiService: api, + preferences: testPrefs(), + ); + + final stats = await dataSource.getStats(); + + expect(stats, isNotNull); + expect(stats.books, greaterThanOrEqualTo(0)); + }); + + test('getIsOpds() is false for a Calibre-Web server', () async { + final api = await setupIntegrationTest(); + final dataSource = MeRemoteDataSource( + apiService: api, + preferences: testPrefs(), + ); + + expect(dataSource.getIsOpds(), isFalse); + }); + + test( + 'logOut() — GET /logout', + () async {}, + skip: 'Skipped: ends the session shared by all integration tests.', + ); +} diff --git a/test/features/shelf_details/shelf_details_integration_test.dart b/test/features/shelf_details/shelf_details_integration_test.dart new file mode 100644 index 0000000..b0b4f4c --- /dev/null +++ b/test/features/shelf_details/shelf_details_integration_test.dart @@ -0,0 +1,108 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; + +import 'package:calibre_web_companion/core/services/api_service.dart'; +import 'package:calibre_web_companion/features/shelf_details/data/datasources/shelf_details_remote_datasource.dart'; +import 'package:calibre_web_companion/features/shelf_view.dart/data/datasources/shelf_view_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + late ApiService api; + late Logger logger; + late ShelfDetailsRemoteDataSource dataSource; + late ShelfViewRemoteDataSource shelfViewSource; + + Future setUpDataSources() async { + api = await setupIntegrationTest(); + logger = Logger(level: Level.off); + dataSource = ShelfDetailsRemoteDataSource( + apiService: api, + logger: logger, + preferences: testPrefs(), + ); + shelfViewSource = ShelfViewRemoteDataSource( + apiService: api, + logger: logger, + preferences: testPrefs(), + shelfDetailsRemoteDataSource: dataSource, + ); + } + + test('getShelfDetails() loads a freshly created shelf', () async { + await setUpDataSources(); + final shelfName = 'cwc_itest_${DateTime.now().millisecondsSinceEpoch}'; + + String? shelfId; + try { + shelfId = await shelfViewSource.createShelf(shelfName); + + // GET /opds/shelf/{id} + final details = await dataSource.getShelfDetails(shelfId); + expect(details, isNotNull); + expect(details.books, isA()); + } finally { + if (shelfId != null) { + await dataSource.deleteShelf(shelfId); + } + } + }); + + test('editShelf() renames a shelf (POST /shelf/edit/{id})', () async { + await setUpDataSources(); + final shelfName = 'cwc_itest_${DateTime.now().millisecondsSinceEpoch}'; + + String? shelfId; + try { + shelfId = await shelfViewSource.createShelf(shelfName); + + final renamed = await dataSource.editShelf( + shelfId, + '${shelfName}_edited', + ); + expect(renamed, isTrue); + } finally { + if (shelfId != null) { + await dataSource.deleteShelf(shelfId); + } + } + }); + + test('removeFromShelf() removes a book (POST /shelf/remove)', () async { + await setUpDataSources(); + final book = await fetchFirstBook(api); + final shelfName = 'cwc_itest_${DateTime.now().millisecondsSinceEpoch}'; + + String? shelfId; + try { + shelfId = await shelfViewSource.createShelf(shelfName); + await shelfViewSource.addBookToShelf( + bookId: book.id.toString(), + shelfId: shelfId, + ); + + final removed = await dataSource.removeFromShelf( + shelfId, + book.id.toString(), + ); + expect(removed, isTrue); + } finally { + if (shelfId != null) { + await dataSource.deleteShelf(shelfId); + } + } + }); + + test('deleteShelf() deletes a shelf (POST /shelf/delete/{id})', () async { + await setUpDataSources(); + final shelfName = 'cwc_itest_${DateTime.now().millisecondsSinceEpoch}'; + + final shelfId = await shelfViewSource.createShelf(shelfName); + final deleted = await dataSource.deleteShelf(shelfId); + + expect(deleted, isTrue); + }); +} diff --git a/test/features/shelf_view/shelf_view_integration_test.dart b/test/features/shelf_view/shelf_view_integration_test.dart new file mode 100644 index 0000000..5dd5ecd --- /dev/null +++ b/test/features/shelf_view/shelf_view_integration_test.dart @@ -0,0 +1,86 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; + +import 'package:calibre_web_companion/core/services/api_service.dart'; +import 'package:calibre_web_companion/features/shelf_details/data/datasources/shelf_details_remote_datasource.dart'; +import 'package:calibre_web_companion/features/shelf_view.dart/data/datasources/shelf_view_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + late ApiService api; + late Logger logger; + late ShelfDetailsRemoteDataSource detailsSource; + late ShelfViewRemoteDataSource dataSource; + + Future setUpDataSources() async { + api = await setupIntegrationTest(); + logger = Logger(level: Level.off); + detailsSource = ShelfDetailsRemoteDataSource( + apiService: api, + logger: logger, + preferences: testPrefs(), + ); + dataSource = ShelfViewRemoteDataSource( + apiService: api, + logger: logger, + preferences: testPrefs(), + shelfDetailsRemoteDataSource: detailsSource, + ); + } + + test('loadShelves() returns the shelf list', () async { + await setUpDataSources(); + + final shelves = await dataSource.loadShelves(); + + expect(shelves, isNotNull); + expect(shelves.shelves, isA()); + }); + + test( + 'shelf lifecycle: create -> add book -> remove book -> delete', + () async { + await setUpDataSources(); + final book = await fetchFirstBook(api); + final shelfName = 'cwc_itest_${DateTime.now().millisecondsSinceEpoch}'; + + String? shelfId; + try { + // POST /shelf/create + shelfId = await dataSource.createShelf(shelfName); + expect(shelfId, isNotEmpty); + + // POST /shelf/add/{shelf}/{book} + await dataSource.addBookToShelf( + bookId: book.id.toString(), + shelfId: shelfId, + ); + + // POST /shelf/remove/{shelf}/{book} + await dataSource.removeBookFromShelf( + bookId: book.id.toString(), + shelfId: shelfId, + ); + } finally { + if (shelfId != null) { + await detailsSource.deleteShelf(shelfId); + } + } + }, + ); + + test('findShelvesContainingBook() runs without error', () async { + await setUpDataSources(); + final book = await fetchFirstBook(api); + + final shelves = await dataSource.findShelvesContainingBook( + book.id.toString(), + ); + + expect(shelves, isA()); + }); +} diff --git a/test/features/sync/sync_integration_test.dart b/test/features/sync/sync_integration_test.dart new file mode 100644 index 0000000..f1565d7 --- /dev/null +++ b/test/features/sync/sync_integration_test.dart @@ -0,0 +1,57 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; + +import 'package:calibre_web_companion/features/shelf_details/data/datasources/shelf_details_remote_datasource.dart'; +import 'package:calibre_web_companion/features/shelf_view.dart/data/datasources/shelf_view_remote_datasource.dart'; + +import '../../helpers/test_setup.dart'; + +void main() { + test('GET /opds/shelf/{id} returns a parseable OPDS feed', () async { + final api = await setupIntegrationTest(); + final logger = Logger(level: Level.off); + + final detailsSource = ShelfDetailsRemoteDataSource( + apiService: api, + logger: logger, + preferences: testPrefs(), + ); + final shelfViewSource = ShelfViewRemoteDataSource( + apiService: api, + logger: logger, + preferences: testPrefs(), + shelfDetailsRemoteDataSource: detailsSource, + ); + final book = await fetchFirstBook(api); + final shelfName = 'cwc_itest_${DateTime.now().millisecondsSinceEpoch}'; + + String? shelfId; + try { + shelfId = await shelfViewSource.createShelf(shelfName); + await shelfViewSource.addBookToShelf( + bookId: book.id.toString(), + shelfId: shelfId, + ); + + final response = await api.get(endpoint: '/opds/shelf/$shelfId'); + + expect(response.statusCode, 200); + expect(response.body, contains('')); + + final hasUuid = RegExp( + r'urn:uuid:([a-fA-F0-9-]+)', + ).hasMatch(response.body); + final hasDownloadId = RegExp( + r'href="\/opds\/download\/(\d+)\/', + ).hasMatch(response.body); + expect(hasUuid && hasDownloadId, isTrue); + } finally { + if (shelfId != null) { + await detailsSource.deleteShelf(shelfId); + } + } + }); +} diff --git a/test/helpers/test_setup.dart b/test/helpers/test_setup.dart new file mode 100644 index 0000000..5f99312 --- /dev/null +++ b/test/helpers/test_setup.dart @@ -0,0 +1,67 @@ +import 'package:calibre_web_companion/core/services/api_service.dart'; +import 'package:calibre_web_companion/features/book_view/data/datasources/book_view_remote_datasource.dart'; +import 'package:calibre_web_companion/features/book_view/data/models/book_view_model.dart'; +import 'package:calibre_web_companion/features/login/bloc/login_state.dart'; +import 'package:calibre_web_companion/features/login/data/datasources/login_remote_datasource.dart'; +import 'package:calibre_web_companion/features/login/data/models/login_credentials.dart'; +import 'package:get_it/get_it.dart'; +import 'package:logger/logger.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../test_env.dart'; + +Future setupIntegrationTest() async { + SharedPreferences.setMockInitialValues({ + 'base_url': TestEnv.baseUrl, + 'username': TestEnv.username, + 'password': TestEnv.password, + 'server_type': 'calibreWeb', + }); + + final prefs = await SharedPreferences.getInstance(); + if (!GetIt.instance.isRegistered()) { + GetIt.instance.registerSingleton(prefs); + } + + if (GetIt.instance.isRegistered()) { + GetIt.instance.unregister(); + } + final apiService = ApiService(); + GetIt.instance.registerSingleton(apiService); + await apiService.initialize(); + + final logger = Logger(level: Level.off); + final loginDataSource = LoginRemoteDataSource( + apiService: apiService, + logger: logger, + ); + + final success = await loginDataSource.login( + LoginCredentials( + baseUrl: TestEnv.baseUrl, + username: TestEnv.username, + password: TestEnv.password, + ), + ServerType.calibreWeb, + ); + + if (!success) { + throw Exception('Login failed during integration test setup.'); + } + + return apiService; +} + +SharedPreferences testPrefs() => GetIt.instance(); + +Future fetchFirstBook(ApiService api) async { + final ds = BookViewRemoteDatasource( + apiService: api, + logger: Logger(level: Level.off), + preferences: testPrefs(), + ); + final books = await ds.fetchBooks(offset: 0, limit: 1); + if (books.isEmpty) { + throw Exception('Library is empty!'); + } + return books.first; +} diff --git a/test/integration_check_test.dart b/test/integration_check_test.dart new file mode 100644 index 0000000..a6e346b --- /dev/null +++ b/test/integration_check_test.dart @@ -0,0 +1,14 @@ +@Tags(['integration']) +library; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart' as http; + +import 'test_env.dart'; + +void main() { + test('server is reachable', () async { + final response = await http.get(Uri.parse(TestEnv.baseUrl)); + expect(response.statusCode, anyOf(200, 302, 401)); + }); +}