From 2c4ec3447b176e9c48cda7d847a940aaba6d7d69 Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Wed, 6 Jul 2022 04:20:24 +0800 Subject: [PATCH] Switch local DB from IndexedDB to SQLite --- app/android/app/src/main/AndroidManifest.xml | 9 - app/build.yaml | 10 + app/lib/app_db.dart | 499 --- app/lib/app_init.dart | 78 +- app/lib/bloc/list_album.dart | 6 +- app/lib/bloc/ls_trashbin.dart | 6 +- app/lib/bloc/scan_account_dir.dart | 35 +- app/lib/di_container.dart | 155 +- app/lib/entity/album.dart | 314 +- app/lib/entity/album/data_source.dart | 307 ++ app/lib/entity/file.dart | 5 +- app/lib/entity/file/data_source.dart | 470 +-- app/lib/entity/file/file_cache_manager.dart | 439 +-- app/lib/entity/sqlite_table.dart | 209 ++ app/lib/entity/sqlite_table.g.dart | 3013 +++++++++++++++++ app/lib/entity/sqlite_table_converter.dart | 141 + app/lib/entity/sqlite_table_extension.dart | 538 +++ app/lib/entity/sqlite_table_isolate.dart | 87 + app/lib/future_util.dart | 33 + app/lib/iterable_extension.dart | 9 +- app/lib/list_util.dart | 5 +- app/lib/main.dart | 2 +- app/lib/metadata_task_manager.dart | 14 +- app/lib/mobile/db_util.dart | 33 +- app/lib/platform/k.dart | 1 + app/lib/service.dart | 13 +- app/lib/share_handler.dart | 8 +- app/lib/use_case/add_to_album.dart | 8 +- app/lib/use_case/cache_favorite.dart | 64 +- app/lib/use_case/compat/v37.dart | 211 -- app/lib/use_case/db_compat/v5.dart | 74 - app/lib/use_case/find_file.dart | 61 +- app/lib/use_case/list_album.dart | 22 +- app/lib/use_case/list_favorite_offline.dart | 40 +- app/lib/use_case/populate_album.dart | 11 +- app/lib/use_case/populate_person.dart | 61 +- app/lib/use_case/preprocess_album.dart | 15 +- app/lib/use_case/remove_from_album.dart | 8 +- app/lib/use_case/resync_album.dart | 50 +- app/lib/use_case/scan_dir_offline.dart | 78 +- app/lib/web/db_util.dart | 32 +- app/lib/widget/album_browser.dart | 29 +- app/lib/widget/album_browser_mixin.dart | 5 +- app/lib/widget/album_importer.dart | 16 +- app/lib/widget/archive_browser.dart | 8 +- app/lib/widget/dynamic_album_browser.dart | 23 +- app/lib/widget/home.dart | 1 + app/lib/widget/home_photos.dart | 3 +- app/lib/widget/new_album_dialog.dart | 17 +- app/lib/widget/person_browser.dart | 13 +- app/lib/widget/settings.dart | 2 +- app/lib/widget/share_album_dialog.dart | 19 +- app/lib/widget/sharing_browser.dart | 1 + app/lib/widget/sign_in.dart | 7 + app/lib/widget/smart_album_browser.dart | 13 +- app/lib/widget/splash.dart | 57 - app/lib/widget/viewer_detail_pane.dart | 23 +- app/pubspec.lock | 198 +- app/pubspec.yaml | 9 +- .../bloc/list_album_share_outlier_test.dart | 253 +- app/test/bloc/ls_dir_test.dart | 56 +- app/test/entity/album/data_source_test.dart | 335 ++ app/test/entity/file/data_source_test.dart | 325 +- .../entity/file/file_cache_manager_test.dart | 502 +++ app/test/entity/file_test.dart | 2 +- app/test/mock_type.dart | 245 +- app/test/test_util.dart | 261 +- app/test/use_case/add_to_album_test.dart | 67 +- app/test/use_case/compat/v37_test.dart | 230 -- app/test/use_case/db_compat/v5_test.dart | 93 - app/test/use_case/find_file_test.dart | 21 +- app/test/use_case/ls_test.dart | 2 +- app/test/use_case/remove_album_test.dart | 24 +- app/test/use_case/remove_from_album_test.dart | 99 +- app/test/use_case/remove_test.dart | 69 +- app/test/use_case/scan_dir_offline_test.dart | 42 +- .../unshare_album_with_user_test.dart | 9 +- app/web/sqlite3.wasm | Bin 0 -> 1348108 bytes 78 files changed, 7468 insertions(+), 2785 deletions(-) create mode 100644 app/build.yaml delete mode 100644 app/lib/app_db.dart create mode 100644 app/lib/entity/album/data_source.dart create mode 100644 app/lib/entity/sqlite_table.dart create mode 100644 app/lib/entity/sqlite_table.g.dart create mode 100644 app/lib/entity/sqlite_table_converter.dart create mode 100644 app/lib/entity/sqlite_table_extension.dart create mode 100644 app/lib/entity/sqlite_table_isolate.dart create mode 100644 app/lib/future_util.dart delete mode 100644 app/lib/use_case/compat/v37.dart delete mode 100644 app/lib/use_case/db_compat/v5.dart create mode 100644 app/test/entity/album/data_source_test.dart create mode 100644 app/test/entity/file/file_cache_manager_test.dart delete mode 100644 app/test/use_case/compat/v37_test.dart delete mode 100644 app/test/use_case/db_compat/v5_test.dart create mode 100644 app/web/sqlite3.wasm diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml index a7ba0a5d..ecf597ea 100644 --- a/app/android/app/src/main/AndroidManifest.xml +++ b/app/android/app/src/main/AndroidManifest.xml @@ -31,15 +31,6 @@ android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> - - diff --git a/app/build.yaml b/app/build.yaml new file mode 100644 index 00000000..5cffa1e9 --- /dev/null +++ b/app/build.yaml @@ -0,0 +1,10 @@ +targets: + $default: + builders: + drift_dev: + options: + apply_converters_on_variables: true + generate_values_in_copy_with: true + new_sql_code_generation: true + scoped_dart_components: true + generate_connect_constructor: true diff --git a/app/lib/app_db.dart b/app/lib/app_db.dart deleted file mode 100644 index a2c7a97c..00000000 --- a/app/lib/app_db.dart +++ /dev/null @@ -1,499 +0,0 @@ -import 'dart:async'; - -import 'package:equatable/equatable.dart'; -import 'package:idb_shim/idb.dart'; -import 'package:logging/logging.dart'; -import 'package:nc_photos/account.dart'; -import 'package:nc_photos/ci_string.dart'; -import 'package:nc_photos/entity/album.dart'; -import 'package:nc_photos/entity/album/upgrader.dart'; -import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/k.dart' as k; -import 'package:nc_photos/mobile/platform.dart' - if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; -import 'package:nc_photos/num_extension.dart'; -import 'package:nc_photos/object_extension.dart'; -import 'package:nc_photos/platform/k.dart' as platform_k; -import 'package:nc_photos/type.dart'; - -class AppDb { - static const dbName = "app.db"; - static const dbVersion = 6; - static const albumStoreName = "albums"; - static const file2StoreName = "files2"; - static const dirStoreName = "dirs"; - static const metaStoreName = "meta"; - - /// Run [fn] with an opened database instance - /// - /// This function guarantees that: - /// 1) Database is always closed after [fn] exits, even with an error - /// 2) Only at most 1 database instance being opened at any time - Future use(Transaction Function(Database db) transactionBuilder, - FutureOr Function(Transaction transaction) fn) async { - // make sure only one client is opening the db - return await platform.Lock.synchronized(k.appDbLockId, () async { - final db = await _open(); - Transaction? transaction; - try { - transaction = transactionBuilder(db); - return await fn(transaction); - } finally { - if (transaction != null) { - await transaction.completed; - } - db.close(); - } - }); - } - - Future delete() async { - _log.warning("[delete] Deleting database"); - return await platform.Lock.synchronized(k.appDbLockId, () async { - final dbFactory = platform.getDbFactory(); - await dbFactory.deleteDatabase(dbName); - }); - } - - /// Open the database - Future _open() { - if (platform_k.isWeb) { - return _openNative(); - } else { - return _openSqflite(); - } - } - - /// Open the sqflite database - /// - /// We can't simply call deleteObjectStore on upgrade failure here, as the - /// package does not remove the corresponding indexes, so when we recreate - /// the indexes later, it'll fail. What we do here, is to delete the whole - /// database instead - Future _openSqflite() async { - final dbFactory = platform.getDbFactory(); - try { - int? fromVersion, toVersion; - final db = await dbFactory.open( - dbName, - version: dbVersion, - onUpgradeNeeded: (event) { - _upgrade(event); - fromVersion = event.oldVersion; - toVersion = event.newVersion; - }, - ); - if (fromVersion != null && toVersion != null) { - await _onPostUpgrade(db, fromVersion!, toVersion!); - } - return db; - } catch (e, stackTrace) { - _log.shout( - "[_openSqflite] Failed while upgrading database", e, stackTrace); - _log.warning("[_openSqflite] Recreating db"); - await dbFactory.deleteDatabase(dbName); - return dbFactory.open(dbName, - version: dbVersion, onUpgradeNeeded: _upgrade); - } - } - - /// Open the native IndexedDB database - /// - /// Errors thrown in onUpgradeNeeded are not propagated properly to us on web, - /// so the sqflite approach will not work - Future _openNative() async { - final dbFactory = platform.getDbFactory(); - int? fromVersion, toVersion; - final db = await dbFactory.open( - dbName, - version: dbVersion, - onUpgradeNeeded: (event) { - try { - _upgrade(event); - fromVersion = event.oldVersion; - toVersion = event.newVersion; - } catch (e, stackTrace) { - _log.shout( - "[_openNative] Failed while upgrading database", e, stackTrace); - // drop the db and rebuild a new one instead - try { - event.database.deleteObjectStore(albumStoreName); - } catch (_) {} - try { - event.database.deleteObjectStore(file2StoreName); - } catch (_) {} - try { - event.database.deleteObjectStore(dirStoreName); - } catch (_) {} - try { - event.database.deleteObjectStore(metaStoreName); - } catch (_) {} - try { - event.database.deleteObjectStore(_fileDbStoreName); - } catch (_) {} - try { - event.database.deleteObjectStore(_fileStoreName); - } catch (_) {} - _log.warning("[_openNative] Recreating db"); - _upgrade(_DummyVersionChangeEvent( - 0, - event.newVersion, - event.transaction, - event.target, - event.currentTarget, - event.database)); - } - }, - ); - if (fromVersion != null && toVersion != null) { - await _onPostUpgrade(db, fromVersion!, toVersion!); - } - return db; - } - - void _upgrade(VersionChangeEvent event) { - _log.info("[_upgrade] Upgrade database: ${event.oldVersion} -> $dbVersion"); - - final db = event.database; - // ignore: unused_local_variable - ObjectStore? albumStore, file2Store, dirStore, metaStore; - if (event.oldVersion < 2) { - // version 2 store things in a new way, just drop all - try { - db.deleteObjectStore(albumStoreName); - } catch (_) {} - albumStore = db.createObjectStore(albumStoreName); - albumStore.createIndex( - AppDbAlbumEntry.indexName, AppDbAlbumEntry.keyPath); - } - if (event.oldVersion < 3) { - // new object store in v3 - // no longer relevant in v4 - - // recreate file store from scratch - // no longer relevant in v4 - } - if (event.oldVersion < 4) { - try { - db.deleteObjectStore(_fileDbStoreName); - } catch (_) {} - try { - db.deleteObjectStore(_fileStoreName); - } catch (_) {} - - file2Store = db.createObjectStore(file2StoreName); - file2Store.createIndex(AppDbFile2Entry.strippedPathIndexName, - AppDbFile2Entry.strippedPathKeyPath); - - dirStore = db.createObjectStore(dirStoreName); - } - file2Store ??= event.transaction.objectStore(file2StoreName); - if (event.oldVersion < 5) { - file2Store.createIndex(AppDbFile2Entry.dateTimeEpochMsIndexName, - AppDbFile2Entry.dateTimeEpochMsKeyPath); - - metaStore = - db.createObjectStore(metaStoreName, keyPath: AppDbMetaEntry.keyPath); - } - if (event.oldVersion < 6) { - file2Store.createIndex(AppDbFile2Entry.fileIsFavoriteIndexName, - AppDbFile2Entry.fileIsFavoriteKeyPath); - } - } - - Future _onPostUpgrade( - Database db, int fromVersion, int toVersion) async { - if (fromVersion.inRange(1, 4) && toVersion >= 5) { - final transaction = db.transaction(AppDb.metaStoreName, idbModeReadWrite); - final metaStore = transaction.objectStore(AppDb.metaStoreName); - await metaStore - .put(const AppDbMetaEntryDbCompatV5(false).toEntry().toJson()); - await transaction.completed; - } - } - - static const _fileDbStoreName = "filesDb"; - static const _fileStoreName = "files"; - - static final _log = Logger("app_db.AppDb"); -} - -class AppDbAlbumEntry { - static const indexName = "albumStore_path_index"; - static const keyPath = ["path", "index"]; - static const maxDataSize = 160; - - AppDbAlbumEntry(this.path, this.index, this.album); - - JsonObj toJson() { - return { - "path": path, - "index": index, - "album": album.toAppDbJson(), - }; - } - - factory AppDbAlbumEntry.fromJson(JsonObj json, Account account) { - return AppDbAlbumEntry( - json["path"], - json["index"], - Album.fromJson( - json["album"].cast(), - upgraderFactory: DefaultAlbumUpgraderFactory( - account: account, - logFilePath: json["path"], - ), - )!, - ); - } - - static String toPath(Account account, String filePath) => - "${account.url}/$filePath"; - static String toPathFromFile(Account account, File albumFile) => - toPath(account, albumFile.path); - static String toPrimaryKey(Account account, File albumFile, int index) => - "${toPathFromFile(account, albumFile)}[$index]"; - - final String path; - final int index; - // properties other than Album.items is undefined when index > 0 - final Album album; -} - -class AppDbFile2Entry with EquatableMixin { - static const strippedPathIndexName = "server_userId_strippedPath"; - static const strippedPathKeyPath = ["server", "userId", "strippedPath"]; - - static const dateTimeEpochMsIndexName = "server_userId_dateTimeEpochMs"; - static const dateTimeEpochMsKeyPath = ["server", "userId", "dateTimeEpochMs"]; - - static const fileIsFavoriteIndexName = "server_userId_fileIsFavorite"; - static const fileIsFavoriteKeyPath = ["server", "userId", "file.isFavorite"]; - - AppDbFile2Entry(this.server, this.userId, this.strippedPath, - this.dateTimeEpochMs, this.file); - - factory AppDbFile2Entry.fromFile(Account account, File file) => - AppDbFile2Entry(account.url, account.username, file.strippedPathWithEmpty, - file.bestDateTime.millisecondsSinceEpoch, file); - - factory AppDbFile2Entry.fromJson(JsonObj json) => AppDbFile2Entry( - json["server"], - (json["userId"] as String).toCi(), - json["strippedPath"], - json["dateTimeEpochMs"], - File.fromJson(json["file"].cast()), - ); - - JsonObj toJson() => { - "server": server, - "userId": userId.toCaseInsensitiveString(), - "strippedPath": strippedPath, - "dateTimeEpochMs": dateTimeEpochMs, - "file": file.toJson(), - }; - - static String toPrimaryKey(Account account, int fileId) => - "${account.url}/${account.username.toCaseInsensitiveString()}/$fileId"; - - static String toPrimaryKeyForFile(Account account, File file) => - toPrimaryKey(account, file.fileId!); - - static List toStrippedPathIndexKey( - Account account, String strippedPath) => - [ - account.url, - account.username.toCaseInsensitiveString(), - strippedPath == "." ? "" : strippedPath - ]; - - static List toStrippedPathIndexKeyForFile( - Account account, File file) => - toStrippedPathIndexKey(account, file.strippedPathWithEmpty); - - /// Return the lower bound key used to query files under [dir] and its sub - /// dirs - static List toStrippedPathIndexLowerKeyForDir( - Account account, File dir) => - [ - account.url, - account.username.toCaseInsensitiveString(), - dir.strippedPath.run((p) => p == "." ? "" : "$p/") - ]; - - /// Return the upper bound key used to query files under [dir] and its sub - /// dirs - static List toStrippedPathIndexUpperKeyForDir( - Account account, File dir) { - return toStrippedPathIndexLowerKeyForDir(account, dir).run((k) { - k[2] = (k[2] as String) + "\uffff"; - return k; - }); - } - - static List toDateTimeEpochMsIndexKey(Account account, int epochMs) => - [ - account.url, - account.username.toCaseInsensitiveString(), - epochMs, - ]; - - static List toFileIsFavoriteIndexKey( - Account account, bool isFavorite) => - [ - account.url, - account.username.toCaseInsensitiveString(), - isFavorite ? 1 : 0, - ]; - - @override - get props => [ - server, - userId, - strippedPath, - dateTimeEpochMs, - file, - ]; - - /// Server URL where this file belongs to - final String server; - final CiString userId; - final String strippedPath; - final int dateTimeEpochMs; - final File file; -} - -class AppDbDirEntry with EquatableMixin { - AppDbDirEntry._( - this.server, this.userId, this.strippedPath, this.dir, this.children); - - factory AppDbDirEntry.fromFiles( - Account account, File dir, List children) => - AppDbDirEntry._( - account.url, - account.username, - dir.strippedPathWithEmpty, - dir, - children.map((f) => f.fileId!).toList(), - ); - - factory AppDbDirEntry.fromJson(JsonObj json) => AppDbDirEntry._( - json["server"], - (json["userId"] as String).toCi(), - json["strippedPath"], - File.fromJson((json["dir"] as Map).cast()), - json["children"].cast(), - ); - - JsonObj toJson() => { - "server": server, - "userId": userId.toCaseInsensitiveString(), - "strippedPath": strippedPath, - "dir": dir.toJson(), - "children": children, - }; - - static String toPrimaryKeyForDir(Account account, File dir) => - "${account.url}/${account.username.toCaseInsensitiveString()}/${dir.strippedPathWithEmpty}"; - - /// Return the lower bound key used to query dirs under [root] and its sub - /// dirs - static String toPrimaryLowerKeyForSubDirs(Account account, File root) { - final strippedPath = root.strippedPath.run((p) => p == "." ? "" : "$p/"); - return "${account.url}/${account.username.toCaseInsensitiveString()}/$strippedPath"; - } - - /// Return the upper bound key used to query dirs under [root] and its sub - /// dirs - static String toPrimaryUpperKeyForSubDirs(Account account, File root) => - toPrimaryLowerKeyForSubDirs(account, root) + "\uffff"; - - @override - get props => [ - server, - userId, - strippedPath, - dir, - children, - ]; - - /// Server URL where this file belongs to - final String server; - final CiString userId; - final String strippedPath; - final File dir; - final List children; -} - -class AppDbMetaEntry with EquatableMixin { - static const keyPath = "key"; - - const AppDbMetaEntry(this.key, this.obj); - - factory AppDbMetaEntry.fromJson(JsonObj json) => AppDbMetaEntry( - json["key"], - json["obj"].cast(), - ); - - JsonObj toJson() => { - "key": key, - "obj": obj, - }; - - @override - get props => [ - key, - obj, - ]; - - final String key; - final JsonObj obj; -} - -class AppDbMetaEntryDbCompatV5 { - static const key = "dbCompatV5"; - - const AppDbMetaEntryDbCompatV5(this.isMigrated); - - factory AppDbMetaEntryDbCompatV5.fromJson(JsonObj json) => - AppDbMetaEntryDbCompatV5(json["isMigrated"]); - - AppDbMetaEntry toEntry() => AppDbMetaEntry(key, { - "isMigrated": isMigrated, - }); - - final bool isMigrated; -} - -class AppDbMetaEntryCompatV37 { - static const key = "compatV37"; - - const AppDbMetaEntryCompatV37(this.isMigrated); - - factory AppDbMetaEntryCompatV37.fromJson(JsonObj json) => - AppDbMetaEntryCompatV37(json["isMigrated"]); - - AppDbMetaEntry toEntry() => AppDbMetaEntry(key, { - "isMigrated": isMigrated, - }); - - final bool isMigrated; -} - -class _DummyVersionChangeEvent implements VersionChangeEvent { - const _DummyVersionChangeEvent(this.oldVersion, this.newVersion, - this.transaction, this.target, this.currentTarget, this.database); - - @override - final int oldVersion; - @override - final int newVersion; - @override - final Transaction transaction; - @override - final Object target; - @override - final Object currentTarget; - @override - final Database database; -} diff --git a/app/lib/app_init.dart b/app/lib/app_init.dart index f750357d..e5ac9639 100644 --- a/app/lib/app_init.dart +++ b/app/lib/app_init.dart @@ -1,12 +1,13 @@ +import 'package:drift/drift.dart'; import 'package:equatable/equatable.dart'; import 'package:event_bus/event_bus.dart'; import 'package:flutter/foundation.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/album/data_source.dart'; import 'package:nc_photos/entity/face.dart'; import 'package:nc_photos/entity/face/data_source.dart'; import 'package:nc_photos/entity/favorite.dart'; @@ -21,6 +22,8 @@ import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/share/data_source.dart'; import 'package:nc_photos/entity/sharee.dart'; import 'package:nc_photos/entity/sharee/data_source.dart'; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; +import 'package:nc_photos/entity/sqlite_table_isolate.dart' as sql_isolate; import 'package:nc_photos/entity/tag.dart'; import 'package:nc_photos/entity/tag/data_source.dart'; import 'package:nc_photos/entity/tagged_file.dart'; @@ -34,13 +37,19 @@ import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref_util.dart' as pref_util; import 'package:visibility_detector/visibility_detector.dart'; -Future initAppLaunch() async { +enum InitIsolateType { + main, + service, +} + +Future init(InitIsolateType isolateType) async { if (_hasInitedInThisIsolate) { _log.warning("[initAppLaunch] Already initialized in this isolate"); return; } initLog(); + _initDrift(); _initKiwi(); await _initPref(); await _initAccountPrefs(); @@ -49,7 +58,7 @@ Future initAppLaunch() async { if (features.isSupportSelfSignedCert) { _initSelfSignedCertManager(); } - _initDiContainer(); + await _initDiContainer(isolateType); _initVisibilityDetector(); _hasInitedInThisIsolate = true; @@ -99,6 +108,10 @@ void initLog() { }); } +void _initDrift() { + driftRuntimeOptions.debugPrint = _debugPrintSql; +} + Future _initPref() async { final provider = PrefSharedPreferencesProvider(); await provider.init(); @@ -146,31 +159,56 @@ void _initSelfSignedCertManager() { SelfSignedCertManager().init(); } -void _initDiContainer() { - LocalFileRepo? localFileRepo; +Future _initDiContainer(InitIsolateType isolateType) async { + final c = DiContainer.late(); + c.pref = Pref(); + c.sqliteDb = await _createDb(isolateType); + + c.albumRepo = AlbumRepo(AlbumCachedDataSource(c)); + c.albumRepoLocal = AlbumRepo(AlbumSqliteDbDataSource(c)); + c.faceRepo = const FaceRepo(FaceRemoteDataSource()); + c.fileRepo = FileRepo(FileCachedDataSource(c)); + c.fileRepoRemote = const FileRepo(FileWebdavDataSource()); + c.fileRepoLocal = FileRepo(FileSqliteDbDataSource(c)); + c.personRepo = const PersonRepo(PersonRemoteDataSource()); + c.shareRepo = ShareRepo(ShareRemoteDataSource()); + c.shareeRepo = ShareeRepo(ShareeRemoteDataSource()); + c.favoriteRepo = const FavoriteRepo(FavoriteRemoteDataSource()); + c.tagRepo = const TagRepo(TagRemoteDataSource()); + c.taggedFileRepo = const TaggedFileRepo(TaggedFileRemoteDataSource()); + if (platform_k.isAndroid) { // local file currently only supported on Android - localFileRepo = const LocalFileRepo(LocalFileMediaStoreDataSource()); + c.localFileRepo = const LocalFileRepo(LocalFileMediaStoreDataSource()); } - KiwiContainer().registerInstance(DiContainer( - albumRepo: AlbumRepo(AlbumCachedDataSource(AppDb())), - faceRepo: const FaceRepo(FaceRemoteDataSource()), - fileRepo: FileRepo(FileCachedDataSource(AppDb())), - personRepo: const PersonRepo(PersonRemoteDataSource()), - shareRepo: ShareRepo(ShareRemoteDataSource()), - shareeRepo: ShareeRepo(ShareeRemoteDataSource()), - favoriteRepo: const FavoriteRepo(FavoriteRemoteDataSource()), - tagRepo: const TagRepo(TagRemoteDataSource()), - taggedFileRepo: const TaggedFileRepo(TaggedFileRemoteDataSource()), - localFileRepo: localFileRepo, - appDb: AppDb(), - pref: Pref(), - )); + + KiwiContainer().registerInstance(c); } void _initVisibilityDetector() { VisibilityDetectorController.instance.updateInterval = Duration.zero; } +Future _createDb(InitIsolateType isolateType) async { + switch (isolateType) { + case InitIsolateType.main: + // use driftIsolate to prevent DB blocking the UI thread + if (platform_k.isWeb) { + // no isolate support on web + return sql.SqliteDb(); + } else { + return sql_isolate.createDb(); + } + + case InitIsolateType.service: + // service already runs in an isolate + return sql.SqliteDb(); + } +} + +void _debugPrintSql(String log) { + _log.finer(log); +} + final _log = Logger("app_init"); var _hasInitedInThisIsolate = false; diff --git a/app/lib/bloc/list_album.dart b/app/lib/bloc/list_album.dart index b9d89f8c..54ea8898 100644 --- a/app/lib/bloc/list_album.dart +++ b/app/lib/bloc/list_album.dart @@ -5,8 +5,6 @@ import 'package:nc_photos/account.dart'; import 'package:nc_photos/bloc/bloc_util.dart' as bloc_util; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; -import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/event/event.dart'; @@ -153,8 +151,8 @@ class ListAlbumBloc extends Bloc { _log.info("[of] New bloc instance for account: $account"); final c = KiwiContainer().resolve(); final offlineC = c.copyWith( - fileRepo: OrNull(FileRepo(FileAppDbDataSource(c.appDb))), - albumRepo: OrNull(AlbumRepo(AlbumAppDbDataSource(c.appDb))), + fileRepo: OrNull(c.fileRepoLocal), + albumRepo: OrNull(c.albumRepoLocal), ); final bloc = ListAlbumBloc(c, offlineC); KiwiContainer().registerInstance(bloc, name: name); diff --git a/app/lib/bloc/ls_trashbin.dart b/app/lib/bloc/ls_trashbin.dart index 18aeb83d..00c38758 100644 --- a/app/lib/bloc/ls_trashbin.dart +++ b/app/lib/bloc/ls_trashbin.dart @@ -3,8 +3,8 @@ import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/bloc/bloc_util.dart' as bloc_util; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/throttler.dart'; @@ -175,9 +175,9 @@ class LsTrashbinBloc extends Bloc { } Future> _query(LsTrashbinBlocQuery ev) async { + final c = KiwiContainer().resolve(); // caching contents in trashbin doesn't sounds useful - const fileRepo = FileRepo(FileWebdavDataSource()); - final files = await LsTrashbin(fileRepo)(ev.account); + final files = await LsTrashbin(c.fileRepoRemote)(ev.account); return files.where((f) => file_util.isSupportedFormat(f)).toList(); } diff --git a/app/lib/bloc/scan_account_dir.dart b/app/lib/bloc/scan_account_dir.dart index 3703b849..4d159222 100644 --- a/app/lib/bloc/scan_account_dir.dart +++ b/app/lib/bloc/scan_account_dir.dart @@ -5,7 +5,6 @@ import 'package:collection/collection.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/bloc/bloc_util.dart' as bloc_util; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; @@ -108,6 +107,11 @@ class ScanAccountDirBlocInconsistent extends ScanAccountDirBlocState { class ScanAccountDirBloc extends Bloc { ScanAccountDirBloc._(this.account) : super(const ScanAccountDirBlocInit()) { + final c = KiwiContainer().resolve(); + assert(require(c)); + assert(ScanDirOffline.require(c)); + _c = c; + _fileRemovedEventListener.begin(); _filePropertyUpdatedEventListener.begin(); _fileTrashbinRestoredEventListener.begin(); @@ -132,6 +136,8 @@ class ScanAccountDirBloc })); } + static bool require(DiContainer c) => DiContainer.has(c, DiType.fileRepo); + static ScanAccountDirBloc of(Account account) { final name = bloc_util.getInstNameForRootAwareAccount("ScanAccountDirBloc", account); @@ -317,12 +323,11 @@ class ScanAccountDirBloc } Future> _queryOffline(ScanAccountDirBlocQueryBase ev) async { - final c = KiwiContainer().resolve(); final files = []; for (final r in account.roots) { try { final dir = File(path: file_util.unstripPath(account, r)); - files.addAll(await ScanDirOffline(c)(account, dir, + files.addAll(await ScanDirOffline(_c)(account, dir, isOnlySupportedFormat: false)); } catch (e, stackTrace) { _log.shout( @@ -341,11 +346,12 @@ class ScanAccountDirBloc final cacheMap = FileForwardCacheManager.prepareFileMap(cache); { final stopwatch = Stopwatch()..start(); - final fileRepo = FileRepo(FileCachedDataSource(AppDb(), - forwardCacheManager: FileForwardCacheManager(AppDb(), cacheMap))); - final fileRepoNoCache = FileRepo(FileCachedDataSource(AppDb())); + final fileRepo = FileRepo(FileCachedDataSource( + _c, + forwardCacheManager: FileForwardCacheManager(_c, cacheMap), + )); await for (final event in _queryWithFileRepo(fileRepo, ev, - fileRepoForShareDir: fileRepoNoCache)) { + fileRepoForShareDir: _c.fileRepo)) { if (event is ExceptionEvent) { _log.shout("[_queryOnline] Exception while request (1st pass)", event.error, event.stackTrace); @@ -378,7 +384,8 @@ class ScanAccountDirBloc emit(ScanAccountDirBlocLoading(files)); } - files = await _queryOnlinePass2(ev, cacheMap, files); + // files = await _queryOnlinePass2(ev, cacheMap, files); + files = await _queryOnlinePass2(ev, {}, files); } } catch (e, stackTrace) { _log.shout( @@ -394,9 +401,11 @@ class ScanAccountDirBloc // files final pass2CacheMap = CombinedMapView( [FileForwardCacheManager.prepareFileMap(pass1Files), cacheMap]); - final fileRepo = FileRepo(FileCachedDataSource(AppDb(), - shouldCheckCache: true, - forwardCacheManager: FileForwardCacheManager(AppDb(), pass2CacheMap))); + final fileRepo = FileRepo(FileCachedDataSource( + _c, + shouldCheckCache: true, + forwardCacheManager: FileForwardCacheManager(_c, pass2CacheMap), + )); final remoteTouchEtag = await touchTokenManager.getRemoteRootEtag(fileRepo, account); if (remoteTouchEtag == null) { @@ -412,7 +421,7 @@ class ScanAccountDirBloc final stopwatch = Stopwatch()..start(); final fileRepoNoCache = - FileRepo(FileCachedDataSource(AppDb(), shouldCheckCache: true)); + FileRepo(FileCachedDataSource(_c, shouldCheckCache: true)); final newFiles = []; await for (final event in _queryWithFileRepo(fileRepo, ev, fileRepoForShareDir: fileRepoNoCache)) { @@ -489,6 +498,8 @@ class ScanAccountDirBloc return false; } + late final DiContainer _c; + final Account account; late final _fileRemovedEventListener = diff --git a/app/lib/di_container.dart b/app/lib/di_container.dart index 36e58978..0401a037 100644 --- a/app/lib/di_container.dart +++ b/app/lib/di_container.dart @@ -1,4 +1,3 @@ -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/face.dart'; import 'package:nc_photos/entity/favorite.dart'; @@ -7,6 +6,7 @@ import 'package:nc_photos/entity/local_file.dart'; import 'package:nc_photos/entity/person.dart'; import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/sharee.dart'; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; import 'package:nc_photos/entity/tag.dart'; import 'package:nc_photos/entity/tagged_file.dart'; import 'package:nc_photos/or_null.dart'; @@ -14,8 +14,11 @@ import 'package:nc_photos/pref.dart'; enum DiType { albumRepo, + albumRepoLocal, faceRepo, fileRepo, + fileRepoRemote, + fileRepoLocal, personRepo, shareRepo, shareeRepo, @@ -23,15 +26,18 @@ enum DiType { tagRepo, taggedFileRepo, localFileRepo, - appDb, pref, + sqliteDb, } class DiContainer { - const DiContainer({ + DiContainer({ AlbumRepo? albumRepo, + AlbumRepo? albumRepoLocal, FaceRepo? faceRepo, FileRepo? fileRepo, + FileRepo? fileRepoRemote, + FileRepo? fileRepoLocal, PersonRepo? personRepo, ShareRepo? shareRepo, ShareeRepo? shareeRepo, @@ -39,11 +45,14 @@ class DiContainer { TagRepo? tagRepo, TaggedFileRepo? taggedFileRepo, LocalFileRepo? localFileRepo, - AppDb? appDb, Pref? pref, + sql.SqliteDb? sqliteDb, }) : _albumRepo = albumRepo, + _albumRepoLocal = albumRepoLocal, _faceRepo = faceRepo, _fileRepo = fileRepo, + _fileRepoRemote = fileRepoRemote, + _fileRepoLocal = fileRepoLocal, _personRepo = personRepo, _shareRepo = shareRepo, _shareeRepo = shareeRepo, @@ -51,17 +60,25 @@ class DiContainer { _tagRepo = tagRepo, _taggedFileRepo = taggedFileRepo, _localFileRepo = localFileRepo, - _appDb = appDb, - _pref = pref; + _pref = pref, + _sqliteDb = sqliteDb; + + DiContainer.late(); static bool has(DiContainer contianer, DiType type) { switch (type) { case DiType.albumRepo: return contianer._albumRepo != null; + case DiType.albumRepoLocal: + return contianer._albumRepoLocal != null; case DiType.faceRepo: return contianer._faceRepo != null; case DiType.fileRepo: return contianer._fileRepo != null; + case DiType.fileRepoRemote: + return contianer._fileRepoRemote != null; + case DiType.fileRepoLocal: + return contianer._fileRepoLocal != null; case DiType.personRepo: return contianer._personRepo != null; case DiType.shareRepo: @@ -76,17 +93,20 @@ class DiContainer { return contianer._taggedFileRepo != null; case DiType.localFileRepo: return contianer._localFileRepo != null; - case DiType.appDb: - return contianer._appDb != null; case DiType.pref: return contianer._pref != null; + case DiType.sqliteDb: + return contianer._sqliteDb != null; } } DiContainer copyWith({ OrNull? albumRepo, + OrNull? albumRepoLocal, OrNull? faceRepo, OrNull? fileRepo, + OrNull? fileRepoRemote, + OrNull? fileRepoLocal, OrNull? personRepo, OrNull? shareRepo, OrNull? shareeRepo, @@ -94,13 +114,18 @@ class DiContainer { OrNull? tagRepo, OrNull? taggedFileRepo, OrNull? localFileRepo, - OrNull? appDb, OrNull? pref, + OrNull? sqliteDb, }) { return DiContainer( albumRepo: albumRepo == null ? _albumRepo : albumRepo.obj, + albumRepoLocal: + albumRepoLocal == null ? _albumRepoLocal : albumRepoLocal.obj, faceRepo: faceRepo == null ? _faceRepo : faceRepo.obj, fileRepo: fileRepo == null ? _fileRepo : fileRepo.obj, + fileRepoRemote: + fileRepoRemote == null ? _fileRepoRemote : fileRepoRemote.obj, + fileRepoLocal: fileRepoLocal == null ? _fileRepoLocal : fileRepoLocal.obj, personRepo: personRepo == null ? _personRepo : personRepo.obj, shareRepo: shareRepo == null ? _shareRepo : shareRepo.obj, shareeRepo: shareeRepo == null ? _shareeRepo : shareeRepo.obj, @@ -109,14 +134,17 @@ class DiContainer { taggedFileRepo: taggedFileRepo == null ? _taggedFileRepo : taggedFileRepo.obj, localFileRepo: localFileRepo == null ? _localFileRepo : localFileRepo.obj, - appDb: appDb == null ? _appDb : appDb.obj, pref: pref == null ? _pref : pref.obj, + sqliteDb: sqliteDb == null ? _sqliteDb : sqliteDb.obj, ); } AlbumRepo get albumRepo => _albumRepo!; + AlbumRepo get albumRepoLocal => _albumRepoLocal!; FaceRepo get faceRepo => _faceRepo!; FileRepo get fileRepo => _fileRepo!; + FileRepo get fileRepoRemote => _fileRepoRemote!; + FileRepo get fileRepoLocal => _fileRepoLocal!; PersonRepo get personRepo => _personRepo!; ShareRepo get shareRepo => _shareRepo!; ShareeRepo get shareeRepo => _shareeRepo!; @@ -125,20 +153,101 @@ class DiContainer { TaggedFileRepo get taggedFileRepo => _taggedFileRepo!; LocalFileRepo get localFileRepo => _localFileRepo!; - AppDb get appDb => _appDb!; + sql.SqliteDb get sqliteDb => _sqliteDb!; Pref get pref => _pref!; - final AlbumRepo? _albumRepo; - final FaceRepo? _faceRepo; - final FileRepo? _fileRepo; - final PersonRepo? _personRepo; - final ShareRepo? _shareRepo; - final ShareeRepo? _shareeRepo; - final FavoriteRepo? _favoriteRepo; - final TagRepo? _tagRepo; - final TaggedFileRepo? _taggedFileRepo; - final LocalFileRepo? _localFileRepo; + set albumRepo(AlbumRepo v) { + assert(_albumRepo == null); + _albumRepo = v; + } - final AppDb? _appDb; - final Pref? _pref; + set albumRepoLocal(AlbumRepo v) { + assert(_albumRepoLocal == null); + _albumRepoLocal = v; + } + + set faceRepo(FaceRepo v) { + assert(_faceRepo == null); + _faceRepo = v; + } + + set fileRepo(FileRepo v) { + assert(_fileRepo == null); + _fileRepo = v; + } + + set fileRepoRemote(FileRepo v) { + assert(_fileRepoRemote == null); + _fileRepoRemote = v; + } + + set fileRepoLocal(FileRepo v) { + assert(_fileRepoLocal == null); + _fileRepoLocal = v; + } + + set personRepo(PersonRepo v) { + assert(_personRepo == null); + _personRepo = v; + } + + set shareRepo(ShareRepo v) { + assert(_shareRepo == null); + _shareRepo = v; + } + + set shareeRepo(ShareeRepo v) { + assert(_shareeRepo == null); + _shareeRepo = v; + } + + set favoriteRepo(FavoriteRepo v) { + assert(_favoriteRepo == null); + _favoriteRepo = v; + } + + set tagRepo(TagRepo v) { + assert(_tagRepo == null); + _tagRepo = v; + } + + set taggedFileRepo(TaggedFileRepo v) { + assert(_taggedFileRepo == null); + _taggedFileRepo = v; + } + + set localFileRepo(LocalFileRepo v) { + assert(_localFileRepo == null); + _localFileRepo = v; + } + + set sqliteDb(sql.SqliteDb v) { + assert(_sqliteDb == null); + _sqliteDb = v; + } + + set pref(Pref v) { + assert(_pref == null); + _pref = v; + } + + AlbumRepo? _albumRepo; + // Explicitly request a AlbumRepo backed by local source + AlbumRepo? _albumRepoLocal; + FaceRepo? _faceRepo; + FileRepo? _fileRepo; + // Explicitly request a FileRepo backed by remote source + FileRepo? _fileRepoRemote; + // Explicitly request a FileRepo backed by local source + FileRepo? _fileRepoLocal; + PersonRepo? _personRepo; + ShareRepo? _shareRepo; + ShareeRepo? _shareeRepo; + FavoriteRepo? _favoriteRepo; + TagRepo? _tagRepo; + TaggedFileRepo? _taggedFileRepo; + LocalFileRepo? _localFileRepo; + + sql.SqliteDb? _sqliteDb; + Pref? _pref; } diff --git a/app/lib/entity/album.dart b/app/lib/entity/album.dart index d58dc9bd..87d3b187 100644 --- a/app/lib/entity/album.dart +++ b/app/lib/entity/album.dart @@ -1,33 +1,16 @@ -import 'dart:convert'; -import 'dart:math'; - import 'package:equatable/equatable.dart'; -import 'package:idb_sqflite/idb_sqflite.dart'; -import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/ci_string.dart'; -import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album/cover_provider.dart'; -import 'package:nc_photos/entity/album/item.dart'; import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/sort_provider.dart'; import 'package:nc_photos/entity/album/upgrader.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; -import 'package:nc_photos/exception.dart'; -import 'package:nc_photos/int_util.dart' as int_util; import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/object_extension.dart'; import 'package:nc_photos/or_null.dart'; -import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/type.dart'; -import 'package:nc_photos/use_case/get_file_binary.dart'; -import 'package:nc_photos/use_case/ls_single_file.dart'; -import 'package:nc_photos/use_case/put_file_binary.dart'; -import 'package:quiver/iterables.dart'; -import 'package:tuple/tuple.dart'; /// Immutable object that represents an album class Album with EquatableMixin { @@ -229,6 +212,8 @@ class Album with EquatableMixin { /// versioning of this class, use to upgrade old persisted album static const version = 8; + + static final _log = Logger("entity.album.Album"); } class AlbumShare with EquatableMixin { @@ -299,6 +284,10 @@ class AlbumRepo { Future get(Account account, File albumFile) => dataSrc.get(account, albumFile); + /// See [AlbumDataSource.getAll] + Stream getAll(Account account, List albumFiles) => + dataSrc.getAll(account, albumFiles); + /// See [AlbumDataSource.create] Future create(Account account, Album album) => dataSrc.create(account, album); @@ -307,11 +296,6 @@ class AlbumRepo { Future update(Account account, Album album) => dataSrc.update(account, album); - /// See [AlbumDataSource.cleanUp] - Future cleanUp( - Account account, String rootDir, List albumFiles) => - dataSrc.cleanUp(account, rootDir, albumFiles); - final AlbumDataSource dataSrc; } @@ -319,292 +303,12 @@ abstract class AlbumDataSource { /// Return the album defined by [albumFile] Future get(Account account, File albumFile); + /// Emit albums defined by [albumFiles] or ExceptionEvent + Stream getAll(Account account, List albumFiles); + // Create a new album Future create(Account account, Album album); /// Update an album Future update(Account account, Album album); - - /// Clean up cached albums - /// - /// Remove dangling albums in cache not listed in [albumFiles] and located - /// inside [rootDir]. Do nothing if this data source does not cache previous - /// results - Future cleanUp(Account account, String rootDir, List albumFiles); } - -class AlbumRemoteDataSource implements AlbumDataSource { - @override - get(Account account, File albumFile) async { - _log.info("[get] ${albumFile.path}"); - const fileRepo = FileRepo(FileWebdavDataSource()); - final data = await GetFileBinary(fileRepo)(account, albumFile); - try { - return Album.fromJson( - jsonDecode(utf8.decode(data)), - upgraderFactory: DefaultAlbumUpgraderFactory( - account: account, - albumFile: albumFile, - logFilePath: albumFile.path, - ), - )! - .copyWith( - lastUpdated: OrNull(null), - albumFile: OrNull(albumFile), - ); - } catch (e, stacktrace) { - dynamic d = data; - try { - d = utf8.decode(data); - } catch (_) {} - _log.severe("[get] Invalid json data: $d", e, stacktrace); - throw const FormatException("Invalid album format"); - } - } - - @override - create(Account account, Album album) async { - _log.info("[create]"); - final fileName = _makeAlbumFileName(); - final filePath = - "${remote_storage_util.getRemoteAlbumsDir(account)}/$fileName"; - const fileRepo = FileRepo(FileWebdavDataSource()); - await PutFileBinary(fileRepo)(account, filePath, - const Utf8Encoder().convert(jsonEncode(album.toRemoteJson())), - shouldCreateMissingDir: true); - // query album file - final newFile = await LsSingleFile(KiwiContainer().resolve())( - account, filePath); - return album.copyWith(albumFile: OrNull(newFile)); - } - - @override - update(Account account, Album album) async { - _log.info("[update] ${album.albumFile!.path}"); - const fileRepo = FileRepo(FileWebdavDataSource()); - await PutFileBinary(fileRepo)(account, album.albumFile!.path, - const Utf8Encoder().convert(jsonEncode(album.toRemoteJson()))); - } - - @override - cleanUp(Account account, String rootDir, List albumFiles) async {} - - String _makeAlbumFileName() { - // just make up something - final timestamp = DateTime.now().millisecondsSinceEpoch; - final random = Random().nextInt(0xFFFFFF); - return "${timestamp.toRadixString(16)}-${random.toRadixString(16).padLeft(6, '0')}.nc_album.json"; - } - - static final _log = Logger("entity.album.AlbumRemoteDataSource"); -} - -class AlbumAppDbDataSource implements AlbumDataSource { - const AlbumAppDbDataSource(this.appDb); - - @override - get(Account account, File albumFile) { - _log.info("[get] ${albumFile.path}"); - return appDb.use( - (db) => db.transaction(AppDb.albumStoreName, idbModeReadOnly), - (transaction) async { - final store = transaction.objectStore(AppDb.albumStoreName); - final index = store.index(AppDbAlbumEntry.indexName); - final path = AppDbAlbumEntry.toPathFromFile(account, albumFile); - final range = KeyRange.bound([path, 0], [path, int_util.int32Max]); - final List results = await index.getAll(range); - if (results.isNotEmpty == true) { - final entries = results.map((e) => - AppDbAlbumEntry.fromJson(e.cast(), account)); - if (entries.length > 1) { - final items = entries.map((e) { - _log.info("[get] ${e.path}[${e.index}]"); - return AlbumStaticProvider.of(e.album).items; - }).reduce((value, element) => value + element); - return entries.first.album.copyWith( - lastUpdated: OrNull(null), - provider: AlbumStaticProvider.of(entries.first.album).copyWith( - items: items, - ), - ); - } else { - return entries.first.album; - } - } else { - throw CacheNotFoundException("No entry: $path"); - } - }, - ); - } - - @override - create(Account account, Album album) async { - _log.info("[create]"); - throw UnimplementedError(); - } - - @override - update(Account account, Album album) { - _log.info("[update] ${album.albumFile!.path}"); - return appDb.use( - (db) => db.transaction(AppDb.albumStoreName, idbModeReadWrite), - (transaction) async { - final store = transaction.objectStore(AppDb.albumStoreName); - await _cacheAlbum(store, account, album); - }, - ); - } - - @override - cleanUp(Account account, String rootDir, List albumFiles) async {} - - final AppDb appDb; - - static final _log = Logger("entity.album.AlbumAppDbDataSource"); -} - -class AlbumCachedDataSource implements AlbumDataSource { - AlbumCachedDataSource(this.appDb) : _appDbSrc = AlbumAppDbDataSource(appDb); - - @override - get(Account account, File albumFile) async { - try { - final cache = await _appDbSrc.get(account, albumFile); - if (cache.albumFile!.etag?.isNotEmpty == true && - cache.albumFile!.etag == albumFile.etag) { - // cache is good - _log.fine( - "[get] etag matched for ${AppDbAlbumEntry.toPathFromFile(account, albumFile)}"); - return cache; - } - _log.info( - "[get] Remote content updated for ${AppDbAlbumEntry.toPathFromFile(account, albumFile)}"); - } on CacheNotFoundException catch (_) { - // normal when there's no cache - } catch (e, stacktrace) { - _log.shout("[get] Cache failure", e, stacktrace); - } - - // no cache - final remote = await _remoteSrc.get(account, albumFile); - await _cacheResult(account, remote); - return remote; - } - - @override - update(Account account, Album album) async { - await _remoteSrc.update(account, album); - await _appDbSrc.update(account, album); - } - - @override - create(Account account, Album album) => _remoteSrc.create(account, album); - - @override - cleanUp(Account account, String rootDir, List albumFiles) async { - appDb.use( - (db) => db.transaction(AppDb.albumStoreName, idbModeReadWrite), - (transaction) async { - final store = transaction.objectStore(AppDb.albumStoreName); - final index = store.index(AppDbAlbumEntry.indexName); - final rootPath = AppDbAlbumEntry.toPath(account, rootDir); - final range = KeyRange.bound( - ["$rootPath/", 0], ["$rootPath/\uffff", int_util.int32Max]); - final danglingKeys = await index - // get all albums for this account - .openKeyCursor(range: range, autoAdvance: true) - .map((cursor) => Tuple2((cursor.key as List)[0], cursor.primaryKey)) - // and pick the dangling ones - .where((pair) => !albumFiles.any((f) => - pair.item1 == AppDbAlbumEntry.toPathFromFile(account, f))) - // map to primary keys - .map((pair) => pair.item2) - .toList(); - for (final k in danglingKeys) { - _log.fine("[cleanUp] Removing albumStore entry: $k"); - try { - await store.delete(k); - } catch (e, stackTrace) { - _log.shout( - "[cleanUp] Failed removing albumStore entry", e, stackTrace); - } - } - }, - ); - } - - Future _cacheResult(Account account, Album result) { - return appDb.use( - (db) => db.transaction(AppDb.albumStoreName, idbModeReadWrite), - (transaction) async { - final store = transaction.objectStore(AppDb.albumStoreName); - await _cacheAlbum(store, account, result); - }, - ); - } - - final AppDb appDb; - final _remoteSrc = AlbumRemoteDataSource(); - final AlbumAppDbDataSource _appDbSrc; - - static final _log = Logger("entity.album.AlbumCachedDataSource"); -} - -Future _cacheAlbum( - ObjectStore store, Account account, Album album) async { - final index = store.index(AppDbAlbumEntry.indexName); - final path = AppDbAlbumEntry.toPathFromFile(account, album.albumFile!); - final range = KeyRange.bound([path, 0], [path, int_util.int32Max]); - // count number of entries for this album - final count = await index.count(range); - - // cut large album into smaller pieces, needed to workaround Android DB - // limitation - final entries = []; - if (album.provider is AlbumStaticProvider) { - var albumItemLists = partition( - AlbumStaticProvider.of(album).items, AppDbAlbumEntry.maxDataSize) - .toList(); - if (albumItemLists.isEmpty) { - albumItemLists = [[]]; - } - entries.addAll(albumItemLists.withIndex().map((pair) => AppDbAlbumEntry( - path, - pair.item1, - album.copyWith( - lastUpdated: OrNull(null), - provider: AlbumStaticProvider.of(album).copyWith( - items: pair.item2, - ), - )))); - } else { - entries.add(AppDbAlbumEntry(path, 0, album)); - } - - for (final e in entries) { - _log.info("[_cacheAlbum] Caching ${e.path}[${e.index}]"); - await store.put(e.toJson(), - AppDbAlbumEntry.toPrimaryKey(account, e.album.albumFile!, e.index)); - } - - if (count > entries.length) { - // index is 0-based - final rmRange = - KeyRange.bound([path, entries.length], [path, int_util.int32Max]); - final rmKeys = await index - .openKeyCursor(range: rmRange, autoAdvance: true) - .map((cursor) => cursor.primaryKey) - .toList(); - for (final k in rmKeys) { - _log.fine("[_cacheAlbum] Removing albumStore entry: $k"); - try { - await store.delete(k); - } catch (e, stackTrace) { - _log.shout( - "[_cacheAlbum] Failed removing albumStore entry", e, stackTrace); - } - } - } -} - -final _log = Logger("entity.album"); diff --git a/app/lib/entity/album/data_source.dart b/app/lib/entity/album/data_source.dart new file mode 100644 index 00000000..d8ae1293 --- /dev/null +++ b/app/lib/entity/album/data_source.dart @@ -0,0 +1,307 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:drift/drift.dart' as sql; +import 'package:kiwi/kiwi.dart'; +import 'package:logging/logging.dart'; +import 'package:nc_photos/account.dart'; +import 'package:nc_photos/di_container.dart'; +import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/album/upgrader.dart'; +import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/entity/file/data_source.dart'; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; +import 'package:nc_photos/entity/sqlite_table_converter.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; +import 'package:nc_photos/exception.dart'; +import 'package:nc_photos/exception_event.dart'; +import 'package:nc_photos/future_util.dart' as future_util; +import 'package:nc_photos/iterable_extension.dart'; +import 'package:nc_photos/or_null.dart'; +import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; +import 'package:nc_photos/use_case/get_file_binary.dart'; +import 'package:nc_photos/use_case/ls_single_file.dart'; +import 'package:nc_photos/use_case/put_file_binary.dart'; + +class AlbumRemoteDataSource implements AlbumDataSource { + @override + get(Account account, File albumFile) async { + _log.info("[get] ${albumFile.path}"); + const fileRepo = FileRepo(FileWebdavDataSource()); + final data = await GetFileBinary(fileRepo)(account, albumFile); + try { + return Album.fromJson( + jsonDecode(utf8.decode(data)), + upgraderFactory: DefaultAlbumUpgraderFactory( + account: account, + albumFile: albumFile, + logFilePath: albumFile.path, + ), + )! + .copyWith( + lastUpdated: OrNull(null), + albumFile: OrNull(albumFile), + ); + } catch (e, stacktrace) { + dynamic d = data; + try { + d = utf8.decode(data); + } catch (_) {} + _log.severe("[get] Invalid json data: $d", e, stacktrace); + throw const FormatException("Invalid album format"); + } + } + + @override + getAll(Account account, List albumFiles) async* { + _log.info( + "[getAll] ${albumFiles.map((f) => f.filename).toReadableString()}"); + final results = await future_util.waitOr( + albumFiles.map((f) => get(account, f)), + (error, stackTrace) => ExceptionEvent(error, stackTrace), + ); + for (final r in results) { + yield r; + } + } + + @override + create(Account account, Album album) async { + _log.info("[create]"); + final fileName = _makeAlbumFileName(); + final filePath = + "${remote_storage_util.getRemoteAlbumsDir(account)}/$fileName"; + const fileRepo = FileRepo(FileWebdavDataSource()); + await PutFileBinary(fileRepo)(account, filePath, + const Utf8Encoder().convert(jsonEncode(album.toRemoteJson())), + shouldCreateMissingDir: true); + // query album file + final newFile = await LsSingleFile(KiwiContainer().resolve())( + account, filePath); + return album.copyWith(albumFile: OrNull(newFile)); + } + + @override + update(Account account, Album album) async { + _log.info("[update] ${album.albumFile!.path}"); + const fileRepo = FileRepo(FileWebdavDataSource()); + await PutFileBinary(fileRepo)(account, album.albumFile!.path, + const Utf8Encoder().convert(jsonEncode(album.toRemoteJson()))); + } + + String _makeAlbumFileName() { + // just make up something + final timestamp = DateTime.now().millisecondsSinceEpoch; + final random = Random().nextInt(0xFFFFFF); + return "${timestamp.toRadixString(16)}-${random.toRadixString(16).padLeft(6, '0')}.nc_album.json"; + } + + static final _log = Logger("entity.album.AlbumRemoteDataSource"); +} + +class AlbumSqliteDbDataSource implements AlbumDataSource { + AlbumSqliteDbDataSource(this._c); + + @override + get(Account account, File albumFile) async { + final results = await getAll(account, [albumFile]).toList(); + if (results.first is! Album) { + throw results.first; + } else { + return results.first; + } + } + + @override + getAll(Account account, List albumFiles) async* { + _log.info( + "[getAll] ${albumFiles.map((f) => f.filename).toReadableString()}"); + late final List dbFiles; + late final List albumWithShares; + await _c.sqliteDb.use((db) async { + dbFiles = await db.completeFilesByFileIds( + albumFiles.map((f) => f.fileId!), + appAccount: account, + ); + final query = db.select(db.albums).join([ + sql.leftOuterJoin( + db.albumShares, db.albumShares.album.equalsExp(db.albums.rowId)), + ]) + ..where(db.albums.file.isIn(dbFiles.map((f) => f.file.rowId))); + albumWithShares = await query + .map((r) => sql.AlbumWithShare( + r.readTable(db.albums), r.readTableOrNull(db.albumShares))) + .get(); + }); + + // group entries together + final fileRowIdMap = {}; + for (var f in dbFiles) { + fileRowIdMap[f.file.rowId] = f; + } + final fileIdMap = {}; + for (final s in albumWithShares) { + final f = fileRowIdMap[s.album.file]; + if (f == null) { + _log.severe("[getAll] File missing for album (rowId: ${s.album.rowId}"); + } else { + if (!fileIdMap.containsKey(f.file.fileId)) { + fileIdMap[f.file.fileId] = { + "file": f, + "album": s.album, + }; + } + if (s.share != null) { + (fileIdMap[f.file.fileId]!["shares"] ??= []) + .add(s.share!); + } + } + } + + // sort as the input list + for (final item in albumFiles.map((f) => fileIdMap[f.fileId])) { + if (item == null) { + // cache not found + yield CacheNotFoundException(); + } else { + try { + final f = SqliteFileConverter.fromSql( + account.homeDir.toString(), item["file"]); + yield SqliteAlbumConverter.fromSql( + item["album"], f, item["shares"] ?? []); + } catch (e, stackTrace) { + _log.severe( + "[getAll] Failed while converting DB entry", e, stackTrace); + yield ExceptionEvent(e, stackTrace); + } + } + } + } + + @override + create(Account account, Album album) async { + _log.info("[create]"); + throw UnimplementedError(); + } + + @override + update(Account account, Album album) async { + _log.info("[update] ${album.albumFile!.path}"); + await _c.sqliteDb.use((db) async { + final rowIds = + await db.accountFileRowIdsOf(album.albumFile!, appAccount: account); + final insert = SqliteAlbumConverter.toSql(album, rowIds.fileRowId); + var rowId = await _updateCache(db, rowIds.fileRowId, insert.album); + if (rowId == null) { + // new album, need insert + _log.info("[update] Insert new album"); + final insertedAlbum = + await db.into(db.albums).insertReturning(insert.album); + rowId = insertedAlbum.rowId; + } else { + await (db.delete(db.albumShares)..where((t) => t.album.equals(rowId))) + .go(); + } + if (insert.albumShares.isNotEmpty) { + await db.batch((batch) { + batch.insertAll( + db.albumShares, + insert.albumShares.map((s) => s.copyWith(album: sql.Value(rowId!))), + ); + }); + } + }); + } + + Future _updateCache( + sql.SqliteDb db, int dbFileRowId, sql.AlbumsCompanion dbAlbum) async { + final rowIdQuery = db.selectOnly(db.albums) + ..addColumns([db.albums.rowId]) + ..where(db.albums.file.equals(dbFileRowId)) + ..limit(1); + final rowId = + await rowIdQuery.map((r) => r.read(db.albums.rowId)!).getSingleOrNull(); + if (rowId == null) { + // new album + return null; + } + + await (db.update(db.albums)..where((t) => t.rowId.equals(rowId))) + .write(dbAlbum); + return rowId; + } + + final DiContainer _c; + + static final _log = Logger("entity.album.AlbumSqliteDbDataSource"); +} + +class AlbumCachedDataSource implements AlbumDataSource { + AlbumCachedDataSource(DiContainer c) + : _sqliteDbSrc = AlbumSqliteDbDataSource(c); + + @override + get(Account account, File albumFile) async { + final result = await getAll(account, [albumFile]).first; + return result as Album; + } + + @override + getAll(Account account, List albumFiles) async* { + var i = 0; + await for (final cache in _sqliteDbSrc.getAll(account, albumFiles)) { + final albumFile = albumFiles[i++]; + if (_validateCache(cache, albumFile)) { + yield cache; + } else { + // no cache + final remote = await _remoteSrc.get(account, albumFile); + await _cacheResult(account, remote); + yield remote; + } + } + } + + @override + update(Account account, Album album) async { + await _remoteSrc.update(account, album); + await _sqliteDbSrc.update(account, album); + } + + @override + create(Account account, Album album) => _remoteSrc.create(account, album); + + Future _cacheResult(Account account, Album result) { + return _sqliteDbSrc.update(account, result); + } + + bool _validateCache(dynamic cache, File albumFile) { + if (cache is Album) { + if (cache.albumFile!.etag?.isNotEmpty == true && + cache.albumFile!.etag == albumFile.etag) { + // cache is good + _log.fine("[_validateCache] etag matched for ${albumFile.path}"); + return true; + } else { + _log.info( + "[_validateCache] Remote content updated for ${albumFile.path}"); + return false; + } + } else if (cache is CacheNotFoundException) { + // normal when there's no cache + return false; + } else if (cache is ExceptionEvent) { + _log.shout( + "[_validateCache] Cache failure", cache.error, cache.stackTrace); + return false; + } else { + _log.shout("[_validateCache] Unknown type: ${cache.runtimeType}"); + return false; + } + } + + final _remoteSrc = AlbumRemoteDataSource(); + final AlbumSqliteDbDataSource _sqliteDbSrc; + + static final _log = Logger("entity.album.AlbumCachedDataSource"); +} diff --git a/app/lib/entity/file.dart b/app/lib/entity/file.dart index 120b22ba..63eeedcb 100644 --- a/app/lib/entity/file.dart +++ b/app/lib/entity/file.dart @@ -379,7 +379,7 @@ class File with EquatableMixin { String? path, int? contentLength, String? contentType, - String? etag, + OrNull? etag, DateTime? lastModified, bool? isCollection, int? usedBytes, @@ -398,7 +398,7 @@ class File with EquatableMixin { path: path ?? this.path, contentLength: contentLength ?? this.contentLength, contentType: contentType ?? this.contentType, - etag: etag ?? this.etag, + etag: etag == null ? this.etag : etag.obj, lastModified: lastModified ?? this.lastModified, isCollection: isCollection ?? this.isCollection, usedBytes: usedBytes ?? this.usedBytes, @@ -447,7 +447,6 @@ class File with EquatableMixin { final bool? isCollection; final int? usedBytes; final bool? hasPreview; - // maybe null when loaded from old cache final int? fileId; final bool? isFavorite; final CiString? ownerId; diff --git a/app/lib/entity/file/data_source.dart b/app/lib/entity/file/data_source.dart index 759cf1dd..4baf9053 100644 --- a/app/lib/entity/file/data_source.dart +++ b/app/lib/entity/file/data_source.dart @@ -1,15 +1,17 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:idb_shim/idb_client.dart'; +import 'package:drift/drift.dart' as sql; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/api/api.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/debug_util.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file/file_cache_manager.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/entity/webdav_response_parser.dart'; import 'package:nc_photos/exception.dart'; import 'package:nc_photos/iterable_extension.dart'; @@ -18,7 +20,6 @@ import 'package:nc_photos/or_null.dart'; import 'package:nc_photos/touch_token_manager.dart'; import 'package:nc_photos/use_case/compat/v32.dart'; import 'package:path/path.dart' as path_lib; -import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; import 'package:xml/xml.dart'; @@ -265,55 +266,38 @@ class FileWebdavDataSource implements FileDataSource { static final _log = Logger("entity.file.data_source.FileWebdavDataSource"); } -class FileAppDbDataSource implements FileDataSource { - const FileAppDbDataSource(this.appDb); +class FileSqliteDbDataSource implements FileDataSource { + FileSqliteDbDataSource(this._c); @override list(Account account, File dir) async { _log.info("[list] ${dir.path}"); - final dbItems = await appDb.use( - (db) => db.transaction( - [AppDb.dirStoreName, AppDb.file2StoreName], idbModeReadOnly), - (transaction) async { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - final dirStore = transaction.objectStore(AppDb.dirStoreName); - final dirItem = await dirStore - .getObject(AppDbDirEntry.toPrimaryKeyForDir(account, dir)) as Map?; - if (dirItem == null) { - throw CacheNotFoundException("No entry: ${dir.path}"); - } - final dirEntry = - AppDbDirEntry.fromJson(dirItem.cast()); - return Tuple2( - dirEntry.dir, - await Future.wait( - dirEntry.children.map((c) async { - final fileItem = await fileStore - .getObject(AppDbFile2Entry.toPrimaryKey(account, c)) as Map?; - if (fileItem == null) { - _log.warning( - "[list] Missing file ($c) in db for dir: ${logFilename(dir.path)}"); - throw CacheNotFoundException("No entry for dir child: $c"); - } else { - return fileItem; - } - }), - eagerError: true, - ), - ); - }, - ); - // we need to add dir to match the remote query - return [ - dbItems.item1, - ...(await dbItems.item2.computeAll(_covertAppDbFile2Entry)) - .where((f) => _validateFile(f)) - ]; + final dbFiles = await _c.sqliteDb.use((db) async { + final dbAccount = await db.accountOf(account); + final sql.File dbDir; + try { + dbDir = await db.fileOf(dir, sqlAccount: dbAccount); + } catch (_) { + throw CacheNotFoundException("No entry: ${dir.path}"); + } + return await db.completeFilesByDirRowId(dbDir.rowId, + sqlAccount: dbAccount); + }); + final results = (await dbFiles.convertToAppFile(account)) + .where((f) => _validateFile(f)) + .toList(); + _log.fine("[list] Queried ${results.length} files"); + if (results.isEmpty) { + // each dir will at least contain its own entry, so an empty list here + // means that the dir has not been queried before + throw CacheNotFoundException("No entry: ${dir.path}"); + } + return results; } @override listSingle(Account account, File f) { - _log.info("[listSingle] ${f.path}"); + _log.severe("[listSingle] ${f.path}"); throw UnimplementedError(); } @@ -322,39 +306,41 @@ class FileAppDbDataSource implements FileDataSource { Future> listByDate( Account account, int fromEpochMs, int toEpochMs) async { _log.info("[listByDate] [$fromEpochMs, $toEpochMs]"); - final items = await appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadOnly), - (transaction) async { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - final dateTimeEpochMsIndex = - fileStore.index(AppDbFile2Entry.dateTimeEpochMsIndexName); - final range = KeyRange.bound( - AppDbFile2Entry.toDateTimeEpochMsIndexKey(account, fromEpochMs), - AppDbFile2Entry.toDateTimeEpochMsIndexKey(account, toEpochMs), - false, - true, - ); - return await dateTimeEpochMsIndex.getAll(range); - }, - ); - return items - .cast() - .map((i) => AppDbFile2Entry.fromJson(i.cast())) - .map((e) => e.file) - .where((f) => _validateFile(f)) - .toList(); + final dbFiles = await _c.sqliteDb.use((db) async { + final dateTime = sql.coalesce([ + db.accountFiles.overrideDateTime, + db.images.dateTimeOriginal, + db.files.lastModified, + ]).secondsSinceEpoch; + final queryBuilder = db.queryFiles() + ..setQueryMode(sql.FilesQueryMode.completeFile) + ..setAppAccount(account); + final query = queryBuilder.build(); + query + ..where(dateTime.isBetweenValues( + fromEpochMs ~/ 1000, (toEpochMs ~/ 1000) - 1)) + ..orderBy([sql.OrderingTerm.desc(dateTime)]); + return await query + .map((r) => sql.CompleteFile( + r.readTable(db.files), + r.readTable(db.accountFiles), + r.readTableOrNull(db.images), + r.readTableOrNull(db.trashes), + )) + .get(); + }); + return await dbFiles.convertToAppFile(account); } - /// Remove a file/dir from database @override remove(Account account, File f) { _log.info("[remove] ${f.path}"); - return FileCacheRemover(appDb)(account, f); + return FileSqliteCacheRemover(_c)(account, f); } @override getBinary(Account account, File f) { - _log.info("[getBinary] ${f.path}"); + _log.severe("[getBinary] ${f.path}"); throw UnimplementedError(); } @@ -365,30 +351,51 @@ class FileAppDbDataSource implements FileDataSource { } @override - updateProperty( - Account account, - File f, { - OrNull? metadata, - OrNull? isArchived, - OrNull? overrideDateTime, - bool? favorite, - }) { + updateProperty(Account account, File f, + {OrNull? metadata, + OrNull? isArchived, + OrNull? overrideDateTime, + bool? favorite}) async { _log.info("[updateProperty] ${f.path}"); - return appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadWrite), - (transaction) async { - // update file store - final newFile = f.copyWith( - metadata: metadata, - isArchived: isArchived, - overrideDateTime: overrideDateTime, - isFavorite: favorite, + await _c.sqliteDb.use((db) async { + final rowIds = await db.accountFileRowIdsOf(f, appAccount: account); + if (isArchived != null || overrideDateTime != null || favorite != null) { + final update = sql.AccountFilesCompanion( + isArchived: isArchived == null + ? const sql.Value.absent() + : sql.Value(isArchived.obj), + overrideDateTime: overrideDateTime == null + ? const sql.Value.absent() + : sql.Value(overrideDateTime.obj), + isFavorite: + favorite == null ? const sql.Value.absent() : sql.Value(favorite), ); - final fileStore = transaction.objectStore(AppDb.file2StoreName); - await fileStore.put(AppDbFile2Entry.fromFile(account, newFile).toJson(), - AppDbFile2Entry.toPrimaryKeyForFile(account, newFile)); - }, - ); + await (db.update(db.accountFiles) + ..where((t) => t.rowId.equals(rowIds.accountFileRowId))) + .write(update); + } + if (metadata != null) { + if (metadata.obj == null) { + await (db.delete(db.images) + ..where((t) => t.accountFile.equals(rowIds.accountFileRowId))) + .go(); + } else { + await db + .into(db.images) + .insertOnConflictUpdate(sql.ImagesCompanion.insert( + accountFile: sql.Value(rowIds.accountFileRowId), + lastUpdated: metadata.obj!.lastUpdated, + fileEtag: sql.Value(metadata.obj!.fileEtag), + width: sql.Value(metadata.obj!.imageWidth), + height: sql.Value(metadata.obj!.imageHeight), + exifRaw: sql.Value( + metadata.obj!.exif?.toJson().run((j) => jsonEncode(j))), + dateTimeOriginal: + sql.Value(metadata.obj!.exif?.dateTimeOriginal), + )); + } + } + }); } @override @@ -416,23 +423,23 @@ class FileAppDbDataSource implements FileDataSource { // do nothing } - final AppDb appDb; + final DiContainer _c; - static final _log = Logger("entity.file.data_source.FileAppDbDataSource"); + static final _log = Logger("entity.file.data_source.FileSqliteDbDataSource"); } class FileCachedDataSource implements FileDataSource { FileCachedDataSource( - this.appDb, { + this._c, { this.shouldCheckCache = false, this.forwardCacheManager, - }) : _appDbSrc = FileAppDbDataSource(appDb); + }) : _sqliteDbSrc = FileSqliteDbDataSource(_c); @override list(Account account, File dir) async { final cacheLoader = FileCacheLoader( - appDb: appDb, - appDbSrc: _appDbSrc, + _c, + cacheSrc: _sqliteDbSrc, remoteSrc: _remoteSrc, shouldCheckCache: shouldCheckCache, forwardCacheManager: forwardCacheManager, @@ -445,7 +452,7 @@ class FileCachedDataSource implements FileDataSource { // no cache or outdated try { final remote = await _remoteSrc.list(account, dir); - await FileCacheUpdater(appDb)(account, dir, remote: remote, cache: cache); + await FileSqliteCacheUpdater(_c)(account, dir, remote: remote); if (shouldCheckCache) { // update our local touch token to match the remote one const tokenManager = TouchTokenManager(); @@ -461,11 +468,15 @@ class FileCachedDataSource implements FileDataSource { } on ApiException catch (e) { if (e.response.statusCode == 404) { _log.info("[list] File removed: $dir"); - _appDbSrc.remove(account, dir); + if (cache != null) { + await _sqliteDbSrc.remove(account, dir); + } return []; } else if (e.response.statusCode == 403) { _log.info("[list] E2E encrypted dir: $dir"); - _appDbSrc.remove(account, dir); + if (cache != null) { + await _sqliteDbSrc.remove(account, dir); + } return []; } else { rethrow; @@ -480,7 +491,7 @@ class FileCachedDataSource implements FileDataSource { @override remove(Account account, File f) async { - await _appDbSrc.remove(account, f); + await _sqliteDbSrc.remove(account, f); await _remoteSrc.remove(account, f); } @@ -503,23 +514,22 @@ class FileCachedDataSource implements FileDataSource { OrNull? overrideDateTime, bool? favorite, }) async { - await _remoteSrc - .updateProperty( - account, - f, - metadata: metadata, - isArchived: isArchived, - overrideDateTime: overrideDateTime, - favorite: favorite, - ) - .then((_) => _appDbSrc.updateProperty( - account, - f, - metadata: metadata, - isArchived: isArchived, - overrideDateTime: overrideDateTime, - favorite: favorite, - )); + await _remoteSrc.updateProperty( + account, + f, + metadata: metadata, + isArchived: isArchived, + overrideDateTime: overrideDateTime, + favorite: favorite, + ); + await _sqliteDbSrc.updateProperty( + account, + f, + metadata: metadata, + isArchived: isArchived, + overrideDateTime: overrideDateTime, + favorite: favorite, + ); // generate a new random token final token = const Uuid().v4().replaceAll("-", ""); @@ -559,12 +569,12 @@ class FileCachedDataSource implements FileDataSource { await _remoteSrc.createDir(account, path); } - final AppDb appDb; + final DiContainer _c; final bool shouldCheckCache; final FileForwardCacheManager? forwardCacheManager; final _remoteSrc = const FileWebdavDataSource(); - final FileAppDbDataSource _appDbSrc; + final FileSqliteDbDataSource _sqliteDbSrc; static final _log = Logger("entity.file.data_source.FileCachedDataSource"); } @@ -576,7 +586,11 @@ class FileCachedDataSource implements FileDataSource { /// passed to us in one transaction. For this reason, this should only be used /// when it's necessary to query everything class FileForwardCacheManager { - FileForwardCacheManager(this.appDb, this.knownFiles); + FileForwardCacheManager(this._c, Map knownFiles) { + _fileCache.addAll(knownFiles); + } + + static bool require(DiContainer c) => true; /// Transform a list of files to a map suitable to be passed as the /// [knownFiles] argument @@ -587,117 +601,155 @@ class FileForwardCacheManager { Future> list(Account account, File dir) async { // check cache - final dirKey = AppDbDirEntry.toPrimaryKeyForDir(account, dir); - final cachedDir = _dirCache[dirKey]; - if (cachedDir != null) { + var childFileIds = _dirCache[dir.strippedPathWithEmpty]; + if (childFileIds == null) { + _log.info( + "[list] No cache and querying everything under ${logFilename(dir.path)}"); + await _cacheDir(account, dir); + childFileIds = _dirCache[dir.strippedPathWithEmpty]; + if (childFileIds == null) { + throw CacheNotFoundException("No entry: ${dir.path}"); + } + } else { _log.fine("[list] Returning data from cache: ${logFilename(dir.path)}"); - return _withDirEntry(cachedDir); } - // no cache, query everything under [dir] - _log.info( - "[list] No cache and querying everything under ${logFilename(dir.path)}"); - await _cacheDir(account, dir); - final cachedDir2 = _dirCache[dirKey]; - if (cachedDir2 == null) { - throw CacheNotFoundException("No entry: ${dir.path}"); - } - return _withDirEntry(cachedDir2); + return _listByFileIds(dir, childFileIds); } Future _cacheDir(Account account, File dir) async { - final dirItems = await appDb.use( - (db) => db.transaction(AppDb.dirStoreName, idbModeReadOnly), - (transaction) async { - final store = transaction.objectStore(AppDb.dirStoreName); - final dirItem = await store - .getObject(AppDbDirEntry.toPrimaryKeyForDir(account, dir)) as Map?; - if (dirItem == null) { - return null; - } - final range = KeyRange.bound( - AppDbDirEntry.toPrimaryLowerKeyForSubDirs(account, dir), - AppDbDirEntry.toPrimaryUpperKeyForSubDirs(account, dir), - ); - return [dirItem] + (await store.getAll(range)).cast(); - }, - ); - if (dirItems == null) { + await _c.sqliteDb.use((db) async { + final dbAccount = await db.accountOf(account); + final dirCache = >{}; + await _fillDirCacheForDir( + db, dirCache, dbAccount, null, dir.fileId, dir.strippedPathWithEmpty); + _log.info( + "[_cacheDir] Cached ${dirCache.length} dirs under ${logFilename(dir.path)}"); + await _fillFileCache( + db, account, dbAccount, dirCache.values.flatten().toSet()); + _dirCache.addAll(dirCache); + }); + } + + Future _fillDirCacheForDir( + sql.SqliteDb db, + Map> dirCache, + sql.Account dbAccount, + int? dirRowId, + int? dirFileId, + String dirRelativePath) async { + // get rowId + final myDirRowId = dirRowId ?? + await _queryFileIdOfDir(db, dbAccount, dirFileId, dirRelativePath); + if (myDirRowId == null) { // no cache return; } - final dirs = dirItems - .map((i) => AppDbDirEntry.fromJson(i.cast())) - .toList(); - _dirCache.addEntries(dirs.map( - (e) => MapEntry(AppDbDirEntry.toPrimaryKeyForDir(account, e.dir), e))); - _log.info( - "[_cacheDir] Cached ${dirs.length} dirs under ${logFilename(dir.path)}"); - - // cache files - final fileIds = dirs.map((e) => e.children).fold>( - [], (previousValue, element) => previousValue + element); - - final needQuery = []; - final files = []; - // check files already known to us - if (knownFiles.isNotEmpty) { - for (final id in fileIds) { - final f = knownFiles[id]; - if (f != null) { - files.add(f); - } else { - needQuery.add(id); - } - } - } else { - needQuery.addAll(fileIds); + final children = await _queryChildOfDir(db, dbAccount, myDirRowId); + if (children.isEmpty) { + // no cache + return; } - _log.info( - "[_cacheDir] ${files.length} files known, ${needQuery.length} files need querying"); + final childFileIds = children.map((c) => c.fileId).toList(); + dirCache[dirRelativePath] = childFileIds; - // query other files + // recursively fill child dirs + for (final c in children + .where((c) => c.rowId != myDirRowId && c.isCollection == true)) { + await _fillDirCacheForDir( + db, dirCache, dbAccount, c.rowId, c.fileId, c.relativePath); + } + } + + Future _fillFileCache(sql.SqliteDb db, Account account, + sql.Account dbAccount, Iterable fileIds) async { + final needQuery = fileIds.where((id) => !_fileCache.containsKey(id)); if (needQuery.isNotEmpty) { - final dbItems = await appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadOnly), - (transaction) async { - final store = transaction.objectStore(AppDb.file2StoreName); - return await Future.wait(needQuery.map((id) => - store.getObject(AppDbFile2Entry.toPrimaryKey(account, id)))); - }, - ); - files.addAll( - await dbItems.whereType().computeAll(_covertAppDbFile2Entry)); + _log.info("[_fillFileCache] ${needQuery.length} files need querying"); + final dbFiles = + await db.completeFilesByFileIds(needQuery, sqlAccount: dbAccount); + for (final f in await dbFiles.convertToAppFile(account)) { + _fileCache[f.fileId!] = f; + } + _log.info("[_fillFileCache] Cached ${dbFiles.length} files"); + } else { + _log.info("[_fillFileCache] 0 files need querying"); } - _fileCache.addEntries(files.map((f) => MapEntry(f.fileId!, f))); - _log.info( - "[_cacheDir] Cached ${files.length} files under ${logFilename(dir.path)}"); } - List _withDirEntry(AppDbDirEntry dirEntry) { - return [dirEntry.dir] + - dirEntry.children.map((id) { - try { - return _fileCache[id]!; - } catch (_) { - _log.warning( - "[list] Missing file ($id) in db for dir: ${logFilename(dirEntry.dir.path)}"); - throw CacheNotFoundException("No entry for dir child: $id"); - } - }).toList(); + List _listByFileIds(File dir, List childFileIds) { + return childFileIds.map((id) { + try { + return _fileCache[id]!; + } catch (_) { + _log.warning( + "[_listByFileIds] Missing file ($id) in db for dir: ${logFilename(dir.path)}"); + throw CacheNotFoundException("No entry for dir child: $id"); + } + }).toList(); } - final AppDb appDb; - final Map knownFiles; - final _dirCache = {}; + Future _queryFileIdOfDir(sql.SqliteDb db, sql.Account dbAccount, + int? dirFileId, String dirRelativePath) async { + final dirQuery = db.queryFiles().run((q) { + q + ..setQueryMode(sql.FilesQueryMode.expression, + expressions: [db.files.rowId]) + ..setSqlAccount(dbAccount); + if (dirFileId != null) { + q.byFileId(dirFileId); + } else { + q.byRelativePath(dirRelativePath); + } + return q.build()..limit(1); + }); + return await dirQuery.map((r) => r.read(db.files.rowId)).getSingleOrNull(); + } + + Future> _queryChildOfDir( + sql.SqliteDb db, sql.Account dbAccount, int dirRowId) async { + final childQuery = db.selectOnly(db.files).join([ + sql.innerJoin(db.dirFiles, db.dirFiles.child.equalsExp(db.files.rowId), + useColumns: false), + sql.innerJoin( + db.accountFiles, db.accountFiles.file.equalsExp(db.files.rowId), + useColumns: false), + ]) + ..addColumns([ + db.files.rowId, + db.files.fileId, + db.files.isCollection, + db.accountFiles.relativePath, + ]) + ..where(db.dirFiles.dir.equals(dirRowId)) + ..where(db.accountFiles.account.equals(dbAccount.rowId)); + return await childQuery + .map((r) => _ForwardCacheQueryChildResult( + r.read(db.files.rowId)!, + r.read(db.files.fileId)!, + r.read(db.accountFiles.relativePath)!, + r.read(db.files.isCollection), + )) + .get(); + } + + final DiContainer _c; + final _dirCache = >{}; final _fileCache = {}; static final _log = Logger("entity.file.data_source.FileForwardCacheManager"); } +class _ForwardCacheQueryChildResult { + const _ForwardCacheQueryChildResult( + this.rowId, this.fileId, this.relativePath, this.isCollection); + + final int rowId; + final int fileId; + final String relativePath; + final bool? isCollection; +} + bool _validateFile(File f) { // See: https://gitlab.com/nkming2/nc-photos/-/issues/9 return f.lastModified != null; } - -File _covertAppDbFile2Entry(Map json) => - AppDbFile2Entry.fromJson(json.cast()).file; diff --git a/app/lib/entity/file/file_cache_manager.dart b/app/lib/entity/file/file_cache_manager.dart index dcd02ef3..1c522a11 100644 --- a/app/lib/entity/file/file_cache_manager.dart +++ b/app/lib/entity/file/file_cache_manager.dart @@ -1,25 +1,28 @@ -import 'package:collection/collection.dart'; -import 'package:idb_shim/idb_client.dart'; +import 'package:drift/drift.dart' as sql; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; -import 'package:nc_photos/debug_util.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file/data_source.dart'; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/exception.dart'; import 'package:nc_photos/iterable_extension.dart'; +import 'package:nc_photos/list_util.dart' as list_util; import 'package:nc_photos/object_extension.dart'; import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/touch_token_manager.dart'; class FileCacheLoader { - FileCacheLoader({ - required this.appDb, - required this.appDbSrc, + FileCacheLoader( + this._c, { + required this.cacheSrc, required this.remoteSrc, this.shouldCheckCache = false, this.forwardCacheManager, - }); + }) : assert(require(_c)); + + static bool require(DiContainer c) => DiContainer.has(c, DiType.fileRepo); /// Return the cached results of listing a directory [dir] /// @@ -30,7 +33,7 @@ class FileCacheLoader { if (forwardCacheManager != null) { cache = await forwardCacheManager!.list(account, dir); } else { - cache = await appDbSrc.list(account, dir); + cache = await cacheSrc.list(account, dir); } // compare the cached root final cacheEtag = @@ -40,8 +43,6 @@ class FileCacheLoader { // if no etag supplied, we need to query it form remote remoteEtag ??= (await remoteSrc.list(account, dir, depth: 0)).first.etag; if (cacheEtag == remoteEtag) { - _log.fine( - "[list] etag matched for ${AppDbDirEntry.toPrimaryKeyForDir(account, dir)}"); if (shouldCheckCache) { await _checkTouchToken(account, dir, cache); } else { @@ -65,11 +66,10 @@ class FileCacheLoader { Account account, File f, List cache) async { final touchPath = "${remote_storage_util.getRemoteTouchDir(account)}/${f.strippedPath}"; - final fileRepo = FileRepo(FileCachedDataSource(appDb)); const tokenManager = TouchTokenManager(); String? remoteToken; try { - remoteToken = await tokenManager.getRemoteToken(fileRepo, account, f); + remoteToken = await tokenManager.getRemoteToken(_c.fileRepo, account, f); } catch (e, stacktrace) { _log.shout( "[_checkTouchToken] Failed getting remote token at '$touchPath'", @@ -96,9 +96,9 @@ class FileCacheLoader { } } - final AppDb appDb; + final DiContainer _c; final FileWebdavDataSource remoteSrc; - final FileAppDbDataSource appDbSrc; + final FileDataSource cacheSrc; final bool shouldCheckCache; final FileForwardCacheManager? forwardCacheManager; @@ -108,215 +108,264 @@ class FileCacheLoader { static final _log = Logger("entity.file.file_cache_manager.FileCacheLoader"); } -class FileCacheUpdater { - const FileCacheUpdater(this.appDb); +class FileSqliteCacheUpdater { + FileSqliteCacheUpdater(this._c) : assert(require(_c)); + + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); Future call( Account account, File dir, { required List remote, - List? cache, }) async { - await _cacheRemote(account, dir, remote); - if (cache != null) { - await _cleanUpCache(account, remote, cache); + final s = Stopwatch()..start(); + try { + await _cacheRemote(account, dir, remote); + } finally { + _log.info("[call] Elapsed time: ${s.elapsedMilliseconds}ms"); } } Future _cacheRemote( Account account, File dir, List remote) async { - final s = Stopwatch()..start(); - try { - await appDb.use( - (db) => db.transaction( - [AppDb.dirStoreName, AppDb.file2StoreName], idbModeReadWrite), - (transaction) async { - final dirStore = transaction.objectStore(AppDb.dirStoreName); - final fileStore = transaction.objectStore(AppDb.file2StoreName); + final sqlFiles = await remote.convertToFileCompanion(null); + await _c.sqliteDb.use((db) async { + final dbAccount = await db.accountOf(account); + final inserts = await _updateCache(db, dbAccount, sqlFiles, remote, dir); + if (inserts.isNotEmpty) { + await _insertCache(db, dbAccount, inserts, dir); + } + if (_dirRowId == null) { + _log.severe("[_cacheRemote] Dir not inserted"); + throw StateError("Row ID for dir is null"); + } - // add files to db - await Future.wait(remote.map((f) => fileStore.put( - AppDbFile2Entry.fromFile(account, f).toJson(), - AppDbFile2Entry.toPrimaryKeyForFile(account, f)))); - - // results from remote also contain the dir itself - final resultGroup = - remote.groupListsBy((f) => f.compareServerIdentity(dir)); - final remoteDir = resultGroup[true]!.first; - final remoteChildren = resultGroup[false] ?? []; - // add dir to db - await dirStore.put( - AppDbDirEntry.fromFiles(account, remoteDir, remoteChildren) - .toJson(), - AppDbDirEntry.toPrimaryKeyForDir(account, remoteDir)); - }, - ); - } finally { - _log.info("[_cacheRemote] Elapsed time: ${s.elapsedMilliseconds}ms"); - } + final dirChildRowIdQuery = db.selectOnly(db.dirFiles) + ..addColumns([db.dirFiles.child]) + ..where(db.dirFiles.dir.equals(_dirRowId)) + ..orderBy([sql.OrderingTerm.asc(db.dirFiles.rowId)]); + final dirChildRowIds = + await dirChildRowIdQuery.map((r) => r.read(db.dirFiles.child)!).get(); + final diff = list_util.diff(dirChildRowIds, _childRowIds.sorted()); + if (diff.item1.isNotEmpty) { + await db.batch((batch) { + // insert new children + batch.insertAll(db.dirFiles, + diff.item1.map((k) => sql.DirFile(dir: _dirRowId!, child: k))); + }); + } + if (diff.item2.isNotEmpty) { + // delete obsolete children + await _removeSqliteFiles(db, dbAccount, diff.item2); + await _cleanUpRemovedFile(db, dbAccount); + } + }); } - /// Remove extra entries from local cache based on remote contents - Future _cleanUpCache( - Account account, List remote, List cache) async { - final removed = cache - .where((c) => !remote.any((r) => r.compareServerIdentity(c))) - .toList(); - if (removed.isEmpty) { - return; - } - _log.info( - "[_cleanUpCache] Removed: ${removed.map((f) => f.path).toReadableString()}"); + /// Update Db files in [sqlFiles] + /// + /// Return a list of DB files that are not yet inserted to the DB (thus not + /// possible to update) + Future> _updateCache( + sql.SqliteDb db, + sql.Account dbAccount, + Iterable sqlFiles, + Iterable remoteFiles, + File dir, + ) async { + // query list of rowIds for files in [remoteFiles] + final rowIds = await db.accountFileRowIdsByFileIds( + remoteFiles.map((f) => f.fileId!), + sqlAccount: dbAccount, + ); + final rowIdsMap = Map.fromEntries(rowIds.map((e) => MapEntry(e.fileId, e))); - await appDb.use( - (db) => db.transaction( - [AppDb.dirStoreName, AppDb.file2StoreName], idbModeReadWrite), - (transaction) async { - final dirStore = transaction.objectStore(AppDb.dirStoreName); - final fileStore = transaction.objectStore(AppDb.file2StoreName); - for (final f in removed) { - try { - if (f.isCollection == true) { - await _removeDirFromAppDb(account, f, - dirStore: dirStore, fileStore: fileStore); - } else { - await _removeFileFromAppDb(account, f, fileStore: fileStore); - } - } catch (e, stackTrace) { - _log.shout( - "[_cleanUpCache] Failed while removing file: ${logFilename(f.path)}", - e, - stackTrace); + final inserts = []; + // for updates, we use batch to speed up the process + await db.batch((batch) { + for (final f in sqlFiles) { + final thisRowIds = rowIdsMap[f.file.fileId.value]; + if (thisRowIds != null) { + // updates + batch.update( + db.files, + f.file, + where: (sql.$FilesTable t) => t.rowId.equals(thisRowIds.fileRowId), + ); + batch.update( + db.accountFiles, + f.accountFile, + where: (sql.$AccountFilesTable t) => + t.rowId.equals(thisRowIds.accountFileRowId), + ); + if (f.image != null) { + batch.update( + db.images, + f.image!, + where: (sql.$ImagesTable t) => + t.accountFile.equals(thisRowIds.accountFileRowId), + ); } + if (f.trash != null) { + batch.update( + db.trashes, + f.trash!, + where: (sql.$TrashesTable t) => + t.file.equals(thisRowIds.fileRowId), + ); + } + _onRowCached(thisRowIds.fileRowId, f, dir); + } else { + // inserts, do it later + inserts.add(f); } - }, + } + }); + _log.info( + "[_updateCache] Updated ${sqlFiles.length - inserts.length} files"); + return inserts; + } + + Future _insertCache(sql.SqliteDb db, sql.Account dbAccount, + List sqlFiles, File dir) async { + _log.info("[_insertCache] Insert ${sqlFiles.length} files"); + // check if the files exist in the db in other accounts + final query = db.queryFiles().run((q) { + q + ..setQueryMode( + sql.FilesQueryMode.expression, + expressions: [db.files.rowId, db.files.fileId], + ) + ..setAccountless() + ..byServerRowId(dbAccount.server) + ..byFileIds(sqlFiles.map((f) => f.file.fileId.value)); + return q.build(); + }); + final fileRowIdMap = Map.fromEntries(await query + .map((r) => MapEntry(r.read(db.files.fileId)!, r.read(db.files.rowId)!)) + .get()); + + await Future.wait( + sqlFiles.map((f) async { + var rowId = fileRowIdMap[f.file.fileId.value]; + if (rowId != null) { + // shared file that exists in other accounts + } else { + final dbFile = await db.into(db.files).insertReturning( + f.file.copyWith(server: sql.Value(dbAccount.server)), + ); + rowId = dbFile.rowId; + } + final dbAccountFile = await db + .into(db.accountFiles) + .insertReturning(f.accountFile.copyWith( + account: sql.Value(dbAccount.rowId), + file: sql.Value(rowId), + )); + if (f.image != null) { + await db.into(db.images).insert( + f.image!.copyWith(accountFile: sql.Value(dbAccountFile.rowId))); + } + if (f.trash != null) { + await db + .into(db.trashes) + .insert(f.trash!.copyWith(file: sql.Value(rowId))); + } + _onRowCached(rowId, f, dir); + }), + eagerError: true, ); } - final AppDb appDb; + void _onRowCached(int rowId, sql.CompleteFileCompanion dbFile, File dir) { + if (_compareIdentity(dbFile, dir)) { + _dirRowId = rowId; + } + _childRowIds.add(rowId); + } - static final _log = Logger("entity.file.file_cache_manager.FileCacheUpdater"); + bool _compareIdentity(sql.CompleteFileCompanion dbFile, File appFile) { + if (appFile.fileId != null) { + return appFile.fileId == dbFile.file.fileId.value; + } else { + return appFile.strippedPathWithEmpty == + dbFile.accountFile.relativePath.value; + } + } + + final DiContainer _c; + + int? _dirRowId; + final _childRowIds = []; + + static final _log = + Logger("entity.file.file_cache_manager.FileSqliteCacheUpdater"); } -class FileCacheRemover { - const FileCacheRemover(this.appDb); +class FileSqliteCacheRemover { + FileSqliteCacheRemover(this._c) : assert(require(_c)); + + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); /// Remove a file/dir from cache - /// - /// If [f] is a dir, the dir and its sub-dirs will be removed from dirStore. - /// The files inside any of these dirs will be removed from file2Store. - /// - /// If [f] is a file, the file will be removed from file2Store, but no changes - /// to dirStore. Future call(Account account, File f) async { - if (f.isCollection != false) { - // removing dir is basically a superset of removing file, so we'll treat - // unspecified file as dir - await appDb.use( - (db) => db.transaction( - [AppDb.dirStoreName, AppDb.file2StoreName], idbModeReadWrite), - (transaction) async { - final dirStore = transaction.objectStore(AppDb.dirStoreName); - final fileStore = transaction.objectStore(AppDb.file2StoreName); - await _removeDirFromAppDb(account, f, - dirStore: dirStore, fileStore: fileStore); - }, - ); - } else { - await appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadWrite), - (transaction) async { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - await _removeFileFromAppDb(account, f, fileStore: fileStore); - }, - ); - } - } - - final AppDb appDb; -} - -Future _removeFileFromAppDb( - Account account, - File file, { - required ObjectStore fileStore, -}) async { - try { - if (file.fileId == null) { - final index = fileStore.index(AppDbFile2Entry.strippedPathIndexName); - final key = await index - .getKey(AppDbFile2Entry.toStrippedPathIndexKeyForFile(account, file)); - if (key != null) { - _log.fine("[_removeFileFromAppDb] Removing fileStore entry: $key"); - await fileStore.delete(key); - } - } else { - await AppDbFile2Entry.toPrimaryKeyForFile(account, file).run((key) { - _log.fine("[_removeFileFromAppDb] Removing fileStore entry: $key"); - return fileStore.delete(key); - }); - } - } catch (e, stackTrace) { - _log.shout( - "[_removeFileFromAppDb] Failed removing fileStore entry: ${logFilename(file.path)}", - e, - stackTrace); - } -} - -/// Remove a dir and all files inside from the database -Future _removeDirFromAppDb( - Account account, - File dir, { - required ObjectStore dirStore, - required ObjectStore fileStore, -}) async { - // delete the dir itself - try { - await AppDbDirEntry.toPrimaryKeyForDir(account, dir).run((key) { - _log.fine("[_removeDirFromAppDb] Removing dirStore entry: $key"); - return dirStore.delete(key); + await _c.sqliteDb.use((db) async { + final dbAccount = await db.accountOf(account); + final rowIds = await db.accountFileRowIdsOf(f, sqlAccount: dbAccount); + await _removeSqliteFiles(db, dbAccount, [rowIds.fileRowId]); + await _cleanUpRemovedFile(db, dbAccount); }); - } catch (e, stackTrace) { - if (dir.isCollection != null) { - _log.shout("[_removeDirFromAppDb] Failed removing dirStore entry", e, - stackTrace); - } - } - // then its children - final childrenRange = KeyRange.bound( - AppDbDirEntry.toPrimaryLowerKeyForSubDirs(account, dir), - AppDbDirEntry.toPrimaryUpperKeyForSubDirs(account, dir), - ); - for (final key in await dirStore.getAllKeys(childrenRange)) { - _log.fine("[_removeDirFromAppDb] Removing dirStore entry: $key"); - try { - await dirStore.delete(key); - } catch (e, stackTrace) { - _log.shout("[_removeDirFromAppDb] Failed removing dirStore entry", e, - stackTrace); - } } - // delete files from fileStore - // first the dir - await _removeFileFromAppDb(account, dir, fileStore: fileStore); - // then files under this dir and sub-dirs - final range = KeyRange.bound( - AppDbFile2Entry.toStrippedPathIndexLowerKeyForDir(account, dir), - AppDbFile2Entry.toStrippedPathIndexUpperKeyForDir(account, dir), - ); - final strippedPathIndex = - fileStore.index(AppDbFile2Entry.strippedPathIndexName); - for (final key in await strippedPathIndex.getAllKeys(range)) { - _log.fine("[_removeDirFromAppDb] Removing fileStore entry: $key"); - try { - await fileStore.delete(key); - } catch (e, stackTrace) { - _log.shout("[_removeDirFromAppDb] Failed removing fileStore entry", e, - stackTrace); - } + final DiContainer _c; +} + +/// Remove a files from the cache db +/// +/// If a file is a dir, its children will also be recursively removed +Future _removeSqliteFiles( + sql.SqliteDb db, sql.Account dbAccount, List fileRowIds) async { + // query list of children, in case some of the files are dirs + final childQuery = db.selectOnly(db.dirFiles) + ..addColumns([db.dirFiles.child]) + ..where(db.dirFiles.dir.isIn(fileRowIds)); + final childRowIds = + await childQuery.map((r) => r.read(db.dirFiles.child)!).get(); + childRowIds.removeWhere((id) => fileRowIds.contains(id)); + + // remove the files in AccountFiles table. We are not removing in Files table + // because a file could be associated with multiple accounts + await (db.delete(db.accountFiles) + ..where( + (t) => t.account.equals(dbAccount.rowId) & t.file.isIn(fileRowIds))) + .go(); + + if (childRowIds.isNotEmpty) { + // remove children recursively + return _removeSqliteFiles(db, dbAccount, childRowIds); + } else { + return; } } -final _log = Logger("entity.file.file_cache_manager"); +Future _cleanUpRemovedFile(sql.SqliteDb db, sql.Account dbAccount) async { + // delete dangling files: entries in Files w/o a corresponding entry in + // AccountFiles + final danglingFileQuery = db.selectOnly(db.files).join([ + sql.leftOuterJoin( + db.accountFiles, db.accountFiles.file.equalsExp(db.files.rowId), + useColumns: false), + ]) + ..addColumns([db.files.rowId]) + ..where(db.accountFiles.relativePath.isNull()); + final danglingFileRowIds = + await danglingFileQuery.map((r) => r.read(db.files.rowId)!).get(); + if (danglingFileRowIds.isNotEmpty) { + __log.info( + "[_cleanUpRemovedFile] Delete ${danglingFileRowIds.length} files"); + await (db.delete(db.files)..where((t) => t.rowId.isIn(danglingFileRowIds))) + .go(); + } +} + +final __log = Logger("entity.file.file_cache_manager"); diff --git a/app/lib/entity/sqlite_table.dart b/app/lib/entity/sqlite_table.dart new file mode 100644 index 00000000..010ae1cd --- /dev/null +++ b/app/lib/entity/sqlite_table.dart @@ -0,0 +1,209 @@ +import 'package:drift/drift.dart'; +import 'package:nc_photos/mobile/platform.dart' + if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; + +part 'sqlite_table.g.dart'; + +class Servers extends Table { + IntColumn get rowId => integer().autoIncrement()(); + TextColumn get address => text().unique()(); +} + +class Accounts extends Table { + IntColumn get rowId => integer().autoIncrement()(); + IntColumn get server => + integer().references(Servers, #rowId, onDelete: KeyAction.cascade)(); + TextColumn get userId => text()(); + + @override + get uniqueKeys => [ + {server, userId}, + ]; +} + +/// A file located on a server +class Files extends Table { + IntColumn get rowId => integer().autoIncrement()(); + IntColumn get server => + integer().references(Servers, #rowId, onDelete: KeyAction.cascade)(); + IntColumn get fileId => integer()(); + IntColumn get contentLength => integer().nullable()(); + TextColumn get contentType => text().nullable()(); + TextColumn get etag => text().nullable()(); + DateTimeColumn get lastModified => + dateTime().map(const _DateTimeConverter()).nullable()(); + BoolColumn get isCollection => boolean().nullable()(); + IntColumn get usedBytes => integer().nullable()(); + BoolColumn get hasPreview => boolean().nullable()(); + TextColumn get ownerId => text().nullable()(); + + @override + get uniqueKeys => [ + {server, fileId}, + ]; +} + +/// Account specific properties associated with a file +/// +/// A file on a Nextcloud server can have more than 1 path when it's shared +class AccountFiles extends Table { + IntColumn get rowId => integer().autoIncrement()(); + IntColumn get account => + integer().references(Accounts, #rowId, onDelete: KeyAction.cascade)(); + IntColumn get file => + integer().references(Files, #rowId, onDelete: KeyAction.cascade)(); + TextColumn get relativePath => text()(); + BoolColumn get isFavorite => boolean().nullable()(); + BoolColumn get isArchived => boolean().nullable()(); + DateTimeColumn get overrideDateTime => + dateTime().map(const _DateTimeConverter()).nullable()(); + + @override + get uniqueKeys => [ + {account, file}, + ]; +} + +/// An image file +class Images extends Table { + // image data technically is identical between accounts, but the way it's + // stored in the server is account specific so we follow the server here + IntColumn get accountFile => + integer().references(AccountFiles, #rowId, onDelete: KeyAction.cascade)(); + DateTimeColumn get lastUpdated => + dateTime().map(const _DateTimeConverter())(); + TextColumn get fileEtag => text().nullable()(); + IntColumn get width => integer().nullable()(); + IntColumn get height => integer().nullable()(); + TextColumn get exifRaw => text().nullable()(); + + // exif columns + DateTimeColumn get dateTimeOriginal => + dateTime().map(const _DateTimeConverter()).nullable()(); + + @override + get primaryKey => {accountFile}; +} + +/// A file inside trashbin +@DataClassName("Trash") +class Trashes extends Table { + IntColumn get file => + integer().references(Files, #rowId, onDelete: KeyAction.cascade)(); + TextColumn get filename => text()(); + TextColumn get originalLocation => text()(); + DateTimeColumn get deletionTime => + dateTime().map(const _DateTimeConverter())(); + + @override + get primaryKey => {file}; +} + +/// A file located under another dir (dir is also a file) +class DirFiles extends Table { + IntColumn get dir => + integer().references(Files, #rowId, onDelete: KeyAction.cascade)(); + IntColumn get child => + integer().references(Files, #rowId, onDelete: KeyAction.cascade)(); + + @override + get primaryKey => {dir, child}; +} + +class Albums extends Table { + IntColumn get rowId => integer().autoIncrement()(); + IntColumn get file => integer() + .references(Files, #rowId, onDelete: KeyAction.cascade) + .unique()(); + IntColumn get version => integer()(); + DateTimeColumn get lastUpdated => + dateTime().map(const _DateTimeConverter())(); + TextColumn get name => text()(); + + // provider + TextColumn get providerType => text()(); + TextColumn get providerContent => text()(); + + // cover provider + TextColumn get coverProviderType => text()(); + TextColumn get coverProviderContent => text()(); + + // sort provider + TextColumn get sortProviderType => text()(); + TextColumn get sortProviderContent => text()(); +} + +class AlbumShares extends Table { + IntColumn get album => + integer().references(Albums, #rowId, onDelete: KeyAction.cascade)(); + TextColumn get userId => text()(); + TextColumn get displayName => text().nullable()(); + DateTimeColumn get sharedAt => dateTime().map(const _DateTimeConverter())(); + + @override + get primaryKey => {album, userId}; +} + +@DriftDatabase( + tables: [ + Servers, + Accounts, + Files, + Images, + Trashes, + AccountFiles, + DirFiles, + Albums, + AlbumShares, + ], +) +class SqliteDb extends _$SqliteDb { + SqliteDb({ + QueryExecutor? executor, + }) : super(executor ?? platform.openSqliteConnection()); + + SqliteDb.connect(DatabaseConnection connection) : super.connect(connection); + + @override + get schemaVersion => 1; + + @override + get migration => MigrationStrategy( + onCreate: (m) async { + await m.createAll(); + + await m.createIndex(Index("files_server_index", + "CREATE INDEX files_server_index ON files(server);")); + await m.createIndex(Index("files_file_id_index", + "CREATE INDEX files_file_id_index ON files(file_id);")); + await m.createIndex(Index("files_content_type_index", + "CREATE INDEX files_content_type_index ON files(content_type);")); + + await m.createIndex(Index("account_files_file_index", + "CREATE INDEX account_files_file_index ON account_files(file);")); + await m.createIndex(Index("account_files_relative_path_index", + "CREATE INDEX account_files_relative_path_index ON account_files(relative_path);")); + + await m.createIndex(Index("dir_files_dir_index", + "CREATE INDEX dir_files_dir_index ON dir_files(dir);")); + await m.createIndex(Index("dir_files_child_index", + "CREATE INDEX dir_files_child_index ON dir_files(child);")); + + await m.createIndex(Index("album_shares_album_index", + "CREATE INDEX album_shares_album_index ON album_shares(album);")); + }, + beforeOpen: (details) async { + await customStatement("PRAGMA foreign_keys = ON"); + }, + ); +} + +class _DateTimeConverter extends TypeConverter { + const _DateTimeConverter(); + + @override + DateTime? mapToDart(DateTime? fromDb) => fromDb?.toUtc(); + + @override + DateTime? mapToSql(DateTime? value) => value?.toUtc(); +} diff --git a/app/lib/entity/sqlite_table.g.dart b/app/lib/entity/sqlite_table.g.dart new file mode 100644 index 00000000..a16991bb --- /dev/null +++ b/app/lib/entity/sqlite_table.g.dart @@ -0,0 +1,3013 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'sqlite_table.dart'; + +// ************************************************************************** +// MoorGenerator +// ************************************************************************** + +// ignore_for_file: type=lint +class Server extends DataClass implements Insertable { + final int rowId; + final String address; + Server({required this.rowId, required this.address}); + factory Server.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return Server( + rowId: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}row_id'])!, + address: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}address'])!, + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['row_id'] = Variable(rowId); + map['address'] = Variable(address); + return map; + } + + ServersCompanion toCompanion(bool nullToAbsent) { + return ServersCompanion( + rowId: Value(rowId), + address: Value(address), + ); + } + + factory Server.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Server( + rowId: serializer.fromJson(json['rowId']), + address: serializer.fromJson(json['address']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'rowId': serializer.toJson(rowId), + 'address': serializer.toJson(address), + }; + } + + Server copyWith({int? rowId, String? address}) => Server( + rowId: rowId ?? this.rowId, + address: address ?? this.address, + ); + @override + String toString() { + return (StringBuffer('Server(') + ..write('rowId: $rowId, ') + ..write('address: $address') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(rowId, address); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Server && + other.rowId == this.rowId && + other.address == this.address); +} + +class ServersCompanion extends UpdateCompanion { + final Value rowId; + final Value address; + const ServersCompanion({ + this.rowId = const Value.absent(), + this.address = const Value.absent(), + }); + ServersCompanion.insert({ + this.rowId = const Value.absent(), + required String address, + }) : address = Value(address); + static Insertable custom({ + Expression? rowId, + Expression? address, + }) { + return RawValuesInsertable({ + if (rowId != null) 'row_id': rowId, + if (address != null) 'address': address, + }); + } + + ServersCompanion copyWith({Value? rowId, Value? address}) { + return ServersCompanion( + rowId: rowId ?? this.rowId, + address: address ?? this.address, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (rowId.present) { + map['row_id'] = Variable(rowId.value); + } + if (address.present) { + map['address'] = Variable(address.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ServersCompanion(') + ..write('rowId: $rowId, ') + ..write('address: $address') + ..write(')')) + .toString(); + } +} + +class $ServersTable extends Servers with TableInfo<$ServersTable, Server> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $ServersTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _rowIdMeta = const VerificationMeta('rowId'); + @override + late final GeneratedColumn rowId = GeneratedColumn( + 'row_id', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: 'PRIMARY KEY AUTOINCREMENT'); + final VerificationMeta _addressMeta = const VerificationMeta('address'); + @override + late final GeneratedColumn address = GeneratedColumn( + 'address', aliasedName, false, + type: const StringType(), + requiredDuringInsert: true, + defaultConstraints: 'UNIQUE'); + @override + List get $columns => [rowId, address]; + @override + String get aliasedName => _alias ?? 'servers'; + @override + String get actualTableName => 'servers'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('row_id')) { + context.handle( + _rowIdMeta, rowId.isAcceptableOrUnknown(data['row_id']!, _rowIdMeta)); + } + if (data.containsKey('address')) { + context.handle(_addressMeta, + address.isAcceptableOrUnknown(data['address']!, _addressMeta)); + } else if (isInserting) { + context.missing(_addressMeta); + } + return context; + } + + @override + Set get $primaryKey => {rowId}; + @override + Server map(Map data, {String? tablePrefix}) { + return Server.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $ServersTable createAlias(String alias) { + return $ServersTable(attachedDatabase, alias); + } +} + +class Account extends DataClass implements Insertable { + final int rowId; + final int server; + final String userId; + Account({required this.rowId, required this.server, required this.userId}); + factory Account.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return Account( + rowId: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}row_id'])!, + server: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}server'])!, + userId: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}user_id'])!, + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['row_id'] = Variable(rowId); + map['server'] = Variable(server); + map['user_id'] = Variable(userId); + return map; + } + + AccountsCompanion toCompanion(bool nullToAbsent) { + return AccountsCompanion( + rowId: Value(rowId), + server: Value(server), + userId: Value(userId), + ); + } + + factory Account.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Account( + rowId: serializer.fromJson(json['rowId']), + server: serializer.fromJson(json['server']), + userId: serializer.fromJson(json['userId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'rowId': serializer.toJson(rowId), + 'server': serializer.toJson(server), + 'userId': serializer.toJson(userId), + }; + } + + Account copyWith({int? rowId, int? server, String? userId}) => Account( + rowId: rowId ?? this.rowId, + server: server ?? this.server, + userId: userId ?? this.userId, + ); + @override + String toString() { + return (StringBuffer('Account(') + ..write('rowId: $rowId, ') + ..write('server: $server, ') + ..write('userId: $userId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(rowId, server, userId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Account && + other.rowId == this.rowId && + other.server == this.server && + other.userId == this.userId); +} + +class AccountsCompanion extends UpdateCompanion { + final Value rowId; + final Value server; + final Value userId; + const AccountsCompanion({ + this.rowId = const Value.absent(), + this.server = const Value.absent(), + this.userId = const Value.absent(), + }); + AccountsCompanion.insert({ + this.rowId = const Value.absent(), + required int server, + required String userId, + }) : server = Value(server), + userId = Value(userId); + static Insertable custom({ + Expression? rowId, + Expression? server, + Expression? userId, + }) { + return RawValuesInsertable({ + if (rowId != null) 'row_id': rowId, + if (server != null) 'server': server, + if (userId != null) 'user_id': userId, + }); + } + + AccountsCompanion copyWith( + {Value? rowId, Value? server, Value? userId}) { + return AccountsCompanion( + rowId: rowId ?? this.rowId, + server: server ?? this.server, + userId: userId ?? this.userId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (rowId.present) { + map['row_id'] = Variable(rowId.value); + } + if (server.present) { + map['server'] = Variable(server.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AccountsCompanion(') + ..write('rowId: $rowId, ') + ..write('server: $server, ') + ..write('userId: $userId') + ..write(')')) + .toString(); + } +} + +class $AccountsTable extends Accounts with TableInfo<$AccountsTable, Account> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $AccountsTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _rowIdMeta = const VerificationMeta('rowId'); + @override + late final GeneratedColumn rowId = GeneratedColumn( + 'row_id', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: 'PRIMARY KEY AUTOINCREMENT'); + final VerificationMeta _serverMeta = const VerificationMeta('server'); + @override + late final GeneratedColumn server = GeneratedColumn( + 'server', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES servers (row_id) ON DELETE CASCADE'); + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + @override + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + @override + List get $columns => [rowId, server, userId]; + @override + String get aliasedName => _alias ?? 'accounts'; + @override + String get actualTableName => 'accounts'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('row_id')) { + context.handle( + _rowIdMeta, rowId.isAcceptableOrUnknown(data['row_id']!, _rowIdMeta)); + } + if (data.containsKey('server')) { + context.handle(_serverMeta, + server.isAcceptableOrUnknown(data['server']!, _serverMeta)); + } else if (isInserting) { + context.missing(_serverMeta); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + return context; + } + + @override + Set get $primaryKey => {rowId}; + @override + List> get uniqueKeys => [ + {server, userId}, + ]; + @override + Account map(Map data, {String? tablePrefix}) { + return Account.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $AccountsTable createAlias(String alias) { + return $AccountsTable(attachedDatabase, alias); + } +} + +class File extends DataClass implements Insertable { + final int rowId; + final int server; + final int fileId; + final int? contentLength; + final String? contentType; + final String? etag; + final DateTime? lastModified; + final bool? isCollection; + final int? usedBytes; + final bool? hasPreview; + final String? ownerId; + File( + {required this.rowId, + required this.server, + required this.fileId, + this.contentLength, + this.contentType, + this.etag, + this.lastModified, + this.isCollection, + this.usedBytes, + this.hasPreview, + this.ownerId}); + factory File.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return File( + rowId: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}row_id'])!, + server: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}server'])!, + fileId: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}file_id'])!, + contentLength: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}content_length']), + contentType: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}content_type']), + etag: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}etag']), + lastModified: $FilesTable.$converter0.mapToDart(const DateTimeType() + .mapFromDatabaseResponse(data['${effectivePrefix}last_modified'])), + isCollection: const BoolType() + .mapFromDatabaseResponse(data['${effectivePrefix}is_collection']), + usedBytes: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}used_bytes']), + hasPreview: const BoolType() + .mapFromDatabaseResponse(data['${effectivePrefix}has_preview']), + ownerId: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}owner_id']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['row_id'] = Variable(rowId); + map['server'] = Variable(server); + map['file_id'] = Variable(fileId); + if (!nullToAbsent || contentLength != null) { + map['content_length'] = Variable(contentLength); + } + if (!nullToAbsent || contentType != null) { + map['content_type'] = Variable(contentType); + } + if (!nullToAbsent || etag != null) { + map['etag'] = Variable(etag); + } + if (!nullToAbsent || lastModified != null) { + final converter = $FilesTable.$converter0; + map['last_modified'] = + Variable(converter.mapToSql(lastModified)); + } + if (!nullToAbsent || isCollection != null) { + map['is_collection'] = Variable(isCollection); + } + if (!nullToAbsent || usedBytes != null) { + map['used_bytes'] = Variable(usedBytes); + } + if (!nullToAbsent || hasPreview != null) { + map['has_preview'] = Variable(hasPreview); + } + if (!nullToAbsent || ownerId != null) { + map['owner_id'] = Variable(ownerId); + } + return map; + } + + FilesCompanion toCompanion(bool nullToAbsent) { + return FilesCompanion( + rowId: Value(rowId), + server: Value(server), + fileId: Value(fileId), + contentLength: contentLength == null && nullToAbsent + ? const Value.absent() + : Value(contentLength), + contentType: contentType == null && nullToAbsent + ? const Value.absent() + : Value(contentType), + etag: etag == null && nullToAbsent ? const Value.absent() : Value(etag), + lastModified: lastModified == null && nullToAbsent + ? const Value.absent() + : Value(lastModified), + isCollection: isCollection == null && nullToAbsent + ? const Value.absent() + : Value(isCollection), + usedBytes: usedBytes == null && nullToAbsent + ? const Value.absent() + : Value(usedBytes), + hasPreview: hasPreview == null && nullToAbsent + ? const Value.absent() + : Value(hasPreview), + ownerId: ownerId == null && nullToAbsent + ? const Value.absent() + : Value(ownerId), + ); + } + + factory File.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return File( + rowId: serializer.fromJson(json['rowId']), + server: serializer.fromJson(json['server']), + fileId: serializer.fromJson(json['fileId']), + contentLength: serializer.fromJson(json['contentLength']), + contentType: serializer.fromJson(json['contentType']), + etag: serializer.fromJson(json['etag']), + lastModified: serializer.fromJson(json['lastModified']), + isCollection: serializer.fromJson(json['isCollection']), + usedBytes: serializer.fromJson(json['usedBytes']), + hasPreview: serializer.fromJson(json['hasPreview']), + ownerId: serializer.fromJson(json['ownerId']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'rowId': serializer.toJson(rowId), + 'server': serializer.toJson(server), + 'fileId': serializer.toJson(fileId), + 'contentLength': serializer.toJson(contentLength), + 'contentType': serializer.toJson(contentType), + 'etag': serializer.toJson(etag), + 'lastModified': serializer.toJson(lastModified), + 'isCollection': serializer.toJson(isCollection), + 'usedBytes': serializer.toJson(usedBytes), + 'hasPreview': serializer.toJson(hasPreview), + 'ownerId': serializer.toJson(ownerId), + }; + } + + File copyWith( + {int? rowId, + int? server, + int? fileId, + Value contentLength = const Value.absent(), + Value contentType = const Value.absent(), + Value etag = const Value.absent(), + Value lastModified = const Value.absent(), + Value isCollection = const Value.absent(), + Value usedBytes = const Value.absent(), + Value hasPreview = const Value.absent(), + Value ownerId = const Value.absent()}) => + File( + rowId: rowId ?? this.rowId, + server: server ?? this.server, + fileId: fileId ?? this.fileId, + contentLength: + contentLength.present ? contentLength.value : this.contentLength, + contentType: contentType.present ? contentType.value : this.contentType, + etag: etag.present ? etag.value : this.etag, + lastModified: + lastModified.present ? lastModified.value : this.lastModified, + isCollection: + isCollection.present ? isCollection.value : this.isCollection, + usedBytes: usedBytes.present ? usedBytes.value : this.usedBytes, + hasPreview: hasPreview.present ? hasPreview.value : this.hasPreview, + ownerId: ownerId.present ? ownerId.value : this.ownerId, + ); + @override + String toString() { + return (StringBuffer('File(') + ..write('rowId: $rowId, ') + ..write('server: $server, ') + ..write('fileId: $fileId, ') + ..write('contentLength: $contentLength, ') + ..write('contentType: $contentType, ') + ..write('etag: $etag, ') + ..write('lastModified: $lastModified, ') + ..write('isCollection: $isCollection, ') + ..write('usedBytes: $usedBytes, ') + ..write('hasPreview: $hasPreview, ') + ..write('ownerId: $ownerId') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + rowId, + server, + fileId, + contentLength, + contentType, + etag, + lastModified, + isCollection, + usedBytes, + hasPreview, + ownerId); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is File && + other.rowId == this.rowId && + other.server == this.server && + other.fileId == this.fileId && + other.contentLength == this.contentLength && + other.contentType == this.contentType && + other.etag == this.etag && + other.lastModified == this.lastModified && + other.isCollection == this.isCollection && + other.usedBytes == this.usedBytes && + other.hasPreview == this.hasPreview && + other.ownerId == this.ownerId); +} + +class FilesCompanion extends UpdateCompanion { + final Value rowId; + final Value server; + final Value fileId; + final Value contentLength; + final Value contentType; + final Value etag; + final Value lastModified; + final Value isCollection; + final Value usedBytes; + final Value hasPreview; + final Value ownerId; + const FilesCompanion({ + this.rowId = const Value.absent(), + this.server = const Value.absent(), + this.fileId = const Value.absent(), + this.contentLength = const Value.absent(), + this.contentType = const Value.absent(), + this.etag = const Value.absent(), + this.lastModified = const Value.absent(), + this.isCollection = const Value.absent(), + this.usedBytes = const Value.absent(), + this.hasPreview = const Value.absent(), + this.ownerId = const Value.absent(), + }); + FilesCompanion.insert({ + this.rowId = const Value.absent(), + required int server, + required int fileId, + this.contentLength = const Value.absent(), + this.contentType = const Value.absent(), + this.etag = const Value.absent(), + this.lastModified = const Value.absent(), + this.isCollection = const Value.absent(), + this.usedBytes = const Value.absent(), + this.hasPreview = const Value.absent(), + this.ownerId = const Value.absent(), + }) : server = Value(server), + fileId = Value(fileId); + static Insertable custom({ + Expression? rowId, + Expression? server, + Expression? fileId, + Expression? contentLength, + Expression? contentType, + Expression? etag, + Expression? lastModified, + Expression? isCollection, + Expression? usedBytes, + Expression? hasPreview, + Expression? ownerId, + }) { + return RawValuesInsertable({ + if (rowId != null) 'row_id': rowId, + if (server != null) 'server': server, + if (fileId != null) 'file_id': fileId, + if (contentLength != null) 'content_length': contentLength, + if (contentType != null) 'content_type': contentType, + if (etag != null) 'etag': etag, + if (lastModified != null) 'last_modified': lastModified, + if (isCollection != null) 'is_collection': isCollection, + if (usedBytes != null) 'used_bytes': usedBytes, + if (hasPreview != null) 'has_preview': hasPreview, + if (ownerId != null) 'owner_id': ownerId, + }); + } + + FilesCompanion copyWith( + {Value? rowId, + Value? server, + Value? fileId, + Value? contentLength, + Value? contentType, + Value? etag, + Value? lastModified, + Value? isCollection, + Value? usedBytes, + Value? hasPreview, + Value? ownerId}) { + return FilesCompanion( + rowId: rowId ?? this.rowId, + server: server ?? this.server, + fileId: fileId ?? this.fileId, + contentLength: contentLength ?? this.contentLength, + contentType: contentType ?? this.contentType, + etag: etag ?? this.etag, + lastModified: lastModified ?? this.lastModified, + isCollection: isCollection ?? this.isCollection, + usedBytes: usedBytes ?? this.usedBytes, + hasPreview: hasPreview ?? this.hasPreview, + ownerId: ownerId ?? this.ownerId, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (rowId.present) { + map['row_id'] = Variable(rowId.value); + } + if (server.present) { + map['server'] = Variable(server.value); + } + if (fileId.present) { + map['file_id'] = Variable(fileId.value); + } + if (contentLength.present) { + map['content_length'] = Variable(contentLength.value); + } + if (contentType.present) { + map['content_type'] = Variable(contentType.value); + } + if (etag.present) { + map['etag'] = Variable(etag.value); + } + if (lastModified.present) { + final converter = $FilesTable.$converter0; + map['last_modified'] = + Variable(converter.mapToSql(lastModified.value)); + } + if (isCollection.present) { + map['is_collection'] = Variable(isCollection.value); + } + if (usedBytes.present) { + map['used_bytes'] = Variable(usedBytes.value); + } + if (hasPreview.present) { + map['has_preview'] = Variable(hasPreview.value); + } + if (ownerId.present) { + map['owner_id'] = Variable(ownerId.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('FilesCompanion(') + ..write('rowId: $rowId, ') + ..write('server: $server, ') + ..write('fileId: $fileId, ') + ..write('contentLength: $contentLength, ') + ..write('contentType: $contentType, ') + ..write('etag: $etag, ') + ..write('lastModified: $lastModified, ') + ..write('isCollection: $isCollection, ') + ..write('usedBytes: $usedBytes, ') + ..write('hasPreview: $hasPreview, ') + ..write('ownerId: $ownerId') + ..write(')')) + .toString(); + } +} + +class $FilesTable extends Files with TableInfo<$FilesTable, File> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $FilesTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _rowIdMeta = const VerificationMeta('rowId'); + @override + late final GeneratedColumn rowId = GeneratedColumn( + 'row_id', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: 'PRIMARY KEY AUTOINCREMENT'); + final VerificationMeta _serverMeta = const VerificationMeta('server'); + @override + late final GeneratedColumn server = GeneratedColumn( + 'server', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES servers (row_id) ON DELETE CASCADE'); + final VerificationMeta _fileIdMeta = const VerificationMeta('fileId'); + @override + late final GeneratedColumn fileId = GeneratedColumn( + 'file_id', aliasedName, false, + type: const IntType(), requiredDuringInsert: true); + final VerificationMeta _contentLengthMeta = + const VerificationMeta('contentLength'); + @override + late final GeneratedColumn contentLength = GeneratedColumn( + 'content_length', aliasedName, true, + type: const IntType(), requiredDuringInsert: false); + final VerificationMeta _contentTypeMeta = + const VerificationMeta('contentType'); + @override + late final GeneratedColumn contentType = GeneratedColumn( + 'content_type', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + final VerificationMeta _etagMeta = const VerificationMeta('etag'); + @override + late final GeneratedColumn etag = GeneratedColumn( + 'etag', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + final VerificationMeta _lastModifiedMeta = + const VerificationMeta('lastModified'); + @override + late final GeneratedColumnWithTypeConverter + lastModified = GeneratedColumn( + 'last_modified', aliasedName, true, + type: const IntType(), requiredDuringInsert: false) + .withConverter($FilesTable.$converter0); + final VerificationMeta _isCollectionMeta = + const VerificationMeta('isCollection'); + @override + late final GeneratedColumn isCollection = GeneratedColumn( + 'is_collection', aliasedName, true, + type: const BoolType(), + requiredDuringInsert: false, + defaultConstraints: 'CHECK (is_collection IN (0, 1))'); + final VerificationMeta _usedBytesMeta = const VerificationMeta('usedBytes'); + @override + late final GeneratedColumn usedBytes = GeneratedColumn( + 'used_bytes', aliasedName, true, + type: const IntType(), requiredDuringInsert: false); + final VerificationMeta _hasPreviewMeta = const VerificationMeta('hasPreview'); + @override + late final GeneratedColumn hasPreview = GeneratedColumn( + 'has_preview', aliasedName, true, + type: const BoolType(), + requiredDuringInsert: false, + defaultConstraints: 'CHECK (has_preview IN (0, 1))'); + final VerificationMeta _ownerIdMeta = const VerificationMeta('ownerId'); + @override + late final GeneratedColumn ownerId = GeneratedColumn( + 'owner_id', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + @override + List get $columns => [ + rowId, + server, + fileId, + contentLength, + contentType, + etag, + lastModified, + isCollection, + usedBytes, + hasPreview, + ownerId + ]; + @override + String get aliasedName => _alias ?? 'files'; + @override + String get actualTableName => 'files'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('row_id')) { + context.handle( + _rowIdMeta, rowId.isAcceptableOrUnknown(data['row_id']!, _rowIdMeta)); + } + if (data.containsKey('server')) { + context.handle(_serverMeta, + server.isAcceptableOrUnknown(data['server']!, _serverMeta)); + } else if (isInserting) { + context.missing(_serverMeta); + } + if (data.containsKey('file_id')) { + context.handle(_fileIdMeta, + fileId.isAcceptableOrUnknown(data['file_id']!, _fileIdMeta)); + } else if (isInserting) { + context.missing(_fileIdMeta); + } + if (data.containsKey('content_length')) { + context.handle( + _contentLengthMeta, + contentLength.isAcceptableOrUnknown( + data['content_length']!, _contentLengthMeta)); + } + if (data.containsKey('content_type')) { + context.handle( + _contentTypeMeta, + contentType.isAcceptableOrUnknown( + data['content_type']!, _contentTypeMeta)); + } + if (data.containsKey('etag')) { + context.handle( + _etagMeta, etag.isAcceptableOrUnknown(data['etag']!, _etagMeta)); + } + context.handle(_lastModifiedMeta, const VerificationResult.success()); + if (data.containsKey('is_collection')) { + context.handle( + _isCollectionMeta, + isCollection.isAcceptableOrUnknown( + data['is_collection']!, _isCollectionMeta)); + } + if (data.containsKey('used_bytes')) { + context.handle(_usedBytesMeta, + usedBytes.isAcceptableOrUnknown(data['used_bytes']!, _usedBytesMeta)); + } + if (data.containsKey('has_preview')) { + context.handle( + _hasPreviewMeta, + hasPreview.isAcceptableOrUnknown( + data['has_preview']!, _hasPreviewMeta)); + } + if (data.containsKey('owner_id')) { + context.handle(_ownerIdMeta, + ownerId.isAcceptableOrUnknown(data['owner_id']!, _ownerIdMeta)); + } + return context; + } + + @override + Set get $primaryKey => {rowId}; + @override + List> get uniqueKeys => [ + {server, fileId}, + ]; + @override + File map(Map data, {String? tablePrefix}) { + return File.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $FilesTable createAlias(String alias) { + return $FilesTable(attachedDatabase, alias); + } + + static TypeConverter $converter0 = + const _DateTimeConverter(); +} + +class AccountFile extends DataClass implements Insertable { + final int rowId; + final int account; + final int file; + final String relativePath; + final bool? isFavorite; + final bool? isArchived; + final DateTime? overrideDateTime; + AccountFile( + {required this.rowId, + required this.account, + required this.file, + required this.relativePath, + this.isFavorite, + this.isArchived, + this.overrideDateTime}); + factory AccountFile.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return AccountFile( + rowId: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}row_id'])!, + account: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}account'])!, + file: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}file'])!, + relativePath: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}relative_path'])!, + isFavorite: const BoolType() + .mapFromDatabaseResponse(data['${effectivePrefix}is_favorite']), + isArchived: const BoolType() + .mapFromDatabaseResponse(data['${effectivePrefix}is_archived']), + overrideDateTime: $AccountFilesTable.$converter0.mapToDart( + const DateTimeType().mapFromDatabaseResponse( + data['${effectivePrefix}override_date_time'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['row_id'] = Variable(rowId); + map['account'] = Variable(account); + map['file'] = Variable(file); + map['relative_path'] = Variable(relativePath); + if (!nullToAbsent || isFavorite != null) { + map['is_favorite'] = Variable(isFavorite); + } + if (!nullToAbsent || isArchived != null) { + map['is_archived'] = Variable(isArchived); + } + if (!nullToAbsent || overrideDateTime != null) { + final converter = $AccountFilesTable.$converter0; + map['override_date_time'] = + Variable(converter.mapToSql(overrideDateTime)); + } + return map; + } + + AccountFilesCompanion toCompanion(bool nullToAbsent) { + return AccountFilesCompanion( + rowId: Value(rowId), + account: Value(account), + file: Value(file), + relativePath: Value(relativePath), + isFavorite: isFavorite == null && nullToAbsent + ? const Value.absent() + : Value(isFavorite), + isArchived: isArchived == null && nullToAbsent + ? const Value.absent() + : Value(isArchived), + overrideDateTime: overrideDateTime == null && nullToAbsent + ? const Value.absent() + : Value(overrideDateTime), + ); + } + + factory AccountFile.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return AccountFile( + rowId: serializer.fromJson(json['rowId']), + account: serializer.fromJson(json['account']), + file: serializer.fromJson(json['file']), + relativePath: serializer.fromJson(json['relativePath']), + isFavorite: serializer.fromJson(json['isFavorite']), + isArchived: serializer.fromJson(json['isArchived']), + overrideDateTime: + serializer.fromJson(json['overrideDateTime']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'rowId': serializer.toJson(rowId), + 'account': serializer.toJson(account), + 'file': serializer.toJson(file), + 'relativePath': serializer.toJson(relativePath), + 'isFavorite': serializer.toJson(isFavorite), + 'isArchived': serializer.toJson(isArchived), + 'overrideDateTime': serializer.toJson(overrideDateTime), + }; + } + + AccountFile copyWith( + {int? rowId, + int? account, + int? file, + String? relativePath, + Value isFavorite = const Value.absent(), + Value isArchived = const Value.absent(), + Value overrideDateTime = const Value.absent()}) => + AccountFile( + rowId: rowId ?? this.rowId, + account: account ?? this.account, + file: file ?? this.file, + relativePath: relativePath ?? this.relativePath, + isFavorite: isFavorite.present ? isFavorite.value : this.isFavorite, + isArchived: isArchived.present ? isArchived.value : this.isArchived, + overrideDateTime: overrideDateTime.present + ? overrideDateTime.value + : this.overrideDateTime, + ); + @override + String toString() { + return (StringBuffer('AccountFile(') + ..write('rowId: $rowId, ') + ..write('account: $account, ') + ..write('file: $file, ') + ..write('relativePath: $relativePath, ') + ..write('isFavorite: $isFavorite, ') + ..write('isArchived: $isArchived, ') + ..write('overrideDateTime: $overrideDateTime') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(rowId, account, file, relativePath, + isFavorite, isArchived, overrideDateTime); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is AccountFile && + other.rowId == this.rowId && + other.account == this.account && + other.file == this.file && + other.relativePath == this.relativePath && + other.isFavorite == this.isFavorite && + other.isArchived == this.isArchived && + other.overrideDateTime == this.overrideDateTime); +} + +class AccountFilesCompanion extends UpdateCompanion { + final Value rowId; + final Value account; + final Value file; + final Value relativePath; + final Value isFavorite; + final Value isArchived; + final Value overrideDateTime; + const AccountFilesCompanion({ + this.rowId = const Value.absent(), + this.account = const Value.absent(), + this.file = const Value.absent(), + this.relativePath = const Value.absent(), + this.isFavorite = const Value.absent(), + this.isArchived = const Value.absent(), + this.overrideDateTime = const Value.absent(), + }); + AccountFilesCompanion.insert({ + this.rowId = const Value.absent(), + required int account, + required int file, + required String relativePath, + this.isFavorite = const Value.absent(), + this.isArchived = const Value.absent(), + this.overrideDateTime = const Value.absent(), + }) : account = Value(account), + file = Value(file), + relativePath = Value(relativePath); + static Insertable custom({ + Expression? rowId, + Expression? account, + Expression? file, + Expression? relativePath, + Expression? isFavorite, + Expression? isArchived, + Expression? overrideDateTime, + }) { + return RawValuesInsertable({ + if (rowId != null) 'row_id': rowId, + if (account != null) 'account': account, + if (file != null) 'file': file, + if (relativePath != null) 'relative_path': relativePath, + if (isFavorite != null) 'is_favorite': isFavorite, + if (isArchived != null) 'is_archived': isArchived, + if (overrideDateTime != null) 'override_date_time': overrideDateTime, + }); + } + + AccountFilesCompanion copyWith( + {Value? rowId, + Value? account, + Value? file, + Value? relativePath, + Value? isFavorite, + Value? isArchived, + Value? overrideDateTime}) { + return AccountFilesCompanion( + rowId: rowId ?? this.rowId, + account: account ?? this.account, + file: file ?? this.file, + relativePath: relativePath ?? this.relativePath, + isFavorite: isFavorite ?? this.isFavorite, + isArchived: isArchived ?? this.isArchived, + overrideDateTime: overrideDateTime ?? this.overrideDateTime, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (rowId.present) { + map['row_id'] = Variable(rowId.value); + } + if (account.present) { + map['account'] = Variable(account.value); + } + if (file.present) { + map['file'] = Variable(file.value); + } + if (relativePath.present) { + map['relative_path'] = Variable(relativePath.value); + } + if (isFavorite.present) { + map['is_favorite'] = Variable(isFavorite.value); + } + if (isArchived.present) { + map['is_archived'] = Variable(isArchived.value); + } + if (overrideDateTime.present) { + final converter = $AccountFilesTable.$converter0; + map['override_date_time'] = + Variable(converter.mapToSql(overrideDateTime.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AccountFilesCompanion(') + ..write('rowId: $rowId, ') + ..write('account: $account, ') + ..write('file: $file, ') + ..write('relativePath: $relativePath, ') + ..write('isFavorite: $isFavorite, ') + ..write('isArchived: $isArchived, ') + ..write('overrideDateTime: $overrideDateTime') + ..write(')')) + .toString(); + } +} + +class $AccountFilesTable extends AccountFiles + with TableInfo<$AccountFilesTable, AccountFile> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $AccountFilesTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _rowIdMeta = const VerificationMeta('rowId'); + @override + late final GeneratedColumn rowId = GeneratedColumn( + 'row_id', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: 'PRIMARY KEY AUTOINCREMENT'); + final VerificationMeta _accountMeta = const VerificationMeta('account'); + @override + late final GeneratedColumn account = GeneratedColumn( + 'account', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES accounts (row_id) ON DELETE CASCADE'); + final VerificationMeta _fileMeta = const VerificationMeta('file'); + @override + late final GeneratedColumn file = GeneratedColumn( + 'file', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES files (row_id) ON DELETE CASCADE'); + final VerificationMeta _relativePathMeta = + const VerificationMeta('relativePath'); + @override + late final GeneratedColumn relativePath = GeneratedColumn( + 'relative_path', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _isFavoriteMeta = const VerificationMeta('isFavorite'); + @override + late final GeneratedColumn isFavorite = GeneratedColumn( + 'is_favorite', aliasedName, true, + type: const BoolType(), + requiredDuringInsert: false, + defaultConstraints: 'CHECK (is_favorite IN (0, 1))'); + final VerificationMeta _isArchivedMeta = const VerificationMeta('isArchived'); + @override + late final GeneratedColumn isArchived = GeneratedColumn( + 'is_archived', aliasedName, true, + type: const BoolType(), + requiredDuringInsert: false, + defaultConstraints: 'CHECK (is_archived IN (0, 1))'); + final VerificationMeta _overrideDateTimeMeta = + const VerificationMeta('overrideDateTime'); + @override + late final GeneratedColumnWithTypeConverter + overrideDateTime = GeneratedColumn( + 'override_date_time', aliasedName, true, + type: const IntType(), requiredDuringInsert: false) + .withConverter($AccountFilesTable.$converter0); + @override + List get $columns => [ + rowId, + account, + file, + relativePath, + isFavorite, + isArchived, + overrideDateTime + ]; + @override + String get aliasedName => _alias ?? 'account_files'; + @override + String get actualTableName => 'account_files'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('row_id')) { + context.handle( + _rowIdMeta, rowId.isAcceptableOrUnknown(data['row_id']!, _rowIdMeta)); + } + if (data.containsKey('account')) { + context.handle(_accountMeta, + account.isAcceptableOrUnknown(data['account']!, _accountMeta)); + } else if (isInserting) { + context.missing(_accountMeta); + } + if (data.containsKey('file')) { + context.handle( + _fileMeta, file.isAcceptableOrUnknown(data['file']!, _fileMeta)); + } else if (isInserting) { + context.missing(_fileMeta); + } + if (data.containsKey('relative_path')) { + context.handle( + _relativePathMeta, + relativePath.isAcceptableOrUnknown( + data['relative_path']!, _relativePathMeta)); + } else if (isInserting) { + context.missing(_relativePathMeta); + } + if (data.containsKey('is_favorite')) { + context.handle( + _isFavoriteMeta, + isFavorite.isAcceptableOrUnknown( + data['is_favorite']!, _isFavoriteMeta)); + } + if (data.containsKey('is_archived')) { + context.handle( + _isArchivedMeta, + isArchived.isAcceptableOrUnknown( + data['is_archived']!, _isArchivedMeta)); + } + context.handle(_overrideDateTimeMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {rowId}; + @override + List> get uniqueKeys => [ + {account, file}, + ]; + @override + AccountFile map(Map data, {String? tablePrefix}) { + return AccountFile.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $AccountFilesTable createAlias(String alias) { + return $AccountFilesTable(attachedDatabase, alias); + } + + static TypeConverter $converter0 = + const _DateTimeConverter(); +} + +class Image extends DataClass implements Insertable { + final int accountFile; + final DateTime lastUpdated; + final String? fileEtag; + final int? width; + final int? height; + final String? exifRaw; + final DateTime? dateTimeOriginal; + Image( + {required this.accountFile, + required this.lastUpdated, + this.fileEtag, + this.width, + this.height, + this.exifRaw, + this.dateTimeOriginal}); + factory Image.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return Image( + accountFile: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}account_file'])!, + lastUpdated: $ImagesTable.$converter0.mapToDart(const DateTimeType() + .mapFromDatabaseResponse(data['${effectivePrefix}last_updated']))!, + fileEtag: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}file_etag']), + width: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}width']), + height: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}height']), + exifRaw: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}exif_raw']), + dateTimeOriginal: $ImagesTable.$converter1.mapToDart(const DateTimeType() + .mapFromDatabaseResponse( + data['${effectivePrefix}date_time_original'])), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['account_file'] = Variable(accountFile); + { + final converter = $ImagesTable.$converter0; + map['last_updated'] = + Variable(converter.mapToSql(lastUpdated)!); + } + if (!nullToAbsent || fileEtag != null) { + map['file_etag'] = Variable(fileEtag); + } + if (!nullToAbsent || width != null) { + map['width'] = Variable(width); + } + if (!nullToAbsent || height != null) { + map['height'] = Variable(height); + } + if (!nullToAbsent || exifRaw != null) { + map['exif_raw'] = Variable(exifRaw); + } + if (!nullToAbsent || dateTimeOriginal != null) { + final converter = $ImagesTable.$converter1; + map['date_time_original'] = + Variable(converter.mapToSql(dateTimeOriginal)); + } + return map; + } + + ImagesCompanion toCompanion(bool nullToAbsent) { + return ImagesCompanion( + accountFile: Value(accountFile), + lastUpdated: Value(lastUpdated), + fileEtag: fileEtag == null && nullToAbsent + ? const Value.absent() + : Value(fileEtag), + width: + width == null && nullToAbsent ? const Value.absent() : Value(width), + height: + height == null && nullToAbsent ? const Value.absent() : Value(height), + exifRaw: exifRaw == null && nullToAbsent + ? const Value.absent() + : Value(exifRaw), + dateTimeOriginal: dateTimeOriginal == null && nullToAbsent + ? const Value.absent() + : Value(dateTimeOriginal), + ); + } + + factory Image.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Image( + accountFile: serializer.fromJson(json['accountFile']), + lastUpdated: serializer.fromJson(json['lastUpdated']), + fileEtag: serializer.fromJson(json['fileEtag']), + width: serializer.fromJson(json['width']), + height: serializer.fromJson(json['height']), + exifRaw: serializer.fromJson(json['exifRaw']), + dateTimeOriginal: + serializer.fromJson(json['dateTimeOriginal']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'accountFile': serializer.toJson(accountFile), + 'lastUpdated': serializer.toJson(lastUpdated), + 'fileEtag': serializer.toJson(fileEtag), + 'width': serializer.toJson(width), + 'height': serializer.toJson(height), + 'exifRaw': serializer.toJson(exifRaw), + 'dateTimeOriginal': serializer.toJson(dateTimeOriginal), + }; + } + + Image copyWith( + {int? accountFile, + DateTime? lastUpdated, + Value fileEtag = const Value.absent(), + Value width = const Value.absent(), + Value height = const Value.absent(), + Value exifRaw = const Value.absent(), + Value dateTimeOriginal = const Value.absent()}) => + Image( + accountFile: accountFile ?? this.accountFile, + lastUpdated: lastUpdated ?? this.lastUpdated, + fileEtag: fileEtag.present ? fileEtag.value : this.fileEtag, + width: width.present ? width.value : this.width, + height: height.present ? height.value : this.height, + exifRaw: exifRaw.present ? exifRaw.value : this.exifRaw, + dateTimeOriginal: dateTimeOriginal.present + ? dateTimeOriginal.value + : this.dateTimeOriginal, + ); + @override + String toString() { + return (StringBuffer('Image(') + ..write('accountFile: $accountFile, ') + ..write('lastUpdated: $lastUpdated, ') + ..write('fileEtag: $fileEtag, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('exifRaw: $exifRaw, ') + ..write('dateTimeOriginal: $dateTimeOriginal') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(accountFile, lastUpdated, fileEtag, width, + height, exifRaw, dateTimeOriginal); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Image && + other.accountFile == this.accountFile && + other.lastUpdated == this.lastUpdated && + other.fileEtag == this.fileEtag && + other.width == this.width && + other.height == this.height && + other.exifRaw == this.exifRaw && + other.dateTimeOriginal == this.dateTimeOriginal); +} + +class ImagesCompanion extends UpdateCompanion { + final Value accountFile; + final Value lastUpdated; + final Value fileEtag; + final Value width; + final Value height; + final Value exifRaw; + final Value dateTimeOriginal; + const ImagesCompanion({ + this.accountFile = const Value.absent(), + this.lastUpdated = const Value.absent(), + this.fileEtag = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.exifRaw = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + }); + ImagesCompanion.insert({ + this.accountFile = const Value.absent(), + required DateTime lastUpdated, + this.fileEtag = const Value.absent(), + this.width = const Value.absent(), + this.height = const Value.absent(), + this.exifRaw = const Value.absent(), + this.dateTimeOriginal = const Value.absent(), + }) : lastUpdated = Value(lastUpdated); + static Insertable custom({ + Expression? accountFile, + Expression? lastUpdated, + Expression? fileEtag, + Expression? width, + Expression? height, + Expression? exifRaw, + Expression? dateTimeOriginal, + }) { + return RawValuesInsertable({ + if (accountFile != null) 'account_file': accountFile, + if (lastUpdated != null) 'last_updated': lastUpdated, + if (fileEtag != null) 'file_etag': fileEtag, + if (width != null) 'width': width, + if (height != null) 'height': height, + if (exifRaw != null) 'exif_raw': exifRaw, + if (dateTimeOriginal != null) 'date_time_original': dateTimeOriginal, + }); + } + + ImagesCompanion copyWith( + {Value? accountFile, + Value? lastUpdated, + Value? fileEtag, + Value? width, + Value? height, + Value? exifRaw, + Value? dateTimeOriginal}) { + return ImagesCompanion( + accountFile: accountFile ?? this.accountFile, + lastUpdated: lastUpdated ?? this.lastUpdated, + fileEtag: fileEtag ?? this.fileEtag, + width: width ?? this.width, + height: height ?? this.height, + exifRaw: exifRaw ?? this.exifRaw, + dateTimeOriginal: dateTimeOriginal ?? this.dateTimeOriginal, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (accountFile.present) { + map['account_file'] = Variable(accountFile.value); + } + if (lastUpdated.present) { + final converter = $ImagesTable.$converter0; + map['last_updated'] = + Variable(converter.mapToSql(lastUpdated.value)!); + } + if (fileEtag.present) { + map['file_etag'] = Variable(fileEtag.value); + } + if (width.present) { + map['width'] = Variable(width.value); + } + if (height.present) { + map['height'] = Variable(height.value); + } + if (exifRaw.present) { + map['exif_raw'] = Variable(exifRaw.value); + } + if (dateTimeOriginal.present) { + final converter = $ImagesTable.$converter1; + map['date_time_original'] = + Variable(converter.mapToSql(dateTimeOriginal.value)); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ImagesCompanion(') + ..write('accountFile: $accountFile, ') + ..write('lastUpdated: $lastUpdated, ') + ..write('fileEtag: $fileEtag, ') + ..write('width: $width, ') + ..write('height: $height, ') + ..write('exifRaw: $exifRaw, ') + ..write('dateTimeOriginal: $dateTimeOriginal') + ..write(')')) + .toString(); + } +} + +class $ImagesTable extends Images with TableInfo<$ImagesTable, Image> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $ImagesTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _accountFileMeta = + const VerificationMeta('accountFile'); + @override + late final GeneratedColumn accountFile = GeneratedColumn( + 'account_file', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: + 'REFERENCES account_files (row_id) ON DELETE CASCADE'); + final VerificationMeta _lastUpdatedMeta = + const VerificationMeta('lastUpdated'); + @override + late final GeneratedColumnWithTypeConverter lastUpdated = + GeneratedColumn('last_updated', aliasedName, false, + type: const IntType(), requiredDuringInsert: true) + .withConverter($ImagesTable.$converter0); + final VerificationMeta _fileEtagMeta = const VerificationMeta('fileEtag'); + @override + late final GeneratedColumn fileEtag = GeneratedColumn( + 'file_etag', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + final VerificationMeta _widthMeta = const VerificationMeta('width'); + @override + late final GeneratedColumn width = GeneratedColumn( + 'width', aliasedName, true, + type: const IntType(), requiredDuringInsert: false); + final VerificationMeta _heightMeta = const VerificationMeta('height'); + @override + late final GeneratedColumn height = GeneratedColumn( + 'height', aliasedName, true, + type: const IntType(), requiredDuringInsert: false); + final VerificationMeta _exifRawMeta = const VerificationMeta('exifRaw'); + @override + late final GeneratedColumn exifRaw = GeneratedColumn( + 'exif_raw', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + final VerificationMeta _dateTimeOriginalMeta = + const VerificationMeta('dateTimeOriginal'); + @override + late final GeneratedColumnWithTypeConverter + dateTimeOriginal = GeneratedColumn( + 'date_time_original', aliasedName, true, + type: const IntType(), requiredDuringInsert: false) + .withConverter($ImagesTable.$converter1); + @override + List get $columns => [ + accountFile, + lastUpdated, + fileEtag, + width, + height, + exifRaw, + dateTimeOriginal + ]; + @override + String get aliasedName => _alias ?? 'images'; + @override + String get actualTableName => 'images'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('account_file')) { + context.handle( + _accountFileMeta, + accountFile.isAcceptableOrUnknown( + data['account_file']!, _accountFileMeta)); + } + context.handle(_lastUpdatedMeta, const VerificationResult.success()); + if (data.containsKey('file_etag')) { + context.handle(_fileEtagMeta, + fileEtag.isAcceptableOrUnknown(data['file_etag']!, _fileEtagMeta)); + } + if (data.containsKey('width')) { + context.handle( + _widthMeta, width.isAcceptableOrUnknown(data['width']!, _widthMeta)); + } + if (data.containsKey('height')) { + context.handle(_heightMeta, + height.isAcceptableOrUnknown(data['height']!, _heightMeta)); + } + if (data.containsKey('exif_raw')) { + context.handle(_exifRawMeta, + exifRaw.isAcceptableOrUnknown(data['exif_raw']!, _exifRawMeta)); + } + context.handle(_dateTimeOriginalMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {accountFile}; + @override + Image map(Map data, {String? tablePrefix}) { + return Image.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $ImagesTable createAlias(String alias) { + return $ImagesTable(attachedDatabase, alias); + } + + static TypeConverter $converter0 = + const _DateTimeConverter(); + static TypeConverter $converter1 = + const _DateTimeConverter(); +} + +class Trash extends DataClass implements Insertable { + final int file; + final String filename; + final String originalLocation; + final DateTime deletionTime; + Trash( + {required this.file, + required this.filename, + required this.originalLocation, + required this.deletionTime}); + factory Trash.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return Trash( + file: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}file'])!, + filename: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}filename'])!, + originalLocation: const StringType().mapFromDatabaseResponse( + data['${effectivePrefix}original_location'])!, + deletionTime: $TrashesTable.$converter0.mapToDart(const DateTimeType() + .mapFromDatabaseResponse(data['${effectivePrefix}deletion_time']))!, + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['file'] = Variable(file); + map['filename'] = Variable(filename); + map['original_location'] = Variable(originalLocation); + { + final converter = $TrashesTable.$converter0; + map['deletion_time'] = + Variable(converter.mapToSql(deletionTime)!); + } + return map; + } + + TrashesCompanion toCompanion(bool nullToAbsent) { + return TrashesCompanion( + file: Value(file), + filename: Value(filename), + originalLocation: Value(originalLocation), + deletionTime: Value(deletionTime), + ); + } + + factory Trash.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Trash( + file: serializer.fromJson(json['file']), + filename: serializer.fromJson(json['filename']), + originalLocation: serializer.fromJson(json['originalLocation']), + deletionTime: serializer.fromJson(json['deletionTime']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'file': serializer.toJson(file), + 'filename': serializer.toJson(filename), + 'originalLocation': serializer.toJson(originalLocation), + 'deletionTime': serializer.toJson(deletionTime), + }; + } + + Trash copyWith( + {int? file, + String? filename, + String? originalLocation, + DateTime? deletionTime}) => + Trash( + file: file ?? this.file, + filename: filename ?? this.filename, + originalLocation: originalLocation ?? this.originalLocation, + deletionTime: deletionTime ?? this.deletionTime, + ); + @override + String toString() { + return (StringBuffer('Trash(') + ..write('file: $file, ') + ..write('filename: $filename, ') + ..write('originalLocation: $originalLocation, ') + ..write('deletionTime: $deletionTime') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(file, filename, originalLocation, deletionTime); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Trash && + other.file == this.file && + other.filename == this.filename && + other.originalLocation == this.originalLocation && + other.deletionTime == this.deletionTime); +} + +class TrashesCompanion extends UpdateCompanion { + final Value file; + final Value filename; + final Value originalLocation; + final Value deletionTime; + const TrashesCompanion({ + this.file = const Value.absent(), + this.filename = const Value.absent(), + this.originalLocation = const Value.absent(), + this.deletionTime = const Value.absent(), + }); + TrashesCompanion.insert({ + this.file = const Value.absent(), + required String filename, + required String originalLocation, + required DateTime deletionTime, + }) : filename = Value(filename), + originalLocation = Value(originalLocation), + deletionTime = Value(deletionTime); + static Insertable custom({ + Expression? file, + Expression? filename, + Expression? originalLocation, + Expression? deletionTime, + }) { + return RawValuesInsertable({ + if (file != null) 'file': file, + if (filename != null) 'filename': filename, + if (originalLocation != null) 'original_location': originalLocation, + if (deletionTime != null) 'deletion_time': deletionTime, + }); + } + + TrashesCompanion copyWith( + {Value? file, + Value? filename, + Value? originalLocation, + Value? deletionTime}) { + return TrashesCompanion( + file: file ?? this.file, + filename: filename ?? this.filename, + originalLocation: originalLocation ?? this.originalLocation, + deletionTime: deletionTime ?? this.deletionTime, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (file.present) { + map['file'] = Variable(file.value); + } + if (filename.present) { + map['filename'] = Variable(filename.value); + } + if (originalLocation.present) { + map['original_location'] = Variable(originalLocation.value); + } + if (deletionTime.present) { + final converter = $TrashesTable.$converter0; + map['deletion_time'] = + Variable(converter.mapToSql(deletionTime.value)!); + } + return map; + } + + @override + String toString() { + return (StringBuffer('TrashesCompanion(') + ..write('file: $file, ') + ..write('filename: $filename, ') + ..write('originalLocation: $originalLocation, ') + ..write('deletionTime: $deletionTime') + ..write(')')) + .toString(); + } +} + +class $TrashesTable extends Trashes with TableInfo<$TrashesTable, Trash> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $TrashesTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _fileMeta = const VerificationMeta('file'); + @override + late final GeneratedColumn file = GeneratedColumn( + 'file', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: 'REFERENCES files (row_id) ON DELETE CASCADE'); + final VerificationMeta _filenameMeta = const VerificationMeta('filename'); + @override + late final GeneratedColumn filename = GeneratedColumn( + 'filename', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _originalLocationMeta = + const VerificationMeta('originalLocation'); + @override + late final GeneratedColumn originalLocation = + GeneratedColumn('original_location', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _deletionTimeMeta = + const VerificationMeta('deletionTime'); + @override + late final GeneratedColumnWithTypeConverter + deletionTime = GeneratedColumn( + 'deletion_time', aliasedName, false, + type: const IntType(), requiredDuringInsert: true) + .withConverter($TrashesTable.$converter0); + @override + List get $columns => + [file, filename, originalLocation, deletionTime]; + @override + String get aliasedName => _alias ?? 'trashes'; + @override + String get actualTableName => 'trashes'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('file')) { + context.handle( + _fileMeta, file.isAcceptableOrUnknown(data['file']!, _fileMeta)); + } + if (data.containsKey('filename')) { + context.handle(_filenameMeta, + filename.isAcceptableOrUnknown(data['filename']!, _filenameMeta)); + } else if (isInserting) { + context.missing(_filenameMeta); + } + if (data.containsKey('original_location')) { + context.handle( + _originalLocationMeta, + originalLocation.isAcceptableOrUnknown( + data['original_location']!, _originalLocationMeta)); + } else if (isInserting) { + context.missing(_originalLocationMeta); + } + context.handle(_deletionTimeMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {file}; + @override + Trash map(Map data, {String? tablePrefix}) { + return Trash.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $TrashesTable createAlias(String alias) { + return $TrashesTable(attachedDatabase, alias); + } + + static TypeConverter $converter0 = + const _DateTimeConverter(); +} + +class DirFile extends DataClass implements Insertable { + final int dir; + final int child; + DirFile({required this.dir, required this.child}); + factory DirFile.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return DirFile( + dir: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}dir'])!, + child: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}child'])!, + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['dir'] = Variable(dir); + map['child'] = Variable(child); + return map; + } + + DirFilesCompanion toCompanion(bool nullToAbsent) { + return DirFilesCompanion( + dir: Value(dir), + child: Value(child), + ); + } + + factory DirFile.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return DirFile( + dir: serializer.fromJson(json['dir']), + child: serializer.fromJson(json['child']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'dir': serializer.toJson(dir), + 'child': serializer.toJson(child), + }; + } + + DirFile copyWith({int? dir, int? child}) => DirFile( + dir: dir ?? this.dir, + child: child ?? this.child, + ); + @override + String toString() { + return (StringBuffer('DirFile(') + ..write('dir: $dir, ') + ..write('child: $child') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(dir, child); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is DirFile && other.dir == this.dir && other.child == this.child); +} + +class DirFilesCompanion extends UpdateCompanion { + final Value dir; + final Value child; + const DirFilesCompanion({ + this.dir = const Value.absent(), + this.child = const Value.absent(), + }); + DirFilesCompanion.insert({ + required int dir, + required int child, + }) : dir = Value(dir), + child = Value(child); + static Insertable custom({ + Expression? dir, + Expression? child, + }) { + return RawValuesInsertable({ + if (dir != null) 'dir': dir, + if (child != null) 'child': child, + }); + } + + DirFilesCompanion copyWith({Value? dir, Value? child}) { + return DirFilesCompanion( + dir: dir ?? this.dir, + child: child ?? this.child, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (dir.present) { + map['dir'] = Variable(dir.value); + } + if (child.present) { + map['child'] = Variable(child.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('DirFilesCompanion(') + ..write('dir: $dir, ') + ..write('child: $child') + ..write(')')) + .toString(); + } +} + +class $DirFilesTable extends DirFiles with TableInfo<$DirFilesTable, DirFile> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $DirFilesTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _dirMeta = const VerificationMeta('dir'); + @override + late final GeneratedColumn dir = GeneratedColumn( + 'dir', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES files (row_id) ON DELETE CASCADE'); + final VerificationMeta _childMeta = const VerificationMeta('child'); + @override + late final GeneratedColumn child = GeneratedColumn( + 'child', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES files (row_id) ON DELETE CASCADE'); + @override + List get $columns => [dir, child]; + @override + String get aliasedName => _alias ?? 'dir_files'; + @override + String get actualTableName => 'dir_files'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('dir')) { + context.handle( + _dirMeta, dir.isAcceptableOrUnknown(data['dir']!, _dirMeta)); + } else if (isInserting) { + context.missing(_dirMeta); + } + if (data.containsKey('child')) { + context.handle( + _childMeta, child.isAcceptableOrUnknown(data['child']!, _childMeta)); + } else if (isInserting) { + context.missing(_childMeta); + } + return context; + } + + @override + Set get $primaryKey => {dir, child}; + @override + DirFile map(Map data, {String? tablePrefix}) { + return DirFile.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $DirFilesTable createAlias(String alias) { + return $DirFilesTable(attachedDatabase, alias); + } +} + +class Album extends DataClass implements Insertable { + final int rowId; + final int file; + final int version; + final DateTime lastUpdated; + final String name; + final String providerType; + final String providerContent; + final String coverProviderType; + final String coverProviderContent; + final String sortProviderType; + final String sortProviderContent; + Album( + {required this.rowId, + required this.file, + required this.version, + required this.lastUpdated, + required this.name, + required this.providerType, + required this.providerContent, + required this.coverProviderType, + required this.coverProviderContent, + required this.sortProviderType, + required this.sortProviderContent}); + factory Album.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return Album( + rowId: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}row_id'])!, + file: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}file'])!, + version: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}version'])!, + lastUpdated: $AlbumsTable.$converter0.mapToDart(const DateTimeType() + .mapFromDatabaseResponse(data['${effectivePrefix}last_updated']))!, + name: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}name'])!, + providerType: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}provider_type'])!, + providerContent: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}provider_content'])!, + coverProviderType: const StringType().mapFromDatabaseResponse( + data['${effectivePrefix}cover_provider_type'])!, + coverProviderContent: const StringType().mapFromDatabaseResponse( + data['${effectivePrefix}cover_provider_content'])!, + sortProviderType: const StringType().mapFromDatabaseResponse( + data['${effectivePrefix}sort_provider_type'])!, + sortProviderContent: const StringType().mapFromDatabaseResponse( + data['${effectivePrefix}sort_provider_content'])!, + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['row_id'] = Variable(rowId); + map['file'] = Variable(file); + map['version'] = Variable(version); + { + final converter = $AlbumsTable.$converter0; + map['last_updated'] = + Variable(converter.mapToSql(lastUpdated)!); + } + map['name'] = Variable(name); + map['provider_type'] = Variable(providerType); + map['provider_content'] = Variable(providerContent); + map['cover_provider_type'] = Variable(coverProviderType); + map['cover_provider_content'] = Variable(coverProviderContent); + map['sort_provider_type'] = Variable(sortProviderType); + map['sort_provider_content'] = Variable(sortProviderContent); + return map; + } + + AlbumsCompanion toCompanion(bool nullToAbsent) { + return AlbumsCompanion( + rowId: Value(rowId), + file: Value(file), + version: Value(version), + lastUpdated: Value(lastUpdated), + name: Value(name), + providerType: Value(providerType), + providerContent: Value(providerContent), + coverProviderType: Value(coverProviderType), + coverProviderContent: Value(coverProviderContent), + sortProviderType: Value(sortProviderType), + sortProviderContent: Value(sortProviderContent), + ); + } + + factory Album.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Album( + rowId: serializer.fromJson(json['rowId']), + file: serializer.fromJson(json['file']), + version: serializer.fromJson(json['version']), + lastUpdated: serializer.fromJson(json['lastUpdated']), + name: serializer.fromJson(json['name']), + providerType: serializer.fromJson(json['providerType']), + providerContent: serializer.fromJson(json['providerContent']), + coverProviderType: serializer.fromJson(json['coverProviderType']), + coverProviderContent: + serializer.fromJson(json['coverProviderContent']), + sortProviderType: serializer.fromJson(json['sortProviderType']), + sortProviderContent: + serializer.fromJson(json['sortProviderContent']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'rowId': serializer.toJson(rowId), + 'file': serializer.toJson(file), + 'version': serializer.toJson(version), + 'lastUpdated': serializer.toJson(lastUpdated), + 'name': serializer.toJson(name), + 'providerType': serializer.toJson(providerType), + 'providerContent': serializer.toJson(providerContent), + 'coverProviderType': serializer.toJson(coverProviderType), + 'coverProviderContent': serializer.toJson(coverProviderContent), + 'sortProviderType': serializer.toJson(sortProviderType), + 'sortProviderContent': serializer.toJson(sortProviderContent), + }; + } + + Album copyWith( + {int? rowId, + int? file, + int? version, + DateTime? lastUpdated, + String? name, + String? providerType, + String? providerContent, + String? coverProviderType, + String? coverProviderContent, + String? sortProviderType, + String? sortProviderContent}) => + Album( + rowId: rowId ?? this.rowId, + file: file ?? this.file, + version: version ?? this.version, + lastUpdated: lastUpdated ?? this.lastUpdated, + name: name ?? this.name, + providerType: providerType ?? this.providerType, + providerContent: providerContent ?? this.providerContent, + coverProviderType: coverProviderType ?? this.coverProviderType, + coverProviderContent: coverProviderContent ?? this.coverProviderContent, + sortProviderType: sortProviderType ?? this.sortProviderType, + sortProviderContent: sortProviderContent ?? this.sortProviderContent, + ); + @override + String toString() { + return (StringBuffer('Album(') + ..write('rowId: $rowId, ') + ..write('file: $file, ') + ..write('version: $version, ') + ..write('lastUpdated: $lastUpdated, ') + ..write('name: $name, ') + ..write('providerType: $providerType, ') + ..write('providerContent: $providerContent, ') + ..write('coverProviderType: $coverProviderType, ') + ..write('coverProviderContent: $coverProviderContent, ') + ..write('sortProviderType: $sortProviderType, ') + ..write('sortProviderContent: $sortProviderContent') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash( + rowId, + file, + version, + lastUpdated, + name, + providerType, + providerContent, + coverProviderType, + coverProviderContent, + sortProviderType, + sortProviderContent); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Album && + other.rowId == this.rowId && + other.file == this.file && + other.version == this.version && + other.lastUpdated == this.lastUpdated && + other.name == this.name && + other.providerType == this.providerType && + other.providerContent == this.providerContent && + other.coverProviderType == this.coverProviderType && + other.coverProviderContent == this.coverProviderContent && + other.sortProviderType == this.sortProviderType && + other.sortProviderContent == this.sortProviderContent); +} + +class AlbumsCompanion extends UpdateCompanion { + final Value rowId; + final Value file; + final Value version; + final Value lastUpdated; + final Value name; + final Value providerType; + final Value providerContent; + final Value coverProviderType; + final Value coverProviderContent; + final Value sortProviderType; + final Value sortProviderContent; + const AlbumsCompanion({ + this.rowId = const Value.absent(), + this.file = const Value.absent(), + this.version = const Value.absent(), + this.lastUpdated = const Value.absent(), + this.name = const Value.absent(), + this.providerType = const Value.absent(), + this.providerContent = const Value.absent(), + this.coverProviderType = const Value.absent(), + this.coverProviderContent = const Value.absent(), + this.sortProviderType = const Value.absent(), + this.sortProviderContent = const Value.absent(), + }); + AlbumsCompanion.insert({ + this.rowId = const Value.absent(), + required int file, + required int version, + required DateTime lastUpdated, + required String name, + required String providerType, + required String providerContent, + required String coverProviderType, + required String coverProviderContent, + required String sortProviderType, + required String sortProviderContent, + }) : file = Value(file), + version = Value(version), + lastUpdated = Value(lastUpdated), + name = Value(name), + providerType = Value(providerType), + providerContent = Value(providerContent), + coverProviderType = Value(coverProviderType), + coverProviderContent = Value(coverProviderContent), + sortProviderType = Value(sortProviderType), + sortProviderContent = Value(sortProviderContent); + static Insertable custom({ + Expression? rowId, + Expression? file, + Expression? version, + Expression? lastUpdated, + Expression? name, + Expression? providerType, + Expression? providerContent, + Expression? coverProviderType, + Expression? coverProviderContent, + Expression? sortProviderType, + Expression? sortProviderContent, + }) { + return RawValuesInsertable({ + if (rowId != null) 'row_id': rowId, + if (file != null) 'file': file, + if (version != null) 'version': version, + if (lastUpdated != null) 'last_updated': lastUpdated, + if (name != null) 'name': name, + if (providerType != null) 'provider_type': providerType, + if (providerContent != null) 'provider_content': providerContent, + if (coverProviderType != null) 'cover_provider_type': coverProviderType, + if (coverProviderContent != null) + 'cover_provider_content': coverProviderContent, + if (sortProviderType != null) 'sort_provider_type': sortProviderType, + if (sortProviderContent != null) + 'sort_provider_content': sortProviderContent, + }); + } + + AlbumsCompanion copyWith( + {Value? rowId, + Value? file, + Value? version, + Value? lastUpdated, + Value? name, + Value? providerType, + Value? providerContent, + Value? coverProviderType, + Value? coverProviderContent, + Value? sortProviderType, + Value? sortProviderContent}) { + return AlbumsCompanion( + rowId: rowId ?? this.rowId, + file: file ?? this.file, + version: version ?? this.version, + lastUpdated: lastUpdated ?? this.lastUpdated, + name: name ?? this.name, + providerType: providerType ?? this.providerType, + providerContent: providerContent ?? this.providerContent, + coverProviderType: coverProviderType ?? this.coverProviderType, + coverProviderContent: coverProviderContent ?? this.coverProviderContent, + sortProviderType: sortProviderType ?? this.sortProviderType, + sortProviderContent: sortProviderContent ?? this.sortProviderContent, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (rowId.present) { + map['row_id'] = Variable(rowId.value); + } + if (file.present) { + map['file'] = Variable(file.value); + } + if (version.present) { + map['version'] = Variable(version.value); + } + if (lastUpdated.present) { + final converter = $AlbumsTable.$converter0; + map['last_updated'] = + Variable(converter.mapToSql(lastUpdated.value)!); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (providerType.present) { + map['provider_type'] = Variable(providerType.value); + } + if (providerContent.present) { + map['provider_content'] = Variable(providerContent.value); + } + if (coverProviderType.present) { + map['cover_provider_type'] = Variable(coverProviderType.value); + } + if (coverProviderContent.present) { + map['cover_provider_content'] = + Variable(coverProviderContent.value); + } + if (sortProviderType.present) { + map['sort_provider_type'] = Variable(sortProviderType.value); + } + if (sortProviderContent.present) { + map['sort_provider_content'] = + Variable(sortProviderContent.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AlbumsCompanion(') + ..write('rowId: $rowId, ') + ..write('file: $file, ') + ..write('version: $version, ') + ..write('lastUpdated: $lastUpdated, ') + ..write('name: $name, ') + ..write('providerType: $providerType, ') + ..write('providerContent: $providerContent, ') + ..write('coverProviderType: $coverProviderType, ') + ..write('coverProviderContent: $coverProviderContent, ') + ..write('sortProviderType: $sortProviderType, ') + ..write('sortProviderContent: $sortProviderContent') + ..write(')')) + .toString(); + } +} + +class $AlbumsTable extends Albums with TableInfo<$AlbumsTable, Album> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $AlbumsTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _rowIdMeta = const VerificationMeta('rowId'); + @override + late final GeneratedColumn rowId = GeneratedColumn( + 'row_id', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: 'PRIMARY KEY AUTOINCREMENT'); + final VerificationMeta _fileMeta = const VerificationMeta('file'); + @override + late final GeneratedColumn file = GeneratedColumn( + 'file', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'UNIQUE REFERENCES files (row_id) ON DELETE CASCADE'); + final VerificationMeta _versionMeta = const VerificationMeta('version'); + @override + late final GeneratedColumn version = GeneratedColumn( + 'version', aliasedName, false, + type: const IntType(), requiredDuringInsert: true); + final VerificationMeta _lastUpdatedMeta = + const VerificationMeta('lastUpdated'); + @override + late final GeneratedColumnWithTypeConverter lastUpdated = + GeneratedColumn('last_updated', aliasedName, false, + type: const IntType(), requiredDuringInsert: true) + .withConverter($AlbumsTable.$converter0); + final VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _providerTypeMeta = + const VerificationMeta('providerType'); + @override + late final GeneratedColumn providerType = GeneratedColumn( + 'provider_type', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _providerContentMeta = + const VerificationMeta('providerContent'); + @override + late final GeneratedColumn providerContent = + GeneratedColumn('provider_content', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _coverProviderTypeMeta = + const VerificationMeta('coverProviderType'); + @override + late final GeneratedColumn coverProviderType = + GeneratedColumn('cover_provider_type', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _coverProviderContentMeta = + const VerificationMeta('coverProviderContent'); + @override + late final GeneratedColumn coverProviderContent = + GeneratedColumn('cover_provider_content', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _sortProviderTypeMeta = + const VerificationMeta('sortProviderType'); + @override + late final GeneratedColumn sortProviderType = + GeneratedColumn('sort_provider_type', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _sortProviderContentMeta = + const VerificationMeta('sortProviderContent'); + @override + late final GeneratedColumn sortProviderContent = + GeneratedColumn('sort_provider_content', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + @override + List get $columns => [ + rowId, + file, + version, + lastUpdated, + name, + providerType, + providerContent, + coverProviderType, + coverProviderContent, + sortProviderType, + sortProviderContent + ]; + @override + String get aliasedName => _alias ?? 'albums'; + @override + String get actualTableName => 'albums'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('row_id')) { + context.handle( + _rowIdMeta, rowId.isAcceptableOrUnknown(data['row_id']!, _rowIdMeta)); + } + if (data.containsKey('file')) { + context.handle( + _fileMeta, file.isAcceptableOrUnknown(data['file']!, _fileMeta)); + } else if (isInserting) { + context.missing(_fileMeta); + } + if (data.containsKey('version')) { + context.handle(_versionMeta, + version.isAcceptableOrUnknown(data['version']!, _versionMeta)); + } else if (isInserting) { + context.missing(_versionMeta); + } + context.handle(_lastUpdatedMeta, const VerificationResult.success()); + if (data.containsKey('name')) { + context.handle( + _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('provider_type')) { + context.handle( + _providerTypeMeta, + providerType.isAcceptableOrUnknown( + data['provider_type']!, _providerTypeMeta)); + } else if (isInserting) { + context.missing(_providerTypeMeta); + } + if (data.containsKey('provider_content')) { + context.handle( + _providerContentMeta, + providerContent.isAcceptableOrUnknown( + data['provider_content']!, _providerContentMeta)); + } else if (isInserting) { + context.missing(_providerContentMeta); + } + if (data.containsKey('cover_provider_type')) { + context.handle( + _coverProviderTypeMeta, + coverProviderType.isAcceptableOrUnknown( + data['cover_provider_type']!, _coverProviderTypeMeta)); + } else if (isInserting) { + context.missing(_coverProviderTypeMeta); + } + if (data.containsKey('cover_provider_content')) { + context.handle( + _coverProviderContentMeta, + coverProviderContent.isAcceptableOrUnknown( + data['cover_provider_content']!, _coverProviderContentMeta)); + } else if (isInserting) { + context.missing(_coverProviderContentMeta); + } + if (data.containsKey('sort_provider_type')) { + context.handle( + _sortProviderTypeMeta, + sortProviderType.isAcceptableOrUnknown( + data['sort_provider_type']!, _sortProviderTypeMeta)); + } else if (isInserting) { + context.missing(_sortProviderTypeMeta); + } + if (data.containsKey('sort_provider_content')) { + context.handle( + _sortProviderContentMeta, + sortProviderContent.isAcceptableOrUnknown( + data['sort_provider_content']!, _sortProviderContentMeta)); + } else if (isInserting) { + context.missing(_sortProviderContentMeta); + } + return context; + } + + @override + Set get $primaryKey => {rowId}; + @override + Album map(Map data, {String? tablePrefix}) { + return Album.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $AlbumsTable createAlias(String alias) { + return $AlbumsTable(attachedDatabase, alias); + } + + static TypeConverter $converter0 = + const _DateTimeConverter(); +} + +class AlbumShare extends DataClass implements Insertable { + final int album; + final String userId; + final String? displayName; + final DateTime sharedAt; + AlbumShare( + {required this.album, + required this.userId, + this.displayName, + required this.sharedAt}); + factory AlbumShare.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return AlbumShare( + album: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}album'])!, + userId: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}user_id'])!, + displayName: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}display_name']), + sharedAt: $AlbumSharesTable.$converter0.mapToDart(const DateTimeType() + .mapFromDatabaseResponse(data['${effectivePrefix}shared_at']))!, + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['album'] = Variable(album); + map['user_id'] = Variable(userId); + if (!nullToAbsent || displayName != null) { + map['display_name'] = Variable(displayName); + } + { + final converter = $AlbumSharesTable.$converter0; + map['shared_at'] = Variable(converter.mapToSql(sharedAt)!); + } + return map; + } + + AlbumSharesCompanion toCompanion(bool nullToAbsent) { + return AlbumSharesCompanion( + album: Value(album), + userId: Value(userId), + displayName: displayName == null && nullToAbsent + ? const Value.absent() + : Value(displayName), + sharedAt: Value(sharedAt), + ); + } + + factory AlbumShare.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return AlbumShare( + album: serializer.fromJson(json['album']), + userId: serializer.fromJson(json['userId']), + displayName: serializer.fromJson(json['displayName']), + sharedAt: serializer.fromJson(json['sharedAt']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'album': serializer.toJson(album), + 'userId': serializer.toJson(userId), + 'displayName': serializer.toJson(displayName), + 'sharedAt': serializer.toJson(sharedAt), + }; + } + + AlbumShare copyWith( + {int? album, + String? userId, + Value displayName = const Value.absent(), + DateTime? sharedAt}) => + AlbumShare( + album: album ?? this.album, + userId: userId ?? this.userId, + displayName: displayName.present ? displayName.value : this.displayName, + sharedAt: sharedAt ?? this.sharedAt, + ); + @override + String toString() { + return (StringBuffer('AlbumShare(') + ..write('album: $album, ') + ..write('userId: $userId, ') + ..write('displayName: $displayName, ') + ..write('sharedAt: $sharedAt') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(album, userId, displayName, sharedAt); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is AlbumShare && + other.album == this.album && + other.userId == this.userId && + other.displayName == this.displayName && + other.sharedAt == this.sharedAt); +} + +class AlbumSharesCompanion extends UpdateCompanion { + final Value album; + final Value userId; + final Value displayName; + final Value sharedAt; + const AlbumSharesCompanion({ + this.album = const Value.absent(), + this.userId = const Value.absent(), + this.displayName = const Value.absent(), + this.sharedAt = const Value.absent(), + }); + AlbumSharesCompanion.insert({ + required int album, + required String userId, + this.displayName = const Value.absent(), + required DateTime sharedAt, + }) : album = Value(album), + userId = Value(userId), + sharedAt = Value(sharedAt); + static Insertable custom({ + Expression? album, + Expression? userId, + Expression? displayName, + Expression? sharedAt, + }) { + return RawValuesInsertable({ + if (album != null) 'album': album, + if (userId != null) 'user_id': userId, + if (displayName != null) 'display_name': displayName, + if (sharedAt != null) 'shared_at': sharedAt, + }); + } + + AlbumSharesCompanion copyWith( + {Value? album, + Value? userId, + Value? displayName, + Value? sharedAt}) { + return AlbumSharesCompanion( + album: album ?? this.album, + userId: userId ?? this.userId, + displayName: displayName ?? this.displayName, + sharedAt: sharedAt ?? this.sharedAt, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (album.present) { + map['album'] = Variable(album.value); + } + if (userId.present) { + map['user_id'] = Variable(userId.value); + } + if (displayName.present) { + map['display_name'] = Variable(displayName.value); + } + if (sharedAt.present) { + final converter = $AlbumSharesTable.$converter0; + map['shared_at'] = + Variable(converter.mapToSql(sharedAt.value)!); + } + return map; + } + + @override + String toString() { + return (StringBuffer('AlbumSharesCompanion(') + ..write('album: $album, ') + ..write('userId: $userId, ') + ..write('displayName: $displayName, ') + ..write('sharedAt: $sharedAt') + ..write(')')) + .toString(); + } +} + +class $AlbumSharesTable extends AlbumShares + with TableInfo<$AlbumSharesTable, AlbumShare> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $AlbumSharesTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _albumMeta = const VerificationMeta('album'); + @override + late final GeneratedColumn album = GeneratedColumn( + 'album', aliasedName, false, + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES albums (row_id) ON DELETE CASCADE'); + final VerificationMeta _userIdMeta = const VerificationMeta('userId'); + @override + late final GeneratedColumn userId = GeneratedColumn( + 'user_id', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _displayNameMeta = + const VerificationMeta('displayName'); + @override + late final GeneratedColumn displayName = GeneratedColumn( + 'display_name', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + final VerificationMeta _sharedAtMeta = const VerificationMeta('sharedAt'); + @override + late final GeneratedColumnWithTypeConverter sharedAt = + GeneratedColumn('shared_at', aliasedName, false, + type: const IntType(), requiredDuringInsert: true) + .withConverter($AlbumSharesTable.$converter0); + @override + List get $columns => [album, userId, displayName, sharedAt]; + @override + String get aliasedName => _alias ?? 'album_shares'; + @override + String get actualTableName => 'album_shares'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('album')) { + context.handle( + _albumMeta, album.isAcceptableOrUnknown(data['album']!, _albumMeta)); + } else if (isInserting) { + context.missing(_albumMeta); + } + if (data.containsKey('user_id')) { + context.handle(_userIdMeta, + userId.isAcceptableOrUnknown(data['user_id']!, _userIdMeta)); + } else if (isInserting) { + context.missing(_userIdMeta); + } + if (data.containsKey('display_name')) { + context.handle( + _displayNameMeta, + displayName.isAcceptableOrUnknown( + data['display_name']!, _displayNameMeta)); + } + context.handle(_sharedAtMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => {album, userId}; + @override + AlbumShare map(Map data, {String? tablePrefix}) { + return AlbumShare.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $AlbumSharesTable createAlias(String alias) { + return $AlbumSharesTable(attachedDatabase, alias); + } + + static TypeConverter $converter0 = + const _DateTimeConverter(); +} + +abstract class _$SqliteDb extends GeneratedDatabase { + _$SqliteDb(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e); + _$SqliteDb.connect(DatabaseConnection c) : super.connect(c); + late final $ServersTable servers = $ServersTable(this); + late final $AccountsTable accounts = $AccountsTable(this); + late final $FilesTable files = $FilesTable(this); + late final $AccountFilesTable accountFiles = $AccountFilesTable(this); + late final $ImagesTable images = $ImagesTable(this); + late final $TrashesTable trashes = $TrashesTable(this); + late final $DirFilesTable dirFiles = $DirFilesTable(this); + late final $AlbumsTable albums = $AlbumsTable(this); + late final $AlbumSharesTable albumShares = $AlbumSharesTable(this); + @override + Iterable get allTables => allSchemaEntities.whereType(); + @override + List get allSchemaEntities => [ + servers, + accounts, + files, + accountFiles, + images, + trashes, + dirFiles, + albums, + albumShares + ]; +} diff --git a/app/lib/entity/sqlite_table_converter.dart b/app/lib/entity/sqlite_table_converter.dart new file mode 100644 index 00000000..c134000d --- /dev/null +++ b/app/lib/entity/sqlite_table_converter.dart @@ -0,0 +1,141 @@ +import 'dart:convert'; + +import 'package:drift/drift.dart'; +import 'package:nc_photos/ci_string.dart'; +import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/album/cover_provider.dart'; +import 'package:nc_photos/entity/album/provider.dart'; +import 'package:nc_photos/entity/album/sort_provider.dart'; +import 'package:nc_photos/entity/exif.dart'; +import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; +import 'package:nc_photos/object_extension.dart'; + +class SqliteAlbumConverter { + static Album fromSql( + sql.Album album, File albumFile, List shares) { + return Album( + lastUpdated: album.lastUpdated, + name: album.name, + provider: AlbumProvider.fromJson({ + "type": album.providerType, + "content": jsonDecode(album.providerContent), + }), + coverProvider: AlbumCoverProvider.fromJson({ + "type": album.coverProviderType, + "content": jsonDecode(album.coverProviderContent), + }), + sortProvider: AlbumSortProvider.fromJson({ + "type": album.sortProviderType, + "content": jsonDecode(album.sortProviderContent), + }), + shares: shares.isEmpty + ? null + : shares + .map((e) => AlbumShare( + userId: e.userId.toCi(), + displayName: e.displayName, + sharedAt: e.sharedAt.toUtc(), + )) + .toList(), + albumFile: albumFile, + savedVersion: album.version, + ); + } + + static sql.CompleteAlbumCompanion toSql(Album album, int albumFileRowId) { + final providerJson = album.provider.toJson(); + final coverProviderJson = album.coverProvider.toJson(); + final sortProviderJson = album.sortProvider.toJson(); + final dbAlbum = sql.AlbumsCompanion.insert( + file: albumFileRowId, + version: Album.version, + lastUpdated: album.lastUpdated, + name: album.name, + providerType: providerJson["type"], + providerContent: jsonEncode(providerJson["content"]), + coverProviderType: coverProviderJson["type"], + coverProviderContent: jsonEncode(coverProviderJson["content"]), + sortProviderType: sortProviderJson["type"], + sortProviderContent: jsonEncode(sortProviderJson["content"]), + ); + final dbAlbumShares = album.shares + ?.map((s) => sql.AlbumSharesCompanion( + userId: Value(s.userId.toCaseInsensitiveString()), + displayName: Value(s.displayName), + sharedAt: Value(s.sharedAt), + )) + .toList(); + return sql.CompleteAlbumCompanion(dbAlbum, dbAlbumShares ?? []); + } +} + +class SqliteFileConverter { + static File fromSql(String homeDir, sql.CompleteFile f) { + final metadata = f.image?.run((obj) => Metadata( + lastUpdated: obj.lastUpdated, + fileEtag: obj.fileEtag, + imageWidth: obj.width, + imageHeight: obj.height, + exif: obj.exifRaw?.run((e) => Exif.fromJson(jsonDecode(e))), + )); + return File( + path: "remote.php/dav/files/$homeDir/${f.accountFile.relativePath}", + contentLength: f.file.contentLength, + contentType: f.file.contentType, + etag: f.file.etag, + lastModified: f.file.lastModified, + isCollection: f.file.isCollection, + usedBytes: f.file.usedBytes, + hasPreview: f.file.hasPreview, + fileId: f.file.fileId, + isFavorite: f.accountFile.isFavorite, + ownerId: f.file.ownerId?.toCi(), + trashbinFilename: f.trash?.filename, + trashbinOriginalLocation: f.trash?.originalLocation, + trashbinDeletionTime: f.trash?.deletionTime, + metadata: metadata, + isArchived: f.accountFile.isArchived, + overrideDateTime: f.accountFile.overrideDateTime, + ); + } + + static sql.CompleteFileCompanion toSql(sql.Account? account, File file) { + final dbFile = sql.FilesCompanion( + server: account == null ? const Value.absent() : Value(account.server), + fileId: Value(file.fileId!), + contentLength: Value(file.contentLength), + contentType: Value(file.contentType), + etag: Value(file.etag), + lastModified: Value(file.lastModified), + isCollection: Value(file.isCollection), + usedBytes: Value(file.usedBytes), + hasPreview: Value(file.hasPreview), + ownerId: Value(file.ownerId!.toCaseInsensitiveString()), + ); + final dbAccountFile = sql.AccountFilesCompanion( + account: account == null ? const Value.absent() : Value(account.rowId), + relativePath: Value(file.strippedPathWithEmpty), + isFavorite: Value(file.isFavorite), + isArchived: Value(file.isArchived), + overrideDateTime: Value(file.overrideDateTime), + ); + final dbImage = file.metadata?.run((m) => sql.ImagesCompanion.insert( + lastUpdated: m.lastUpdated, + fileEtag: Value(m.fileEtag), + width: Value(m.imageWidth), + height: Value(m.imageHeight), + exifRaw: Value(m.exif?.toJson().run((j) => jsonEncode(j))), + dateTimeOriginal: Value(m.exif?.dateTimeOriginal), + )); + final dbTrash = file.trashbinDeletionTime == null + ? null + : sql.TrashesCompanion.insert( + filename: file.trashbinFilename!, + originalLocation: file.trashbinOriginalLocation!, + deletionTime: file.trashbinDeletionTime!, + ); + return sql.CompleteFileCompanion(dbFile, dbAccountFile, dbImage, dbTrash); + } +} diff --git a/app/lib/entity/sqlite_table_extension.dart b/app/lib/entity/sqlite_table_extension.dart new file mode 100644 index 00000000..e72fb356 --- /dev/null +++ b/app/lib/entity/sqlite_table_extension.dart @@ -0,0 +1,538 @@ +import 'package:drift/drift.dart'; +import 'package:nc_photos/account.dart' as app; +import 'package:nc_photos/entity/file.dart' as app; +import 'package:nc_photos/entity/sqlite_table.dart'; +import 'package:nc_photos/entity/sqlite_table_converter.dart'; +import 'package:nc_photos/entity/sqlite_table_isolate.dart'; +import 'package:nc_photos/future_extension.dart'; +import 'package:nc_photos/iterable_extension.dart'; +import 'package:nc_photos/k.dart' as k; +import 'package:nc_photos/mobile/platform.dart' + if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; +import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/platform/k.dart' as platform_k; + +class CompleteFile { + const CompleteFile(this.file, this.accountFile, this.image, this.trash); + + final File file; + final AccountFile accountFile; + final Image? image; + final Trash? trash; +} + +class CompleteFileCompanion { + const CompleteFileCompanion( + this.file, this.accountFile, this.image, this.trash); + + final FilesCompanion file; + final AccountFilesCompanion accountFile; + final ImagesCompanion? image; + final TrashesCompanion? trash; +} + +extension CompleteFileListExtension on List { + Future> convertToAppFile(app.Account account) { + return map((f) => { + "homeDir": account.homeDir.toString(), + "completeFile": f, + }).computeAll(_covertSqliteDbFile); + } +} + +extension FileListExtension on List { + Future> convertToFileCompanion(Account? account) { + return map((f) => { + "account": account, + "file": f, + }).computeAll(_convertAppFile); + } +} + +class AlbumWithShare { + const AlbumWithShare(this.album, this.share); + + final Album album; + final AlbumShare? share; +} + +class CompleteAlbumCompanion { + const CompleteAlbumCompanion(this.album, this.albumShares); + + final AlbumsCompanion album; + final List albumShares; +} + +class AccountFileRowIds { + const AccountFileRowIds( + this.accountFileRowId, this.accountRowId, this.fileRowId); + + final int accountFileRowId; + final int accountRowId; + final int fileRowId; +} + +class AccountFileRowIdsWithFileId { + const AccountFileRowIdsWithFileId( + this.accountFileRowId, this.accountRowId, this.fileRowId, this.fileId); + + final int accountFileRowId; + final int accountRowId; + final int fileRowId; + final int fileId; +} + +extension SqliteDbExtension on SqliteDb { + /// Start a transaction and run [block] + /// + /// The [db] argument passed to [block] is identical to this + /// + /// Do NOT call this when using [isolate], call [useInIsolate] instead + Future use(Future Function(SqliteDb db) block) async { + return await platform.Lock.synchronized(k.appDbLockId, () async { + return await transaction(() async { + return await block(this); + }); + }); + } + + /// Start an isolate and run [callback] there, with access to the + /// SQLite database + Future isolate(T args, ComputeWithDbCallback callback) async { + // we need to acquire the lock here as method channel is not supported in + // background isolates + return await platform.Lock.synchronized(k.appDbLockId, () async { + // in unit tests we use an in-memory db, which mean there's no way to + // access it in other isolates + if (platform_k.isUnitTest) { + return await callback(this, args); + } else { + return await computeWithDb(callback, args); + } + }); + } + + /// Start a transaction and run [block], this version is suitable to be called + /// in [isolate] + /// + /// See: [use] + Future useInIsolate(Future Function(SqliteDb db) block) async { + return await transaction(() async { + return await block(this); + }); + } + + Future insertAccountOf(app.Account account) async { + Server dbServer; + try { + dbServer = await into(servers).insertReturning( + ServersCompanion.insert( + address: account.url, + ), + mode: InsertMode.insertOrIgnore, + ); + } on StateError catch (_) { + // already exists + final query = select(servers) + ..where((t) => t.address.equals(account.url)); + dbServer = await query.getSingle(); + } + await into(accounts).insert( + AccountsCompanion.insert( + server: dbServer.rowId, + userId: account.username.toCaseInsensitiveString(), + ), + mode: InsertMode.insertOrIgnore, + ); + } + + Future accountOf(app.Account account) { + final query = select(accounts).join([ + innerJoin(servers, servers.rowId.equalsExp(accounts.server), + useColumns: false) + ]) + ..where(servers.address.equals(account.url)) + ..where( + accounts.userId.equals(account.username.toCaseInsensitiveString())) + ..limit(1); + return query.map((r) => r.readTable(accounts)).getSingle(); + } + + FilesQueryBuilder queryFiles() => FilesQueryBuilder(this); + + /// Query File by app File + /// + /// Only one of [sqlAccount] and [appAccount] must be passed + Future fileOf( + app.File file, { + Account? sqlAccount, + app.Account? appAccount, + }) { + assert((sqlAccount != null) != (appAccount != null)); + final query = queryFiles().run((q) { + q.setQueryMode(FilesQueryMode.file); + if (sqlAccount != null) { + q.setSqlAccount(sqlAccount); + } else { + q.setAppAccount(appAccount!); + } + if (file.fileId != null) { + q.byFileId(file.fileId!); + } else { + q.byRelativePath(file.strippedPathWithEmpty); + } + return q.build()..limit(1); + }); + return query.map((r) => r.readTable(files)).getSingle(); + } + + /// Query AccountFiles, Accounts and Files row ID by app File + /// + /// Only one of [sqlAccount] and [appAccount] must be passed + Future accountFileRowIdsOfOrNull( + app.File file, { + Account? sqlAccount, + app.Account? appAccount, + }) { + assert((sqlAccount != null) != (appAccount != null)); + final query = queryFiles().run((q) { + q.setQueryMode(FilesQueryMode.expression, expressions: [ + accountFiles.rowId, + accountFiles.account, + accountFiles.file, + ]); + if (sqlAccount != null) { + q.setSqlAccount(sqlAccount); + } else { + q.setAppAccount(appAccount!); + } + if (file.fileId != null) { + q.byFileId(file.fileId!); + } else { + q.byRelativePath(file.strippedPathWithEmpty); + } + return q.build()..limit(1); + }); + return query + .map((r) => AccountFileRowIds( + r.read(accountFiles.rowId)!, + r.read(accountFiles.account)!, + r.read(accountFiles.file)!, + )) + .getSingleOrNull(); + } + + /// See [accountFileRowIdsOfOrNull] + Future accountFileRowIdsOf( + app.File file, { + Account? sqlAccount, + app.Account? appAccount, + }) => + accountFileRowIdsOfOrNull(file, + sqlAccount: sqlAccount, appAccount: appAccount) + .notNull(); + + /// Query AccountFiles, Accounts and Files row ID by fileIds + /// + /// Returned files are NOT guaranteed to be sorted as [fileIds] + Future> accountFileRowIdsByFileIds( + Iterable fileIds, { + Account? sqlAccount, + app.Account? appAccount, + }) { + assert((sqlAccount != null) != (appAccount != null)); + final query = queryFiles().run((q) { + q.setQueryMode(FilesQueryMode.expression, expressions: [ + accountFiles.rowId, + accountFiles.account, + accountFiles.file, + files.fileId, + ]); + if (sqlAccount != null) { + q.setSqlAccount(sqlAccount); + } else { + q.setAppAccount(appAccount!); + } + q.byFileIds(fileIds); + return q.build(); + }); + return query + .map((r) => AccountFileRowIdsWithFileId( + r.read(accountFiles.rowId)!, + r.read(accountFiles.account)!, + r.read(accountFiles.file)!, + r.read(files.fileId)!, + )) + .get(); + } + + /// Query CompleteFile by fileId + /// + /// Returned files are NOT guaranteed to be sorted as [fileIds] + Future> completeFilesByFileIds( + Iterable fileIds, { + Account? sqlAccount, + app.Account? appAccount, + }) { + assert((sqlAccount != null) != (appAccount != null)); + final query = queryFiles().run((q) { + q.setQueryMode(FilesQueryMode.completeFile); + if (sqlAccount != null) { + q.setSqlAccount(sqlAccount); + } else { + q.setAppAccount(appAccount!); + } + q.byFileIds(fileIds); + return q.build(); + }); + return query + .map((r) => CompleteFile( + r.readTable(files), + r.readTable(accountFiles), + r.readTableOrNull(images), + r.readTableOrNull(trashes), + )) + .get(); + } + + Future> completeFilesByDirRowId( + int dirRowId, { + Account? sqlAccount, + app.Account? appAccount, + }) { + assert((sqlAccount != null) != (appAccount != null)); + final query = queryFiles().run((q) { + q.setQueryMode(FilesQueryMode.completeFile); + if (sqlAccount != null) { + q.setSqlAccount(sqlAccount); + } else { + q.setAppAccount(appAccount!); + } + q.byDirRowId(dirRowId); + return q.build(); + }); + return query + .map((r) => CompleteFile( + r.readTable(files), + r.readTable(accountFiles), + r.readTableOrNull(images), + r.readTableOrNull(trashes), + )) + .get(); + } + + /// Query CompleteFile by favorite + Future> completeFilesByFavorite({ + Account? sqlAccount, + app.Account? appAccount, + }) { + assert((sqlAccount != null) != (appAccount != null)); + final query = queryFiles().run((q) { + q.setQueryMode(FilesQueryMode.completeFile); + if (sqlAccount != null) { + q.setSqlAccount(sqlAccount); + } else { + q.setAppAccount(appAccount!); + } + q.byFavorite(true); + return q.build(); + }); + return query + .map((r) => CompleteFile( + r.readTable(files), + r.readTable(accountFiles), + r.readTableOrNull(images), + r.readTableOrNull(trashes), + )) + .get(); + } +} + +enum FilesQueryMode { + file, + completeFile, + expression, +} + +/// Build a Files table query +/// +/// If you call more than one by* methods, the condition will be added up +/// instead of replaced. No validations will be made to make sure the resulting +/// conditions make sense +class FilesQueryBuilder { + FilesQueryBuilder(this.db); + + /// Set the query mode + /// + /// If [mode] == FilesQueryMode.expression, [expressions] must be defined and + /// not empty + void setQueryMode( + FilesQueryMode mode, { + Iterable? expressions, + }) { + assert( + (mode == FilesQueryMode.expression) != (expressions?.isEmpty != false)); + _queryMode = mode; + _selectExpressions = expressions; + } + + void setSqlAccount(Account account) { + assert(_appAccount == null); + _sqlAccount = account; + } + + void setAppAccount(app.Account account) { + assert(_sqlAccount == null); + _appAccount = account; + } + + void setAccountless() { + assert(_sqlAccount == null && _appAccount == null); + _isAccountless = true; + } + + void byRowId(int rowId) { + _byRowId = rowId; + } + + void byFileId(int fileId) { + _byFileId = fileId; + } + + void byFileIds(Iterable fileIds) { + _byFileIds = fileIds; + } + + void byRelativePath(String path) { + _byRelativePath = path; + } + + void byRelativePathPattern(String pattern) { + _byRelativePathPattern = pattern; + } + + void byMimePattern(String pattern) { + (_byMimePatterns ??= []).add(pattern); + } + + void byFavorite(bool favorite) { + _byFavorite = favorite; + } + + void byDirRowId(int dirRowId) { + _byDirRowId = dirRowId; + } + + void byServerRowId(int serverRowId) { + _byServerRowId = serverRowId; + } + + JoinedSelectStatement build() { + if (_sqlAccount == null && _appAccount == null && !_isAccountless) { + throw StateError("Invalid query: missing account"); + } + final dynamic select = _queryMode == FilesQueryMode.expression + ? db.selectOnly(db.files) + : db.select(db.files); + final query = select.join([ + innerJoin(db.accountFiles, db.accountFiles.file.equalsExp(db.files.rowId), + useColumns: _queryMode == FilesQueryMode.completeFile), + if (_appAccount != null) ...[ + innerJoin( + db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account), + useColumns: false), + innerJoin(db.servers, db.servers.rowId.equalsExp(db.accounts.server), + useColumns: false), + ], + if (_byDirRowId != null) + innerJoin(db.dirFiles, db.dirFiles.child.equalsExp(db.files.rowId), + useColumns: false), + if (_queryMode == FilesQueryMode.completeFile) ...[ + leftOuterJoin( + db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)), + leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)), + ], + ]) as JoinedSelectStatement; + if (_queryMode == FilesQueryMode.expression) { + query.addColumns(_selectExpressions!); + } + + if (_sqlAccount != null) { + query.where(db.accountFiles.account.equals(_sqlAccount!.rowId)); + } else if (_appAccount != null) { + query + ..where(db.servers.address.equals(_appAccount!.url)) + ..where(db.accounts.userId + .equals(_appAccount!.username.toCaseInsensitiveString())); + } + + if (_byRowId != null) { + query.where(db.files.rowId.equals(_byRowId)); + } + if (_byFileId != null) { + query.where(db.files.fileId.equals(_byFileId)); + } + if (_byFileIds != null) { + query.where(db.files.fileId.isIn(_byFileIds!)); + } + if (_byRelativePath != null) { + query.where(db.accountFiles.relativePath.equals(_byRelativePath)); + } + if (_byRelativePathPattern != null) { + query.where(db.accountFiles.relativePath.like(_byRelativePathPattern!)); + } + if (_byMimePatterns?.isNotEmpty == true) { + final expression = _byMimePatterns!.sublist(1).fold>( + db.files.contentType.like(_byMimePatterns![0]), + (previousValue, element) => + previousValue | db.files.contentType.like(element)); + query.where(expression); + } + if (_byFavorite != null) { + if (_byFavorite!) { + query.where(db.accountFiles.isFavorite.equals(true)); + } else { + // null are treated as false + query.where(db.accountFiles.isFavorite.equals(true).not()); + } + } + if (_byDirRowId != null) { + query.where(db.dirFiles.dir.equals(_byDirRowId)); + } + if (_byServerRowId != null) { + query.where(db.files.server.equals(_byServerRowId)); + } + return query; + } + + final SqliteDb db; + + FilesQueryMode _queryMode = FilesQueryMode.file; + Iterable? _selectExpressions; + + Account? _sqlAccount; + app.Account? _appAccount; + bool _isAccountless = false; + + int? _byRowId; + int? _byFileId; + Iterable? _byFileIds; + String? _byRelativePath; + String? _byRelativePathPattern; + List? _byMimePatterns; + bool? _byFavorite; + int? _byDirRowId; + int? _byServerRowId; +} + +app.File _covertSqliteDbFile(Map map) { + final homeDir = map["homeDir"] as String; + final file = map["completeFile"] as CompleteFile; + return SqliteFileConverter.fromSql(homeDir, file); +} + +CompleteFileCompanion _convertAppFile(Map map) { + final account = map["account"] as Account?; + final file = map["file"] as app.File; + return SqliteFileConverter.toSql(account, file); +} diff --git a/app/lib/entity/sqlite_table_isolate.dart b/app/lib/entity/sqlite_table_isolate.dart new file mode 100644 index 00000000..9eb48d3e --- /dev/null +++ b/app/lib/entity/sqlite_table_isolate.dart @@ -0,0 +1,87 @@ +import 'dart:isolate'; + +import 'package:drift/drift.dart'; +import 'package:drift/isolate.dart'; +import 'package:flutter/foundation.dart'; +import 'package:nc_photos/entity/sqlite_table.dart'; +import 'package:nc_photos/mobile/platform.dart' + if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; + +typedef ComputeWithDbCallback = Future Function( + SqliteDb db, T message); + +/// Create a drift db running in an isolate +/// +/// This is only expected to be used in the main isolate +Future createDb() async { + // see: https://drift.simonbinder.eu/docs/advanced-features/isolates/ + final driftIsolate = await _createDriftIsolate(); + final connection = await driftIsolate.connect(); + return SqliteDb.connect(connection); +} + +Future computeWithDb( + ComputeWithDbCallback callback, T args) async { + return await compute( + _computeWithDbImpl, + _ComputeWithDbMessage( + await platform.getSqliteConnectionArgs(), callback, args), + ); +} + +class _IsolateStartRequest { + const _IsolateStartRequest(this.sendDriftIsolate, this.platformArgs); + + final SendPort sendDriftIsolate; + final Map platformArgs; +} + +class _ComputeWithDbMessage { + const _ComputeWithDbMessage( + this.sqliteConnectionArgs, this.callback, this.args); + + final Map sqliteConnectionArgs; + final ComputeWithDbCallback callback; + final T args; +} + +Future _createDriftIsolate() async { + final args = await platform.getSqliteConnectionArgs(); + final receivePort = ReceivePort(); + await Isolate.spawn( + _startBackground, + _IsolateStartRequest(receivePort.sendPort, args), + ); + // _startBackground will send the DriftIsolate to this ReceivePort + return await receivePort.first as DriftIsolate; +} + +void _startBackground(_IsolateStartRequest request) { + // this is the entry point from the background isolate! Let's create + // the database from the path we received + final executor = platform.openSqliteConnectionWithArgs(request.platformArgs); + // we're using DriftIsolate.inCurrent here as this method already runs on a + // background isolate. If we used DriftIsolate.spawn, a third isolate would be + // started which is not what we want! + final driftIsolate = DriftIsolate.inCurrent( + () => DatabaseConnection.fromExecutor(executor), + // this breaks background service! + serialize: false, + ); + // inform the starting isolate about this, so that it can call .connect() + request.sendDriftIsolate.send(driftIsolate); +} + +Future _computeWithDbImpl(_ComputeWithDbMessage message) async { + // we don't use driftIsolate because opening a DB normally is found to perform + // better + final sqliteDb = SqliteDb( + executor: + platform.openSqliteConnectionWithArgs(message.sqliteConnectionArgs), + ); + try { + return await message.callback(sqliteDb, message.args); + } finally { + await sqliteDb.close(); + } +} diff --git a/app/lib/future_util.dart b/app/lib/future_util.dart new file mode 100644 index 00000000..39c03ad5 --- /dev/null +++ b/app/lib/future_util.dart @@ -0,0 +1,33 @@ +import 'dart:async'; + +import 'package:nc_photos/iterable_extension.dart'; + +Future> waitOr( + Iterable> futures, + T Function(Object error, StackTrace? stackTrace) onError, +) async { + final completer = Completer>(); + final results = List.filled(futures.length, null); + var remaining = results.length; + if (remaining == 0) { + return Future.value(const []); + } + + void onResult() { + if (--remaining <= 0) { + // finished + completer.complete(results.cast()); + } + } + + for (final p in futures.withIndex()) { + p.item2.then((value) { + results[p.item1] = value; + onResult(); + }).onError((error, stackTrace) { + results[p.item1] = onError(error!, stackTrace); + onResult(); + }); + } + return completer.future; +} diff --git a/app/lib/iterable_extension.dart b/app/lib/iterable_extension.dart index f253e157..93a624ba 100644 --- a/app/lib/iterable_extension.dart +++ b/app/lib/iterable_extension.dart @@ -67,8 +67,13 @@ extension IterableExtension on Iterable { } Future> computeAll(ComputeCallback callback) async { - return await compute( - _computeAllImpl, _ComputeAllMessage(callback, asList())); + final list = asList(); + if (list.isEmpty) { + return []; + } else { + return await compute( + _computeAllImpl, _ComputeAllMessage(callback, list)); + } } /// Return a list containing elements in this iterable diff --git a/app/lib/list_util.dart b/app/lib/list_util.dart index 7334d767..e426c1dc 100644 --- a/app/lib/list_util.dart +++ b/app/lib/list_util.dart @@ -9,7 +9,7 @@ import 'package:tuple/tuple.dart'; /// The first returned list contains items exist in [b] but not [a], the second /// returned list contains items exist in [a] but not [b] Tuple2, List> diffWith( - List a, List b, int Function(T a, T b) comparator) { + Iterable a, Iterable b, int Function(T a, T b) comparator) { final aIt = a.iterator, bIt = b.iterator; final aMissing = [], bMissing = []; while (true) { @@ -31,7 +31,8 @@ Tuple2, List> diffWith( } } -Tuple2, List> diff(List a, List b) => +Tuple2, List> diff( + Iterable a, Iterable b) => diffWith(a, b, Comparable.compare); Tuple2, List> _diffUntilEqual( diff --git a/app/lib/main.dart b/app/lib/main.dart index 20fee5bc..a8e8cbf6 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -9,7 +9,7 @@ import 'package:nc_photos/widget/my_app.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - await app_init.initAppLaunch(); + await app_init.init(app_init.InitIsolateType.main); if (platform_k.isMobile) { // reset orientation override just in case, see #59 diff --git a/app/lib/metadata_task_manager.dart b/app/lib/metadata_task_manager.dart index cb7608c3..0fd46d60 100644 --- a/app/lib/metadata_task_manager.dart +++ b/app/lib/metadata_task_manager.dart @@ -4,9 +4,8 @@ import 'package:event_bus/event_bus.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/pref.dart'; @@ -14,7 +13,9 @@ import 'package:nc_photos/use_case/update_missing_metadata.dart'; /// Task to update metadata for missing files class MetadataTask { - MetadataTask(this.account, this.pref); + MetadataTask(this._c, this.account, this.pref) : assert(require(_c)); + + static bool require(DiContainer c) => DiContainer.has(c, DiType.fileRepo); @override toString() { @@ -28,12 +29,11 @@ class MetadataTask { final shareFolder = File(path: file_util.unstripPath(account, pref.getShareFolderOr())); bool hasScanShareFolder = false; - final fileRepo = FileRepo(FileCachedDataSource(AppDb())); for (final r in account.roots) { final dir = File(path: file_util.unstripPath(account, r)); hasScanShareFolder |= file_util.isOrUnderDir(shareFolder, dir); final op = UpdateMissingMetadata( - fileRepo, const _UpdateMissingMetadataConfigProvider()); + _c.fileRepo, const _UpdateMissingMetadataConfigProvider()); await for (final _ in op(account, dir)) { if (!Pref().isEnableExifOr()) { _log.info("[call] EXIF disabled, task ending immaturely"); @@ -44,7 +44,7 @@ class MetadataTask { } if (!hasScanShareFolder) { final op = UpdateMissingMetadata( - fileRepo, const _UpdateMissingMetadataConfigProvider()); + _c.fileRepo, const _UpdateMissingMetadataConfigProvider()); await for (final _ in op( account, shareFolder, @@ -65,6 +65,8 @@ class MetadataTask { } } + final DiContainer _c; + final Account account; final AccountPref pref; diff --git a/app/lib/mobile/db_util.dart b/app/lib/mobile/db_util.dart index 806c78e8..45592ea7 100644 --- a/app/lib/mobile/db_util.dart +++ b/app/lib/mobile/db_util.dart @@ -1,4 +1,31 @@ -import 'package:idb_sqflite/idb_sqflite.dart'; -import 'package:sqflite/sqflite.dart'; +import 'dart:io' as dart; -IdbFactory getDbFactory() => getIdbFactorySqflite(databaseFactory); +import 'package:drift/drift.dart'; +import 'package:drift/native.dart'; +import 'package:path/path.dart' as path_lib; +import 'package:path_provider/path_provider.dart'; + +Future> getSqliteConnectionArgs() async { + // put the database file, called db.sqlite here, into the documents folder + // for your app. + final dbFolder = await getApplicationDocumentsDirectory(); + return { + "path": path_lib.join(dbFolder.path, "db.sqlite"), + }; +} + +QueryExecutor openSqliteConnectionWithArgs(Map args) { + final file = dart.File(args["path"]); + return NativeDatabase( + file, + // logStatements: true, + ); +} + +QueryExecutor openSqliteConnection() { + // the LazyDatabase util lets us find the right location for the file async. + return LazyDatabase(() async { + final args = await getSqliteConnectionArgs(); + return openSqliteConnectionWithArgs(args); + }); +} diff --git a/app/lib/platform/k.dart b/app/lib/platform/k.dart index f0deb7c1..9853cdb6 100644 --- a/app/lib/platform/k.dart +++ b/app/lib/platform/k.dart @@ -8,3 +8,4 @@ final isMobile = !kIsWeb && (Platform.isAndroid || Platform.isIOS); final isAndroid = !kIsWeb && Platform.isAndroid; final isDesktop = !kIsWeb && (Platform.isLinux || Platform.isMacOS || Platform.isWindows); +final isUnitTest = !kIsWeb && Platform.environment.containsKey("FLUTTER_TEST"); diff --git a/app/lib/service.dart b/app/lib/service.dart index 8f5fa8a9..88a36225 100644 --- a/app/lib/service.dart +++ b/app/lib/service.dart @@ -3,13 +3,13 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_background_service/flutter_background_service.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations_en.dart'; +import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_init.dart' as app_init; import 'package:nc_photos/app_localizations.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/event/native_event.dart'; @@ -69,7 +69,7 @@ class _Service { final service = FlutterBackgroundService(); service.setForegroundMode(true); - await app_init.initAppLaunch(); + await app_init.init(app_init.InitIsolateType.service); await _L10n().init(); _log.info("[call] Service started"); @@ -87,6 +87,7 @@ class _Service { } onCancelSubscription.cancel(); onDataSubscription.cancel(); + await KiwiContainer().resolve().sqliteDb.close(); service.stopBackgroundService(); _log.info("[call] Service stopped"); } @@ -235,12 +236,12 @@ class _MetadataTask { final shareFolder = File( path: file_util.unstripPath(account, accountPref.getShareFolderOr())); bool hasScanShareFolder = false; - final fileRepo = FileRepo(FileCachedDataSource(AppDb())); + final c = KiwiContainer().resolve(); for (final r in account.roots) { final dir = File(path: file_util.unstripPath(account, r)); hasScanShareFolder |= file_util.isOrUnderDir(shareFolder, dir); final updater = UpdateMissingMetadata( - fileRepo, const _UpdateMissingMetadataConfigProvider()); + c.fileRepo, const _UpdateMissingMetadataConfigProvider()); void onServiceStop() { _log.info("[_updateMetadata] Stopping task: user canceled"); updater.stop(); @@ -263,7 +264,7 @@ class _MetadataTask { } if (!hasScanShareFolder) { final shareUpdater = UpdateMissingMetadata( - fileRepo, const _UpdateMissingMetadataConfigProvider()); + c.fileRepo, const _UpdateMissingMetadataConfigProvider()); void onServiceStop() { _log.info("[_updateMetadata] Stopping task: user canceled"); shareUpdater.stop(); diff --git a/app/lib/share_handler.dart b/app/lib/share_handler.dart index a3e98395..a9cb50a9 100644 --- a/app/lib/share_handler.dart +++ b/app/lib/share_handler.dart @@ -6,12 +6,10 @@ import 'package:flutter/services.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/local_file.dart'; import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/share/data_source.dart'; @@ -179,9 +177,9 @@ class ShareHandler { clearSelection?.call(); isSelectionCleared = true; - final fileRepo = FileRepo(FileCachedDataSource(AppDb())); - final path = await _createDir(fileRepo, account, result.albumName); - await _copyFilesToDir(fileRepo, account, files, path); + final c = KiwiContainer().resolve(); + final path = await _createDir(c.fileRepo, account, result.albumName); + await _copyFilesToDir(c.fileRepo, account, files, path); controller?.close(); return _shareFileAsLink( account, diff --git a/app/lib/use_case/add_to_album.dart b/app/lib/use_case/add_to_album.dart index d115b794..a239faf6 100644 --- a/app/lib/use_case/add_to_album.dart +++ b/app/lib/use_case/add_to_album.dart @@ -17,12 +17,12 @@ import 'package:nc_photos/use_case/update_album_with_actual_items.dart'; class AddToAlbum { AddToAlbum(this._c) : assert(require(_c)), - assert(ListShare.require(_c)); + assert(ListShare.require(_c)), + assert(PreProcessAlbum.require(_c)); static bool require(DiContainer c) => DiContainer.has(c, DiType.albumRepo) && - DiContainer.has(c, DiType.shareRepo) && - DiContainer.has(c, DiType.appDb); + DiContainer.has(c, DiType.shareRepo); /// Add a list of AlbumItems to [album] Future call( @@ -30,7 +30,7 @@ class AddToAlbum { _log.info("[call] Add ${items.length} items to album '${album.name}'"); assert(album.provider is AlbumStaticProvider); // resync is needed to work out album cover and latest item - final oldItems = await PreProcessAlbum(_c.appDb)(account, album); + final oldItems = await PreProcessAlbum(_c)(account, album); final itemSet = oldItems .map((e) => OverrideComparator( e, _isItemFileEqual, _getItemHashCode)) diff --git a/app/lib/use_case/cache_favorite.dart b/app/lib/use_case/cache_favorite.dart index bf84419a..2a95ec25 100644 --- a/app/lib/use_case/cache_favorite.dart +++ b/app/lib/use_case/cache_favorite.dart @@ -1,12 +1,12 @@ +import 'package:drift/drift.dart' as sql; import 'package:event_bus/event_bus.dart'; -import 'package:idb_shim/idb_client.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; -import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/list_util.dart' as list_util; @@ -17,7 +17,7 @@ class CacheFavorite { : assert(require(_c)), assert(ListFavoriteOffline.require(_c)); - static bool require(DiContainer c) => DiContainer.has(c, DiType.appDb); + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); /// Cache favorites Future call( @@ -34,39 +34,45 @@ class CacheFavorite { final newFavorites = result.item1; final removedFavorites = result.item2.map((f) => f.copyWith(isFavorite: false)).toList(); - if (newFavorites.isEmpty && removedFavorites.isEmpty) { + final newFileIds = newFavorites.map((f) => f.fileId!).toList(); + final removedFileIds = removedFavorites.map((f) => f.fileId!).toList(); + if (newFileIds.isEmpty && removedFileIds.isEmpty) { return; } - await _c.appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadWrite), - (transaction) async { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - await Future.wait(newFavorites.map((f) async { - _log.info("[call] New favorite: ${f.path}"); + await _c.sqliteDb.use((db) async { + final rowIds = await db.accountFileRowIdsByFileIds( + newFileIds + removedFileIds, + appAccount: account, + ); + final rowIdsMap = + Map.fromEntries(rowIds.map((e) => MapEntry(e.fileId, e))); + await db.batch((batch) { + for (final id in newFileIds) { try { - await fileStore.put(AppDbFile2Entry.fromFile(account, f).toJson(), - AppDbFile2Entry.toPrimaryKeyForFile(account, f)); + batch.update( + db.accountFiles, + const sql.AccountFilesCompanion(isFavorite: sql.Value(true)), + where: (sql.$AccountFilesTable t) => + t.rowId.equals(rowIdsMap[id]!.accountFileRowId), + ); } catch (e, stackTrace) { - _log.shout( - "[call] Failed while writing new favorite to AppDb: ${logFilename(f.path)}", - e, - stackTrace); + _log.shout("[call] File not found in DB: $id", e, stackTrace); } - })); - await Future.wait(removedFavorites.map((f) async { - _log.info("[call] Remove favorite: ${f.path}"); + } + for (final id in removedFileIds) { try { - await fileStore.put(AppDbFile2Entry.fromFile(account, f).toJson(), - AppDbFile2Entry.toPrimaryKeyForFile(account, f)); + batch.update( + db.accountFiles, + const sql.AccountFilesCompanion(isFavorite: sql.Value(null)), + where: (sql.$AccountFilesTable t) => + t.rowId.equals(rowIdsMap[id]!.accountFileRowId), + ); } catch (e, stackTrace) { - _log.shout( - "[call] Failed while writing removed favorite to AppDb: ${logFilename(f.path)}", - e, - stackTrace); + _log.shout("[call] File not found in DB: $id", e, stackTrace); } - })); - }, - ); + } + }); + }); KiwiContainer() .resolve() diff --git a/app/lib/use_case/compat/v37.dart b/app/lib/use_case/compat/v37.dart deleted file mode 100644 index 64cc58cf..00000000 --- a/app/lib/use_case/compat/v37.dart +++ /dev/null @@ -1,211 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:idb_shim/idb_client.dart'; -import 'package:logging/logging.dart'; -import 'package:nc_photos/app_db.dart'; -import 'package:nc_photos/entity/file_util.dart' as file_util; -import 'package:nc_photos/iterable_extension.dart'; -import 'package:nc_photos/object_extension.dart'; -import 'package:path/path.dart' as path_lib; - -/// Compatibility helper for v37 -class CompatV37 { - static Future setAppDbMigrationFlag(AppDb appDb) async { - _log.info("[setAppDbMigrationFlag] Set db flag"); - try { - await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadWrite), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - await metaStore - .put(const AppDbMetaEntryCompatV37(false).toEntry().toJson()); - await transaction.completed; - }, - ); - } catch (e, stackTrace) { - _log.shout( - "[setAppDbMigrationFlag] Failed while setting db flag, drop db instead", - e, - stackTrace); - await appDb.delete(); - } - } - - static Future isAppDbNeedMigration(AppDb appDb) async { - final dbItem = await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadOnly), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - return await metaStore.getObject(AppDbMetaEntryCompatV37.key) as Map?; - }, - ); - if (dbItem == null) { - return false; - } - try { - final dbEntry = AppDbMetaEntry.fromJson(dbItem.cast()); - final compatV37 = AppDbMetaEntryCompatV37.fromJson(dbEntry.obj); - return !compatV37.isMigrated; - } catch (e, stackTrace) { - _log.shout("[isAppDbNeedMigration] Failed", e, stackTrace); - return true; - } - } - - static Future migrateAppDb(AppDb appDb) async { - _log.info("[migrateAppDb] Migrate AppDb"); - try { - await appDb.use( - (db) => db.transaction( - [AppDb.file2StoreName, AppDb.dirStoreName, AppDb.metaStoreName], - idbModeReadWrite), - (transaction) async { - final noMediaFiles = <_NoMediaFile>[]; - try { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - final dirStore = transaction.objectStore(AppDb.dirStoreName); - // scan the db to see which dirs contain a no media marker - await for (final c in fileStore.openCursor()) { - final item = c.value as Map; - final strippedPath = item["strippedPath"] as String; - if (file_util.isNoMediaMarkerPath(strippedPath)) { - noMediaFiles.add(_NoMediaFile( - item["server"], - item["userId"], - path_lib - .dirname(item["strippedPath"]) - .run((p) => p == "." ? "" : p), - item["file"]["fileId"], - )); - } - c.next(); - } - // sort to make sure parent dirs are always in front of sub dirs - noMediaFiles - .sort((a, b) => a.strippedDirPath.compareTo(b.strippedDirPath)); - _log.info( - "[migrateAppDb] nomedia dirs: ${noMediaFiles.toReadableString()}"); - - if (noMediaFiles.isNotEmpty) { - await _migrateAppDbFileStore(appDb, noMediaFiles, - fileStore: fileStore); - await _migrateAppDbDirStore(appDb, noMediaFiles, - dirStore: dirStore); - } - - final metaStore = transaction.objectStore(AppDb.metaStoreName); - await metaStore - .put(const AppDbMetaEntryCompatV37(true).toEntry().toJson()); - } catch (_) { - transaction.abort(); - rethrow; - } - }, - ); - } catch (e, stackTrace) { - _log.shout("[migrateAppDb] Failed while migrating, drop db instead", e, - stackTrace); - await appDb.delete(); - rethrow; - } - } - - /// Remove files under no media dirs - static Future _migrateAppDbFileStore( - AppDb appDb, - List<_NoMediaFile> noMediaFiles, { - required ObjectStore fileStore, - }) async { - await for (final c in fileStore.openCursor()) { - final item = c.value as Map; - final under = noMediaFiles.firstWhereOrNull((e) { - if (e.server != item["server"] || e.userId != item["userId"]) { - return false; - } - final prefix = e.strippedDirPath.isEmpty ? "" : "${e.strippedDirPath}/"; - final itemDir = path_lib - .dirname(item["strippedPath"]) - .run((p) => p == "." ? "" : p); - // check isNotEmpty to prevent user root being removed when the - // marker is placed in root - return item["strippedPath"].isNotEmpty && - item["strippedPath"].startsWith(prefix) && - // keep no media marker in top-most dir - !(itemDir == e.strippedDirPath && - file_util.isNoMediaMarkerPath(item["strippedPath"])); - }); - if (under != null) { - _log.fine("[_migrateAppDbFileStore] Remove db entry: ${c.primaryKey}"); - await c.delete(); - } - c.next(); - } - } - - /// Remove dirs under no media dirs - static Future _migrateAppDbDirStore( - AppDb appDb, - List<_NoMediaFile> noMediaFiles, { - required ObjectStore dirStore, - }) async { - await for (final c in dirStore.openCursor()) { - final item = c.value as Map; - final under = noMediaFiles.firstWhereOrNull((e) { - if (e.server != item["server"] || e.userId != item["userId"]) { - return false; - } - final prefix = e.strippedDirPath.isEmpty ? "" : "${e.strippedDirPath}/"; - return item["strippedPath"].startsWith(prefix) || - e.strippedDirPath == item["strippedPath"]; - }); - if (under != null) { - if (under.strippedDirPath == item["strippedPath"]) { - // this dir contains the no media marker - // remove all children, keep only the marker - final newChildren = (item["children"] as List) - .where((childId) => childId == under.fileId) - .toList(); - if (newChildren.isEmpty) { - // ??? - _log.severe( - "[_migrateAppDbDirStore] Marker not found in dir: ${item["strippedPath"]}"); - // drop this dir - await c.delete(); - } - _log.fine( - "[_migrateAppDbDirStore] Migrate db entry: ${c.primaryKey}"); - await c.update(Map.of(item).apply((obj) { - obj["children"] = newChildren; - })); - } else { - // this dir is a sub dir - // drop this dir - _log.fine("[_migrateAppDbDirStore] Remove db entry: ${c.primaryKey}"); - await c.delete(); - } - } - c.next(); - } - } - - static final _log = Logger("use_case.compat.v37.CompatV37"); -} - -class _NoMediaFile { - const _NoMediaFile( - this.server, this.userId, this.strippedDirPath, this.fileId); - - @override - toString() => "$runtimeType {" - "server: $server, " - "userId: $userId, " - "strippedDirPath: $strippedDirPath, " - "fileId: $fileId, " - "}"; - - final String server; - // no need to use CiString as all strings are stored with the same casing in - // db - final String userId; - final String strippedDirPath; - final int fileId; -} diff --git a/app/lib/use_case/db_compat/v5.dart b/app/lib/use_case/db_compat/v5.dart deleted file mode 100644 index d0434c2b..00000000 --- a/app/lib/use_case/db_compat/v5.dart +++ /dev/null @@ -1,74 +0,0 @@ -import 'package:idb_shim/idb_client.dart'; -import 'package:logging/logging.dart'; -import 'package:nc_photos/app_db.dart'; -import 'package:nc_photos/ci_string.dart'; -import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/object_extension.dart'; - -class DbCompatV5 { - static Future isNeedMigration(AppDb appDb) async { - final dbItem = await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadOnly), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - return await metaStore.getObject(AppDbMetaEntryDbCompatV5.key) as Map?; - }, - ); - if (dbItem == null) { - return false; - } - try { - final dbEntry = AppDbMetaEntry.fromJson(dbItem.cast()); - final compatV35 = AppDbMetaEntryDbCompatV5.fromJson(dbEntry.obj); - return !compatV35.isMigrated; - } catch (e, stackTrace) { - _log.shout("[isNeedMigration] Failed", e, stackTrace); - return true; - } - } - - static Future migrate(AppDb appDb) async { - _log.info("[migrate] Migrate AppDb"); - try { - await appDb.use( - (db) => db.transaction( - [AppDb.file2StoreName, AppDb.metaStoreName], idbModeReadWrite), - (transaction) async { - try { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - await for (final c in fileStore.openCursor()) { - final item = c.value as Map; - // migrate file entry: add bestDateTime - final fileEntry = item.cast().run((json) { - final f = File.fromJson(json["file"].cast()); - return AppDbFile2Entry( - json["server"], - (json["userId"] as String).toCi(), - json["strippedPath"], - f.bestDateTime.millisecondsSinceEpoch, - File.fromJson(json["file"].cast()), - ); - }); - await c.update(fileEntry.toJson()); - - c.next(); - } - final metaStore = transaction.objectStore(AppDb.metaStoreName); - await metaStore - .put(const AppDbMetaEntryDbCompatV5(true).toEntry().toJson()); - } catch (_) { - transaction.abort(); - rethrow; - } - }, - ); - } catch (e, stackTrace) { - _log.shout( - "[migrate] Failed while migrating, drop db instead", e, stackTrace); - await appDb.delete(); - rethrow; - } - } - - static final _log = Logger("use_case.db_compat.v5.DbCompatV5"); -} diff --git a/app/lib/use_case/find_file.dart b/app/lib/use_case/find_file.dart index 0120c30a..eca16279 100644 --- a/app/lib/use_case/find_file.dart +++ b/app/lib/use_case/find_file.dart @@ -1,14 +1,14 @@ -import 'package:flutter/foundation.dart'; -import 'package:idb_shim/idb_client.dart'; +import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; +import 'package:nc_photos/iterable_extension.dart'; class FindFile { FindFile(this._c) : assert(require(_c)); - static bool require(DiContainer c) => DiContainer.has(c, DiType.appDb); + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); /// Find list of files in the DB by [fileIds] /// @@ -19,37 +19,34 @@ class FindFile { List fileIds, { void Function(int fileId)? onFileNotFound, }) async { - final dbItems = await _c.appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadOnly), - (transaction) async { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - return await Future.wait(fileIds.map((id) => - fileStore.getObject(AppDbFile2Entry.toPrimaryKey(account, id)))); - }, - ); - final fileMap = await compute(_covertFileMap, dbItems); - final files = []; - for (final id in fileIds) { - final f = fileMap[id]; - if (f == null) { - if (onFileNotFound == null) { - throw StateError("File ID not found: $id"); - } else { - onFileNotFound(id); - } - } else { - files.add(f); - } + _log.info("[call] fileIds: ${fileIds.toReadableString()}"); + final dbFiles = await _c.sqliteDb.use((db) async { + return await db.completeFilesByFileIds(fileIds, appAccount: account); + }); + final files = await dbFiles.convertToAppFile(account); + final fileMap = {}; + for (final f in files) { + fileMap[f.fileId!] = f; } - return files; + + return () sync* { + for (final id in fileIds) { + final f = fileMap[id]; + if (f == null) { + if (onFileNotFound == null) { + throw StateError("File ID not found: $id"); + } else { + onFileNotFound(id); + } + } else { + yield fileMap[id]!; + } + } + }() + .toList(); } final DiContainer _c; -} -Map _covertFileMap(List dbItems) { - return Map.fromEntries(dbItems - .whereType() - .map((j) => AppDbFile2Entry.fromJson(j.cast()).file) - .map((f) => MapEntry(f.fileId!, f))); + static final _log = Logger("use_case.find_file.FindFile"); } diff --git a/app/lib/use_case/list_album.dart b/app/lib/use_case/list_album.dart index 81ba9bae..97e8ebf2 100644 --- a/app/lib/use_case/list_album.dart +++ b/app/lib/use_case/list_album.dart @@ -1,4 +1,4 @@ -import 'package:logging/logging.dart'; +import 'package:collection/collection.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; @@ -50,30 +50,22 @@ class ListAlbum { yield ExceptionEvent(e, stackTrace); return; } - final albumFiles = + final List albumFiles = ls.where((element) => element.isCollection != true).toList(); + // migrate files for (var i = 0; i < albumFiles.length; ++i) { - var f = albumFiles[i]; + var f = albumFiles[i]!; try { if (CompatV25.isAlbumFileNeedMigration(f)) { - f = await CompatV25.migrateAlbumFile(_c, account, f); + albumFiles[i] = await CompatV25.migrateAlbumFile(_c, account, f); } - albumFiles[i] = f; - yield await _c.albumRepo.get(account, f); } catch (e, stackTrace) { yield ExceptionEvent(e, stackTrace); + albumFiles[i] = null; } } - try { - _c.albumRepo.cleanUp( - account, remote_storage_util.getRemoteAlbumsDir(account), albumFiles); - } catch (e, stacktrace) { - // not important, log and ignore - _log.shout("[_call] Failed while cleanUp", e, stacktrace); - } + yield* _c.albumRepo.getAll(account, albumFiles.whereNotNull().toList()); } final DiContainer _c; - - static final _log = Logger("use_case.list_album.ListAlbum"); } diff --git a/app/lib/use_case/list_favorite_offline.dart b/app/lib/use_case/list_favorite_offline.dart index f5a0b8da..b9075876 100644 --- a/app/lib/use_case/list_favorite_offline.dart +++ b/app/lib/use_case/list_favorite_offline.dart @@ -1,43 +1,19 @@ -import 'package:idb_shim/idb_client.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file_util.dart' as file_util; -import 'package:nc_photos/use_case/find_file.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; class ListFavoriteOffline { - ListFavoriteOffline(this._c) - : assert(require(_c)), - assert(FindFile.require(_c)); + ListFavoriteOffline(this._c) : assert(require(_c)); - static bool require(DiContainer c) => DiContainer.has(c, DiType.appDb); + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); /// List all favorites for [account] from the local DB - Future> call(Account account) { - final rootDirs = account.roots - .map((r) => File(path: file_util.unstripPath(account, r))) - .toList(); - return _c.appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadOnly), - (transaction) async { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - final fileIsFavoriteIndex = - fileStore.index(AppDbFile2Entry.fileIsFavoriteIndexName); - return await fileIsFavoriteIndex - .openCursor( - key: AppDbFile2Entry.toFileIsFavoriteIndexKey(account, true), - autoAdvance: true, - ) - .map((c) => AppDbFile2Entry.fromJson( - (c.value as Map).cast())) - .map((e) => e.file) - .where((f) => - file_util.isSupportedFormat(f) && - rootDirs.any((r) => file_util.isOrUnderDir(f, r))) - .toList(); - }, - ); + Future> call(Account account) async { + final dbFiles = await _c.sqliteDb.use((db) async { + return await db.completeFilesByFavorite(appAccount: account); + }); + return await dbFiles.convertToAppFile(account); } final DiContainer _c; diff --git a/app/lib/use_case/populate_album.dart b/app/lib/use_case/populate_album.dart index 1e1fb4e0..3c5dc6c9 100644 --- a/app/lib/use_case/populate_album.dart +++ b/app/lib/use_case/populate_album.dart @@ -1,7 +1,6 @@ import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; @@ -15,7 +14,9 @@ import 'package:nc_photos/use_case/list_tagged_file.dart'; import 'package:nc_photos/use_case/scan_dir.dart'; class PopulateAlbum { - const PopulateAlbum(this.appDb); + PopulateAlbum(this._c) : assert(require(_c)); + + static bool require(DiContainer c) => DiContainer.has(c, DiType.fileRepo); Future> call(Account account, Album album) async { if (album.provider is AlbumStaticProvider) { @@ -40,7 +41,7 @@ class PopulateAlbum { final provider = album.provider as AlbumDirProvider; final products = []; for (final d in provider.dirs) { - final stream = ScanDir(FileRepo(FileCachedDataSource(appDb)))(account, d); + final stream = ScanDir(_c.fileRepo)(account, d); await for (final result in stream) { if (result is ExceptionEvent) { _log.shout( @@ -81,7 +82,7 @@ class PopulateAlbum { final date = DateTime(provider.year, provider.month, provider.day); final from = date.subtract(const Duration(days: 2)); final to = date.add(const Duration(days: 3)); - final files = await FileAppDbDataSource(appDb).listByDate( + final files = await FileSqliteDbDataSource(_c).listByDate( account, from.millisecondsSinceEpoch, to.millisecondsSinceEpoch); return files .where((f) => file_util.isSupportedFormat(f)) @@ -93,7 +94,7 @@ class PopulateAlbum { .toList(); } - final AppDb appDb; + final DiContainer _c; static final _log = Logger("use_case.populate_album.PopulateAlbum"); } diff --git a/app/lib/use_case/populate_person.dart b/app/lib/use_case/populate_person.dart index fb02589f..1d1aeca1 100644 --- a/app/lib/use_case/populate_person.dart +++ b/app/lib/use_case/populate_person.dart @@ -1,51 +1,38 @@ -import 'package:idb_shim/idb_client.dart'; +import 'package:collection/collection.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/face.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/exception.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; class PopulatePerson { - const PopulatePerson(this.appDb); + PopulatePerson(this._c) : assert(require(_c)); + + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); /// Return a list of files of the faces Future> call(Account account, List faces) async { - return await appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadOnly), - (transaction) async { - final store = transaction.objectStore(AppDb.file2StoreName); - final products = []; - for (final f in faces) { - try { - products.add(await _populateOne(account, f, fileStore: store)); - } catch (e, stackTrace) { - _log.severe("[call] Failed populating file of face: ${f.fileId}", e, - stackTrace); + final fileIds = faces.map((f) => f.fileId).toList(); + final dbFiles = await _c.sqliteDb.use((db) async { + return await db.completeFilesByFileIds(fileIds, appAccount: account); + }); + final files = await dbFiles.convertToAppFile(account); + final fileMap = Map.fromEntries(files.map((f) => MapEntry(f.fileId, f))); + return faces + .map((f) { + final file = fileMap[f.fileId]; + if (file == null) { + _log.warning( + "[call] File doesn't exist in DB, removed?: ${f.fileId}"); } - } - return products; - }, - ); + return file; + }) + .whereNotNull() + .toList(); } - Future _populateOne( - Account account, - Face face, { - required ObjectStore fileStore, - }) async { - final dbItem = await fileStore - .getObject(AppDbFile2Entry.toPrimaryKey(account, face.fileId)) as Map?; - if (dbItem == null) { - _log.warning( - "[_populateOne] File doesn't exist in DB, removed?: '${face.fileId}'"); - throw CacheNotFoundException(); - } - final dbEntry = AppDbFile2Entry.fromJson(dbItem.cast()); - return dbEntry.file; - } + final DiContainer _c; - final AppDb appDb; - - static final _log = Logger("use_case.populate_album.PopulatePerson"); + static final _log = Logger("use_case.populate_person.PopulatePerson"); } diff --git a/app/lib/use_case/preprocess_album.dart b/app/lib/use_case/preprocess_album.dart index fd2db685..52d924db 100644 --- a/app/lib/use_case/preprocess_album.dart +++ b/app/lib/use_case/preprocess_album.dart @@ -1,5 +1,5 @@ import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album/item.dart'; import 'package:nc_photos/entity/album/provider.dart'; @@ -12,19 +12,24 @@ import 'package:nc_photos/use_case/resync_album.dart'; /// - with AlbumStaticProvider: [ResyncAlbum] /// - with AlbumDynamicProvider/AlbumSmartProvider: [PopulateAlbum] class PreProcessAlbum { - const PreProcessAlbum(this.appDb); + PreProcessAlbum(this._c) + : assert(require(_c)), + assert(PopulateAlbum.require(_c)), + assert(ResyncAlbum.require(_c)); + + static bool require(DiContainer c) => true; Future> call(Account account, Album album) { if (album.provider is AlbumStaticProvider) { - return ResyncAlbum(appDb)(account, album); + return ResyncAlbum(_c)(account, album); } else if (album.provider is AlbumDynamicProvider || album.provider is AlbumSmartProvider) { - return PopulateAlbum(appDb)(account, album); + return PopulateAlbum(_c)(account, album); } else { throw ArgumentError( "Unknown album provider: ${album.provider.runtimeType}"); } } - final AppDb appDb; + final DiContainer _c; } diff --git a/app/lib/use_case/remove_from_album.dart b/app/lib/use_case/remove_from_album.dart index 44ba39b1..ca0bc235 100644 --- a/app/lib/use_case/remove_from_album.dart +++ b/app/lib/use_case/remove_from_album.dart @@ -15,10 +15,10 @@ import 'package:nc_photos/use_case/update_album_with_actual_items.dart'; class RemoveFromAlbum { RemoveFromAlbum(this._c) : assert(require(_c)), - assert(UnshareFileFromAlbum.require(_c)); + assert(UnshareFileFromAlbum.require(_c)), + assert(PreProcessAlbum.require(_c)); - static bool require(DiContainer c) => - DiContainer.has(c, DiType.albumRepo) && DiContainer.has(c, DiType.appDb); + static bool require(DiContainer c) => DiContainer.has(c, DiType.albumRepo); /// Remove a list of AlbumItems from [album] /// @@ -91,7 +91,7 @@ class RemoveFromAlbum { _log.info( "[_fixAlbumPostRemove] Resync as interesting item is being removed"); // need to update the album properties - final newItemsSynced = await PreProcessAlbum(_c.appDb)(account, newAlbum); + final newItemsSynced = await PreProcessAlbum(_c)(account, newAlbum); newAlbum = await UpdateAlbumWithActualItems(null)( account, newAlbum, diff --git a/app/lib/use_case/resync_album.dart b/app/lib/use_case/resync_album.dart index dca7bb3a..f3f1ed5f 100644 --- a/app/lib/use_case/resync_album.dart +++ b/app/lib/use_case/resync_album.dart @@ -1,17 +1,19 @@ -import 'package:flutter/foundation.dart'; -import 'package:idb_shim/idb_client.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/debug_util.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album/item.dart'; import 'package:nc_photos/entity/album/provider.dart'; -import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/use_case/find_file.dart'; /// Resync files inside an album with the file db class ResyncAlbum { - const ResyncAlbum(this.appDb); + ResyncAlbum(this._c) + : assert(require(_c)), + assert(FindFile.require(_c)); + + static bool require(DiContainer c) => true; Future> call(Account account, Album album) async { _log.info("[call] Resync album: ${album.name}"); @@ -20,22 +22,27 @@ class ResyncAlbum { "Resync only make sense for static albums: ${album.name}"); } final items = AlbumStaticProvider.of(album).items; - final dbItems = await appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadOnly), - (transaction) async { - final store = transaction.objectStore(AppDb.file2StoreName); - return await Future.wait(items.whereType().map((i) => - store.getObject( - AppDbFile2Entry.toPrimaryKey(account, i.file.fileId!)))); - }, + + final files = await FindFile(_c)( + account, + items.whereType().map((i) => i.file.fileId!).toList(), + onFileNotFound: (_) {}, ); - final fileMap = await compute(_covertFileMap, dbItems); + final fileIt = files.iterator; + var nextFile = fileIt.moveNext() ? fileIt.current : null; return items.map((i) { if (i is AlbumFileItem) { try { - return i.copyWith( - file: fileMap[i.file.fileId]!, - ); + if (i.file.fileId! == nextFile?.fileId) { + final newItem = i.copyWith( + file: nextFile, + ); + nextFile = fileIt.moveNext() ? fileIt.current : null; + return newItem; + } else { + _log.warning("[call] File not found: ${logFilename(i.file.path)}"); + return i; + } } catch (e, stackTrace) { _log.shout( "[call] Failed syncing file in album: ${logFilename(i.file.path)}", @@ -49,14 +56,7 @@ class ResyncAlbum { }).toList(); } - final AppDb appDb; + final DiContainer _c; static final _log = Logger("use_case.resync_album.ResyncAlbum"); } - -Map _covertFileMap(List dbItems) { - return Map.fromEntries(dbItems - .whereType() - .map((j) => AppDbFile2Entry.fromJson(j.cast()).file) - .map((f) => MapEntry(f.fileId!, f))); -} diff --git a/app/lib/use_case/scan_dir_offline.dart b/app/lib/use_case/scan_dir_offline.dart index dbc3655f..6d0e129b 100644 --- a/app/lib/use_case/scan_dir_offline.dart +++ b/app/lib/use_case/scan_dir_offline.dart @@ -1,50 +1,60 @@ -import 'package:idb_shim/idb_client.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file_util.dart' as file_util; -import 'package:nc_photos/iterable_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_converter.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; +import 'package:nc_photos/object_extension.dart'; class ScanDirOffline { ScanDirOffline(this._c) : assert(require(_c)); - static bool require(DiContainer c) => DiContainer.has(c, DiType.appDb); + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); - /// List all files under a dir recursively from the local DB - Future> call( + Future> call( Account account, File root, { bool isOnlySupportedFormat = true, }) async { - final dbItems = await _c.appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadOnly), - (transaction) async { - final store = transaction.objectStore(AppDb.file2StoreName); - final index = store.index(AppDbFile2Entry.strippedPathIndexName); - final range = KeyRange.bound( - AppDbFile2Entry.toStrippedPathIndexLowerKeyForDir(account, root), - AppDbFile2Entry.toStrippedPathIndexUpperKeyForDir(account, root), - ); - return await index - .openCursor(range: range, autoAdvance: false) - .map((c) { - final v = c.value as Map; - c.next(); - return v; - }).toList(); - }, - ); - final results = await dbItems.computeAll(_covertAppDbFile2Entry); - if (isOnlySupportedFormat) { - return results.where((f) => file_util.isSupportedFormat(f)); - } else { - return results; - } + return await _c.sqliteDb.isolate({ + "account": account, + "root": root, + "isOnlySupportedFormat": isOnlySupportedFormat, + }, (db, Map args) async { + final Account account = args["account"]; + final File root = args["root"]; + final bool isOnlySupportedFormat = args["isOnlySupportedFormat"]; + final dbFiles = await db.useInIsolate((db) async { + final query = db.queryFiles().run((q) { + q + ..setQueryMode(sql.FilesQueryMode.completeFile) + ..setAppAccount(account); + root.strippedPathWithEmpty.run((p) { + if (p.isNotEmpty) { + q.byRelativePathPattern("$p/%"); + } + }); + if (isOnlySupportedFormat) { + q + ..byMimePattern("image/%") + ..byMimePattern("video/%"); + } + return q.build(); + }); + return await query + .map((r) => sql.CompleteFile( + r.readTable(db.files), + r.readTable(db.accountFiles), + r.readTableOrNull(db.images), + r.readTableOrNull(db.trashes), + )) + .get(); + }); + return dbFiles + .map( + (f) => SqliteFileConverter.fromSql(account.homeDir.toString(), f)) + .toList(); + }); } final DiContainer _c; } - -File _covertAppDbFile2Entry(Map json) => - AppDbFile2Entry.fromJson(json.cast()).file; diff --git a/app/lib/web/db_util.dart b/app/lib/web/db_util.dart index dcd90c07..f86846a7 100644 --- a/app/lib/web/db_util.dart +++ b/app/lib/web/db_util.dart @@ -1,4 +1,30 @@ -import 'package:idb_shim/idb_browser.dart'; -import 'package:idb_shim/idb_shim.dart'; +import 'package:drift/drift.dart'; +import 'package:drift/wasm.dart'; +import 'package:http/http.dart' as http; +import 'package:sqlite3/wasm.dart'; -IdbFactory getDbFactory() => idbFactoryBrowser; +Future> getSqliteConnectionArgs() async => {}; + +QueryExecutor openSqliteConnectionWithArgs(Map args) => + openSqliteConnection(); + +QueryExecutor openSqliteConnection() { + return LazyDatabase(() async { + // Load wasm bundle + final response = await http.get(Uri.parse("sqlite3.wasm")); + // Create a virtual file system backed by IndexedDb with everything in + // `/drift/my_app/` being persisted. + final fs = await IndexedDbFileSystem.open(dbName: "nc-photos"); + final sqlite3 = await WasmSqlite3.load( + response.bodyBytes, + SqliteEnvironment(fileSystem: fs), + ); + + // Then, open a database inside that persisted folder. + return WasmDatabase( + sqlite3: sqlite3, + path: "/drift/nc-photos/app.db", + // logStatements: true, + ); + }); +} diff --git a/app/lib/widget/album_browser.dart b/app/lib/widget/album_browser.dart index bd25afdc..a992cdf4 100644 --- a/app/lib/widget/album_browser.dart +++ b/app/lib/widget/album_browser.dart @@ -4,7 +4,6 @@ import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/api/api_util.dart' as api_util; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/download_handler.dart'; @@ -82,6 +81,15 @@ class _AlbumBrowserState extends State SelectableItemStreamListMixin, DraggableItemListMixin, AlbumBrowserMixin { + _AlbumBrowserState() { + final c = KiwiContainer().resolve(); + assert(require(c)); + assert(PreProcessAlbum.require(c)); + _c = c; + } + + static bool require(DiContainer c) => DiContainer.has(c, DiType.albumRepo); + @override initState() { super.initState(); @@ -156,11 +164,10 @@ class _AlbumBrowserState extends State if (newAlbum.copyWith(lastUpdated: OrNull(_album!.lastUpdated)) != _album) { _log.info("[doneEditMode] Album modified: $newAlbum"); - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); setState(() { _album = newAlbum; }); - UpdateAlbum(albumRepo)( + UpdateAlbum(_c.albumRepo)( widget.account, newAlbum, ).catchError((e, stackTrace) { @@ -184,15 +191,14 @@ class _AlbumBrowserState extends State } Future _initAlbum() async { - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); - var album = await albumRepo.get(widget.account, widget.album.albumFile!); + var album = await _c.albumRepo.get(widget.account, widget.album.albumFile!); if (widget.album.shares?.isNotEmpty == true) { try { - final file = await LsSingleFile(KiwiContainer().resolve())( - widget.account, album.albumFile!.path); + final file = + await LsSingleFile(_c)(widget.account, album.albumFile!.path); if (file.etag != album.albumFile!.etag) { _log.info("[_initAlbum] Album modified in remote, forcing download"); - album = await albumRepo.get(widget.account, File(path: file.path)); + album = await _c.albumRepo.get(widget.account, File(path: file.path)); } } catch (e, stackTrace) { _log.warning("[_initAlbum] Failed while syncing remote album file", e, @@ -815,7 +821,7 @@ class _AlbumBrowserState extends State Future _setAlbum(Album album) async { assert(album.provider is AlbumStaticProvider); - final items = await PreProcessAlbum(AppDb())(widget.account, album); + final items = await PreProcessAlbum(_c)(widget.account, album); if (album.albumFile!.isOwned(widget.account.username)) { album = await _updateAlbumPostResync(album, items); } @@ -835,8 +841,7 @@ class _AlbumBrowserState extends State Future _updateAlbumPostResync( Album album, List items) async { - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); - return await UpdateAlbumWithActualItems(albumRepo)( + return await UpdateAlbumWithActualItems(_c.albumRepo)( widget.account, album, items); } @@ -866,6 +871,8 @@ class _AlbumBrowserState extends State static List _getAlbumItemsOf(Album a) => AlbumStaticProvider.of(a).items; + late final DiContainer _c; + Album? _album; var _sortedItems = []; var _backingFiles = []; diff --git a/app/lib/widget/album_browser_mixin.dart b/app/lib/widget/album_browser_mixin.dart index ff5e1340..505c342d 100644 --- a/app/lib/widget/album_browser_mixin.dart +++ b/app/lib/widget/album_browser_mixin.dart @@ -3,12 +3,12 @@ import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/api/api_util.dart' as api_util; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album/cover_provider.dart'; +import 'package:nc_photos/entity/album/data_source.dart'; import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/notified_action.dart'; import 'package:nc_photos/pref.dart'; @@ -197,10 +197,11 @@ mixin AlbumBrowserMixin Future _onUnsetCoverPressed(Account account, Album album) async { _log.info("[_onUnsetCoverPressed] Unset album cover for '${album.name}'"); + final c = KiwiContainer().resolve(); try { await NotifiedAction( () async { - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); + final albumRepo = AlbumRepo(AlbumCachedDataSource(c)); await UpdateAlbum(albumRepo)( account, album.copyWith( diff --git a/app/lib/widget/album_importer.dart b/app/lib/widget/album_importer.dart index 6bea7450..0410cc47 100644 --- a/app/lib/widget/album_importer.dart +++ b/app/lib/widget/album_importer.dart @@ -3,7 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/bloc/list_importable_album.dart'; import 'package:nc_photos/di_container.dart'; @@ -54,6 +53,15 @@ class AlbumImporter extends StatefulWidget { } class _AlbumImporterState extends State { + _AlbumImporterState() { + final c = KiwiContainer().resolve(); + assert(require(c)); + assert(PreProcessAlbum.require(c)); + _c = c; + } + + static bool require(DiContainer c) => DiContainer.has(c, DiType.albumRepo); + @override initState() { super.initState(); @@ -236,12 +244,11 @@ class _AlbumImporterState extends State { ); _log.info("[_createAllAlbums] Creating dir album: $album"); - final items = await PreProcessAlbum(AppDb())(widget.account, album); + final items = await PreProcessAlbum(_c)(widget.account, album); album = await UpdateAlbumWithActualItems(null)( widget.account, album, items); - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); - await CreateAlbum(albumRepo)(widget.account, album); + await CreateAlbum(_c.albumRepo)(widget.account, album); } catch (e, stacktrace) { _log.shout( "[_createAllAlbums] Failed creating dir album", e, stacktrace); @@ -260,6 +267,7 @@ class _AlbumImporterState extends State { .toList(); } + late final DiContainer _c; late ListImportableAlbumBloc _bloc; var _backingFiles = []; diff --git a/app/lib/widget/archive_browser.dart b/app/lib/widget/archive_browser.dart index 8d1d4bcf..02c26e62 100644 --- a/app/lib/widget/archive_browser.dart +++ b/app/lib/widget/archive_browser.dart @@ -2,15 +2,15 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/bloc/scan_account_dir.dart'; import 'package:nc_photos/compute_queue.dart'; import 'package:nc_photos/debug_util.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/language_util.dart' as language_util; @@ -237,11 +237,11 @@ class _ArchiveBrowserState extends State setState(() { clearSelectedItems(); }); - final fileRepo = FileRepo(FileCachedDataSource(AppDb())); + final c = KiwiContainer().resolve(); final failures = []; for (final f in selectedFiles) { try { - await UpdateProperty(fileRepo) + await UpdateProperty(c.fileRepo) .updateIsArchived(widget.account, f, false); } catch (e, stacktrace) { _log.shout( diff --git a/app/lib/widget/dynamic_album_browser.dart b/app/lib/widget/dynamic_album_browser.dart index 6990b8fb..c90b5962 100644 --- a/app/lib/widget/dynamic_album_browser.dart +++ b/app/lib/widget/dynamic_album_browser.dart @@ -4,7 +4,6 @@ import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/api/api_util.dart' as api_util; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; @@ -76,6 +75,15 @@ class _DynamicAlbumBrowserState extends State with SelectableItemStreamListMixin, AlbumBrowserMixin { + _DynamicAlbumBrowserState() { + final c = KiwiContainer().resolve(); + assert(require(c)); + assert(PreProcessAlbum.require(c)); + _c = c; + } + + static bool require(DiContainer c) => DiContainer.has(c, DiType.albumRepo); + @override initState() { super.initState(); @@ -139,11 +147,10 @@ class _DynamicAlbumBrowserState extends State if (newAlbum.copyWith(lastUpdated: OrNull(_album!.lastUpdated)) != _album) { _log.info("[doneEditMode] Album modified: $newAlbum"); - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); setState(() { _album = newAlbum; }); - UpdateAlbum(albumRepo)( + UpdateAlbum(_c.albumRepo)( widget.account, newAlbum, ).catchError((e, stackTrace) { @@ -171,7 +178,7 @@ class _DynamicAlbumBrowserState extends State final List items; final Album album; try { - items = await PreProcessAlbum(AppDb())(widget.account, widget.album); + items = await PreProcessAlbum(_c)(widget.account, widget.album); album = await _updateAlbumPostPopulate(widget.album, items); } catch (e, stackTrace) { _log.severe("[_initAlbum] Failed while PreProcessAlbum", e, stackTrace); @@ -350,9 +357,8 @@ class _DynamicAlbumBrowserState extends State } _log.info( "[_onConvertBasicPressed] Converting album '${_album!.name}' to static"); - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); try { - await UpdateAlbum(albumRepo)( + await UpdateAlbum(_c.albumRepo)( widget.account, _album!.copyWith( provider: AlbumStaticProvider( @@ -632,11 +638,12 @@ class _DynamicAlbumBrowserState extends State Future _updateAlbumPostPopulate( Album album, List items) async { - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); - return await UpdateAlbumWithActualItems(albumRepo)( + return await UpdateAlbumWithActualItems(_c.albumRepo)( widget.account, album, items); } + late final DiContainer _c; + Album? _album; var _sortedItems = []; var _backingFiles = []; diff --git a/app/lib/widget/home.dart b/app/lib/widget/home.dart index 8b64dc1f..fa349965 100644 --- a/app/lib/widget/home.dart +++ b/app/lib/widget/home.dart @@ -5,6 +5,7 @@ import 'package:nc_photos/account.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/album/data_source.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/k.dart' as k; diff --git a/app/lib/widget/home_photos.dart b/app/lib/widget/home_photos.dart index f60cef83..ecebc4c3 100644 --- a/app/lib/widget/home_photos.dart +++ b/app/lib/widget/home_photos.dart @@ -737,8 +737,9 @@ class _Web { } void startMetadataTask(int missingMetadataCount) { + final c = KiwiContainer().resolve(); MetadataTaskManager().addTask(MetadataTask( - state.widget.account, AccountPref.of(state.widget.account))); + c, state.widget.account, AccountPref.of(state.widget.account))); _metadataTaskProcessTotalCount = missingMetadataCount; } diff --git a/app/lib/widget/new_album_dialog.dart b/app/lib/widget/new_album_dialog.dart index f297eb52..76afc72f 100644 --- a/app/lib/widget/new_album_dialog.dart +++ b/app/lib/widget/new_album_dialog.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; @@ -37,6 +36,14 @@ class NewAlbumDialog extends StatefulWidget { } class _NewAlbumDialogState extends State { + _NewAlbumDialogState() { + final c = KiwiContainer().resolve(); + assert(require(c)); + _c = c; + } + + static bool require(DiContainer c) => DiContainer.has(c, DiType.albumRepo); + @override initState() { super.initState(); @@ -139,8 +146,7 @@ class _NewAlbumDialogState extends State { sortProvider: const AlbumTimeSortProvider(isAscending: false), ); _log.info("[_onConfirmStaticAlbum] Creating static album: $album"); - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); - final newAlbum = await CreateAlbum(albumRepo)(widget.account, album); + final newAlbum = await CreateAlbum(_c.albumRepo)(widget.account, album); Navigator.of(context).pop(newAlbum); } catch (e, stacktrace) { _log.shout("[_onConfirmStaticAlbum] Failed", e, stacktrace); @@ -173,8 +179,7 @@ class _NewAlbumDialogState extends State { sortProvider: const AlbumTimeSortProvider(isAscending: false), ); _log.info("[_onConfirmDirAlbum] Creating dir album: $album"); - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); - final newAlbum = await CreateAlbum(albumRepo)(widget.account, album); + final newAlbum = await CreateAlbum(_c.albumRepo)(widget.account, album); Navigator.of(context).pop(newAlbum); } catch (e, stacktrace) { _log.shout("[_onConfirmDirAlbum] Failed", e, stacktrace); @@ -220,6 +225,8 @@ class _NewAlbumDialogState extends State { } } + late final DiContainer _c; + final _formKey = GlobalKey(); var _provider = _Provider.static; diff --git a/app/lib/widget/person_browser.dart b/app/lib/widget/person_browser.dart index 24bef6b2..c9da4da1 100644 --- a/app/lib/widget/person_browser.dart +++ b/app/lib/widget/person_browser.dart @@ -8,7 +8,6 @@ import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/api/api.dart'; import 'package:nc_photos/api/api_util.dart' as api_util; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/bloc/list_face.dart'; import 'package:nc_photos/cache_manager_util.dart'; @@ -76,6 +75,14 @@ class PersonBrowser extends StatefulWidget { class _PersonBrowserState extends State with SelectableItemStreamListMixin { + _PersonBrowserState() { + final c = KiwiContainer().resolve(); + assert(require(c)); + _c = c; + } + + static bool require(DiContainer c) => DiContainer.has(c, DiType.sqliteDb); + @override initState() { super.initState(); @@ -414,7 +421,7 @@ class _PersonBrowserState extends State } void _transformItems(List items) async { - final files = await PopulatePerson(AppDb())(widget.account, items); + final files = await PopulatePerson(_c)(widget.account, items); _backingFiles = files .sorted(compareFileDateTimeDescending) .where((element) => @@ -442,6 +449,8 @@ class _PersonBrowserState extends State _bloc.add(ListFaceBlocQuery(widget.account, widget.person)); } + late final DiContainer _c; + final ListFaceBloc _bloc = ListFaceBloc(); List? _backingFiles; diff --git a/app/lib/widget/settings.dart b/app/lib/widget/settings.dart index 6887ef83..c45b04ce 100644 --- a/app/lib/widget/settings.dart +++ b/app/lib/widget/settings.dart @@ -12,9 +12,9 @@ import 'package:nc_photos/language_util.dart' as language_util; import 'package:nc_photos/mobile/android/android_info.dart'; import 'package:nc_photos/mobile/platform.dart' if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; +import 'package:nc_photos/platform/features.dart' as features; import 'package:nc_photos/platform/k.dart' as platform_k; import 'package:nc_photos/platform/notification.dart'; -import 'package:nc_photos/platform/features.dart' as features; import 'package:nc_photos/pref.dart'; import 'package:nc_photos/service.dart'; import 'package:nc_photos/snack_bar_manager.dart'; diff --git a/app/lib/widget/share_album_dialog.dart b/app/lib/widget/share_album_dialog.dart index 5b7b6e40..504cf69f 100644 --- a/app/lib/widget/share_album_dialog.dart +++ b/app/lib/widget/share_album_dialog.dart @@ -5,7 +5,6 @@ import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:mutex/mutex.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/async_util.dart' as async_util; import 'package:nc_photos/bloc/list_sharee.dart'; @@ -13,8 +12,6 @@ import 'package:nc_photos/bloc/search_suggestion.dart'; import 'package:nc_photos/ci_string.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; -import 'package:nc_photos/entity/share.dart'; -import 'package:nc_photos/entity/share/data_source.dart'; import 'package:nc_photos/entity/sharee.dart'; import 'package:nc_photos/exception_util.dart' as exception_util; import 'package:nc_photos/k.dart' as k; @@ -41,6 +38,16 @@ class ShareAlbumDialog extends StatefulWidget { } class _ShareAlbumDialogState extends State { + _ShareAlbumDialogState() { + final c = KiwiContainer().resolve(); + assert(require(c)); + _c = c; + } + + static bool require(DiContainer c) => + DiContainer.has(c, DiType.albumRepo) && + DiContainer.has(c, DiType.shareRepo); + @override initState() { super.initState(); @@ -227,12 +234,10 @@ class _ShareAlbumDialogState extends State { } Future _createShare(Sharee sharee) async { - final shareRepo = ShareRepo(ShareRemoteDataSource()); - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); var hasFailure = false; try { _album = await _editMutex.protect(() async { - return await ShareAlbumWithUser(shareRepo, albumRepo)( + return await ShareAlbumWithUser(_c.shareRepo, _c.albumRepo)( widget.account, _album, sharee, @@ -320,6 +325,8 @@ class _ShareAlbumDialogState extends State { } } + late final DiContainer _c; + late final _shareeBloc = ListShareeBloc.of(widget.account); final _suggestionBloc = SearchSuggestionBloc( itemToKeywords: (item) => [item.shareWith, item.label.toCi()], diff --git a/app/lib/widget/sharing_browser.dart b/app/lib/widget/sharing_browser.dart index 518343c7..c3c79b27 100644 --- a/app/lib/widget/sharing_browser.dart +++ b/app/lib/widget/sharing_browser.dart @@ -13,6 +13,7 @@ import 'package:nc_photos/bloc/list_sharing.dart'; import 'package:nc_photos/cache_manager_util.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/album/data_source.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/share.dart'; diff --git a/app/lib/widget/sign_in.dart b/app/lib/widget/sign_in.dart index c61122ec..5d8ab68d 100644 --- a/app/lib/widget/sign_in.dart +++ b/app/lib/widget/sign_in.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/ci_string.dart'; +import 'package:nc_photos/di_container.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/help_utils.dart' as help_utils; import 'package:nc_photos/iterable_extension.dart'; import 'package:nc_photos/platform/k.dart' as platform_k; @@ -253,6 +256,10 @@ class _SignInState extends State { return; } // we've got a good account + final c = KiwiContainer().resolve(); + await c.sqliteDb.use((db) async { + await db.insertAccountOf(account!); + }); // only signing in with app password would trigger distinct final accounts = (Pref().getAccounts3Or([])..add(account)).distinct(); try { diff --git a/app/lib/widget/smart_album_browser.dart b/app/lib/widget/smart_album_browser.dart index f94a884b..8b0937e6 100644 --- a/app/lib/widget/smart_album_browser.dart +++ b/app/lib/widget/smart_album_browser.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; import 'package:nc_photos/api/api_util.dart' as api_util; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/download_handler.dart'; import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album/item.dart'; @@ -60,6 +61,12 @@ class _SmartAlbumBrowserState extends State with SelectableItemStreamListMixin, AlbumBrowserMixin { + _SmartAlbumBrowserState() { + final c = KiwiContainer().resolve(); + assert(PreProcessAlbum.require(c)); + _c = c; + } + @override initState() { super.initState(); @@ -89,7 +96,7 @@ class _SmartAlbumBrowserState extends State Future _initAlbum() async { assert(widget.album.provider is AlbumSmartProvider); _log.info("[_initAlbum] ${widget.album}"); - final items = await PreProcessAlbum(AppDb())(widget.account, widget.album); + final items = await PreProcessAlbum(_c)(widget.account, widget.album); if (mounted) { setState(() { _album = widget.album; @@ -314,6 +321,8 @@ class _SmartAlbumBrowserState extends State .toList(); } + late final DiContainer _c; + Album? _album; var _sortedItems = []; var _backingFiles = []; diff --git a/app/lib/widget/splash.dart b/app/lib/widget/splash.dart index deedb577..bd3da4a9 100644 --- a/app/lib/widget/splash.dart +++ b/app/lib/widget/splash.dart @@ -1,20 +1,15 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/changelog.dart' as changelog; -import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/mobile/android/activity.dart'; import 'package:nc_photos/platform/k.dart' as platform_k; import 'package:nc_photos/pref.dart'; -import 'package:nc_photos/snack_bar_manager.dart'; import 'package:nc_photos/theme.dart'; import 'package:nc_photos/use_case/compat/v29.dart'; -import 'package:nc_photos/use_case/compat/v37.dart'; -import 'package:nc_photos/use_case/db_compat/v5.dart'; import 'package:nc_photos/widget/home.dart'; import 'package:nc_photos/widget/processing_dialog.dart'; import 'package:nc_photos/widget/setup.dart'; @@ -47,7 +42,6 @@ class _SplashState extends State { if (_shouldUpgrade()) { await _handleUpgrade(); } - await _migrateDb(); _initTimedExit(); } @@ -162,10 +156,6 @@ class _SplashState extends State { showUpdateDialog(); await _upgrade29(lastVersion); } - if (lastVersion < 370) { - showUpdateDialog(); - await _upgrade37(lastVersion); - } if (isShowDialog) { Navigator.of(context).pop(); } @@ -181,53 +171,6 @@ class _SplashState extends State { } } - Future _upgrade37(int lastVersion) async { - final c = KiwiContainer().resolve(); - return CompatV37.setAppDbMigrationFlag(c.appDb); - } - - Future _migrateDb() async { - bool isShowDialog = false; - void showUpdateDialog() { - if (!isShowDialog) { - isShowDialog = true; - showDialog( - context: context, - builder: (_) => ProcessingDialog( - text: L10n.global().migrateDatabaseProcessingNotification, - ), - ); - } - } - - final c = KiwiContainer().resolve(); - if (await DbCompatV5.isNeedMigration(c.appDb)) { - showUpdateDialog(); - try { - await DbCompatV5.migrate(c.appDb); - } catch (_) { - SnackBarManager().showSnackBar(SnackBar( - content: Text(L10n.global().migrateDatabaseFailureNotification), - duration: k.snackBarDurationNormal, - )); - } - } - if (await CompatV37.isAppDbNeedMigration(c.appDb)) { - showUpdateDialog(); - try { - await CompatV37.migrateAppDb(c.appDb); - } catch (_) { - SnackBarManager().showSnackBar(SnackBar( - content: Text(L10n.global().migrateDatabaseFailureNotification), - duration: k.snackBarDurationNormal, - )); - } - } - if (isShowDialog) { - Navigator.of(context).pop(); - } - } - String _gatherChangelog(int from) { if (from < 100) { from *= 10; diff --git a/app/lib/widget/viewer_detail_pane.dart b/app/lib/widget/viewer_detail_pane.dart index d00c6837..29f92cee 100644 --- a/app/lib/widget/viewer_detail_pane.dart +++ b/app/lib/widget/viewer_detail_pane.dart @@ -7,7 +7,6 @@ import 'package:intl/intl.dart'; import 'package:kiwi/kiwi.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/app_localizations.dart'; import 'package:nc_photos/debug_util.dart'; import 'package:nc_photos/di_container.dart'; @@ -17,7 +16,6 @@ import 'package:nc_photos/entity/album/cover_provider.dart'; import 'package:nc_photos/entity/album/item.dart'; import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/k.dart' as k; import 'package:nc_photos/notified_action.dart'; import 'package:nc_photos/platform/features.dart' as features; @@ -59,6 +57,16 @@ class ViewerDetailPane extends StatefulWidget { } class _ViewerDetailPaneState extends State { + _ViewerDetailPaneState() { + final c = KiwiContainer().resolve(); + assert(require(c)); + _c = c; + } + + static bool require(DiContainer c) => + DiContainer.has(c, DiType.fileRepo) && + DiContainer.has(c, DiType.albumRepo); + @override initState() { super.initState(); @@ -380,8 +388,7 @@ class _ViewerDetailPaneState extends State { try { await NotifiedAction( () async { - final albumRepo = AlbumRepo(AlbumCachedDataSource(AppDb())); - await UpdateAlbum(albumRepo)( + await UpdateAlbum(_c.albumRepo)( widget.account, widget.album!.copyWith( coverProvider: AlbumManualCoverProvider( @@ -427,8 +434,7 @@ class _ViewerDetailPaneState extends State { try { await NotifiedAction( () async { - final fileRepo = FileRepo(FileCachedDataSource(AppDb())); - await UpdateProperty(fileRepo) + await UpdateProperty(_c.fileRepo) .updateIsArchived(widget.account, widget.file, false); if (mounted) { Navigator.of(context).pop(); @@ -464,9 +470,8 @@ class _ViewerDetailPaneState extends State { if (value == null || value is! DateTime) { return; } - final fileRepo = FileRepo(FileCachedDataSource(AppDb())); try { - await UpdateProperty(fileRepo) + await UpdateProperty(_c.fileRepo) .updateOverrideDateTime(widget.account, widget.file, value); if (mounted) { setState(() { @@ -520,6 +525,8 @@ class _ViewerDetailPaneState extends State { return false; } + late final DiContainer _c; + late DateTime _dateTime; // EXIF data String? _model; diff --git a/app/pubspec.lock b/app/pubspec.lock index 01eae0bf..a3f78862 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -15,6 +15,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.0" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.0" android_intent_plus: dependency: "direct main" description: @@ -108,6 +115,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.9" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.11" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.3" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.3.3" cached_network_image: dependency: "direct main" description: @@ -143,6 +206,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -150,6 +227,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" collection: dependency: "direct main" description: @@ -227,6 +311,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.2" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.3" dbus: dependency: transitive description: @@ -299,6 +390,20 @@ packages: url: "https://gitlab.com/nc-photos/flutter-draggable-scrollbar" source: git version: "0.1.0" + drift: + dependency: "direct main" + description: + name: drift + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.1" + drift_dev: + dependency: "direct dev" + description: + name: drift_dev + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" equatable: dependency: "direct main" description: @@ -336,6 +441,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" flutter: dependency: "direct main" description: flutter @@ -467,6 +579,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.0" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" hashcodes: dependency: transitive description: @@ -502,20 +621,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.1" - idb_shim: - dependency: "direct main" - description: - name: idb_shim - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - idb_sqflite: - dependency: "direct main" - description: - name: idb_sqflite - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" image_size_getter: dependency: "direct main" description: @@ -546,6 +651,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.0" kiwi: dependency: "direct main" description: @@ -833,6 +945,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" quiver: dependency: "direct main" description: @@ -840,6 +959,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.0" + recase: + dependency: transitive + description: + name: recase + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" rxdart: dependency: transitive description: @@ -882,13 +1008,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.0" - sembast: - dependency: transitive - description: - name: sembast - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.2" shared_preferences: dependency: "direct main" description: @@ -978,6 +1097,13 @@ packages: description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.2" source_map_stack_trace: dependency: transitive description: @@ -1000,7 +1126,7 @@ packages: source: hosted version: "1.9.0" sqflite: - dependency: "direct main" + dependency: transitive description: name: sqflite url: "https://pub.dartlang.org" @@ -1013,6 +1139,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.1+1" + sqlite3: + dependency: transitive + description: + name: sqlite3 + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.2" + sqlite3_flutter_libs: + dependency: "direct main" + description: + name: sqlite3_flutter_libs + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.8" + sqlparser: + dependency: transitive + description: + name: sqlparser + url: "https://pub.dartlang.org" + source: hosted + version: "0.22.0" stack_trace: dependency: transitive description: @@ -1076,6 +1223,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.16" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" tuple: dependency: "direct main" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 020218aa..0efd41dc 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -45,6 +45,7 @@ dependencies: git: url: https://gitlab.com/nc-photos/flutter-draggable-scrollbar ref: v0.1.0-nc-photos-5 + drift: ^1.7.1 equatable: ^2.0.0 event_bus: ^2.0.0 exifdart: @@ -65,9 +66,6 @@ dependencies: # android/ios only google_maps_flutter: ^2.1.0 http: ^0.13.1 - idb_shim: ^2.0.0 - # android/ios only - idb_sqflite: ^1.0.0 image_size_getter: git: url: https://gitlab.com/nc-photos/dart_image_size_getter @@ -88,8 +86,7 @@ dependencies: quiver: ^3.1.0 screen_brightness: ^0.2.1 shared_preferences: ^2.0.8 - # android/ios only - sqflite: ^2.0.0 + sqlite3_flutter_libs: ^0.5.8 synchronized: ^3.0.0 tuple: ^2.0.0 url_launcher: ^6.0.3 @@ -113,6 +110,8 @@ dependency_overrides: dev_dependencies: test: any bloc_test: any + build_runner: ^2.1.11 + drift_dev: ^1.7.0 flutter_lints: ^2.0.1 # flutter_test: # sdk: flutter diff --git a/app/test/bloc/list_album_share_outlier_test.dart b/app/test/bloc/list_album_share_outlier_test.dart index 1a5cf2be..97fc379b 100644 --- a/app/test/bloc/list_album_share_outlier_test.dart +++ b/app/test/bloc/list_album_share_outlier_test.dart @@ -2,7 +2,7 @@ import 'package:bloc_test/bloc_test.dart'; import 'package:nc_photos/bloc/list_album_share_outlier.dart'; import 'package:nc_photos/ci_string.dart'; import 'package:nc_photos/di_container.dart'; -import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:test/test.dart'; import '../mock_type.dart'; @@ -56,8 +56,9 @@ void _initialState() { final c = DiContainer( shareRepo: MockShareRepo(), shareeRepo: MockShareeRepo(), - appDb: MockAppDb(), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); final bloc = ListAlbumShareOutlierBloc(c); expect(bloc.state.account, null); expect(bloc.state.items, const []); @@ -84,11 +85,14 @@ void _testQueryUnsharedAlbumExtraShare(String description) { shareeRepo: MockShareeMemoryRepo([ util.buildSharee(shareWith: "user1".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -112,18 +116,22 @@ void _testQueryUnsharedAlbumExtraJsonShare(String description) { final account = util.buildAccount(); final album = util.AlbumBuilder().build(); final albumFile = album.albumFile!; - final c = DiContainer( - shareRepo: MockShareMemoryRepo([ - util.buildShare(id: "0", file: albumFile, shareWith: "user1"), - ]), - shareeRepo: MockShareeMemoryRepo([ - util.buildSharee(shareWith: "user1".toCi()), - ]), - appDb: MockAppDb(), - ); + late final DiContainer c; blocTest( description, + setUp: () async { + c = DiContainer( + shareRepo: MockShareMemoryRepo([ + util.buildShare(id: "0", file: albumFile, shareWith: "user1"), + ]), + shareeRepo: MockShareeMemoryRepo([ + util.buildSharee(shareWith: "user1".toCi()), + ]), + sqliteDb: util.buildTestDb(), + ); + }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -164,11 +172,14 @@ void _testQuerySharedAlbumMissingShare(String description) { shareeRepo: MockShareeMemoryRepo([ util.buildSharee(shareWith: "user1".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -215,11 +226,14 @@ void _testQuerySharedAlbumMissingManagedShareOtherAdded(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -272,12 +286,16 @@ void _testQuerySharedAlbumMissingManagedShareOtherReshared(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDb(obj, user1Account, user1Files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -321,11 +339,14 @@ void _testQuerySharedAlbumMissingUnmanagedShareOtherAdded(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -343,16 +364,20 @@ void _testQuerySharedAlbumMissingJsonShare(String description) { final account = util.buildAccount(); final album = (util.AlbumBuilder()..addShare("user1")).build(); final albumFile = album.albumFile!; - final c = DiContainer( - shareRepo: MockShareMemoryRepo(), - shareeRepo: MockShareeMemoryRepo([ - util.buildSharee(shareWith: "user1".toCi()), - ]), - appDb: MockAppDb(), - ); + late final DiContainer c; blocTest( description, + setUp: () async { + c = DiContainer( + shareRepo: MockShareMemoryRepo(), + shareeRepo: MockShareeMemoryRepo([ + util.buildSharee(shareWith: "user1".toCi()), + ]), + sqliteDb: util.buildTestDb(), + ); + }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -396,11 +421,14 @@ void _testQuerySharedAlbumExtraShare(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -451,12 +479,16 @@ void _testQuerySharedAlbumExtraShareOtherAdded(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDb(obj, user1Account, user1Files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -513,12 +545,16 @@ void _testQuerySharedAlbumExtraUnmanagedShare(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDb(obj, user1Account, user1Files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -537,20 +573,24 @@ void _testQuerySharedAlbumExtraJsonShare(String description) { final account = util.buildAccount(); final album = (util.AlbumBuilder()..addShare("user1")).build(); final albumFile = album.albumFile!; - final c = DiContainer( - shareRepo: MockShareMemoryRepo([ - util.buildShare(id: "0", file: albumFile, shareWith: "user1"), - util.buildShare(id: "1", file: albumFile, shareWith: "user2"), - ]), - shareeRepo: MockShareeMemoryRepo([ - util.buildSharee(shareWith: "user1".toCi()), - util.buildSharee(shareWith: "user2".toCi()), - ]), - appDb: MockAppDb(), - ); + late final DiContainer c; blocTest( description, + setUp: () async { + c = DiContainer( + shareRepo: MockShareMemoryRepo([ + util.buildShare(id: "0", file: albumFile, shareWith: "user1"), + util.buildShare(id: "1", file: albumFile, shareWith: "user2"), + ]), + shareeRepo: MockShareeMemoryRepo([ + util.buildSharee(shareWith: "user1".toCi()), + util.buildSharee(shareWith: "user2".toCi()), + ]), + sqliteDb: util.buildTestDb(), + ); + }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -592,11 +632,14 @@ void _testQuerySharedAlbumNotOwnedMissingShareToOwner(String description) { shareeRepo: MockShareeMemoryRepo([ util.buildSharee(shareWith: "user1".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -643,11 +686,14 @@ void _testQuerySharedAlbumNotOwnedMissingManagedShare(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -692,11 +738,14 @@ void _testQuerySharedAlbumNotOwnedMissingUnmanagedShare(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -718,20 +767,24 @@ void _testQuerySharedAlbumNotOwnedMissingJsonShare(String description) { ..addShare("user2")) .build(); final albumFile = album.albumFile!; - final c = DiContainer( - shareRepo: MockShareMemoryRepo([ - util.buildShare( - id: "0", file: albumFile, uidOwner: "user1", shareWith: "admin"), - ]), - shareeRepo: MockShareeMemoryRepo([ - util.buildSharee(shareWith: "user1".toCi()), - util.buildSharee(shareWith: "user2".toCi()), - ]), - appDb: MockAppDb(), - ); + late final DiContainer c; blocTest( description, + setUp: () async { + c = DiContainer( + shareRepo: MockShareMemoryRepo([ + util.buildShare( + id: "0", file: albumFile, uidOwner: "user1", shareWith: "admin"), + ]), + shareeRepo: MockShareeMemoryRepo([ + util.buildSharee(shareWith: "user1".toCi()), + util.buildSharee(shareWith: "user2".toCi()), + ]), + sqliteDb: util.buildTestDb(), + ); + }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -772,11 +825,14 @@ void _testQuerySharedAlbumNotOwnedExtraManagedShare(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -822,11 +878,14 @@ void _testQuerySharedAlbumNotOwnedExtraUnmanagedShare(String description) { util.buildSharee(shareWith: "user1".toCi()), util.buildSharee(shareWith: "user2".toCi()), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), @@ -851,22 +910,26 @@ void _testQuerySharedAlbumNotOwnedExtraJsonShare(String description) { final album = (util.AlbumBuilder(ownerId: "user1")..addShare("admin")).build(); final albumFile = album.albumFile!; - final c = DiContainer( - shareRepo: MockShareMemoryRepo([ - util.buildShare( - id: "0", file: albumFile, uidOwner: "user1", shareWith: "admin"), - util.buildShare( - id: "1", file: albumFile, uidOwner: "user1", shareWith: "user2"), - ]), - shareeRepo: MockShareeMemoryRepo([ - util.buildSharee(shareWith: "user1".toCi()), - util.buildSharee(shareWith: "user2".toCi()), - ]), - appDb: MockAppDb(), - ); + late final DiContainer c; blocTest( description, + setUp: () async { + c = DiContainer( + shareRepo: MockShareMemoryRepo([ + util.buildShare( + id: "0", file: albumFile, uidOwner: "user1", shareWith: "admin"), + util.buildShare( + id: "1", file: albumFile, uidOwner: "user1", shareWith: "user2"), + ]), + shareeRepo: MockShareeMemoryRepo([ + util.buildSharee(shareWith: "user1".toCi()), + util.buildSharee(shareWith: "user2".toCi()), + ]), + sqliteDb: util.buildTestDb(), + ); + }, + tearDown: () => c.sqliteDb.close(), build: () => ListAlbumShareOutlierBloc(c), act: (bloc) => bloc.add(ListAlbumShareOutlierBlocQuery(account, album)), wait: const Duration(milliseconds: 500), diff --git a/app/test/bloc/ls_dir_test.dart b/app/test/bloc/ls_dir_test.dart index 1134c16e..d303826a 100644 --- a/app/test/bloc/ls_dir_test.dart +++ b/app/test/bloc/ls_dir_test.dart @@ -1,8 +1,6 @@ import 'package:bloc_test/bloc_test.dart'; -import 'package:nc_photos/account.dart'; import 'package:nc_photos/bloc/ls_dir.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:path/path.dart' as path_lib; import 'package:test/test.dart'; import '../mock_type.dart'; @@ -134,32 +132,30 @@ void main() { }); } -class _MockFileRepo extends MockFileRepo { - @override - list(Account account, File root) async { - return [ - File( - path: "remote.php/dav/files/admin/test1.jpg", - ), - File( - path: "remote.php/dav/files/admin/d1", - isCollection: true, - ), - File( - path: "remote.php/dav/files/admin/d1/test2.jpg", - ), - File( - path: "remote.php/dav/files/admin/d1/d2-1", - isCollection: true, - ), - File( - path: "remote.php/dav/files/admin/d1/d2-2", - isCollection: true, - ), - File( - path: "remote.php/dav/files/admin/d1/d2-1/d3", - isCollection: true, - ), - ].where((element) => path_lib.dirname(element.path) == root.path).toList(); - } +class _MockFileRepo extends MockFileMemoryRepo { + _MockFileRepo() + : super([ + File( + path: "remote.php/dav/files/admin/test1.jpg", + ), + File( + path: "remote.php/dav/files/admin/d1", + isCollection: true, + ), + File( + path: "remote.php/dav/files/admin/d1/test2.jpg", + ), + File( + path: "remote.php/dav/files/admin/d1/d2-1", + isCollection: true, + ), + File( + path: "remote.php/dav/files/admin/d1/d2-2", + isCollection: true, + ), + File( + path: "remote.php/dav/files/admin/d1/d2-1/d3", + isCollection: true, + ), + ]); } diff --git a/app/test/entity/album/data_source_test.dart b/app/test/entity/album/data_source_test.dart new file mode 100644 index 00000000..69079e04 --- /dev/null +++ b/app/test/entity/album/data_source_test.dart @@ -0,0 +1,335 @@ +import 'package:nc_photos/ci_string.dart'; +import 'package:nc_photos/di_container.dart'; +import 'package:nc_photos/entity/album.dart'; +import 'package:nc_photos/entity/album/cover_provider.dart'; +import 'package:nc_photos/entity/album/data_source.dart'; +import 'package:nc_photos/entity/album/item.dart'; +import 'package:nc_photos/entity/album/provider.dart'; +import 'package:nc_photos/entity/album/sort_provider.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; +import 'package:nc_photos/exception.dart'; +import 'package:nc_photos/or_null.dart'; +import 'package:test/test.dart'; + +import '../../test_util.dart' as util; + +void main() { + group("AlbumSqliteDbDataSource", () { + group("get", () { + test("normal", _dbGet); + test("n/a", _dbGetNa); + }); + group("getAll", () { + test("normal", _dbGetAll); + test("n/a", _dbGetAllNa); + }); + group("update", () { + test("existing album", _dbUpdateExisting); + test("new album", _dbUpdateNew); + test("shares", _dbUpdateShares); + test("delete shares", _dbUpdateDeleteShares); + }); + }); +} + +/// Get an album from DB +/// +/// Expect: album +Future _dbGet() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + (util.AlbumBuilder.ofId(albumId: 1)).build(), + ]; + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles( + c.sqliteDb, account, albums.map((a) => a.albumFile!)); + await util.insertAlbums(c.sqliteDb, account, albums); + }); + + final src = AlbumSqliteDbDataSource(c); + expect(await src.get(account, albums[0].albumFile!), albums[0]); +} + +/// Get an album that doesn't exist in DB +/// +/// Expect: CacheNotFoundException +Future _dbGetNa() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + ]; + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + }); + + final src = AlbumSqliteDbDataSource(c); + expect( + () async => await src.get(account, albums[0].albumFile!), + throwsA(const TypeMatcher()), + ); +} + +/// Get multiple albums from DB +/// +/// Expect: albums +Future _dbGetAll() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + (util.AlbumBuilder.ofId(albumId: 1)).build(), + (util.AlbumBuilder.ofId(albumId: 2)).build(), + ]; + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles( + c.sqliteDb, account, albums.map((a) => a.albumFile!)); + await util.insertAlbums(c.sqliteDb, account, albums); + }); + + final src = AlbumSqliteDbDataSource(c); + expect( + await src + .getAll(account, [albums[0].albumFile!, albums[2].albumFile!]).toList(), + [albums[0], albums[2]], + ); +} + +/// Get multiple albums that doesn't exists in DB +/// +/// Expect: ExceptionEvent with CacheNotFoundException +Future _dbGetAllNa() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + (util.AlbumBuilder.ofId(albumId: 1)).build(), + (util.AlbumBuilder.ofId(albumId: 2)).build(), + ]; + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, [albums[0].albumFile!]); + await util.insertAlbums(c.sqliteDb, account, [albums[0]]); + }); + + final src = AlbumSqliteDbDataSource(c); + final results = await src + .getAll(account, [albums[0].albumFile!, albums[2].albumFile!]).toList(); + expect(results.length, 2); + expect(results[0], albums[0]); + expect( + () => throw results[1], + throwsA(const TypeMatcher()), + ); +} + +/// Update an existing album in DB +/// +/// Expect: album updated +Future _dbUpdateExisting() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + (util.AlbumBuilder.ofId(albumId: 1)).build(), + ]; + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg")) + .build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles( + c.sqliteDb, account, albums.map((a) => a.albumFile!)); + await util.insertAlbums(c.sqliteDb, account, albums); + }); + + final updateAlbum = albums[1].copyWith( + name: "edit", + lastUpdated: OrNull(DateTime.utc(2021, 2, 3, 4, 5, 6)), + provider: AlbumStaticProvider( + items: [ + AlbumLabelItem( + addedBy: "admin".toCi(), + addedAt: DateTime.utc(2021, 2, 3, 4, 5, 6), + text: "test", + ), + AlbumFileItem( + addedBy: "admin".toCi(), + addedAt: DateTime.utc(2021, 2, 3, 4, 5, 6), + file: files[1], + ), + ], + ), + coverProvider: AlbumManualCoverProvider(coverFile: files[1]), + sortProvider: const AlbumTimeSortProvider(isAscending: true), + ); + final src = AlbumSqliteDbDataSource(c); + await src.update(account, updateAlbum); + expect( + await util.listSqliteDbAlbums(c.sqliteDb), + {albums[0], updateAlbum}, + ); +} + +/// Update an album that doesn't exist in DB +/// +/// Expect: album inserted +Future _dbUpdateNew() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + ]; + final newAlbum = (util.AlbumBuilder.ofId(albumId: 1)).build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, + [...albums.map((a) => a.albumFile!), newAlbum.albumFile!]); + await util.insertAlbums(c.sqliteDb, account, albums); + }); + + final src = AlbumSqliteDbDataSource(c); + await src.update(account, newAlbum); + expect( + await util.listSqliteDbAlbums(c.sqliteDb), + {...albums, newAlbum}, + ); +} + +/// Update shares of an album +/// +/// Expect: album shares updated +Future _dbUpdateShares() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + (util.AlbumBuilder.ofId(albumId: 1)..addShare("user1")).build(), + ]; + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg")) + .build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles( + c.sqliteDb, account, albums.map((a) => a.albumFile!)); + await util.insertAlbums(c.sqliteDb, account, albums); + }); + + final updateAlbum = albums[1].copyWith( + name: "edit", + lastUpdated: OrNull(DateTime.utc(2021, 2, 3, 4, 5, 6)), + provider: AlbumStaticProvider( + items: [ + AlbumLabelItem( + addedBy: "admin".toCi(), + addedAt: DateTime.utc(2021, 2, 3, 4, 5, 6), + text: "test", + ), + AlbumFileItem( + addedBy: "admin".toCi(), + addedAt: DateTime.utc(2021, 2, 3, 4, 5, 6), + file: files[1], + ), + ], + ), + coverProvider: AlbumManualCoverProvider(coverFile: files[1]), + sortProvider: const AlbumTimeSortProvider(isAscending: true), + shares: OrNull([ + AlbumShare( + userId: "user1".toCi(), + sharedAt: DateTime.utc(2021, 2, 3, 4, 5, 6), + ), + AlbumShare( + userId: "user2".toCi(), + sharedAt: DateTime.utc(2021, 2, 3, 4, 5, 7), + ), + ]), + ); + final src = AlbumSqliteDbDataSource(c); + await src.update(account, updateAlbum); + expect( + await util.listSqliteDbAlbums(c.sqliteDb), + {albums[0], updateAlbum}, + ); +} + +/// Delete shares of an album +/// +/// Expect: album shares deleted +Future _dbUpdateDeleteShares() async { + final account = util.buildAccount(); + final albums = [ + (util.AlbumBuilder.ofId(albumId: 0)).build(), + (util.AlbumBuilder.ofId(albumId: 1)..addShare("user1")).build(), + ]; + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg")) + .build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles( + c.sqliteDb, account, albums.map((a) => a.albumFile!)); + await util.insertAlbums(c.sqliteDb, account, albums); + }); + + final updateAlbum = albums[1].copyWith( + name: "edit", + lastUpdated: OrNull(DateTime.utc(2021, 2, 3, 4, 5, 6)), + provider: AlbumStaticProvider( + items: [ + AlbumLabelItem( + addedBy: "admin".toCi(), + addedAt: DateTime.utc(2021, 2, 3, 4, 5, 6), + text: "test", + ), + AlbumFileItem( + addedBy: "admin".toCi(), + addedAt: DateTime.utc(2021, 2, 3, 4, 5, 6), + file: files[1], + ), + ], + ), + coverProvider: AlbumManualCoverProvider(coverFile: files[1]), + sortProvider: const AlbumTimeSortProvider(isAscending: true), + shares: OrNull(null), + ); + final src = AlbumSqliteDbDataSource(c); + await src.update(account, updateAlbum); + expect( + await util.listSqliteDbAlbums(c.sqliteDb), + {albums[0], updateAlbum}, + ); +} diff --git a/app/test/entity/file/data_source_test.dart b/app/test/entity/file/data_source_test.dart index 5f455828..8023e89a 100644 --- a/app/test/entity/file/data_source_test.dart +++ b/app/test/entity/file/data_source_test.dart @@ -1,16 +1,15 @@ -import 'package:nc_photos/app_db.dart'; +import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file/data_source.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/list_extension.dart'; -import 'package:nc_photos/object_extension.dart'; import 'package:nc_photos/or_null.dart'; import 'package:test/test.dart'; -import '../../mock_type.dart'; import '../../test_util.dart' as util; void main() { - group("FileAppDbDataSource", () { + group("FileSqliteDbDataSource", () { test("list", _list); test("listSingle", _listSingle); group("remove", () { @@ -19,7 +18,12 @@ void main() { test("dir w/ file", _removeDir); test("dir w/ sub dir", _removeDirWithSubDir); }); - test("updateProperty", _updateProperty); + group("updateProperty", () { + test("file properties", _updateFileProperty); + test("update metadata", _updateMetadata); + test("add metadata", _updateAddMetadata); + test("delete metadata", _updateDeleteMetadata); + }); }); } @@ -38,12 +42,19 @@ Future _list() async { ..addDir("admin/test") ..addJpeg("admin/test/test2.jpg")) .build(); - final appDb = await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDbDir(obj, account, files[0], files.slice(1, 3)); - await util.fillAppDbDir(obj, account, files[2], [files[3]]); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); }); - final src = FileAppDbDataSource(appDb); + + final src = FileSqliteDbDataSource(c); expect(await src.list(account, files[0]), files.slice(0, 3)); expect(await src.list(account, files[2]), files.slice(2, 4)); } @@ -54,69 +65,83 @@ Future _list() async { Future _listSingle() async { final account = util.buildAccount(); final files = (util.FilesBuilder()..addDir("admin")).build(); - final appDb = await MockAppDb().applyFuture((obj) async { - await util.fillAppDbDir(obj, account, files[0], []); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], const []); }); - final src = FileAppDbDataSource(appDb); + + final src = FileSqliteDbDataSource(c); expect(() async => await src.listSingle(account, files[0]), throwsUnimplementedError); } /// Remove a file /// -/// Expect: entry removed from file2Store +/// Expect: entry removed from Files table Future _removeFile() async { final account = util.buildAccount(); final files = (util.FilesBuilder() ..addDir("admin") ..addJpeg("admin/test1.jpg")) .build(); - final appDb = await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDbDir(obj, account, files[0], [files[1]]); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); }); - final src = FileAppDbDataSource(appDb); + + final src = FileSqliteDbDataSource(c); await src.remove(account, files[1]); expect( - (await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e))) - .map((e) => e.file) - .toList(), - [files[0]], + await util.listSqliteDbFiles(c.sqliteDb), + {files[0]}, ); } /// Remove an empty dir /// -/// Expect: dir entry removed from dirStore; -/// no changes to parent dir entry +/// Expect: entry removed from DirFiles table Future _removeEmptyDir() async { final account = util.buildAccount(); final files = (util.FilesBuilder() ..addDir("admin") ..addDir("admin/test")) .build(); - final appDb = await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDbDir(obj, account, files[0], [files[1]]); - await util.fillAppDbDir(obj, account, files[1], []); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); + await util.insertDirRelation(c.sqliteDb, account, files[1], const []); }); - final src = FileAppDbDataSource(appDb); + + final src = FileSqliteDbDataSource(c); await src.remove(account, files[1]); // parent dir is not updated, parent dir is only updated when syncing with // remote expect( - await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)), - [ - AppDbDirEntry.fromFiles(account, files[0], [files[1]]), - ], + await util.listSqliteDbDirs(c.sqliteDb), + { + files[0]: {files[0]}, + }, ); } /// Remove a dir with file /// -/// Expect: file entries under the dir removed from file2Store +/// Expect: file entries under the dir removed from Files table Future _removeDir() async { final account = util.buildAccount(); final files = (util.FilesBuilder() @@ -124,25 +149,28 @@ Future _removeDir() async { ..addDir("admin/test") ..addJpeg("admin/test/test1.jpg")) .build(); - final appDb = await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDbDir(obj, account, files[0], [files[1]]); - await util.fillAppDbDir(obj, account, files[1], [files[2]]); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); + await util.insertDirRelation(c.sqliteDb, account, files[1], [files[2]]); }); - final src = FileAppDbDataSource(appDb); + + final src = FileSqliteDbDataSource(c); await src.remove(account, files[1]); expect( - (await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e))) - .map((e) => e.file) - .toList(), - [files[0]], + await util.listSqliteDbFiles(c.sqliteDb), + {files[0]}, ); } /// Remove a dir with file /// -/// Expect: file entries under the dir removed from file2Store +/// Expect: file entries under the dir removed from Files table Future _removeDirWithSubDir() async { final account = util.buildAccount(); final files = (util.FilesBuilder() @@ -151,75 +179,192 @@ Future _removeDirWithSubDir() async { ..addDir("admin/test/test2") ..addJpeg("admin/test/test2/test3.jpg")) .build(); - final appDb = await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDbDir(obj, account, files[0], [files[1]]); - await util.fillAppDbDir(obj, account, files[1], [files[2]]); - await util.fillAppDbDir(obj, account, files[2], [files[3]]); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); + await util.insertDirRelation(c.sqliteDb, account, files[1], [files[2]]); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); }); - final src = FileAppDbDataSource(appDb); + + final src = FileSqliteDbDataSource(c); await src.remove(account, files[1]); expect( - await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)), - [ - AppDbDirEntry.fromFiles(account, files[0], [files[1]]), - ], + await util.listSqliteDbDirs(c.sqliteDb), + { + files[0]: {files[0]} + }, ); expect( - (await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e))) - .map((e) => e.file) - .toList(), - [files[0]], + await util.listSqliteDbFiles(c.sqliteDb), + {files[0]}, ); } /// Update the properties of a file /// -/// Expect: file's property updated in file2Store; -/// file's property updated in dirStore -Future _updateProperty() async { +/// Expect: file's property updated in Files table +Future _updateFileProperty() async { final account = util.buildAccount(); final files = (util.FilesBuilder() ..addDir("admin") ..addJpeg("admin/test1.jpg")) .build(); - final appDb = await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDbDir(obj, account, files[0], [files[1]]); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); }); - final src = FileAppDbDataSource(appDb); + + final src = FileSqliteDbDataSource(c); + await src.updateProperty( + account, + files[1], + isArchived: OrNull(true), + overrideDateTime: OrNull(DateTime.utc(2020, 1, 2, 3, 4, 5)), + ); + final expectFile = files[1].copyWith( + isArchived: OrNull(true), + overrideDateTime: OrNull(DateTime.utc(2020, 1, 2, 3, 4, 5)), + ); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {files[0], expectFile}, + ); +} + +/// Update metadata of a file +/// +/// Expect: Metadata updated in Images table +Future _updateMetadata() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg")) + .build(); + files[1] = files[1].copyWith( + metadata: OrNull(Metadata( + lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), + imageWidth: 123, + )), + ); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); + }); + + final src = FileSqliteDbDataSource(c); await src.updateProperty( account, files[1], metadata: OrNull(Metadata( - lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678), - imageWidth: 123, + lastUpdated: DateTime.utc(2021, 1, 2, 3, 4, 5), + imageWidth: 321, + imageHeight: 123, )), - isArchived: OrNull(true), - overrideDateTime: OrNull(DateTime.utc(2020, 1, 2, 3, 4, 5, 678)), ); final expectFile = files[1].copyWith( metadata: OrNull(Metadata( - lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5, 678), - imageWidth: 123, + lastUpdated: DateTime.utc(2021, 1, 2, 3, 4, 5), + imageWidth: 321, + imageHeight: 123, )), - isArchived: OrNull(true), - overrideDateTime: OrNull(DateTime.utc(2020, 1, 2, 3, 4, 5, 678)), ); expect( - await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)), - [ - AppDbDirEntry.fromFiles(account, files[0], [expectFile]), - ], - ); - expect( - (await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e))) - .map((e) => e.file) - .toList(), - [files[0], expectFile], + await util.listSqliteDbFiles(c.sqliteDb), + {files[0], expectFile}, + ); +} + +/// Add metadata to a file +/// +/// Expect: Metadata added to Images table +Future _updateAddMetadata() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg")) + .build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); + }); + + final src = FileSqliteDbDataSource(c); + await src.updateProperty( + account, + files[1], + metadata: OrNull(Metadata( + lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), + imageWidth: 123, + )), + ); + final expectFile = files[1].copyWith( + metadata: OrNull(Metadata( + lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), + imageWidth: 123, + )), + ); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {files[0], expectFile}, + ); +} + +/// Delete metadata of a file +/// +/// Expect: Metadata deleted from Images table +Future _updateDeleteMetadata() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg")) + .build(); + files[1] = files[1].copyWith( + metadata: OrNull(Metadata( + lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), + imageWidth: 123, + )), + ); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation(c.sqliteDb, account, files[0], [files[1]]); + }); + + final src = FileSqliteDbDataSource(c); + await src.updateProperty( + account, + files[1], + metadata: OrNull(null), + ); + final expectFile = files[1].copyWith( + metadata: OrNull(null), + ); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {files[0], expectFile}, ); } diff --git a/app/test/entity/file/file_cache_manager_test.dart b/app/test/entity/file/file_cache_manager_test.dart new file mode 100644 index 00000000..61c6d000 --- /dev/null +++ b/app/test/entity/file/file_cache_manager_test.dart @@ -0,0 +1,502 @@ +import 'package:nc_photos/di_container.dart'; +import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/entity/file/data_source.dart'; +import 'package:nc_photos/entity/file/file_cache_manager.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; +import 'package:nc_photos/list_extension.dart'; +import 'package:nc_photos/or_null.dart'; +import 'package:test/test.dart'; + +import '../../mock_type.dart'; +import '../../test_util.dart' as util; + +void main() { + group("FileCacheLoader", () { + group("default", () { + test("no cache", _loaderNoCache); + test("outdated", _loaderOutdatedCache); + test("query remote etag", _loaderQueryRemoteSameEtag); + test("query remote etag (updated)", _loaderQueryRemoteDiffEtag); + }); + }); + group("FileSqliteCacheUpdater", () { + test("identical", _updaterIdentical); + test("new file", _updaterNewFile); + test("delete file", _updaterDeleteFile); + test("delete dir", _updaterDeleteDir); + test("update file", _updaterUpdateFile); + test("new shared file", _updaterNewSharedFile); + test("new shared dir", _updaterNewSharedDir); + test("delete shared file", _updaterDeleteSharedFile); + test("delete shared dir", _updaterDeleteSharedDir); + }); +} + +/// Load dir: no cache +/// +/// Expect: null +Future _loaderNoCache() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin", etag: "1") + ..addJpeg("admin/test1.jpg", etag: "2") + ..addDir("admin/test", etag: "3") + ..addJpeg("admin/test/test2.jpg", etag: "4")) + .build(); + final c = DiContainer( + fileRepo: MockFileMemoryRepo(files), + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + }); + + final cacheSrc = FileSqliteDbDataSource(c); + final remoteSrc = MockFileWebdavDataSource(MockFileMemoryDataSource(files)); + final loader = FileCacheLoader(c, cacheSrc: cacheSrc, remoteSrc: remoteSrc); + expect(await loader(account, files[0]), null); +} + +/// Load dir: outdated cache +/// +/// Expect: return cache; +/// isGood == false +Future _loaderOutdatedCache() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin", etag: "1") + ..addJpeg("admin/test1.jpg", etag: "2") + ..addDir("admin/test", etag: "3") + ..addJpeg("admin/test/test2.jpg", etag: "4")) + .build(); + final c = DiContainer( + fileRepo: MockFileMemoryRepo(files), + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + final dbFiles = [ + files[0].copyWith(etag: OrNull("a")), + ...files.slice(1), + ]; + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, dbFiles); + await util.insertDirRelation( + c.sqliteDb, account, dbFiles[0], dbFiles.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, dbFiles[2], [dbFiles[3]]); + }); + + final cacheSrc = FileSqliteDbDataSource(c); + final remoteSrc = MockFileWebdavDataSource(MockFileMemoryDataSource(files)); + final loader = FileCacheLoader(c, cacheSrc: cacheSrc, remoteSrc: remoteSrc); + expect( + (await loader(account, files[0]))?.toSet(), + dbFiles.slice(0, 3).toSet(), + ); + expect(loader.isGood, false); +} + +/// Load dir: no etag, up-to-date cache +/// +/// Expect: return cache; +/// isGood == true +Future _loaderQueryRemoteSameEtag() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin", etag: "1") + ..addJpeg("admin/test1.jpg", etag: "2") + ..addDir("admin/test", etag: "3") + ..addJpeg("admin/test/test2.jpg", etag: "4")) + .build(); + final c = DiContainer( + fileRepo: MockFileMemoryRepo(files), + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final cacheSrc = FileSqliteDbDataSource(c); + final remoteSrc = MockFileWebdavDataSource(MockFileMemoryDataSource(files)); + final loader = FileCacheLoader(c, cacheSrc: cacheSrc, remoteSrc: remoteSrc); + expect( + (await loader(account, files[0].copyWith(etag: OrNull(null))))?.toSet(), + files.slice(0, 3).toSet(), + ); + expect(loader.isGood, true); +} + +/// Load dir: no etag, outdated cache +/// +/// Expect: return cache; +/// isGood == false +Future _loaderQueryRemoteDiffEtag() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin", etag: "1") + ..addJpeg("admin/test1.jpg", etag: "2") + ..addDir("admin/test", etag: "3") + ..addJpeg("admin/test/test2.jpg", etag: "4")) + .build(); + final c = DiContainer( + fileRepo: MockFileMemoryRepo(files), + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + final dbFiles = [ + files[0].copyWith(etag: OrNull("a")), + ...files.slice(1), + ]; + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, dbFiles); + await util.insertDirRelation( + c.sqliteDb, account, dbFiles[0], dbFiles.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, dbFiles[2], [dbFiles[3]]); + }); + + final cacheSrc = FileSqliteDbDataSource(c); + final remoteSrc = MockFileWebdavDataSource(MockFileMemoryDataSource(files)); + final loader = FileCacheLoader(c, cacheSrc: cacheSrc, remoteSrc: remoteSrc); + expect( + (await loader(account, files[0].copyWith(etag: OrNull(null))))?.toSet(), + dbFiles.slice(0, 3).toSet(), + ); + expect(loader.isGood, false); +} + +/// Update dir in cache: same set of files +/// +/// Expect: nothing happens +Future _updaterIdentical() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(account, files[0], remote: files.slice(0, 3)); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + files.toSet(), + ); +} + +/// Update dir in cache: new file +/// +/// Expect: new file added to Files table +Future _updaterNewFile() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final newFile = (util.FilesBuilder(initialFileId: files.length) + ..addJpeg("admin/test2.jpg")) + .build() + .first; + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(account, files[0], remote: [...files.slice(0, 3), newFile]); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {...files, newFile}, + ); +} + +/// Update dir in cache: file missing +/// +/// Expect: missing file deleted from Files table +Future _updaterDeleteFile() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(account, files[0], remote: [files[0], files[2]]); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {files[0], ...files.slice(2)}, + ); +} + +/// Update dir in cache: dir missing +/// +/// Expect: missing dir deleted from Files table; +/// missing dir deleted from DirFiles table +/// files under dir deleted from Files table; +/// dirs under dir deleted from DirFiles table; +Future _updaterDeleteDir() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(account, files[0], remote: files.slice(0, 2)); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + files.slice(0, 2).toSet(), + ); + expect( + await util.listSqliteDbDirs(c.sqliteDb), + { + files[0]: files.slice(0, 2).toSet(), + }, + ); +} + +/// Update dir in cache: file updated +/// +/// Expect: file updated in Files table +Future _updaterUpdateFile() async { + final account = util.buildAccount(); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg", contentLength: 321) + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final newFile = files[1].copyWith(contentLength: 654); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(account, files[0], + remote: [files[0], newFile, ...files.slice(2)]); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {files[0], newFile, ...files.slice(2)}, + ); +} + +/// Update dir in cache: new shared file +/// +/// Expect: file added to AccountFiles table +Future _updaterNewSharedFile() async { + final account = util.buildAccount(); + final user1Account = util.buildAccount(username: "user1"); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final user1Files = (util.FilesBuilder(initialFileId: files.length) + ..addDir("user1", ownerId: "user1")) + .build(); + user1Files + .add(files[1].copyWith(path: "remote.php/dav/files/user1/test1.jpg")); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(user1Account, user1Files[0], remote: user1Files); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {...files, ...user1Files}, + ); +} + +/// Update dir in cache: new shared dir +/// +/// Expect: file added to AccountFiles table +Future _updaterNewSharedDir() async { + final account = util.buildAccount(); + final user1Account = util.buildAccount(username: "user1"); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg", ownerId: "user1") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final user1Files = []; + user1Files.add(files[2].copyWith(path: "remote.php/dav/files/user1/share")); + user1Files.add( + files[3].copyWith(path: "remote.php/dav/files/user1/share/test2.jpg")); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(user1Account, user1Files[0], remote: user1Files); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {...files, ...user1Files}, + ); +} + +/// Update dir in cache: shared file missing +/// +/// Expect: file removed from AccountFiles table; +/// file remained in Files table +Future _updaterDeleteSharedFile() async { + final account = util.buildAccount(); + final user1Account = util.buildAccount(username: "user1"); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final user1Files = + (util.FilesBuilder(initialFileId: files.length)..addDir("user1")).build(); + user1Files + .add(files[1].copyWith(path: "remote.php/dav/files/user1/test1.jpg")); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + await util.insertDirRelation( + c.sqliteDb, user1Account, user1Files[0], [user1Files[1]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(user1Account, user1Files[0], remote: [user1Files[0]]); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {...files, user1Files[0]}, + ); +} + +/// Update dir in cache: shared dir missing +/// +/// Expect: file removed from AccountFiles table; +/// file remained in Files table +Future _updaterDeleteSharedDir() async { + final account = util.buildAccount(); + final user1Account = util.buildAccount(username: "user1"); + final files = (util.FilesBuilder() + ..addDir("admin") + ..addJpeg("admin/test1.jpg") + ..addDir("admin/test") + ..addJpeg("admin/test/test2.jpg")) + .build(); + final user1Files = + (util.FilesBuilder(initialFileId: files.length)..addDir("user1")).build(); + user1Files.add(files[2].copyWith(path: "remote.php/dav/files/user1/share")); + user1Files.add( + files[3].copyWith(path: "remote.php/dav/files/user1/share/test2.jpg")); + final c = DiContainer( + sqliteDb: util.buildTestDb(), + ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertDirRelation( + c.sqliteDb, account, files[0], files.slice(1, 3)); + await util.insertDirRelation(c.sqliteDb, account, files[2], [files[3]]); + + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + await util.insertDirRelation( + c.sqliteDb, user1Account, user1Files[0], [user1Files[1]]); + }); + + final updater = FileSqliteCacheUpdater(c); + await updater(user1Account, user1Files[0], remote: [user1Files[0]]); + expect( + await util.listSqliteDbFiles(c.sqliteDb), + {...files, user1Files[0]}, + ); +} diff --git a/app/test/entity/file_test.dart b/app/test/entity/file_test.dart index a1470b53..d5c0d4e3 100644 --- a/app/test/entity/file_test.dart +++ b/app/test/entity/file_test.dart @@ -752,7 +752,7 @@ void main() { }); test("etag", () { - final file = src.copyWith(etag: "000"); + final file = src.copyWith(etag: OrNull("000")); expect( file, File( diff --git a/app/test/mock_type.dart b/app/test/mock_type.dart index cec8bfe0..9680383e 100644 --- a/app/test/mock_type.dart +++ b/app/test/mock_type.dart @@ -3,26 +3,22 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'package:event_bus/event_bus.dart'; -import 'package:idb_shim/idb.dart'; -import 'package:idb_shim/idb_client_memory.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/ci_string.dart'; import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/file.dart'; +import 'package:nc_photos/entity/file/data_source.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/sharee.dart'; +import 'package:nc_photos/exception_event.dart'; +import 'package:nc_photos/future_util.dart' as future_util; import 'package:nc_photos/or_null.dart'; +import 'package:path/path.dart' as path_lib; /// Mock of [AlbumRepo] where all methods will throw UnimplementedError class MockAlbumRepo implements AlbumRepo { - @override - Future cleanUp(Account account, String rootDir, List albumFiles) { - throw UnimplementedError(); - } - @override Future create(Account account, Album album) { throw UnimplementedError(); @@ -36,6 +32,11 @@ class MockAlbumRepo implements AlbumRepo { throw UnimplementedError(); } + @override + Stream getAll(Account account, List albumFiles) { + throw UnimplementedError(); + } + @override Future update(Account account, Album album) { throw UnimplementedError(); @@ -54,6 +55,17 @@ class MockAlbumMemoryRepo extends MockAlbumRepo { element.albumFile?.compareServerIdentity(albumFile) == true); } + @override + getAll(Account account, List albumFiles) async* { + final results = await future_util.waitOr( + albumFiles.map((f) => get(account, f)), + (error, stackTrace) => ExceptionEvent(error, stackTrace), + ); + for (final r in results) { + yield r; + } + } + @override update(Account account, Album album) async { final i = albums.indexWhere((element) => @@ -67,120 +79,6 @@ class MockAlbumMemoryRepo extends MockAlbumRepo { final List albums; } -/// Each MockAppDb instance contains a unique memory database -class MockAppDb implements AppDb { - static Future create({ - bool hasAlbumStore = true, - bool hasFileDb2Store = true, - bool hasDirStore = true, - bool hasMetaStore = true, - // compat - bool hasFileStore = false, - bool hasFileDbStore = false, - }) async { - final inst = MockAppDb(); - final db = await inst._dbFactory.open( - "test.db", - version: 1, - onUpgradeNeeded: (event) async { - final db = event.database; - _createDb( - db, - hasAlbumStore: hasAlbumStore, - hasFileDb2Store: hasFileDb2Store, - hasDirStore: hasDirStore, - hasMetaStore: hasMetaStore, - hasFileStore: hasFileStore, - hasFileDbStore: hasFileDbStore, - ); - }, - ); - db.close(); - return inst; - } - - @override - Future use(Transaction Function(Database db) transactionBuilder, - FutureOr Function(Transaction transaction) fn) async { - final db = await _dbFactory.open( - "test.db", - version: 1, - onUpgradeNeeded: (event) async { - final db = event.database; - _createDb(db); - }, - ); - - Transaction? transaction; - try { - transaction = transactionBuilder(db); - return await fn(transaction); - } finally { - if (transaction != null) { - await transaction.completed; - } - db.close(); - } - } - - @override - Future delete() async { - await _dbFactory.deleteDatabase("test.db"); - } - - static void _createDb( - Database db, { - bool hasAlbumStore = true, - bool hasFileDb2Store = true, - bool hasDirStore = true, - bool hasMetaStore = true, - // compat - bool hasFileStore = false, - bool hasFileDbStore = false, - }) { - if (hasAlbumStore) { - final albumStore = db.createObjectStore(AppDb.albumStoreName); - albumStore.createIndex( - AppDbAlbumEntry.indexName, AppDbAlbumEntry.keyPath); - } - if (hasFileDb2Store) { - final file2Store = db.createObjectStore(AppDb.file2StoreName); - file2Store.createIndex(AppDbFile2Entry.strippedPathIndexName, - AppDbFile2Entry.strippedPathKeyPath); - file2Store.createIndex(AppDbFile2Entry.dateTimeEpochMsIndexName, - AppDbFile2Entry.dateTimeEpochMsKeyPath); - } - if (hasDirStore) { - db.createObjectStore(AppDb.dirStoreName); - } - if (hasMetaStore) { - db.createObjectStore(AppDb.metaStoreName, - keyPath: AppDbMetaEntry.keyPath); - } - - // compat - if (hasFileStore) { - final fileStore = db.createObjectStore(_fileStoreName); - fileStore.createIndex(_fileIndexName, _fileKeyPath); - } - if (hasFileDbStore) { - final fileDbStore = db.createObjectStore(_fileDbStoreName); - fileDbStore.createIndex(_fileDbIndexName, _fileDbKeyPath, unique: false); - } - } - - late final _dbFactory = newIdbFactoryMemory(); - - // compat only - static const _fileDbStoreName = "filesDb"; - static const _fileDbIndexName = "fileDbStore_namespacedFileId"; - static const _fileDbKeyPath = "namespacedFileId"; - - static const _fileStoreName = "files"; - static const _fileIndexName = "fileStore_path_index"; - static const _fileKeyPath = ["path", "index"]; -} - /// EventBus that ignore all events class MockEventBus implements EventBus { @override @@ -200,10 +98,10 @@ class MockEventBus implements EventBus { final _streamController = StreamController.broadcast(); } -/// Mock of [FileRepo] where all methods will throw UnimplementedError -class MockFileRepo implements FileRepo { +/// Mock of [FileDataSource] where all methods will throw UnimplementedError +class MockFileDataSource implements FileDataSource { @override - Future copy(Object account, File f, String destination, + Future copy(Account account, File f, String destination, {bool? shouldOverwrite}) { throw UnimplementedError(); } @@ -214,20 +112,17 @@ class MockFileRepo implements FileRepo { } @override - FileDataSource get dataSrc => throw UnimplementedError(); - - @override - Future getBinary(Account account, File file) { + Future getBinary(Account account, File f) { throw UnimplementedError(); } @override - Future> list(Account account, File root) async { + Future> list(Account account, File dir) { throw UnimplementedError(); } @override - Future listSingle(Account account, File root) async { + Future listSingle(Account account, File f) { throw UnimplementedError(); } @@ -243,14 +138,14 @@ class MockFileRepo implements FileRepo { } @override - Future remove(Account account, File file) { + Future remove(Account account, File f) { throw UnimplementedError(); } @override Future updateProperty( Account account, - File file, { + File f, { OrNull? metadata, OrNull? isArchived, OrNull? overrideDateTime, @@ -260,9 +155,9 @@ class MockFileRepo implements FileRepo { } } -/// [FileRepo] mock that support some ops with an internal List -class MockFileMemoryRepo extends MockFileRepo { - MockFileMemoryRepo([ +/// [FileDataSource] mock that support some ops with an internal List +class MockFileMemoryDataSource extends MockFileDataSource { + MockFileMemoryDataSource([ List initialData = const [], ]) : files = initialData.map((f) => f.copyWith()).toList() { _id = files @@ -274,7 +169,12 @@ class MockFileMemoryRepo extends MockFileRepo { @override list(Account account, File root) async { - return files.where((f) => file_util.isOrUnderDir(f, root)).toList(); + return files.where((f) => path_lib.dirname(f.path) == root.path).toList(); + } + + @override + listSingle(Account account, File file) async { + return files.where((f) => f.strippedPath == file.strippedPath).first; } @override @@ -289,9 +189,78 @@ class MockFileMemoryRepo extends MockFileRepo { } final List files; + // ignore: unused_field var _id = 0; } +class MockFileWebdavDataSource implements FileWebdavDataSource { + const MockFileWebdavDataSource(this.src); + + @override + copy(Account account, File f, String destination, {bool? shouldOverwrite}) => + src.copy(account, f, destination, shouldOverwrite: shouldOverwrite); + + @override + createDir(Account account, String path) => src.createDir(account, path); + + @override + getBinary(Account account, File f) => src.getBinary(account, f); + + @override + list(Account account, File dir, {int? depth}) async { + if (depth == 0) { + return [await src.listSingle(account, dir)]; + } else { + return src.list(account, dir); + } + } + + @override + listSingle(Account account, File f) => src.listSingle(account, f); + + @override + move(Account account, File f, String destination, {bool? shouldOverwrite}) => + src.move(account, f, destination, shouldOverwrite: shouldOverwrite); + + @override + putBinary(Account account, String path, Uint8List content) => + src.putBinary(account, path, content); + + @override + remove(Account account, File f) => src.remove(account, f); + + @override + updateProperty( + Account account, + File f, { + OrNull? metadata, + OrNull? isArchived, + OrNull? overrideDateTime, + bool? favorite, + }) => + src.updateProperty( + account, + f, + metadata: metadata, + isArchived: isArchived, + overrideDateTime: overrideDateTime, + favorite: favorite, + ); + + final MockFileMemoryDataSource src; +} + +/// [FileRepo] mock that support some ops with an internal List +class MockFileMemoryRepo extends FileRepo { + MockFileMemoryRepo([ + List initialData = const [], + ]) : super(MockFileMemoryDataSource(initialData)); + + List get files { + return (dataSrc as MockFileMemoryDataSource).files; + } +} + /// Mock of [ShareRepo] where all methods will throw UnimplementedError class MockShareRepo implements ShareRepo { @override @@ -426,6 +395,4 @@ extension MockDiContainerExtension on DiContainer { MockShareMemoryRepo get shareMemoryRepo => shareRepo as MockShareMemoryRepo; MockShareeMemoryRepo get shareeMemoryRepo => shareeRepo as MockShareeMemoryRepo; - - MockAppDb get appMemeoryDb => appDb as MockAppDb; } diff --git a/app/test/test_util.dart b/app/test/test_util.dart index e43afcc8..feb23067 100644 --- a/app/test/test_util.dart +++ b/app/test/test_util.dart @@ -1,9 +1,9 @@ import 'package:collection/collection.dart'; +import 'package:drift/drift.dart' as sql; +import 'package:drift/native.dart' as sql; import 'package:flutter/foundation.dart'; -import 'package:idb_shim/idb.dart'; import 'package:logging/logging.dart'; import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; import 'package:nc_photos/ci_string.dart'; import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album/cover_provider.dart'; @@ -13,8 +13,12 @@ import 'package:nc_photos/entity/album/sort_provider.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/share.dart'; import 'package:nc_photos/entity/sharee.dart'; +import 'package:nc_photos/entity/sqlite_table.dart' as sql; +import 'package:nc_photos/entity/sqlite_table_converter.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/iterable_extension.dart'; -import 'package:nc_photos/type.dart'; +import 'package:nc_photos/or_null.dart'; +import 'package:tuple/tuple.dart'; class FilesBuilder { FilesBuilder({ @@ -29,21 +33,25 @@ class FilesBuilder { String relativePath, { int? contentLength, String? contentType, + String? etag, DateTime? lastModified, bool isCollection = false, bool hasPreview = true, String ownerId = "admin", + Metadata? metadata, }) { files.add(File( path: "remote.php/dav/files/$relativePath", contentLength: contentLength, contentType: contentType, + etag: etag, lastModified: lastModified ?? DateTime.utc(2020, 1, 2, 3, 4, 5 + files.length), isCollection: isCollection, hasPreview: hasPreview, fileId: fileId++, ownerId: ownerId.toCi(), + metadata: metadata, )); } @@ -51,6 +59,7 @@ class FilesBuilder { String relativePath, String contentType, { int contentLength = 1024, + String? etag, DateTime? lastModified, bool hasPreview = true, String ownerId = "admin", @@ -59,6 +68,7 @@ class FilesBuilder { relativePath, contentLength: contentLength, contentType: contentType, + etag: etag, lastModified: lastModified, hasPreview: hasPreview, ownerId: ownerId, @@ -67,33 +77,62 @@ class FilesBuilder { void addJpeg( String relativePath, { int contentLength = 1024, + String? etag, DateTime? lastModified, bool hasPreview = true, String ownerId = "admin", + OrNull? metadata, }) => add( relativePath, contentLength: contentLength, contentType: "image/jpeg", + etag: etag, lastModified: lastModified, hasPreview: hasPreview, ownerId: ownerId, + metadata: metadata?.obj ?? + Metadata( + lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), + imageWidth: 640, + imageHeight: 480, + ), ); void addDir( String relativePath, { int contentLength = 1024, + String? etag, DateTime? lastModified, String ownerId = "admin", }) => add( relativePath, + etag: etag, lastModified: lastModified, isCollection: true, hasPreview: false, ownerId: ownerId, ); + void addAlbumJson( + String homeDir, + String filename, { + int contentLength = 1024, + String? etag, + DateTime? lastModified, + String ownerId = "admin", + }) => + add( + "$homeDir/.com.nkming.nc_photos/albums/$filename.nc_album.json", + contentLength: contentLength, + contentType: "application/json", + etag: etag, + lastModified: lastModified, + hasPreview: false, + ownerId: ownerId, + ); + final files = []; int fileId; } @@ -339,45 +378,189 @@ Sharee buildSharee({ shareWith: shareWith, ); -Future fillAppDb( - AppDb appDb, Account account, Iterable files) async { - await appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadWrite), - (transaction) async { - final file2Store = transaction.objectStore(AppDb.file2StoreName); - for (final f in files) { - await file2Store.put(AppDbFile2Entry.fromFile(account, f).toJson(), - AppDbFile2Entry.toPrimaryKeyForFile(account, f)); - } - }, +sql.SqliteDb buildTestDb() { + sql.driftRuntimeOptions.debugPrint = _debugPrintSql; + return sql.SqliteDb( + executor: sql.NativeDatabase.memory( + logStatements: true, + ), ); } -Future fillAppDbDir( - AppDb appDb, Account account, File dir, List children) async { - await appDb.use( - (db) => db.transaction(AppDb.dirStoreName, idbModeReadWrite), - (transaction) async { - final dirStore = transaction.objectStore(AppDb.dirStoreName); - await dirStore.put( - AppDbDirEntry.fromFiles(account, dir, children).toJson(), - AppDbDirEntry.toPrimaryKeyForDir(account, dir)); - }, - ); +Future insertFiles( + sql.SqliteDb db, Account account, Iterable files) async { + final dbAccount = await db.accountOf(account); + for (final f in files) { + final sharedQuery = db.selectOnly(db.files).join([ + sql.innerJoin( + db.accountFiles, db.accountFiles.file.equalsExp(db.files.rowId), + useColumns: false), + ]) + ..addColumns([db.files.rowId]) + ..where(db.accountFiles.account.equals(dbAccount.rowId).not()) + ..where(db.files.fileId.equals(f.fileId!)); + var rowId = (await sharedQuery.map((r) => r.read(db.files.rowId)).get()) + .firstOrNull; + final insert = SqliteFileConverter.toSql(dbAccount, f); + if (rowId == null) { + final dbFile = await db.into(db.files).insertReturning(insert.file); + rowId = dbFile.rowId; + } + final dbAccountFile = await db + .into(db.accountFiles) + .insertReturning(insert.accountFile.copyWith(file: sql.Value(rowId))); + if (insert.image != null) { + await db.into(db.images).insert( + insert.image!.copyWith(accountFile: sql.Value(dbAccountFile.rowId))); + } + if (insert.trash != null) { + await db + .into(db.trashes) + .insert(insert.trash!.copyWith(file: sql.Value(rowId))); + } + } } -Future> listAppDb( - AppDb appDb, String storeName, T Function(JsonObj) transform) { - return appDb.use( - (db) => db.transaction(storeName, idbModeReadOnly), - (transaction) async { - final store = transaction.objectStore(storeName); - return await store - .openCursor(autoAdvance: true) - .map((c) => c.value) - .cast() - .map((e) => transform(e.cast())) - .toList(); - }, - ); +Future insertDirRelation( + sql.SqliteDb db, Account account, File dir, Iterable children) async { + final dbAccount = await db.accountOf(account); + final dirRowIds = (await db + .accountFileRowIdsByFileIds([dir.fileId!], sqlAccount: dbAccount)) + .first; + final childRowIds = await db.accountFileRowIdsByFileIds( + [dir, ...children].map((f) => f.fileId!), + sqlAccount: dbAccount); + await db.batch((batch) { + batch.insertAll( + db.dirFiles, + childRowIds.map((c) => sql.DirFilesCompanion.insert( + dir: dirRowIds.fileRowId, + child: c.fileRowId, + )), + ); + }); +} + +Future insertAlbums( + sql.SqliteDb db, Account account, Iterable albums) async { + final dbAccount = await db.accountOf(account); + for (final a in albums) { + final rowIds = + await db.accountFileRowIdsOf(a.albumFile!, sqlAccount: dbAccount); + final insert = SqliteAlbumConverter.toSql(a, rowIds.fileRowId); + final dbAlbum = await db.into(db.albums).insertReturning(insert.album); + for (final s in insert.albumShares) { + await db + .into(db.albumShares) + .insert(s.copyWith(album: sql.Value(dbAlbum.rowId))); + } + } +} + +Future> listSqliteDbFiles(sql.SqliteDb db) async { + final query = db.select(db.files).join([ + sql.innerJoin( + db.accountFiles, db.accountFiles.file.equalsExp(db.files.rowId)), + sql.innerJoin( + db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account)), + sql.leftOuterJoin( + db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)), + sql.leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)), + ]); + return (await query + .map((r) => SqliteFileConverter.fromSql( + r.readTable(db.accounts).userId, + sql.CompleteFile( + r.readTable(db.files), + r.readTable(db.accountFiles), + r.readTableOrNull(db.images), + r.readTableOrNull(db.trashes), + ), + )) + .get()) + .toSet(); +} + +Future>> listSqliteDbDirs(sql.SqliteDb db) async { + final query = db.select(db.files).join([ + sql.innerJoin( + db.accountFiles, db.accountFiles.file.equalsExp(db.files.rowId)), + sql.innerJoin( + db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account)), + sql.leftOuterJoin( + db.images, db.images.accountFile.equalsExp(db.accountFiles.rowId)), + sql.leftOuterJoin(db.trashes, db.trashes.file.equalsExp(db.files.rowId)), + ]); + final fileMap = Map.fromEntries(await query.map((r) { + final f = sql.CompleteFile( + r.readTable(db.files), + r.readTable(db.accountFiles), + r.readTableOrNull(db.images), + r.readTableOrNull(db.trashes), + ); + return MapEntry( + f.file.rowId, + SqliteFileConverter.fromSql(r.readTable(db.accounts).userId, f), + ); + }).get()); + + final dirQuery = db.select(db.dirFiles); + final dirs = await dirQuery.map((r) => Tuple2(r.dir, r.child)).get(); + final result = >{}; + for (final d in dirs) { + (result[fileMap[d.item1]!] ??= {}).add(fileMap[d.item2]!); + } + return result; +} + +Future> listSqliteDbAlbums(sql.SqliteDb db) async { + final albumQuery = db.select(db.albums).join([ + sql.innerJoin(db.files, db.files.rowId.equalsExp(db.albums.file)), + sql.innerJoin( + db.accountFiles, db.accountFiles.file.equalsExp(db.files.rowId)), + sql.innerJoin( + db.accounts, db.accounts.rowId.equalsExp(db.accountFiles.account)), + ]); + final albums = await albumQuery.map((r) { + final albumFile = SqliteFileConverter.fromSql( + r.readTable(db.accounts).userId, + sql.CompleteFile( + r.readTable(db.files), + r.readTable(db.accountFiles), + null, + null, + ), + ); + return Tuple2( + r.read(db.albums.rowId), + SqliteAlbumConverter.fromSql(r.readTable(db.albums), albumFile, []), + ); + }).get(); + + final results = {}; + for (final a in albums) { + final shareQuery = db.select(db.albumShares) + ..where((t) => t.album.equals(a.item1)); + final dbShares = await shareQuery.get(); + results.add(a.item2.copyWith( + lastUpdated: OrNull(null), + shares: dbShares.isEmpty + ? null + : OrNull(dbShares + .map((s) => AlbumShare( + userId: s.userId.toCi(), + displayName: s.displayName, + sharedAt: s.sharedAt)) + .toList()), + )); + } + return results; +} + +bool shouldPrintSql = false; + +void _debugPrintSql(String log) { + if (shouldPrintSql) { + debugPrint(log, wrapWidth: 1024); + } } diff --git a/app/test/use_case/add_to_album_test.dart b/app/test/use_case/add_to_album_test.dart index 0434d6d9..6dc5ac9d 100644 --- a/app/test/use_case/add_to_album_test.dart +++ b/app/test/use_case/add_to_album_test.dart @@ -8,7 +8,7 @@ import 'package:nc_photos/entity/album/item.dart'; import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/sort_provider.dart'; import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/or_null.dart'; import 'package:nc_photos/pref.dart'; import 'package:nc_photos/use_case/add_to_album.dart'; @@ -44,13 +44,17 @@ Future _addFile() async { final album = util.AlbumBuilder().build(); final albumFile = album.albumFile!; final c = DiContainer( + fileRepo: MockFileMemoryRepo(), albumRepo: MockAlbumMemoryRepo([album]), shareRepo: MockShareRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, [file]); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, [file]); + }); await AddToAlbum(c)( account, @@ -80,7 +84,7 @@ Future _addFile() async { addedBy: "admin".toCi(), addedAt: DateTime.utc(2020, 1, 2, 3, 4, 5), file: file, - ), + ).minimize(), ], latestItemTime: DateTime.utc(2020, 1, 2, 3, 4, 5), ), @@ -106,13 +110,17 @@ Future _addExistingFile() async { final newFile = files[0].copyWith(); final albumFile = album.albumFile!; final c = DiContainer( + fileRepo: MockFileMemoryRepo(), albumRepo: MockAlbumMemoryRepo([album]), shareRepo: MockShareRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await AddToAlbum(c)( account, @@ -188,14 +196,19 @@ Future _addExistingSharedFile() async { final album = (util.AlbumBuilder()..addFileItem(files[0])).build(); final albumFile = album.albumFile!; final c = DiContainer( + fileRepo: MockFileMemoryRepo(), albumRepo: MockAlbumMemoryRepo([album]), shareRepo: MockShareRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDb(obj, user1Account, user1Files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + }); await AddToAlbum(c)( account, @@ -247,17 +260,21 @@ Future _addFileToSharedAlbumOwned() async { final album = (util.AlbumBuilder()..addShare("user1")).build(); final albumFile = album.albumFile!; final c = DiContainer( + fileRepo: MockFileMemoryRepo(), albumRepo: MockAlbumMemoryRepo([album]), shareRepo: MockShareMemoryRepo([ util.buildShare(id: "0", file: albumFile, shareWith: "user1"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, [file]); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider({ "isLabEnableSharedAlbum": true, })), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, [file]); + }); await AddToAlbum(c)( account, @@ -290,17 +307,21 @@ Future _addFileOwnedByUserToSharedAlbumOwned() async { final album = (util.AlbumBuilder()..addShare("user1")).build(); final albumFile = album.albumFile!; final c = DiContainer( + fileRepo: MockFileMemoryRepo(), albumRepo: MockAlbumMemoryRepo([album]), shareRepo: MockShareMemoryRepo([ util.buildShare(id: "0", file: albumFile, shareWith: "user1"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, [file]); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider({ "isLabEnableSharedAlbum": true, })), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, [file]); + }); await AddToAlbum(c)( account, @@ -335,6 +356,7 @@ Future _addFileToMultiuserSharedAlbumNotOwned() async { .build(); final albumFile = album.albumFile!; final c = DiContainer( + fileRepo: MockFileMemoryRepo(), albumRepo: MockAlbumMemoryRepo([album]), shareRepo: MockShareMemoryRepo([ util.buildShare( @@ -342,13 +364,16 @@ Future _addFileToMultiuserSharedAlbumNotOwned() async { util.buildShare( id: "1", file: albumFile, uidOwner: "user1", shareWith: "user2"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, [file]); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider({ "isLabEnableSharedAlbum": true, })), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, [file]); + }); await AddToAlbum(c)( account, diff --git a/app/test/use_case/compat/v37_test.dart b/app/test/use_case/compat/v37_test.dart deleted file mode 100644 index fa5b1dd7..00000000 --- a/app/test/use_case/compat/v37_test.dart +++ /dev/null @@ -1,230 +0,0 @@ -import 'package:idb_shim/idb_client.dart'; -import 'package:nc_photos/app_db.dart'; -import 'package:nc_photos/list_extension.dart'; -import 'package:nc_photos/use_case/compat/v37.dart'; -import 'package:test/test.dart'; - -import '../../mock_type.dart'; -import '../../test_util.dart' as util; - -void main() { - group("CompatV37", () { - group("isAppDbNeedMigration", () { - test("w/ meta entry == false", _isAppDbNeedMigrationEntryFalse); - test("w/ meta entry == true", _isAppDbNeedMigrationEntryTrue); - test("w/o meta entry", _isAppDbNeedMigrationWithoutEntry); - }); - group("migrateAppDb", () { - test("w/o nomedia", _migrateAppDbWithoutNomedia); - test("w/ nomedia", _migrateAppDb); - test("w/ nomedia nested dir", _migrateAppDbNestedDir); - test("w/ nomedia nested no media marker", _migrateAppDbNestedMarker); - test("w/ nomedia root", _migrateAppDbRoot); - }); - }); -} - -/// Check if migration is necessary with isMigrated flag = false -/// -/// Expect: true -Future _isAppDbNeedMigrationEntryFalse() async { - final appDb = MockAppDb(); - await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadWrite), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - const entry = AppDbMetaEntryCompatV37(false); - await metaStore.put(entry.toEntry().toJson()); - }, - ); - - expect(await CompatV37.isAppDbNeedMigration(appDb), true); -} - -/// Check if migration is necessary with isMigrated flag = true -/// -/// Expect: false -Future _isAppDbNeedMigrationEntryTrue() async { - final appDb = MockAppDb(); - await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadWrite), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - const entry = AppDbMetaEntryCompatV37(true); - await metaStore.put(entry.toEntry().toJson()); - }, - ); - - expect(await CompatV37.isAppDbNeedMigration(appDb), false); -} - -/// Check if migration is necessary with isMigrated flag missing -/// -/// Expect: false -Future _isAppDbNeedMigrationWithoutEntry() async { - final appDb = MockAppDb(); - await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadWrite), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - const entry = AppDbMetaEntryCompatV37(true); - await metaStore.put(entry.toEntry().toJson()); - }, - ); - - expect(await CompatV37.isAppDbNeedMigration(appDb), false); -} - -/// Migrate db without nomedia file -/// -/// Expect: all files remain -Future _migrateAppDbWithoutNomedia() async { - final account = util.buildAccount(); - final files = (util.FilesBuilder() - ..addDir("admin") - ..addJpeg("admin/test1.jpg") - ..addDir("admin/dir1") - ..addJpeg("admin/dir1/test2.jpg")) - .build(); - final appDb = MockAppDb(); - await util.fillAppDb(appDb, account, files); - await util.fillAppDbDir(appDb, account, files[0], files.slice(1, 3)); - await util.fillAppDbDir(appDb, account, files[2], [files[3]]); - await CompatV37.migrateAppDb(appDb); - - final fileObjs = await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e).file); - expect(fileObjs, files); - final dirEntries = await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)); - expect(dirEntries, [ - AppDbDirEntry.fromFiles(account, files[0], files.slice(1, 3)), - AppDbDirEntry.fromFiles(account, files[2], [files[3]]), - ]); -} - -/// Migrate db with nomedia file -/// -/// nomedia: admin/dir1/.nomedia -/// Expect: files (except .nomedia) under admin/dir1 removed -Future _migrateAppDb() async { - final account = util.buildAccount(); - final files = (util.FilesBuilder() - ..addDir("admin") - ..addJpeg("admin/test1.jpg") - ..addDir("admin/dir1") - ..addGenericFile("admin/dir1/.nomedia", "text/plain") - ..addJpeg("admin/dir1/test2.jpg")) - .build(); - final appDb = MockAppDb(); - await util.fillAppDb(appDb, account, files); - await util.fillAppDbDir(appDb, account, files[0], files.slice(1, 3)); - await util.fillAppDbDir(appDb, account, files[2], files.slice(3, 5)); - await CompatV37.migrateAppDb(appDb); - - final fileObjs = await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e).file); - expect(fileObjs, files.slice(0, 4)); - final dirEntries = await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)); - expect(dirEntries, [ - AppDbDirEntry.fromFiles(account, files[0], files.slice(1, 3)), - AppDbDirEntry.fromFiles(account, files[2], [files[3]]), - ]); -} - -/// Migrate db with nomedia file -/// -/// nomedia: admin/dir1/.nomedia -/// Expect: files (except .nomedia) under admin/dir1 removed -Future _migrateAppDbNestedDir() async { - final account = util.buildAccount(); - final files = (util.FilesBuilder() - ..addDir("admin") - ..addJpeg("admin/test1.jpg") - ..addDir("admin/dir1") - ..addGenericFile("admin/dir1/.nomedia", "text/plain") - ..addJpeg("admin/dir1/test2.jpg") - ..addDir("admin/dir1/dir1-1") - ..addJpeg("admin/dir1/dir1-1/test3.jpg")) - .build(); - final appDb = MockAppDb(); - await util.fillAppDb(appDb, account, files); - await util.fillAppDbDir(appDb, account, files[0], files.slice(1, 3)); - await util.fillAppDbDir(appDb, account, files[2], files.slice(3, 6)); - await util.fillAppDbDir(appDb, account, files[5], [files[6]]); - await CompatV37.migrateAppDb(appDb); - - final fileObjs = await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e).file); - expect(fileObjs, files.slice(0, 4)); - final dirEntries = await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)); - expect(dirEntries, [ - AppDbDirEntry.fromFiles(account, files[0], files.slice(1, 3)), - AppDbDirEntry.fromFiles(account, files[2], [files[3]]), - ]); -} - -/// Migrate db with nomedia file -/// -/// nomedia: admin/dir1/.nomedia, admin/dir1/dir1-1/.nomedia -/// Expect: files (except admin/dir1/.nomedia) under admin/dir1 removed -Future _migrateAppDbNestedMarker() async { - final account = util.buildAccount(); - final files = (util.FilesBuilder() - ..addDir("admin") - ..addJpeg("admin/test1.jpg") - ..addDir("admin/dir1") - ..addGenericFile("admin/dir1/.nomedia", "text/plain") - ..addJpeg("admin/dir1/test2.jpg") - ..addDir("admin/dir1/dir1-1") - ..addGenericFile("admin/dir1/dir1-1/.nomedia", "text/plain") - ..addJpeg("admin/dir1/dir1-1/test3.jpg")) - .build(); - final appDb = MockAppDb(); - await util.fillAppDb(appDb, account, files); - await util.fillAppDbDir(appDb, account, files[0], files.slice(1, 3)); - await util.fillAppDbDir(appDb, account, files[2], files.slice(3, 6)); - await util.fillAppDbDir(appDb, account, files[5], files.slice(6, 8)); - await CompatV37.migrateAppDb(appDb); - - final fileObjs = await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e).file); - expect(fileObjs, files.slice(0, 4)); - final dirEntries = await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)); - expect(dirEntries, [ - AppDbDirEntry.fromFiles(account, files[0], files.slice(1, 3)), - AppDbDirEntry.fromFiles(account, files[2], [files[3]]), - ]); -} - -/// Migrate db with nomedia file -/// -/// nomedia: admin/.nomedia -/// Expect: files (except .nomedia) under admin removed -Future _migrateAppDbRoot() async { - final account = util.buildAccount(); - final files = (util.FilesBuilder() - ..addDir("admin") - ..addGenericFile("admin/.nomedia", "text/plain") - ..addJpeg("admin/test1.jpg") - ..addDir("admin/dir1") - ..addJpeg("admin/dir1/test2.jpg")) - .build(); - final appDb = MockAppDb(); - await util.fillAppDb(appDb, account, files); - await util.fillAppDbDir(appDb, account, files[0], files.slice(1, 4)); - await util.fillAppDbDir(appDb, account, files[3], [files[4]]); - await CompatV37.migrateAppDb(appDb); - - final objs = await util.listAppDb( - appDb, AppDb.file2StoreName, (e) => AppDbFile2Entry.fromJson(e).file); - expect(objs, files.slice(0, 2)); - final dirEntries = await util.listAppDb( - appDb, AppDb.dirStoreName, (e) => AppDbDirEntry.fromJson(e)); - expect(dirEntries, [ - AppDbDirEntry.fromFiles(account, files[0], [files[1]]), - ]); -} diff --git a/app/test/use_case/db_compat/v5_test.dart b/app/test/use_case/db_compat/v5_test.dart deleted file mode 100644 index 9d30a77d..00000000 --- a/app/test/use_case/db_compat/v5_test.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'package:idb_shim/idb_client.dart'; -import 'package:nc_photos/account.dart'; -import 'package:nc_photos/app_db.dart'; -import 'package:nc_photos/entity/file.dart'; -import 'package:nc_photos/use_case/db_compat/v5.dart'; -import 'package:test/test.dart'; - -import '../../mock_type.dart'; -import '../../test_util.dart' as util; - -void main() { - group("DbCompatV5", () { - group("isNeedMigration", () { - test("w/ meta entry == false", () async { - final appDb = MockAppDb(); - await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadWrite), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - const entry = AppDbMetaEntryDbCompatV5(false); - await metaStore.put(entry.toEntry().toJson()); - }, - ); - - expect(await DbCompatV5.isNeedMigration(appDb), true); - }); - - test("w/ meta entry == true", () async { - final appDb = MockAppDb(); - await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadWrite), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - const entry = AppDbMetaEntryDbCompatV5(true); - await metaStore.put(entry.toEntry().toJson()); - }, - ); - - expect(await DbCompatV5.isNeedMigration(appDb), false); - }); - - test("w/o meta entry", () async { - final appDb = MockAppDb(); - await appDb.use( - (db) => db.transaction(AppDb.metaStoreName, idbModeReadWrite), - (transaction) async { - final metaStore = transaction.objectStore(AppDb.metaStoreName); - const entry = AppDbMetaEntryDbCompatV5(true); - await metaStore.put(entry.toEntry().toJson()); - }, - ); - - expect(await DbCompatV5.isNeedMigration(appDb), false); - }); - }); - - test("migrate", () async { - final account = util.buildAccount(); - final files = (util.FilesBuilder() - ..addJpeg( - "admin/test1.jpg", - lastModified: DateTime.utc(2020, 1, 2, 3, 4, 5), - )) - .build(); - final appDb = MockAppDb(); - await appDb.use( - (db) => db.transaction(AppDb.file2StoreName, idbModeReadWrite), - (transaction) async { - final fileStore = transaction.objectStore(AppDb.file2StoreName); - await fileStore.put({ - "server": account.url, - "userId": account.username.toCaseInsensitiveString(), - "strippedPath": files[0].strippedPathWithEmpty, - "file": files[0].toJson(), - }, "${account.url}/${account.username.toCaseInsensitiveString()}/${files[0].fileId}"); - }, - ); - await DbCompatV5.migrate(appDb); - - final objs = - await util.listAppDb(appDb, AppDb.file2StoreName, (item) => item); - expect(objs, [ - { - "server": account.url, - "userId": account.username.toCaseInsensitiveString(), - "strippedPath": files[0].strippedPathWithEmpty, - "dateTimeEpochMs": 1577934245000, - "file": files[0].toJson(), - } - ]); - }); - }); -} diff --git a/app/test/use_case/find_file_test.dart b/app/test/use_case/find_file_test.dart index 0b3ec394..ebc4edaf 100644 --- a/app/test/use_case/find_file_test.dart +++ b/app/test/use_case/find_file_test.dart @@ -1,9 +1,8 @@ import 'package:nc_photos/di_container.dart'; -import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/use_case/find_file.dart'; import 'package:test/test.dart'; -import '../mock_type.dart'; import '../test_util.dart' as util; void main() { @@ -23,10 +22,13 @@ Future _findFile() async { ..addJpeg("admin/test2.jpg")) .build(); final c = DiContainer( - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); expect(await FindFile(c)(account, [1]), [files[1]]); } @@ -38,10 +40,13 @@ Future _findMissingFile() async { final account = util.buildAccount(); final files = (util.FilesBuilder()..addJpeg("admin/test1.jpg")).build(); final c = DiContainer( - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); expect(() => FindFile(c)(account, [1]), throwsStateError); } diff --git a/app/test/use_case/ls_test.dart b/app/test/use_case/ls_test.dart index 630bc7dd..1be9698b 100644 --- a/app/test/use_case/ls_test.dart +++ b/app/test/use_case/ls_test.dart @@ -30,7 +30,7 @@ Future _root() async { expect( await Ls(fileRepo)( account, File(path: file_util.unstripPath(account, "."))), - files.slice(1, 4), + files.slice(1, 3), ); } diff --git a/app/test/use_case/remove_album_test.dart b/app/test/use_case/remove_album_test.dart index 946ae76f..b14aecce 100644 --- a/app/test/use_case/remove_album_test.dart +++ b/app/test/use_case/remove_album_test.dart @@ -1,7 +1,7 @@ import 'package:event_bus/event_bus.dart'; import 'package:kiwi/kiwi.dart'; import 'package:nc_photos/di_container.dart'; -import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/pref.dart'; import 'package:nc_photos/use_case/remove_album.dart'; import 'package:test/test.dart'; @@ -35,9 +35,10 @@ Future _removeAlbum() async { albumRepo: MockAlbumMemoryRepo([album1, album2]), fileRepo: MockFileMemoryRepo([albumFile1, albumFile2]), shareRepo: MockShareRepo(), - appDb: MockAppDb(), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); await RemoveAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile1.path)); @@ -65,11 +66,12 @@ Future _removeSharedAlbum() async { util.buildShare(id: "0", file: albumFile, shareWith: "user1"), util.buildShare(id: "1", file: files[0], shareWith: "user1"), ]), - appDb: MockAppDb(), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider({ "isLabEnableSharedAlbum": true, })), ); + addTearDown(() => c.sqliteDb.close()); await RemoveAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path)); @@ -106,11 +108,12 @@ Future _removeSharedAlbumFileInOtherAlbum() async { util.buildShare(id: "1", file: files[0], shareWith: "user1"), util.buildShare(id: "2", file: albumFiles[1], shareWith: "user1"), ]), - appDb: MockAppDb(), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider({ "isLabEnableSharedAlbum": true, })), ); + addTearDown(() => c.sqliteDb.close()); await RemoveAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFiles[0].path)); @@ -146,14 +149,19 @@ Future _removeSharedAlbumResyncedFile() async { util.buildShare(id: "0", file: albumFile, shareWith: "user1"), util.buildShare(id: "1", file: files[0], shareWith: "user1"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDb(obj, user1Account, user1Files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider({ "isLabEnableSharedAlbum": true, })), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + }); await RemoveAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path)); diff --git a/app/test/use_case/remove_from_album_test.dart b/app/test/use_case/remove_from_album_test.dart index 97a470b0..cc6edc7c 100644 --- a/app/test/use_case/remove_from_album_test.dart +++ b/app/test/use_case/remove_from_album_test.dart @@ -5,7 +5,7 @@ import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album/cover_provider.dart'; import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/sort_provider.dart'; -import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/or_null.dart'; import 'package:nc_photos/use_case/remove_from_album.dart'; import 'package:test/test.dart'; @@ -52,10 +52,13 @@ Future _removeLastFile() async { albumRepo: MockAlbumMemoryRepo([album]), fileRepo: MockFileMemoryRepo([albumFile, file1]), shareRepo: MockShareRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItem1]); @@ -100,10 +103,13 @@ Future _remove1OfNFiles() async { albumRepo: MockAlbumMemoryRepo([album]), fileRepo: MockFileMemoryRepo([albumFile, ...files]), shareRepo: MockShareRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)(account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItems[0]]); @@ -119,7 +125,7 @@ Future _remove1OfNFiles() async { lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), name: "test", provider: AlbumStaticProvider( - items: [fileItems[1], fileItems[2]], + items: [fileItems[1].minimize(), fileItems[2].minimize()], latestItemTime: files[2].lastModified, ), coverProvider: AlbumAutoCoverProvider(coverFile: files[2]), @@ -154,10 +160,13 @@ Future _removeLatestOfNFiles() async { albumRepo: MockAlbumMemoryRepo([album]), fileRepo: MockFileMemoryRepo([albumFile, ...files]), shareRepo: MockShareRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)(account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItems[0]]); @@ -173,7 +182,7 @@ Future _removeLatestOfNFiles() async { lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), name: "test", provider: AlbumStaticProvider( - items: [fileItems[1], fileItems[2]], + items: [fileItems[1].minimize(), fileItems[2].minimize()], latestItemTime: files[1].lastModified, ), coverProvider: AlbumAutoCoverProvider(coverFile: files[1]), @@ -205,10 +214,13 @@ Future _removeManualCoverFile() async { albumRepo: MockAlbumMemoryRepo([album]), fileRepo: MockFileMemoryRepo([albumFile, ...files]), shareRepo: MockShareRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)(account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItems[0]]); @@ -224,7 +236,7 @@ Future _removeManualCoverFile() async { lastUpdated: DateTime.utc(2020, 1, 2, 3, 4, 5), name: "test", provider: AlbumStaticProvider( - items: [fileItems[1], fileItems[2]], + items: [fileItems[1].minimize(), fileItems[2].minimize()], latestItemTime: files[2].lastModified, ), coverProvider: AlbumAutoCoverProvider(coverFile: files[2]), @@ -256,10 +268,13 @@ Future _removeFromSharedAlbumOwned() async { util.buildShare(id: "0", file: albumFile, shareWith: "user1"), util.buildShare(id: "1", file: file1, shareWith: "user1"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItem1]); @@ -299,10 +314,14 @@ Future _removeFromSharedAlbumOwnedWithOtherShare() async { util.buildShare( id: "3", uidOwner: "user1", file: file1, shareWith: "user2"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, user1Account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, user1Account, files); + }); await RemoveFromAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItem1]); @@ -343,10 +362,13 @@ Future _removeFromSharedAlbumOwnedLeaveExtraShare() async { util.buildShare(id: "1", file: file1, shareWith: "user1"), util.buildShare(id: "2", file: file1, shareWith: "user2"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItem1]); @@ -389,10 +411,13 @@ Future _removeFromSharedAlbumOwnedFileInOtherAlbum() async { util.buildShare(id: "2", file: files[0], shareWith: "user2"), util.buildShare(id: "3", file: album2File, shareWith: "user1"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)(account, c.albumMemoryRepo.findAlbumByPath(album1File.path), [album1fileItems[0]]); @@ -432,10 +457,13 @@ Future _removeFromSharedAlbumNotOwned() async { util.buildShare(id: "2", file: file1, shareWith: "user1"), util.buildShare(id: "3", file: file1, shareWith: "user2"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItem1]); @@ -479,10 +507,13 @@ Future _removeFromSharedAlbumNotOwnedWithOwnerShare() async { util.buildShare( id: "3", uidOwner: "user1", file: file1, shareWith: "user2"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await RemoveFromAlbum(c)( account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), [fileItem1]); diff --git a/app/test/use_case/remove_test.dart b/app/test/use_case/remove_test.dart index e8e731e6..9376da73 100644 --- a/app/test/use_case/remove_test.dart +++ b/app/test/use_case/remove_test.dart @@ -5,7 +5,7 @@ import 'package:nc_photos/entity/album.dart'; import 'package:nc_photos/entity/album/cover_provider.dart'; import 'package:nc_photos/entity/album/provider.dart'; import 'package:nc_photos/entity/album/sort_provider.dart'; -import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/or_null.dart'; import 'package:nc_photos/pref.dart'; import 'package:nc_photos/use_case/remove.dart'; @@ -45,11 +45,14 @@ Future _removeFile() async { albumRepo: MockAlbumMemoryRepo(), fileRepo: MockFileMemoryRepo(files), shareRepo: MockShareMemoryRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await Remove(c)(account, [files[0]]); expect(c.fileMemoryRepo.files, [files[1]]); @@ -68,11 +71,14 @@ Future _removeFileNoCleanUp() async { albumRepo: MockAlbumMemoryRepo(), fileRepo: MockFileMemoryRepo(files), shareRepo: MockShareMemoryRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await Remove(c)(account, [files[0]], shouldCleanUp: false); expect(c.fileMemoryRepo.files, [files[1]]); @@ -91,11 +97,14 @@ Future _removeAlbumFile() async { albumRepo: MockAlbumMemoryRepo([album]), fileRepo: MockFileMemoryRepo([albumFile, ...files]), shareRepo: MockShareMemoryRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await Remove(c)(account, [files[0]]); expect( @@ -132,11 +141,14 @@ Future _removeAlbumFileNoCleanUp() async { albumRepo: MockAlbumMemoryRepo([album]), fileRepo: MockFileMemoryRepo([albumFile, ...files]), shareRepo: MockShareMemoryRepo(), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await Remove(c)(account, [files[0]], shouldCleanUp: false); expect( @@ -182,11 +194,14 @@ Future _removeSharedAlbumFile() async { util.buildShare(id: "0", file: albumFile, shareWith: "user1"), util.buildShare(id: "1", file: files[0], shareWith: "user1"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await Remove(c)(account, [files[0]]); expect( @@ -246,12 +261,17 @@ Future _removeSharedAlbumSharedFile() async { id: "2", file: user1Files[0], uidOwner: "user1", shareWith: "admin"), util.buildShare(id: "3", file: files[0], shareWith: "user2"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDb(obj, user1Account, user1Files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, account, files); + + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + }); await Remove(c)(account, [files[0]]); expect( @@ -309,11 +329,14 @@ Future _removeSharedAlbumResyncedFile() async { util.buildShare(id: "0", file: albumFile, shareWith: "user1"), util.buildShare(id: "1", file: files[0], shareWith: "user1"), ]), - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), pref: Pref.scoped(PrefMemoryProvider()), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); await Remove(c)(account, [files[0]]); expect( diff --git a/app/test/use_case/scan_dir_offline_test.dart b/app/test/use_case/scan_dir_offline_test.dart index 9adf7685..54ae625c 100644 --- a/app/test/use_case/scan_dir_offline_test.dart +++ b/app/test/use_case/scan_dir_offline_test.dart @@ -1,11 +1,10 @@ import 'package:nc_photos/di_container.dart'; import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/entity/file_util.dart' as file_util; -import 'package:nc_photos/object_extension.dart'; +import 'package:nc_photos/entity/sqlite_table_extension.dart' as sql; import 'package:nc_photos/use_case/scan_dir_offline.dart'; import 'package:test/test.dart'; -import '../mock_type.dart'; import '../test_util.dart' as util; void main() { @@ -33,10 +32,13 @@ Future _root() async { ..addJpeg("admin/test/test2.jpg")) .build(); final c = DiContainer( - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); // convert to set because ScanDirOffline does not guarantee order expect( @@ -59,10 +61,13 @@ Future _subDir() async { ..addJpeg("admin/test/test2.jpg")) .build(); final c = DiContainer( - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); expect( (await ScanDirOffline(c)( @@ -84,10 +89,13 @@ Future _unsupportedFile() async { ..addGenericFile("admin/test2.pdf", "application/pdf")) .build(); final c = DiContainer( - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + }); // convert to set because ScanDirOffline does not guarantee order expect( @@ -118,11 +126,15 @@ Future _multiAccountRoot() async { ..addJpeg("user1/test/test2.jpg", ownerId: "user1")) .build(); final c = DiContainer( - appDb: await MockAppDb().applyFuture((obj) async { - await util.fillAppDb(obj, account, files); - await util.fillAppDb(obj, user1Account, user1Files); - }), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); + await c.sqliteDb.transaction(() async { + await c.sqliteDb.insertAccountOf(account); + await util.insertFiles(c.sqliteDb, account, files); + await c.sqliteDb.insertAccountOf(user1Account); + await util.insertFiles(c.sqliteDb, user1Account, user1Files); + }); expect( (await ScanDirOffline(c)( diff --git a/app/test/use_case/unshare_album_with_user_test.dart b/app/test/use_case/unshare_album_with_user_test.dart index a0ea82dc..077d11c3 100644 --- a/app/test/use_case/unshare_album_with_user_test.dart +++ b/app/test/use_case/unshare_album_with_user_test.dart @@ -36,8 +36,9 @@ Future _unshareWithoutFile() async { util.buildShare(id: "0", file: albumFile, shareWith: "user1"), util.buildShare(id: "1", file: albumFile, shareWith: "user2"), ]), - appDb: MockAppDb(), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); await UnshareAlbumWithUser(c)(account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), "user1".toCi()); @@ -74,8 +75,9 @@ Future _unshareWithFile() async { util.buildShare(id: "2", file: file1, shareWith: "user1"), util.buildShare(id: "3", file: file1, shareWith: "user2"), ]), - appDb: MockAppDb(), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); await UnshareAlbumWithUser(c)(account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), "user1".toCi()); @@ -123,8 +125,9 @@ Future _unshareWithFileNotOwned() async { util.buildShare( id: "5", uidOwner: "user2", file: files[1], shareWith: "user1"), ]), - appDb: MockAppDb(), + sqliteDb: util.buildTestDb(), ); + addTearDown(() => c.sqliteDb.close()); await UnshareAlbumWithUser(c)(account, c.albumMemoryRepo.findAlbumByPath(albumFile.path), "user1".toCi()); diff --git a/app/web/sqlite3.wasm b/app/web/sqlite3.wasm new file mode 100644 index 0000000000000000000000000000000000000000..faed541c065cfe57c51c2b5cbabd3d5f8aa15edf GIT binary patch literal 1348108 zcmeFa3!Gk6dGEjP?{$)Qk^usVu;16%jzTn6j21jKdy3&ADy_HL({n;d2FOg3NhTA- z^N(aeQL5JB9jjH^YN0kLty;07Mn%Pnii(1Y5*3uIMn%Pna=yQ3?fvdOmxOq0_47Z0 zBv8JvWMU zy%cpVSG9tj>LjA50eBvNazOc|-Sccz=eZIyTC-wQBeB`dY&cJNSGX5x52C1Yn|8UPHrUIy|;Lun%uEv{W_9b{Tkah{-04V z=(o6@7RYxA3shxv^VYR_>Vkf;b?euUZr|?3mat&!x~a3*Zkd?eyl#_PbE(PXx-ANekMRnZJgM$_S`i*d6A_q?5CbNF?rVLl;_Vb{Pd~Ot#b;WyJq8- zb(`|SWgF){Yu%kJQJ}>aX z@F&e5H=`u~<44JYzze)1k6gUiZ?&T6F~|C?#|A;P$P2{E7J+cpcAc_`i3E-}wE6`q3cOy_z2eQP2p2 zqk>>~5$yq2^6)Tj)#&liFs?Nc8VPH)u-6J}t--JcNJ$*jXfmL?M?B)NhsL!i4r?K$ znzdT98H9%^Cl36`An^QJ5XNo5_v-Z)>9rvC__r4y>icvaMeT>i36;aP2QnB=Vk4ry zmoP9!1-L=fi0ZV%|NLVk4ZOvH*J!0)trbSGP{4Q^OFW?Q!&rE&#dIAEHk(ba4hkE! zrchi1Awd#{(UNu}4BJOH+EF8plcB@nD2l=;;QuID7%ptaA?<>jAV{KG)Ls}d@~AfG zwSmHq+Ck7zjRu1a68=VULP{J*yd(fgqCGXjXeddRGc1zYLDFa>jiB9*!X)y+?@*8& z&Flx!!eB7!u3EUHORLEtiQn*|#!$P~h?DlhAZj-njfL$-5JyYmuEyW=z*-b}Mg{cT zh}3+jS3%Qc5TwLIdWmAd^}NGdhbN6Biu^XCTf)d1gGUAN!e%3RNDcf3{!!`U7=Fln zQwIpcM!0-A_1nx6)$|WP`LBDM@vo*_#rSuC|DtF>|InD1)Y`t_;WeN{`JXkXSH|N0 zKsk^FuSo*jjDkNxG|eVzJMn9xa_C=+Am$yG&`@g4Z-ZC;X$~^gzAXvL)S9f7Pz&Ml zpeH;uUUX;^B5ct~w-FxWv%-7`eNppJs7>Xl0<4gk7dE`5D*%pZsQGpMNt!~aD0PwV zH(n|a6pbNG0&?(yK%6<^OJ!A z51Q1V|bj^RFmGrZ4O`*H5Td#Fce=*M`(d<2qyk8+Rh;z*CFIG1QQAwB*b5H5P_^( zGxiRHN!5H-!IKPvum(nIwHnLW-|D|3d`Flpi+1_h-tX00yS!}L{@r(1q?fz-sr}Q@ zxBCmXZ`*{Jd(2v~cEn2PA6lerSU0t9?S_q$qwA;O>0!{%FsW8%gq@GOH&RCl#{&QoXNZf3ab$6rR^f^e=GdFJ8;9b#J zR215{W#iOFCpF(*_OO0p%b6R`^4?LVAXzs}toN>L^ane!eXS~c|I!#L8dC?8qi1d0 zJ~cY&{cEE?Sf%gS($9HknKOz0ux|V4S|{_o-r+@4+b7PPT6^~Bx~*$BZQQ(Z3Vgh) zvAD=|rPuD*KDxnscjK@kc~%|o-x~eq&R#dUVPJ~iUuCklr$l3!x}K4GA8H&@z*^=2qxa#N4M7YWx1a5OWM;3UlauQw zHjH}L%q+ZVbjw*&XL}!=3HLds=6tL~hC19b`dshhB@WNoymfNpmZ>wnYs+Fq(kII1 z&e^^tFZUm1-G169OK6;4w?+Ejb!Cfmym9^Jt=^|9m8T}RSlXu>%L;^OMV=v&J9Fcv z(X|t2jIlJm&oq`6`J-Fbok7NS@Ho0*?fP}=&mQ%zFA;Rcy7l8bwmQoH?3`o>f2;So z68m}S9M7LGNiNTr9NoN*IoNWRcf*{#t?SMjT|cp7%ar$pazwP`7V8(wb?!*##*!M= zv!*83p213|DTl{zmq1pM z8P@G{GIHG9QQ|DG!HS!h^zJOX&C`XnyXKU3Si5@;I9qnG!tW`Enm1A)?K^XF3Os*z zPE$q;`{oQl$&BoKb3ihDd*3fvao+d;8J(OkYWqRSif3if-o0}&4Iyid3;nQMnt4r^ zIW;kH1|sT5jU$ScJ0p9`1YF(wamlo8Y2H^(H^O6bt(bxLld^l{p2oNqc?#uhfRO*Q zM8Y{R4vfs4rhYmrW8)S$%H;Mb@BR`yR)dT!T3SCVyIFVESqMW!4MVgJy`Ps;fa$q* z-Hvk&vnAqt*t~^y#3;^h_T{=M9xnBQW?yjTrEN-HFsG3-Y^}er z*_Yczaiz1^FKqV3N}iKb^oz=V^9)h$i|2IUDEFc{@EE!M<(%Sn`d4Myej;@D@>$9GX#Tp{*O;ud#&U5v!Xk|ZUNNgPTY;}E$6-Z_ z_4le-g>BHUo&`d_!d^40JBNwamiV`p`>X49&AtvaBLfgGY4#>`&D zJ2sD^H>@>*^OmwhEs?bosA}F@n|;L_&a-*@S>8WZW=F-=Z<@fPbJ?uQ<_WueR#E2< z`=?o{ZsEPH9GUe#Icoj?bF;5W_)Wlk_I=V$Bi+5%7Aq5{@zi!L=(M>R$83q2Oqy!kPF{2sz|60P7 zcj&!y9vB|uy{p8NSRG6iHv8_fsDy2v`fnv6IS1g{%@Z4TQ2ag3zVbdJLu0(Eocaxu z6I=5t+r9Tz(nr^CGK|o<_wQv}#;ny^oZ&z~ro{E8jc4RGtM}1n-&iVB*KXOd`3w}UkCj!X&K6;BUw7uH z_wlmv?Pu?p+A#6lE#9@|YQaFn(y5k$MQq*yi}SAY`<;Oy02-jb+p&f33vmD^>AB30@-f}kkDK`QzFq>QTftnR4wYD!HxpF_uUdJ zPE7^LHlN^aur_4+wT3K#E{wQ(v_hH z@7^*Uy>v>9z|!yZ`&v*z)tLCkIDc4Dl!+I$XBj^#Gj>dFgp_ja$op}LQ)R$zz56QE zO41n<6WG~Xyq}bdPbHm>`=2Fk6@8hpA;5to zBri-ZOkSK^l>BA#lH{ey%aXrJUY`6l|6a_$uSi~*yefHh@|xte$?K9!lGi5}`hSzW zA$eo+rsU1ZrODqVf1mtA@|NVS$=i~*C;yVXGx@jVJ;{5M_a#>+?@vCEd@$LQd^q_? za!vBlYbC z|K41G0rPZe{qO4kP=8DPI{&Tpf2{v={fheA>+h)lOZ{K#@2tPO{_pjx>+i3Bp#H)7 zHT93yKUV*E{o48s^)FEKi}f4pU#fqlesle+^}Y44*S}H!X8qRsZFT67zxwan_1o)r z)bFg{RlmD_PyIWjez)Fg4=h;N8En4cbx;0r^J@0dc0H8skzl+RF88wguZo5PFIt_3 zX|O72r(t%#KbCpN`(7H3c#jM2^-21izbe?L2X9qyJHI@2##RM)E9rKBEcMf%^N75u zZjepCS8b+Vuq&Y5VaoOVCk=QM6z3oEnZYj*q@v!gf74pVBgLq3?ZO8MmYnj96=G{z`)oM`8AC8gr6%EXBYq_(_55pn~f@8!=o5j)#=Ew(KgdtK8$D za9!mdX*A%qppqQpA~r=MiSDwMVtwK(K}h~gs$@Re-MFAGC^(JM7?~h$EOLafpO8I% zER7-XG#0HYr%0uCy+Xn5UZgpWj8sZ)bgck91Dq1ZiyCFAo{b?15o z9Dq`%v$&Q6_BYD64vH9N@GT)V3!fUT&Vp{7)w_;Ik-9Q9<;(GolKpC}R|fK%5_ShQ zkgBj_5~DHZJkI>FUTm~-Qb{)}nZuwRGr#Mdg#((oP{S15R%o69QKsa z$6d9zUquY|dn-n%1pu9&;wY0IC0|fF5HhocWuG4*EFpLirBh7i2+O`qM_8)lEMe)E zp!Kvrx%rD?u_7^Ho~C=J{v-Wf=A8oSyl!j~(-!Q1qvmx`qnbsG?J6-cA`zozG3o{; zmW_$b7Nmu_^xMTF;AYZi;AcL}Rm{`W3~3P37)tgl0+AWp)6c3Ps#Y^rY#4B=5RH~v z#DGyHy7PnTbCFRuvT}ZXF081XRekQDX0Wolb8%y!YKSsqHEm2Frq%Dz+zH}NUwLze zOo?|1&NMdyjphmquwW5>MV~GVKU1f3tFPn`F1O^ZzmmQ8p~W-IJ%{+6j_mwL`Iq>P zQ=sT(!<)vsu|#hwyKi5JST~*#WsR{Fo|i4(#vr54Qc3p+tFI@JC7YvcNVMDyY29j4 z4wI}9ZzPqr9500}$K&-f9aMG|kD?UPO6`r8Ys&)H2I^S6t3*vz5Y(zhUF{&W+BC^m z65?hooA%{2V*J@K(f|_&aJ*KIfF&AVWvEV+1D`o(enVrOf0#*in90Emvoa>>UcQVJHJLZOa!Nh`T2F9oO+FxoBW^H<@gEP))k%;Zq^ z)-U|v-Ezf%Y~DBJ3;U6N=l`v1Xz~9)>)Or#MUI`%U3vdyny2*T+16DQdgU@A>9f_=U8$ z3eYHM*9UUkSM|3F!zce*@=JdID`{}8v)oRUgSOcIk$Q>Fg4^Eh|D+`NNAOzROYpL{ z2V;-&Jt)*F9zV8LIAr@V=z~F1v+< zdXbQOI`PJ9Q|oa3pii3k4>~WEL|0O$^PM2qI(S>I0+7_K2@(1C)rEtQ!F_chw`eL; z;$(1DUHH{x@N9MALHxErQm6}kRhP6<)vbU^fm!N8Rm%;k>R)g$>Yp!lq4h3KROVZc zD0kWP^!eJcbj#S;VKOnj>|bqPNBR#gZCEpUL_T-s)guMpLN?uzEx-$O;k<}J;YD<* zVYEvVja94n2oGS3KBw!pa{|FZSe<*!eD|}&tP9_=$bga#XcZPKpdg6f!VORsTg?W= zc;_SR-a;m}_%qXzFHZ(G?eGF=d4fXugVKVf>1E z^e?{86rvt>C649(Gcq+dr;pKB9TEmn$;qom#z8H`ijiSm;IkqepxSYuUd?-Fz5X|| z!e3mX&Sr%Nc7jwm;eW9heJqh9BG#O_h^t8k%Iq^HwS-WH9z?h#4a^k8n={mEJ>VPP zM6gzzAYSJJXDlvptqgTdn5n@uj}^%cNxv{8{aI|wpTV|#iww{@l0Sq>`R2A?i1S>c z`I$lkW|adJExVFPtD?=X$_tCtc#z-?Myf3wqV!r=ia)VDQ_V6IkkIL z-JvZ=4$zYUQtheM5^!wp?9@fg8>W5D^*V88bsdT*mw}eo!GH6$fo=j}OWHPK&9}9o8l}4NE4!Asr+Qv7 zyVg~rz3c2Ln~q@R+4b(lI|VMHGK8UpUMsuK8qTgM!m4_n^6A(h$?oezz?1dS%I@Wf zzeez5VofZ`u9puZyVY_g2SPo$M(({U%AixP^PlWKW>Y$6M$Fjy7OkZ(ssUEhhov`Z8aVfXe!c3X)|}v z#@WSRv?Pzg-?YC$%^Xk$D#{`G>A?)?L=CBcw1jz$MkyP`ABb#N<|&*r2u49hcFkN= zp!)8;!;wLDQ}J+p@c>B~g<$DqHy4AamHyzbDhEG(<3Z2pOa$PgKZrR!7zDrxlLH`t zyDH`)06Kr+jrp{a-5=TBa%7kP4vg&8i~&NZQaK~rU5t$E{>U!6u}`qq{|=1o>Ul?Y zLoqV4`y;!u7+Dgo7B^zW4C8gqrf-VO06<$NxT?x+P_XyjNI*d&XFGApb{vr^rZ11H zsuF2DlkwCY<7tZV)N{r|(|6PK%vq^vk=Fa`xLG_sDDR=Q7cvS99n4$Khh0k>Vr_{m zg(O>eA__ZWpM`g zFmN?Z|N1a+gIdcmpqA&wz~cEZfC>6uhk>~=m*AG`$?RjGB77^Wzy%#vSHUdtJMSup zvzux9*M)&NyH~A=fdRByo)-gO@q_}js(pRU<$lv`(8O7yt?W{1PhPetZJ|14E)V4+ zyU$9c9--w<2ciL|zBD^{3Z;bAOfQ&Uz5PWEn$EsD-FT)sz3?8%PdeCrPt@1bay_mW zEbSSCY~vP_EgXyDdW#TFO6^GS=SgvU}Y1vo})OG_y-oEo*LuM`TT&zU-a4 zRO7#rR%EMWm*)>?QqCwqOF|n8F=o0oernr#iTPav3k-J|xF^z}2it)givNuF60oj) z*72^NlGswaC@Zz6MY}>Q4Of?a1Rc zAYtQ{Cp2xF(w6C_HhibZ3Sge31Il-)UjnbB{pLj0BF1#NmwK&N)y?ome_x4NUeVtn zt{}Vk`!qVt!v&W&R|U&?n7)maG&`glW`|_odMSgarOqOu*am-$#Lt2LLm`dE7cBAo zh1`C(aN)vwXJMn6)LIMM3*&(Wq1j;=pU3nlhrj$7nF{7U?|Baoq~mATDuKX={B@7L zc8b@l?6sc1w%H#jZ4JP8s|C!+&;aCWS9v$8@bHjRE#QZ4)L;L#GnUa`|CNnT`g5=C z1+&}J%Ca_@g7(0i+)MIYj=8kkb8<0hin>}JdbSmT-J@rjM}Y5P27shC+WkCZ$u5=o z)o#wt%;drLWC+2!up7_<;wH$=;SF@tDyps7DmoM|d1ieg0_6s1{pUYqx$ zsaK5W%obl)$&FgsRk?AS?a3eV@;JXUIHt~69it7LS*_e$!et>pGyB+Gj+C{V`CT;t z0l*Z(*4u&@1D`uM?x^tww&ABuBiV^?$BR~Jy0}s@m1xJCxjn$LQy5P}HGV!+C zjx9Y|Lf{T?!pupCVUDp_dclbIY$|is>9I0~fjr#Z3!eWRN@Kz~DTN8AqVZ`cp)kPb zr_nP9xWv+oyqt-J`O-EKC##SK>H6vd5WNEuELt>ui9wY5C({eh#;IE~ymWcNtMh_7 z3WHxLz;0>6g26H1Ej$YmfeQd>NNLR;sXCgMBb%L|h$(BG z5oiuacFA?BdCaFkj)4*H>F!W2CG@}tY*J51%BC=e;M-Z7vPR8x*6P&$bj8Fe_mqExuc(RM}!5-bbjt= z+i3H0N2gairWX|4QHis;qZQ1#qa741xT7+}DpS8gsCqqZe>gv=O}z@vGi!b1fn4rX z$APaD48tf3w%-foybx^t=?-SG2pb*K#!<%cUd<#Mi`#&bL}H)FIAU76q8B}1Tr%g7 zu}zKag6F6HvpKn-T5yw4YM`Vam9KutM@d(jm+ibYidiOJrGKMLpS^Sq1W&Umi%Cq~`zuY`;dE5bSXT0}Dpa8|6 z6|%xRBn!6njxbftRC>nLT?o&M##%b`7pxBXYat9^{9(c~nuC?pwvnGbtn<@)kB4!| z8woN(x#jid;43<-jWmUac8<>LKsITD_usT8EGWyoua0W&b6A!$-(VBj#)EI%7EI&L z_Oo5xCa7=lcZk1T{&x6#7=H)&`w;#v#%v>!Hdvhjp&*~{KSs7>DqFIH!KC90p5ljX z4l?Rb-HTgX63)fJ?vG3TMgC3Nt?cOTfb`##pSpCc!`S}fr-SQ^pDwCjc1(Au9koC{ zVId4LyW7J(OlAXQ`eRbf0zI$r0tn5|0_MRlpzgW@LRfC>ujlnwj%N?}+p@-!i40K- zoJRp?O=9JgK9-lI9cxawbPhjsKUcGPvW!kuZFTEZ)pka08|btKI63ynH5`730aU*^ z{%EY;^)-;y=@HTD5wEMKg%-r1AMdFsEutfZKt)Qy!@`D$3ubtfU#DG*dk@e6I`nK2udCmD-$nC*haqF3$Y)A-En&Y}!~gDKp0^?0~qi`w#$SpoaT6dxSju zmKOrO5muMBDH#{oZ9Jv$JuoLW8#F^}JvpkF{^}%X7IN%283_ISmZKKVG#_f0cAJa@ zii1dx@t|W_8b;?}P%6DJfS;w6K16z~kjZ?3T!%{t6vaPkiPsKhzu!HC-zEIz95Ltr zyl%+f1%a0LE?p&Y@c#kD!^RgpYjEhme+GsY^b15oLyLK7_7jGZ!`m%?XrU51wMF5O zH&h>r8$-d6R``N8KS6gv=IbHkeNiim_!(?vv62~(rKkLMaPg3ns|Euhi^N>qZ1V=f4BsIbDz?n|f*X&9B;~WbeoYgMP?Y6>7CO z;ih^%%isrx3pp@GxVLM4SN5N8zRyn=oRblsW_#q0)Y~(72&*f?n+N?IEGy|^54jpM zxJfk`hEldGrv&W6owdzt&c|L{v*4C^x$G$I}vYO2X*0Cco06G z_Q(@o+*_2k(?vTk?6$HM=>SRI)9tJeBL*P@^NpBQanK`%;b~b2OEbqjBcmKOZO<9C zrOm@s^QPfN=N(|=#&pGP88_Ngi-GdbK-$9M(`Gz!S^`2suM6%LrvoOkyc2OircL;9 z^AuP{D{W>EI|-b8jHRB|vWsaDW~#=USBx}wGKX!7gj=rI$-|JESW23=!W$aU9WOjS zHmIXW>&fixEA)b={5Wq&r)pEL^GLI`O=Vl6Leqh?Hy*P^GNmcahP277X=Nn?`sI;h=i|`@MzEL9txEOp=Jq> z9~B8M;lD%aEDy6n1}%bi-?1R`ptowTlQcWozlQ75sYu4FOE z&2h^aPZM>(e&x!vo;JtQ4#i0sBRJ#;rq@xX)RY8jr68l*+zZF)u9+#2MZ?`HeM0ig zft-v{7zsF5fLT|?y7(07(iVcTbO@v%Qlz3W23xT-qKyMWVu*Bft4dW2ymWx_g6A-; z6yV7oxb2qEaa@2%v)gih9c8a1h=his>=iDWq#J_Byp>Q>q0khBxgb%8*4rR<4f@t1 zbpa;GN^74Idvs@)l_x7bDjiCfzJKJ{ zi!RF^Shy{Fpf(QaW}T_5vtuk<2nO@+F15aCPn}%Z?^2!QNMR&oT?!hU%wuda)7+Tw z&vo8_C3osTXVw_sbIEP5yy8`#cvW!MTDNUGyqB?#T zTe}k7gU|pROB}l+|AZ683P7x74?E7g7(cTF3N@W@;e;i%7Ul#D86T|q!eX*J%mQb} zTo7%`E{NE*)jDCx+Y>N|D7ouln~|>Hd34JKW7N#b?ZpK|l-c8-jA>;yuU@ug(=@`} z2PuVK5us38W`NB!EAy2R9KkZfxtXs50jyBg6b_G~H@8wGtC4L&7ex4ghmk^Wfh(jU zBrePovnL9kNkO7AS#l0g@CrW7+@k0M;q0=nbYfw~>{6P;6d#VELLh(QGMn_{{T-I#|?+_%%c77^eNg=A+_N!Si zi>24Ndh{>aVhL6Xe`y5li6^=h1Nt z=`eJU>Kv$>68m#}AxO3(4g&MEDy$O-U>rq|3)@PDGR@_|v%@wb|35GBvn$@`r-Mt= z!yNCGwh_@$Q)n3wMJ7;kJsq%P=h~@4136?(9!S&4l?J*I%h_X0&92^|R3gis{vl$= zeDHP~)8f2zOW>fspxy}DhO{(OgPNu_s- zK6fYYUzLycr^>ga%D4KeJS?kJ<)d=br`I4_-cdCR%Y7^P$yi5Cvl~_cfVJLjIGG(U?u`jEl<2obfr~>5=xdYmi%V%8e)!(xDf zDx(!RY^%_C{b`Uk5Ws~i5a8m^A&_UvLzfmDR{rFH2)};;KHSZWbdC7ehtT{WC29uk zt_r3BF8lWdNY&|Rtn(N#tNvsUfK@Y=m^7Ph#}u8FzB5M2DcU?4x;*0L7WF9(8`k{AB7p?V%d$5QJW!MhlWa z9*e9_$munwCi%4>2u>j6XV!Fl-`LYdPrH7xHM>*l^*?HT#bp)EE6BggVSZ`1c_DCw3XdWVs z5N{M^3y>&Gmo6VQdYw{mH<%=}oKQ7bnXZPlnWt+X1p$Xl19we@YPQk^LP)=3b?dBV zHA1*XdWayDD$blm>MPH7ZE2KNSp#*jYAI08E<_gJkp0TqGM+=}q^rF)333e>;?(UV z5GM%5l2CI7KHVvw=bj2xWVETIr{t0uB-+iO>Jp1yDzx=U^O}tur!?@S0ol^7Jqn_(U z#?bhfmGNGanRM zU1>=P0QCa+(tJ>6P+yXC8BV6ddxwsA5_%Wkvgaii@9|`%=N9tCVQ(334d*R5+)Q8R z2Es8QZ_X{j$!N-<`~*;Nm%R)ABNXN@-Z9z>h6|3Lz9NhdJGF*MBl8NKORXM?z3qB8irx9ey2R&A>6 zBml|6c}-q14A;JiNb}~5MhW#!oXkFP^XtP^V)hxlaj7@}9s*ySCsyrj4*<+_2ko>H=a9I0vs!8 z$8FHF{}PPzxm>^U$HVJRMHbo4lUUb7r%d+ZrC4t4o%0$m9q$h1enIYsEU_UMsFgS} z3)U>{!FI%YPFZ?IItiT@PPEtk%c=Uyu$O&lVnm-^}HuAq#2%f z3k`4zyROHc>v>N=c;R_hZ5*{uS3h)QpNj{nDC&zY!xdZV>J6xQW+)WG0wGkot-)}=6H6=fYG z3T2%DQzrTpm`f);Y?5t1#AU0cfxHi{9rzEBPbrR)O0i;0|FBEsX*YxE_@L zucWzVfvt|~|5DQW*t*gOyOsVgHsI+0Qh&eL>d*}%oq?Q-)xQJGd8*Q;L#K2cVQ9RE z)h|hASc7uHY-NdXv>2m_1wb8|>YvYqm|rtH?-ZtgC{`Wbc5Uy4YhW^wPAe#&V|2bUC-c?&owuBBX3X14z#E!FHtAfd z>5TP;3e==CXht~c(1=md9Gv9DQmYcHcM!B&rmiSVQthJ8KOVP8~)KUzDxNHK{TRb)r1y17U56oK{v6a{N|#c`gGKnjri zQl!J|XcFYWxRnCCcn`*C+1|GZGPns^C&1n6ZIZ4KW+6nX0`R`9S(Jg}SgGcw@oXi& zJcZ{7@&azMr52}M_)Y560p~U@U(s>JB=bxHr^Xc$;5g@E(@Le2(u>{5qcs<3K>%A? zKZ#Y6lSR|?p_rBuGk`!OPm3`Z#%*sgUF;MR&51hcfkrVIM6S$o^JN1hx#rA{u1F8c zi;Zb%UTiGm{dlpRwTRiTT_y_UVSQ{(I=2S4pT$J>y$;y?%5-iG;6aa?X=u8tnmtG= zg=^p!3V_^84X>^lr%5cRUI&Z~iA3i*+%X}w7h;mWur+$88jhurKVlANg!n5L@z5k9&YDyBQ97-T! zwn75?i*c{sR-y^e$bRZ?V?#q^0DUr_;3tS$`+U3Q#~ffn((YjFF~0XK$9*o>;ZhQ> z7NN>3g};Vrw0IHPd^XMrv@}rUk4*a1 zfY0n|*XCK*%x&?SJZsM^xacMIJ8$#5FcCXHkX=Oy!0JOzG>Z|+&Icouw}?=Vo=GS_ zit83{t@vygn=N|dv?cUr2=ugX9At|e4Fv?IT7ZW2uYcO|U!cOS&U^@vFb9P{2xvH5 z=Ul?BZKYU21frmpd>~&*_73)WpquQ0pW+x}oRT@gWG_12ms;-=bz%5j;SsH)M-t}+ z#B^x^!Wt<7L1F=jTf)}s*Z~14K`{VC3V@nl@?<X<%MD!HDDNmBOQ$4YQ7CtA!eG8e+U(l1N$Bt1 zIpXhR&aj%fh#loe&re^<5+dc9>c8{I90ozqb}7!~Y!JDF90rkloa>vgV=2((AF)Fj znHXC50y?m5XAxuJwovGsaYbeg--U6%uuu!~>-xfqS`dw#@Bg_)J%i86jaQmIT{a4{ z{WCikAzi9-tY%ve!xn-EO@kIZIiOa!$tNcdme*L>HqIUR+WoV2i<4S=zEz-n;yg&m zFFpmz0OnSKMw$5rxj2epQ_cs7!`2hKh5U9NX-KLFqkR8dKxVdGo;udsdMHAr!eIp) zY%BFq6&^uf61=T9gnhC5Y&arEWrSzuF~^c!^WVQj%)Sl)Np~J)K5+(wg$ix(UvZ=B z$rua81+Fm#T407kz9>|u(Lq=KX+Un=Q;H*4uG*jb=>ZdDJrR$TI3U+g-UyeF9^k`s zDpgAE$|bVhgSuy|^65G2PbeGK^#LM<98XLOqGAPvL#h@#r#Od$YcQhBYS5|MOEr%Y z=8oY|ZaBC+u*G+|O(|}=d~x22BfBn?)kHe2( zsnUo8E_%>{45S%D+nq-QFf|ybVy1yX&m6v&T+!o@64_{ah~q%2b*$@ko$ z&2zjF#eU-5F2OfPX^`DzuTG-?OqKP=-7D}})%=yQ={3w>zwKV5{PkPzHO^lNg_b$= zfMR}3I`(mZ3IwERr(ncfErK9-1&y&)W1baDs|#lh+{r{Rs%S$$GSF3%!$7L1R(df` z5t=A#CaPIS#j={j2)O})1mVd*(oDh50FGg*cp$*Ud7N*@Ajn&13$1Ki0coi^P@8!V zoYhKIcB~IVo{wd#Ghc8{F2xikK(X!Is#nEInteNMAE4c0GAdYY$AU8*i}Kk$(&S34 zWd1_8rRUSMTqyc6uNRy5xv(s*^n(StAZ!+}K9p5LG1m3k9-mIZHhGDbd9^Pcz0ErU zhyb#V97bHYqV=bIP^FCoR-)?!b4@T6uL?Sy(P0{D^!y{gF|?dF zE7}C%Y9R5mmn@N!)t6bBX}g>}cpdXj{6H^36mxV1bR|$ePiP9KO5QqyQcImS7z!

j`!kI@W4dY^&V@yl<`IzHVsw6%IJm*SbNBzthY00!KN)fiz z&ZTRGh3U~)DMXpGQq^;;R8?ACAFPnOEUOtp5%|LEuPo?;Cy9Y)^9XuFZNc^ZkzE-? z(pgRH4o)Vq^wycsBS5)wc{`PReFN_Gb({`N)-}QVCk(Xz6F6_9!>l5Vph6g}>Dqie z{Ytq)CG4aa(zf+aGZ=zc(V{-|65@_v8alQSP1)9#D;&Bibt6d|zdJ)L{CaHM#QL#I zIco#HDB;9`28#kx!fKoZ!dLrddvjSRPA{An&J;(T;vrxuvG5KTU=(L}eZkJ%^k8g!l&C-GNc@S-N0dFL+VKoT zTmA&QusGnNRUFwJ?TaPwANsR^4md7mO=5nF(% zm795EFL;&^t*ViI?XCNZs?zyPoB)pmLz)Q-X5!gtJblZc_<+bPi>@#+?A*tkAr)F+ z-*hQHr!Z?sR<1gviYaw)Lz>~&GvYeI7D2a>5hX4Oz!W`IvxnX+7Kf0_Zax-u>UfyE zR;sqqStzKcTmt|BUMVq$jsIi!rS&SW*U|~I^DOvGt%=|5hcm)A#Th~De4LRLf{H0V z@=J5ZK$ZKPF?5`fADKW%F_}PgUYJ0nI1?x=O(0uXoAS- zW`*}ZBlwDAM3gpj5=^s7r9@J6=4IW5$?eD{w3Ptku$5qJ!&XAo5{EC+idMp`a{D8j zU)&umUiZ-(8{Npjn_Em z%<<+{v>WfNa@Fxx?6&SfUAJE`q8X6vi;K)H=Ef^hE+yP}F5!M%!gjw_HA>K(RY#h0 zOw73^-`RcAOt8zH*COrJqw~`GvBA0V$n>l4x;bohYZ*>kE?7kI4a^Z~)TfBa5&3N7 zoMei9#hIFTfbpBio0KOf);=gP6jTlPBGGeD0X6eJ?!zm(@Qx&#jwZVnti!6yc4-@z zHu1D^0G+K(T@Zp`W&OZC(R%0crY(|pWyBv5HT!Fpj!4;>j<#_mbSK``H0AFzmtKZc zg1(k$l^NL$^|%cYx3P08uh`~Xl^mo;VFM7kdFf96UEGu0qL?-=%blwME%ZM)V7emh zI_G+4sfZeeAXC%VSnQ23_~J-Onn%+Xt5?*F{|G$I_*76lLt=r?+-HWVEzVn^QnX$B z_zOVmu0@7k=L;}tv{YE7`-Fk<6L1`lKRR{N=2f472^lF)-4)(5T6kwOIcLGVJR-up zvT|*$KtH&ei++&Py3%fb%eN{523>K^ctQ07rOV**RSykJ(@qE%SH8)dWj2dAD>ja1 zcxV{M?)}`rm3wHofy=IZn-OPK_0XW$+0G_PYG20pJv34Tia4tWz4A@7kRNZhC(XOb zJx`;YdEb}JC9sZ~*A?}*jsce{zq+(c-1;jG6TLfe@M1pSVBQBLrrU88jwLdsl)CSG zI_3Q{zSC5t^ol9ArB1#n>fGw14O1uk@x!6)Kca6KQ#^U}2q1?w;(TWO{<^WTCg-H6LZiY zO6eEo#KmO&aFQd!MsESkpkb5A48Ss-9S=zU-A{=QYWFwNbHP#FNJlX4M{xAdbmfA> z?V$gr1c#f?Y2QgdrV3UHVojXE98mb>-{YV9V8Viuo2N2JlaC~o-eq3ghg_*!eBFvh zijQHERyvk>DL&*%fotV(m|qe8CBz|<%$WM0Ypsk)1X>x>uct?mh3k+bjbLy%Sp6Wh z@!N^C6MFJjFk$xLY1<8#Cw+yt1S55ooa2#kW_LPhUASPeVXFAG2CY>Zlj|X`o-5}lo>f3FT;%0$;S+0 zo65fKxlLhL*8NLqEIOU$=rS*^mKj4>#zWeS_2jN(&Fe;Bt$FF+oR84}BV#>l#0T*0 zoTwvsV1}t>KX8%)NNnj_4l=<-4ac`~uya6`3-mr4(;gE|m`7GO1-V{r>mx6(M)8=e zv5!jU=Pno`Y*X$lwcT5w7W0nTZ{W zNN_4DKjXwabnXvw&w!0k>9CRSOLydDo<;-6YrHdse(%3wJMgd`V8`onY5*ZFb@lsv* zvHCqo`q;IrJKD;p{wrL&?lW>qMMjhxP1wjhJa8Kw@@f4Z|7YIIP{5Uv)RA#l1X zSV=KP#}jHA`}Kb3lwJiQEv2Hg`!x=%;(|~SJ=AWi>&K%i@pF=%-Iu0>dL-jAb}-Br z#FrLTVu>AM8V=5uR_u44EG?Kuj$uk{fxpopy4*(-BKuTj`<$mWR^Cye59oMOuF zuWf@gmP}3ZZ~dHX`sbm&pEEhR${QAdAjMjFDo3`VGM)>n3_4G<7TIEMr0tW)Y3wGP zySCdR2v?6&*F1ymw6Ph#F834p<7uGBAg498)YDfX9KrP>k=z;_%{XqB8HN{dU@=^+ zSpySAHCK%J(58@4C686AGy;UChVlamW`R2tvS{#-<|yRlY%P23roa=T&Xe6DCSABh zRUQt&CI32HMx9e#fvEEo1!TH@G&9zN5xTmSGZ{i(C|nz%bI95VSWV3!^aw&{Wa>+o zVTsZ;wBvV{ez2R^=w!6oTPW|UWN;cC$uFxIC zTtXAT&mx}(A?j&o*JX5AAh2B4;*_`+`>UGS9T3$qOYOlrxDvz(vIi<8dhd6qVJp1$yHNbUw;olKq@0nd5!F;ifmZj)L2>x|k5YG&OC_YXL)`NJo9* zD8xk66(D}b2_&1AQ+u@mJ27WjcHJeDb()+h%%FK~)s#&a|#;kg&v2C8J zDIWHgsriEIhQ@VC$hj`>a9!JyrRWkc;QfUKp>aN@oJ*RG`ZU2%!llB7KHn>=Tbsh! z5t@~3?>;~4bbhQa=z!KmStw^-PBy;79O;WWB!So0&$t-}6!4;XfLN9wwwX)Lb*0S} zd^^BPn>tHN(gK<%X+Ud{bHJJnvQ}%jGHFCr=CeH32#Kr{ESz!xXD&=n5x~|I}F_9`2aVtrQUFb zh4d48dxjB=mIEh4Aqb>0=%CEawoP5aGF-*tbL|O%XfMmEB8tHh;-9 zEsPKxK4QXOOTZZ_Uj`pIp&LGbLgGoed!qWq;v~C|R`^SPnxM;7F6WMWoKd z>)yoLjd*zHr)bj4e6t#lg+=#QZ(^&Lgnae# z&g#Xe5D{DP)dyL8k!BSHujGf&dqPP7;-TZm``l}z@a5dct2Hf+vg=W zAvdY!9-&+=P|`o}OrB0&s{3FV+Jmg7UzQ>@H*Fmh0Q+t3)YOd&1SepDXm+GF%M3B8 zWPC-!CntTBwqwNP5p1}94owNt;MDtxa29enxbMz4kZPYxYOL^%rfefST9-vZ<|@Ak zmKr^c(Z(k#%#f4;79aM=ah`n=hK5$Fi1-E~c$w6Q7_sL{6#ZC}sdXSe4;c{^(Ridk z%n==SqS$b<+KAmXIfg+T%Pj`D zMaj-q!hEFg%+ml;rQZO|i$luPc64upuVt~;ID&a9d#KY9gn?aY4S%;AI{KA0kq;f* zg0+@{OS)hUX3oD-JS5EP8DS(4r0E8J$n>dP6~z*iLb3)rFK*QsBF8CXHVabAQ; zdwiI`sscl|*7jpTz;3LkIFdNKFj@m5V+jOP;snlMS|<)7JPnnO1`wg*d~8f>UD^)} zIO?1Nxuq}#rVlDZ@rU98RhkuK0l(JXwJgD73OxmtZkWkcy^|7Oi!F8Qt!J&DVRm+@;H}!oZFom1K zo+sKm+ph9h;Q<}*#5Deeh^p<>{95ZZAzN-KDwkN5uNfx}rVDapqAx*3rxv!ua{V(* zh!)`Umz!kSLX?gQ&jOt3Xgr&~Uy?ZuHfGKv%svalP@cRv3^F~1Pl{PX&v5%DbeAFE z>2rpF_bLLO;Lg5)4@|&Q+5-fv6~1P4U;(e9Cg9n!m?7XRAG7HORRQl#arIAo%`8_D z@cTRMRr$1n_>D%!FPw_$4?BO}1(yz+PLQEapzmm6NY)}V-HYYf`Y7=nc|0YjTMDP6 zd&(V;1X!B=l`H5FqPuiPrUTE;EL-Ao^P~hFj@dP?-iD#Uo4LqOo;TaW0}d={(TgJZ zSf5ODJ56@?7{e9kVS=}w->YAy@V?!>=4IUl#!4Au8`={ca9_)=-onc;K%Lhu+5!tE zy&=A#JNC>#K|nYIC8i@Yy#RekP8AoGPjyMIC*C6Ql?s!?|jCr~!N%jEBJ}-xXgjAF~S7dy(8}z7{C!-_HKzoR*rY zJECH__)^rSq+ypIx2_S2+yISmwUC+R>W%0i!J`5&4-;UTVK|CBpn1CWZ9a$;_lpE3 ze2NN2D#q3FQBY9gu?qz$8F4}5y3v~-OR2Yr444xD2WkLir2sLk$$U22J4trnknY+s z>czk*{F>m0Q$@K`ju)fe&`~e1#}w8()XS@*-q86qLs2iGaE_@5a#7#D&&L8#SY;q9 zxOg@MAq|f62q^~{zc=MD-T`%vc+!K`XC_g>k@9-2K?=Mmx zvVbYZvN)cjht_F3W$ybt+I7ujNbwpx&U+jf1+rE8Io>C$vy#3?IC0B_>s;A+d8}`0?$4EIA%B;hla(i`S5KD zZRjl^R+5YI!qp%|_pzHA>3!je1kt1}fm`0pr2I&`NKx ziA1zKy&DU}C&UD#f%a0m7%_AMPH4#*3_um^HM^VW9JLX+Hb@>Xp7whE$BWsKu|8N} z<>S8c@lv|U3tV45PKP=Kz#hf8`+mH9E-^BN{V7ctGidC^(^MII@v}&77>XTgOpX#B zD<{kzKPGd631p1L({TSO?LS%gwUx8*YdxuWo!d(M?0#$)J_&9&a)Q%eN8>EW931z9 z5EM1skE)t+wFB+)oE6C6*=mP!!1*CN4C}oUL#p>_B)b6sIA(6%3I^vTZzOfIUsULT^@O z1IJ){`OcJGa!K>}7Wt$HAz|{zxJDsLM@Os-mcmI|MG!QLKztx4ds{cPlJsS{#|uHQ_K}3&U6=J}9}-uwCB0yL68Z^TN^N{w z*HjC^yR28Y{W}JxWha7T4YtS9y4+oG2bb&?x*g7D39Aq)3IXNfWBO038xFiwn+t08 z3B5pCG{uAg_?HJa1B<^_PR3P$qTN0xYaW1;>6Q_JyeN= zoUY8!oUR-|a461gw&*}BOiC|3YzFhb^N9{!ZD(6`kl>JX61M8JXbQcOHAIM_Xn2|- zpzX0IEvDBwS!-Uv&=)@FV|7M+i=h+~>#{-oity96^kT??=Eks6Y7z>jEkcDxH_QM@vVBE5 zGsdX>vvQ1P9=kDm6vQ>rAEPIto^OmAoNVgEhGq=eP_T?OTgOMT49Q&135_r(sO$YX z;o32audL2VJ|>)2qIXFD1DYAq3S*A_cpbSmKj;{nJ79R)A>{5EgD3TAiW-^M< zL~N%@Xd?ITaCW>`pZD-+Th}$W)B5w%=IoDyvf#=foed4e#q_~L{$HYUJIHjDOr&4aZmp#e-t~Mo5PAryCrW+98$}EFnjt2Gk2ArrP z$S#sk2PV?Cz#OoXhaUQz>V0{dy{MBmaLkE*uC_DbhLBG$5MDz$- z_&Bqhyd33G=jXlx=2R4^(;3aFBjxNNk2ui=v(SRIodNA=sS_uLS*0&o&6?#4xsVq`p(MPj^qSp`vEm_Bjb>quu4oSYmW6@rqRi z=joW|ECHjotFs|xOasp8D2;VM!{cUj228lU8b4d^XK?_=qyrSWZdP&9y@5 zb3e(jb{bHq7dpOaYFr=tS4x!#rKJ`VYH&jrB zdV^zydKZs+<2g zv`{;qi<20P2!W%3NLsF3V4PzQ4{(Kgq-)UbMbTL>Q_RSjQzjH@)|fO@${~@|DQ>UP zlS_^LJW6z6Iz&K(bYY@A^@|?x{L$c&evgoYbC>i>mp)<^HAVvKL!KvI%t!1UIQG?ZK4PyD z`-<@AyUZy+iv$g-NI4+6GQ-w)7B=%C%R111x-%`mq0g@B5EvF8s!=Osfrt?=Snb|) z9g3dVd>2CjSRQZn75mI*B<$|c5jgVhk>-myUZg?s&yum-yHMKfkQ`Te+3(YrUS@$` z%4Zd`s7G}2*>C9wUXhI4>g_~Oke%XX5hpU1i0If&Wakq5A_IM&ZWj+x0Y9ScmM?P6DmE$Mv*Y-g?Y$CQfKS)$q2N0@}hXGu{$z>=^3Wdx<3ZUMTI-|pCnKXdbj z`7$FLQph)N%*aMto6n%LIBr84J}V7TXsJJlJuU6sJ`M7WG;zW7IsFqUQe3SPYoWI_AfUQ_Clpi*r@ z_~kB-MLPg>iD3xdk%0^dp?nrvZOIt!Xe*Cdp1r|`v?@3Fc&Tpi@hWmO!7DdYu|-0- zvQ!Y;;0sX^To=+bT|Z-cE;Lqi5|B4P$fjT<`A6jyJT!+3L(ay2~wG92-R7U4%;X6L_U_R zeuq>DE!OtcfB`CYW*{x%?ADu7p)`dV*tfHF+SEQ7g=1BPaL!l*w%E9y?=<-+h%kW; zkte4`=Z$#8E^uH`H^siu?H1RfMhSD~rOxnUkwuI*(= zx#G*fwOk3Wgl18Mq#2vuIJ*E$7dx|5i6e`QAR&)k<_P3#yavNiJGju95+Gpn)E}7FATG^r)gsq=n#F4z(2gKs z5zqo?S}w;iX22YBTf;@r5P9hA!f3g1BZY|>qqXnom_Wk_L}Hs<6MESdkW)(6zQ~)J zV;)F^Bck!~CpJgY7mcJZ?zPjH_=n_AOd#%(p`uWIU|J1m)j84daYC~^@MEdKUbZ>X zCdXZMu+{EZT+IZ$j?JgzVRQn&d#q&f;||RNEY!3C@J6?Oq?URW5-`G;Q8er&wRl^zQRL$*H6>g z5!MKm)f)c~5y~V}&2N3%&rh7HC%8sl+*yDqRw{3vicHSOLY`rrIQFh4dE5loSQTud z4Lllr%$Q9IJy~cBzr-O}ia6dNl27H7KZKBe4h&q=+8kdHF%(9?5EDh%p*kxvj&n^J z#Ee_$X7UUNuvIV!_mh{0VKN}|iR1ENP7ANjYLMJH(;+r&eSiy2XKjuY?+_lBtmRr1 zIB@XOYX58mA+SUUNF)qu4n*LKbEu@=}E1uy(erSvtldL1(c2!%9xCrFtBL5cORA zeI`qc`DJfGO7Wr4GNd@jTu5=vg%s1J3r{0Fqhy=&ho|+LkUpe-zu!|FD^Hzno#F7n zhr`U?*22+wJG)6stWc*Yv;&W6s_kMKKF&%`F%Maps(dd7xHFqnAtsR%K-vwYcG`UM zQa*g7VJQqiYuX{HtCDq&cR^IPr$);N$~TMZQl$^l}wofKGc?x^cLAaVpgsLG|CXX3c>jG2_^T}!EO#P$@jdhu*5Q>yf zD-C6?u^q{ecxx;+n9mg7`^YZSObrz?)gk!1KT{yjCM%$~G*+iLh1M`Uzv}^v_SMKT zDzvM>T&_)pD`x&Tx2<3o+J5>Ev*5$BHw5J9xQ`uZsb? z?H)OD$qk{{*Z|z32$ew$lx7ew`S~@wQ4DLyAe9DqjD-U6P*n)Ahg<>h5y{Co$`xB7m z(dm8>ot{sEmXz87A{Mh7m?lEVo{fJG{JW@h5Vg!)Yb64GcR{5!hY*w>wDSrr20)Nl z4zu$WCde|Dm!2N425jbnWH)5mbbA^L7J7d5PXNxC1VxLff=vRKSo+~o4pIFOYV9-u1D*9g94kO_fb4QH^Bjs}%P+^$&|K;v& zz%0AUde8lFs_ImoQ&qbb>?=N1}scbeOqO@u9Cz@X6)k7>5ya6_WY=|7-1i z_NlH;stNL3=}!9WkG0pwyWaO*@7H=4$gj54bI(ge&VUjTIRPfCk!aeuiL{^(YIwd; z@C2ESLaZyPS7MKITXf#!^_rPixBL~n%kHHR&8&f9SE!hv{X+*4Js=(BD(MEfeH5=L_OlJVc2% zLIFU{4Q<(!6(p#Mi3F4<=0xHWzm}v-6WiDh6Z$33A@z{bhhNVZg9eR?6{6-mZAK#* zV8}qone6~YB#9x)l&Sj3Xc#~8J`wfki$VAdV!ZO|?)DHuBMe$?eO?SkJJr=tJ%27S33-l|O#h7KG9R;nGU>L$Gv zSYr(Gb}$qHU<2B<;x*=IHrsfU|ca3eH9z{;4vZQ%Nt`jo2W9 zUkc(Q#ESF@XkXHxZomZE(vC!l%J#KTyVo66XF?#FbbGRm>iF^g9|0J;WYwsM?4U8$ zP;DGi6=3^b{b&!6e|GQ`j;-=KFkq|>C_8N8ikpxaM!PP;HP1_z4a7%?V5#77IqP}A z6{f!UA1T1eB(%X`NQWh<$m>QyI;|w2QG+*HLzx~iZ~fI2JPBq<#8HvmV@ryqkbt;q zXnaY@8w43!QosT;5-ln8Np|PERktoqlj+WsM`y1zO=>AtS`w)@LJCd7PKga^@24l% zI;^76mb@bx5acWrv}6Dp0g}K_!*JWu0aPP0VSHw)VX)p(Mw3w%91Y%j64hF|kYE9y zEMYI=!8GRGRiVf1tYV1p8mwR_EY#~>NgaiF?oWf-`}q_JLe*n$;>T;75a$sl6V$36 zOZMGYRIK(;3<*mF7T&-{1G<0{+*>DM0YX*euIoj~! z1lol?!noK*E~lxM%gF~1)h?&baa>MQBbSq_WeU`$)@QUJg=S|=ozyOkFNdgxxjf+R zu9Og;)8mztXW{^K($mL824vuAcc=;VmR&EWVO67~g@eXn){5C-tgX#7$#Hr=mN>A< zOK?vXlHpqy2eP!yzDBR$az;o-$#?UdnbrX>VfVUp0)=#0tJI94Rtm>t1aJmjO)#u~ zd&1n=JysR^v2h4o;3?;Pot~E~yKcGlFrpEgDU2DQOfz|4jnKA3%)$_--Gu|8VRi|y z1+o|RP(k5X+FTE7Q1m+XiE|TN;L0CgqU~?4WRX?K#^x#`bG-uH#pALYQ1~%pZUJ|( z36ZxC)GCuL9HS;S19v^SdOSVAy9tF!Ux)UkvxRz}NSiYq7C_obc^2sPw#`0lA*-?w z0?s4*O2E$QQ1RAG3#}-a11E}?u}6@licwMO0!F-N55UVV3L;y@92YNRn3SG}?6Ev( zm+@NRL9)a)Cu>VAjjWM4(lk;1ZAn8_V6#bs&8ByFqLtN5K{v)NM=9(L)I$_P?!jFh zoZpm*AqJU{+PrvgbZpl_)q}L=k#JDO5qUx37rD_aT69m(m^LuS0&gC0TEMt^h;df{$U-K z<|G@7B!;m%7}nT2ETc=arhAEo=X&NPF-BOm)<&p<8AsyWOa%py zbF@OK;DY-EG)2A=j#UF6LHlvW)KA15a z%LB${G4v5O=k_?tXULKkW+7PY-SE}o-Xm;oCpOs7LNk`wU<{j?#|iaI+NNTiBCB@K z06&jNPZCU^8b#~K;iuDyGL7a_OnIzA%&VwMe+8il)`fKcT%M(H9zDX>a(UQFL%Mov zgvz}$A^gFd8-#cZ<}!ouXeL-CJgB_1Y{a#V;!>WB9=5D78&WS|W}=7+fffW6)=AVz zF7ocUcJo1CngUBYdvL5JFEXQTbxIh@LCpA9*Z@HEVy0=7aa`Jc39G!8Y;Br!p>=ZK?;-vDsx-=F)~#Rfwl#912eJ&-u&^T^UW>e3%g*&LZZlk9JdcynHxSBRZl| zhnWJOP6$X)%j&oT5~gB6Li|-gLU6UJk77eBY@`Ov`hg0kRuqt6_gq<<MM_Z#TX+ zgaP^5%<9dp>_slMNac!H9P{h*M1Fm^zI|s&v~9nB=(U7CfcY>1>X8XH1FHQK zs{aeb4JhW$T}Na=fZ~)k7>Znoy1>ro={}8(R<1d^9u>7!+N8wAQt2Z*x!MZKL>S?$ zGmMbl+x|#_$B#rg0X$qa;E{RJ;Ib>S8^F`8i9P^!J@5!z0!}vqht}5vj^Z7}A*LzH zaI|7TXVZX4KOQg(anjmH5X_Z^vR*GKQXIM`v4)^S*gkHV_k^7llZuuX)TNRN3(&ZQ zTI0)fTU=R8O9vmNUZ6(*S*uu2@m3h;yW zqDPe6X?R4ZYL6&ecv>D&Qw!~hOQ>7@a`qq@s~H*(j{>i<7d@h0%66meh*YM^*&AhC zq)^S(L|dM1jY!a{M;L|!N~4Ymbk!-;iZtSAb);qav-}PJ@y5(2?l3~ zJ9H2eZD+P&0>@4RaW}xye}=`v?Idgo%SKBYiW@Oo`ZAwOU$z?jBnq=QoxPA&{#l;$ za)NDfngv^C^4{M~PB%hDIQ9?KCm6|aIjZM`PPKR>y#<1&HGBy@mm)%7&AYdY-(wwz z#0qkKX)VC`RWFWqP*MT2BIuf7OJ`<<5a}``@uVI~y24aR0Q!$pL*I!FO2JBXMlJg@Vn(eA3|4hU zEnhgM47`*a^%W=Fm}prpl6Jz4p!+u?A1}878^OfL!hx<+P7^NkogpkGVt4B)V8|pH zAcF5me=eQCDR&;fa0sv`Mox5kKM<8>gwvDY*%5N@=#mCH%`19F$a_ z+061DIC&kkhL6(4F6;F^(s_o!8u_vj#y?I*6$NjArvT zTn=G@Gt{r~79>ba>_+xx%jwDeE1|BDt{`@a^e*R{FDL8$UwXK9|CgS@y2kf^=^^Z0qrAV4>kc6~nU2as z;t*_ba+nTep+r!_%ENyD2r#UIRfe_-=osC26yuuY%Y2@k|1 zs|Q;Ta6!QVujQ@CJ1Bv{=8jg#s#W4+ksl5m%X#2b5orU(0!@fgj7Zn2tBW4}q2Pw3z9kwIiIi-jkJp51R*^EyQpDOa*&Bq+vTTA2~ zkQF+C2pd!b`$w_$8)~6tO(}6xSTJ=%9KQ(0XEG0obdWKNliXY^G|?VdoBM3&D3>wr zldu@FCeohBPa|q6v#qlf2v%#sY~naDYaK3BrV4wItuoAyjFRC>2$hT6p>JC3MrXMO zxP)-0Bbo_Z6$c@7jBNnwRjdn(=m_2rLyhx;4Oy=y+ibU`zPAn-oLE&0CukM1}Y!*rOIUP>YKj!}NpT%G~o7YIV$;;|$5c4afka zW}P5?kpY#UZzB=$rdCwElOy%9N%Bk8$F9WFlhf8d4%wo|4-t}o#xikz7)z%8Gb*P; zlVDk9X!J_ukQwW>gkg>l?nI#q9WWM0u`>8VhS_z-lN6_DNv?;ZJYs;iJsjO>IAT8Z z4=$=7e-sZrRw6QgG=2nBC^i~QJ4@JxFuk26toNqQ8g`9ne?K#g1Ke{Qwv-JLn2H~i zL)tG&1bR8!SbbJ?HXc(CE2GTBP(YC>NXSigFQEa?B^!{tB^W7egM!1y>C3Cz-rQ(;wdpv7o7Q*Qu%jp5xD$V4 z5SjEqOmkstw`^DpQz_QtLk|v2@Zb~+KbQg1GvL2=dI4}kk~6|3dEyay!kEbE7idA# zYN}lpnD^jN)q`}O^y>hw?7+2v92JD4oVfB#EiO9;P!nIberUc;*`px5^$W3t;TdnJ#R6& z)@#hQI_LtHAT!IZA-%@vy05zb_P>V@_DkESl70IsRieyt6V<2bIg#p0uE8y?GaW!o zK`t-lGCsZBPp8SrLY!u`*~7O zar0!C%8=G;p?*>pzKZ+udAUsA<4a9gWhXlw>Q2lEvR7fF;b%1szkB&1kLNYv=i2b&tlMY6U)-O7L(@XFh(q{& z)MqiDSR%)uXeUjpgdBBv@qOE8SAFrF-(4F{<*PU&^zX`B%TM@?f$ z5IKgPk3RmcJ8!@HZU3;O&Wyj%fuJagX6FUvf0w^OSJDdt~S$O-3yJ$q#CO$ur7L_uaHo9@OC)G&oQ~%~@v8(J;Z@tgqfYKzC7e z`e0gXnBxYB9-tuEz!H8iF&Fg4HoHy23bunvKJzw6?KP7{I*xR#*LG(g=CMb!1pQM54YB{(%dyhb!2vqOzoZPQU(N%oy)TD(_ro+KB`HRy_rrVU zb-Do%j?+O}Q!1m@lU?}a_*U>Y!)HQd@ntGj62_=j;8?aDYD>W;cI?n31E0} zm|uA%CoYyVw*6E1q=P=_v3}4m=T`QX^EVC`57V!9T^LKfF=78k`UPVpqvu??7_97N zm*!IpLun+_bVakWqbb5(8voDfJJR%Egy8JfocB%P|UqEb&>DZ5{#g&PD!Eo@(w~ z+z8JV5uQ}`sDDcNAeRHfSOB5cG7RDzaNN%@{3Q&Zn|;+SPdmuzKbvXm6wqR+_0jrW zm?`H76=42Sil4G?a7ygUow+*$0G&4@I1BLBKSu% zW13(TLoBTl7MQIUNnTh33-(HYDLb^bk({o81#^b2s4bF|nP;G);1U9-SVKVQeO}3i z^RxnDyqHZ`ay=BvR~)~s$ZMc= z?u=-$Cf0A&L=A&Yo)IAUJX+;vKiElE>>S<{T2~6%iR$-|PG-W1V|egh2V?en%;2RU zz*>WXFcQ-x1Ut@kqBwyz@G1`K5SW?_vT@>tUlBylD@G& zY8x7^Ow0I^(Pb3kYsu(xBXD_zo`%XLru+4kn3!XOjoQS~pS-rvo=5pO8wu^5=1~;d zoBLX1pQ)cTB0GnMx<*9yTH*%H+9JEd30TvE$euMKdnS>+{w9;iKI#&*J?adLx-^Ko zX;g=@?guD>iY&cY;ur{I_w!XDzoG15O#Td$X+1b-oyC_a9kgPh5gof~FjFVlc8GR| z@Wjcex=TSBa}U_0FbRL}9sG zDJ7PWImKx>0|c3ll7HY1wRUaQQQY3W8```8gc23gfKt&x!!ao!&4`KGS^&xcm5MfG zn{kkH4!5Uk=qH_(zxd$KKk(D*-2CV4na_mRs29Q-~h0A?-Jt` zwA8-hx430E&V|PPXh$;V6sNmfD{5d{RcTJ zEw)_Vl~(`t@n7j4sGh}XK*Es_H6N(RCE_Oi<)O1KiDFa>zo>R>tJCt%xbMO0ci&Ay zBSUDn638T2II+y2^eUV{{7FF^o7L=T_@p4&Wz8fm5FjSVYVS~70pu@L8$epcB?G2f z5(Y5}7!^f0&!U?wDU?E3$Qr=$Pqt6^dm_Wawj+4>RwEQ?t)K0tI-y5 z3!4lU)a|f^j%fxhJJn#{_JqyO2U-zR%4~xM0)DtO>%pLkd-o>z(pem;J3=rA5CK0H zadulP;~F)@M4==$2A!tAOEfa1268EYP7A*k3+uI5^4R?k8Tku#7B;1%DO=4&=Mol% zB~)8ehm)gCx9+MkOJF|5-POdgDA{2o)_5|WjE0m`uO=D%1X*IEz#*Q4JBJDD(}+64 z4M}rlJ-3wuOeNtiqSQRc+cSSfs$UHi!-zUV7yYOv(1Q zS*t7DBNX0?N!FWO$bkjmUH)pNwiX!m9XtP(J|D)VSAC35t8JxBr(DF@)dd z-f640f=~yZG<{eB5i&S%hynC!Y)=ehsHk{LCT%#vOy6M57I=j%;TTGuh3qI$NetEm zW+7NpACwT42WzYsFao}CyH)Q)S`?-kTGAV^V?0z7(F?yjFGPoO=Gm2}pg_K+r|qCj zhF_ltNTZq)%?crV?E?XmunV2X;5ftPuMY!cSDDs95w%P|X8x1C*Xo>~gb`3TxqT`C zz+3=x(WduHU`tC`_2rmosi9BLyY;!Y7gHu#@RogIVKiQu=??#~H#cLeAkP8LI!^XM^(LhBKN1W?QGKAxLDR2er< z=tc#RA1m^qNDMU~%8tR1Yh_Ob0bGUJoZ$7*v4kQ4fZP=@bx0ME)cAs%OEB$IAnu}P zwTnK2P(E)R>0j*NAfHc)y27-{(R)T9J4`sCmIq^m6%JDpOs7`N9P<|`CX$BTQaqn<) z-SDQK!kdtQVtVUNuR2P;>_DFr?QkO&CK-BYx^a)|o=ybocOBl;sl%JJSgZ|i@&ZDP zjysR&r7N#00^a1|@%92dH7m-9kre+y+AiQW2i`@i1ezo;P*w>~fCZB9j1>VHAC5bs zlUBb68}fv=Vm>@)n*D!B4=4vt2O>_kB^Mw*c=M8+{)7%9`q9tYi3?pVoK3TZ(xTY{BnYHIFkJ}-PZ}f#}ddv3?#CFFI#oPR8l=#0{POu;ukVx z%Pe*isrA`Ig8TQ+Wl1VIvQ7&zQT^?Ep-B0$YrjQ-7$%pdQrFO55nD1lp!q8dXdK&0;AR@s87zn`2_M4%V%Uh-uVNQ$VTJPfp(Z zMaPGO}QdAH)sZ?;v&8j0VDqTn(gMlobHLpgu}g2QXA2 zz@%E?$L1q3M1t(s>HYhx6-y?Jj;FRMoq2G&StHfDD&o+o)ci=72@Ne z6xQk}oHzx$92O+s$u{okkmbh!mTi_m`KV*rlodoZXj6)gs3(s%)Z>QgxJ3rDn@5;A zXgDj*7f=}4U4Fpo6duUSet|oa6#M->C_Gw(o|eE0uI$HB^2N+i;9-{qraZO6E^{{q zkm#eeVVJ*TE|KFjDIVo3O|L>j4dI%QFM*9o5@INi(9YMo0QS;|eI_D z?ROEu&I!k2saQN=56b^RB z;zB-!8UrmMYAD~Msi?J*MnZ&g$CQ#ZC?!0WQW8L-6UtL5CD4WTy3mx8?Bx=Hb_1#6 zM}UKNyY#+rYTNt}lO?~RI_&g+nuEZ-oi*-x0F+0C)@&o9049A@DLS~81t8|h7VR|( zLQ=d+-+eL{3j%@ZC2Zns9xySyI3~5VlZiW#N2>Rqa{4x3KFFLTszAxaEp~G5Du`e^ zl*-mw#3}HAXn%yI?a0*)h1|A6oQ?bHzfBtn;#mF=xG4ec`@$GF0SKo?02T{~kXJO6 z6|dHmSn;$Jtv*8Sni+D+Fcfo679qiM>xw(kjme55SxVhbT!k!CW> zxBOs5r9oHimg1C%x3X5KD$FygA|PK_7mDxmv-OhB(<|Dv4RlS?dD=7CV6lkLj(K<*X8k9w|1~Zgx-u9#u%{CuD(i&wvIbOE; zrt%TGv}5i!QY@6AJ5}4gqTdbmT=@aSD?ckd%WBVr(|=126KN)Vv6m)aFGoBAc=`FQUL2Ueq>k zY-r$P<_!kauUGP~J@4F5f5#?D9Kt3yn}!AD+w&0G3X$9{K6*!(JUGpW0G}3&Knmta zM7U}`eRg&Si?kUT&`Sm+k@NlwD6_pTY{=Bq8e7>c3DvE*iUZrN?h2z}WrQuV^dhl{ z%Zs~n0lGOjl1tDsJY&;L{cKnLj5AC1Ea2eRewt5wiL{6XO_|x=l@DYT5=idS47?}6 zgeh1b@+Xc}uKUh7yYIoI7?vr`?s2vOZK#bFrIkq9THNUVJLBwvS7J7tQA#_KeOfb& zjKpl3$DD>%lX6J>Y4z;M!s9pXT|zPiAtA6$$RdJ%jUbktu!Qq5?dws4JpG6$BTh9s z5aeH-ML$iH_Ursj0nE9PpVDu8$yXT!Lyu1 zl%T2IwD<_;YKrcaXC^96bfa*tq`QLU!0HpGm*O>)|GyB(UlGuv5x`^+_%|}6bn~&) zA|qF%gHFx2lIs7chgIF5$>SJ@^bqhG(-qsmKVf_t;mOldIeQ=M*JrZ?w|sQYYgXLv zsG`GLpmM2uX5tF+%@HZ|w{*xsj*(3^3w+-^;tpvXyE=cxw%NU_I4R8PO(=#9NE*x;p1A?u%e!u9!0^RY-NRtapNCeNuea(}!i9?a{KV%j_2{>ypL8Gh(|iw`eqt zSkUS>>&XUoQ;y01%-NU$HeyuTV3Y&_?KLN^PCYJ$*nUQhKP~hIVKCk?YQ?4i58)X5 zvt;;2Es^1SLMUd-K5)|BGhr*JURxlZh7C;PzCeCt={TVDl(bHr&F7O)tb5WJBW^7F zPoptSxGno!$iyw-!}eVP6gnCKv^|>}+6}yBHf{771E?_YL|{7E*cGwlE)I!ww4Ilf zHnuBHYUc)Ld1?#8YTJP^i5cjGVcKaLV_NHzaF~V0sEmu|_$T2sFb&RxHMsosKIj^e zpbU~}Pxk(DVvWND{AFEe3_iIcM;uF245mOx8xN; zWE78COFo)~CNZMZG1wj8^O&L7ZaDlFf}jVSv!vm0HW4xK*e}huFm}kEBwo_AM%kmX zojDYkn`3mNdJA%GL2T`)P63CuAgc#jTaXd8npjnddys2eVx>LEYs!5U?TO;bM`>5Q zm_gWF$W)*t9CNlKorq>OEVmpVY5U_*X+DqS`(%quO8z1+tUU3=XP)?hTiBNckf~Ie zmju(0p>BK3KO&oQklT7c-_G+%7xao24OKs{09HNTtF8%qI~LU=B|Jxi9E7-xgm;15WG;y`{uiPQ$`N z7Q{uP~l6{W3X%16OFMb$TA5Ko!&T2#MlsP)# zsnYWZxty3Nt?n|MG<2;T`DS( zQ(a=fU-C27U7j&l=)0}9o|X*r*)#@E36Vp>;A(5gflJGl^^#&sG>()3ZxE@>3h3Rx zl~e?OnU8s2zJY^rorgf9Ms$T?h5#HpT^O^TCs340G5qBAtZ7cvte>=#B)J&<1FiIp@-MM5Sh zwtC>rzi>Y?cnDlHe;I?k-NQ8t-f$L(@YPeNfuMII>Udfxrj(!Clb0IIrD90|77K83 zeQ%Huzqns5ojgdYldE4n8D6-FRVW_T1W~*T0I=#-tDhB6DD$^(g9B<4jaEjvFMI!Y z8q#JfH0xk%W&_|c9x)@q2V^Gcqds8VwdrQx^%5bhj4iX-d&`Y6CKj4FC-lYt2DwVT8Ewp!B=Q+K^8O-=BNI0T$CqTCQ{8rW* z;imfdr@s%PDs^|KIL{yP5))JCi59~VvdYNM3f!bD`JXuhi>dEcfuZ{1fBM`fP*;@) z8RT09SU?7xWndRG2k{U)?ho{CG#3TS0UYCe>yq<`Gbc7*@ZBGztZtq;)pa*WAl3M# zz@L}*WYH3NkDlL~5hxSS{H{Kf?c0HIn!Q%)5!%FV{S@a{Qwk!ZBWnGYw8+29g$0lUN$B8q9xD!a7wp?%JwBH@{{nNFz!q`PF z@gIY7!GauR)_V(}4LVkuNrL`F<1aRyS zrs5E4X?IFIQH1s>8&h=tqwdCYo+&-0#E!{2h1-<4qsomZJ#)FXwA((6W<$zb>o6Lx zVB!-pn`niTX@Kr|9!0B6l#d0_1^f1bS0_&2BdG^(gdOq7IDb4C%^x@Q{Bc>Y2F?8O zY&3t|)T;pno@D+`T)&Uw(^#1_?zSqTJ<)ab%Ql8#8iNglm+xmm7ZVaJ#KxpeIh2cQ z@^MlKImp5$4^Ws?Hl|MTR#s_8RmQR`%ZSf-(bWNzE`(HVe91|V<=5GM+XLagskwqU z1xBV+hsdZ__V{a8*7{ATAF6m?Q~J0?sR-*K9V)vvy{MG|TOqAuaDaPVgU;!Wro^Df z1viDJ9U;Wl#LQCT5>D6t6=;uUK}_KCF{puRI@k-D3B5c*WwuI!Ift$XS(!!6FdYQFkz8Y!*jpV5 z4ujz7`6JkbPS1~$amf~o*e`m;5*a(kZ{0BlLo-(Gj529|j!t0J9L`#oEpNFT2^JN0 z7BlA)!OW?%cNy{unJLgkA58WSyXf8?1KI?Tl@+==#IBTFvPHHVPB$$9XF81e`4})0 zV=LT<;dJ9ZUf-M_(iD(P2!pixhH>Dqbc$e&7CFdbfUNtN{rvHg3N^8qL5<;b1|v2` zcb=h~$kJy=|&>}J^8E6g>BEr9@$uhbuz7(|K|i>6gbS>&s;C^jJpUS!M! z@wv{2oX|zFXP-B5Y8M-abpliRD{eoVGIR=XoNaSxo%T}bSvc{BMVfb^MN}4T!fnp8 zRkrGo2SK)f=Rx4#RvrX-f~l+*5$0%Msnt6=Va(`889*dMK=m-kKBbvq!v}%~a0tU@ zs6)Cl?-U7Y=3}Xt4!D>WU+$8UjihX5GHe&Z^xR`&0i{LFT$9R-n|sT}X%_Ccz&&T| zhJ5gGq~U$>B0w~wk=d8gszQRVIge(m{^pSCEMAO~p@WLzM@E7^ej=(TNtky$Vl)e* z6fwq8Fl~v%Zar!Z2J|h-8K9iFK62x%aHmXrZ+o4vTj2V_jA$|p2VQh#zc18Lc6wpdXWNbxRr;+Xj=|Mx7CHD&e~NAw=WLF3cb#vJ z7Q@M*B4ApPj7%jcwg@9WT6OxYtixf1ac8=>iP1Ug`?*!1rY?u$b-{*_kk`&0y&)lQ zEPFH=N#ewL!4DM5K!r~cGvnO*^qYPp(xmJ+*joLL_wo*1V501EOm%~&jIsnEpaqhZ za%(`2JQy!=-$A9+0cjN(6;Udt!bydMEZMP&aOjt|**h65-^4XfYB^_}bZQwCy&Oiw z{YVDY-MG_B*0S(bw78<7hp)z+UM?3l=R=xI9!v&um4lAC0dI-eXd)(_&U6H%R0{zo zGvTDEsx?e)4Idk*j0z_{(D2o|104;ft)g!Tw^}N?PVy$#ZJashIT4@m{c)hk((=v6 zg8`P8XM(A4yAgIqBoXR7e;5u#G|}*2jANBE>u@Yloe=ZM`r@P7KnXVu*dxbrC=}{^VS3xrw8VKY2u0 zBVn>8t*E57F;3>zaneGrw0hU6)w}3VX2Tz%zIrOIi6pObtYHoLJUx}w(7~S!&>WT3 zRQt3LnXSgur$tBm5}XYN-03Py)z$>8V40tr?4*iPvRqQ;-$wEvPIS2^UFjUWsd!^XubU!XsOcSpfjr9@1(<|G zC=nvqz{XKR#q;>UsjB;<{c!ncKV0q&zdVQ=ez||$b=ToOK2+w2+4OI;ACC2~M9gB# zqG0R=QVCp!{n9HViUW;CY2?$nt#izB#_|ZhuKQA}hvtpWQ=_yTO??hu6@QAr65bz)?>S&7rW?{rvfk+9-!YGH$b@8q zPK*OUL@)-E{%?z%m2zy#enRQA_juYm2HV93c0TjE!ED7#AQEj)u7p*cn_S5Yxb9sU zdcNMQEEhZCr6_{!0gOFE!y4v{HDRg5b5+MFXZ53{ef3oluULsCL?A=S#|4*EUFy=U zse|*%eC1G;a<=qtMG`j*jZk8BW>Hn8_tuB&mXe+Y7$!EWB}66O0}Hd3 z@|9LMr!UZ0OSZFvY$6tta@wlEu^W`nB{6GSM7p9|yu||Q)PUpt(cQR1g8Ajk(f4aQNQd}j+&8iI6U&LMJ$3DH z>kYXo#=@-;kOZiJDh!xI*+iw96XrqbIlKlsgJvV=J{|Gd(<_v4%R0hE3ouZOO|p%e z8`>^o@{VThlJ+hBRU<(3inmn+iK+s)BnD9}nvz6+e>Kv+X_<0@@|to$;rKrC4eeKK zX{HcC3xUP0av@kqMk*9gYS5L(W6q|wZgQkKu1b_VzMDkM2x!&2Nyd+%BTEwp_a5gM zx+&#pA};;La`KpC=-S7^$qMM*B&}I)c9RI4^==a7Y1Fl0ymmK<3x>TUWiI0w+>&{4 zx+cBzJ@8IP8JilUU~`_RPH4~$pIFN@O@i^PwIT$=)ahSK+1zNOjVdf%JP4MW65JtO ze_Hbf2Ti0g(niG4(&T!mHgu&Hxty`a#IabyLExUnV_jIknRKqCsSH-6qkp#I+w+?+ zHl8eMGXMx!J@E-;e8V8wyTREw0@AzUKCHOr>9jgx>6*FT_cnEe1uCrlV{1X5r9#HsqF%d{9W<_7 zOaK63IQ!<&b9k)!72uN=2YbCmK!N!-q;n6^O#RT}O`)@C2&zH;Ne+9(36MV{Pl|0k zU`$#vEhuA)rJ;ZmNi`#TKF#>#Sen=_Eg?JHdzprFY~^d~KJlu1|2d72ssSB)=01)s z;{arQ_Un~=Z0a|%nvYHUO$UZS(4c;uSIdvFW|2&Qpl-36N_7sHst17XiO)p*3=-K7 z65SU2pgvaY(FF+!QJZqSYlDN@1*HORf--UYSL>1XaJp2$$<>bJ3&^1Na0(*Uk^x;P zvwJ~{yx2W=QkJg$gAIf!+@!UNx(PD*Okz1KK@Rf_=_x`}OXx}wx?DIM6$QST7A$!} z%UW^3T{h>54 z@+q5A)K!A>8A#!$5~-ridnOG%d1*1uzq$IRQ^xX8{nl2-N_k zZF#+0GC?x4r?vZX2?nB*n0UwGAeM*%w3$HwMfXGpX|nc@r2%90FmEG!-XMF(0y>WD zSfaib$S$^h92)I?gCO0aPOa`L-Vvl2G*i*bq4M>(0`|SHGp_Kq6GsUtC^&O3-12pY z8n>m2WhP)a;Ptv_0`W%q?retVcoDb(-4Illtmls?7LD@+K2y znZ)I0SRniV>d6z;pP!7ooGlr7b+Wh*p6pi6#|M7NJ2D8wZ12cWzDH9qtNSmeP_jZ( z*#T4Ci9h2Me&53{c>$|?uq-daWI5|)5%xMbHTu$7T4H2)Okhb&LdB>6ZEV z%A?miTf9i4(qAw6U6YKVUBNw516D*Eq=JIayRAgENpOnWA#_=B-l0yd%gd9tCG_X{ zvOE;8vz{ZX^v9e<&jx!$2C#zKwE;w}&cuzPVIBRX#03>FqVZ2Kbc00~2PHVwSvcCO zA_%9<1?N->$-*v`Q*^e~8To^0Yn#gE@og%b*KSi0dkyXb+4vA$8XF%vjBR}K5~xQ< z!uuo4h2oNI<74=KClepv1`{6>vXwfegN^=%kE%Wbs9?67T@|9O@Bsljg{gJq9O+lz zAgLS`fY>=8L4almb!L$AN>?_{^8z1@EM2=5yC*<)I9EncbE3~!7zkme@fs>1jchaA zgy=N%>N+}&vUPMC&xlTodCRy7(P=L5fV~8b0i6ECQtO8+#~WvFt{uS zX4sqJBEAiI5FH~ zBS#!Y?38-Fv)(n32^d)fh6Dggtfs=0PIsWIcDBP(c-0Cr#A_wz4)$RWmqQ#Qqi_bj}hZ zG%e+tfLM+hqy>QG-82hSnlj3hiQd|cLyMR^xi^V-qRw(&bd2}3GqgW;Q_}~96si_l zFMBE(3O(Pw<~kY5%)5Av$cEYZD3N=J;zYMz2zyALcYr&9r*6(+UY^ou%LSA`^f+@d zut;3&55T(OZ9=!^DLBo`hZCxQIJt0ka&vz|=@&QDe-FF{K zCoXOjNJ<8SjOKYkk7>;dZE0Q*>KP}OgKL}VQWs|xf+BwjM*6Ec2Bc^h< zVyBQwg8=d~{|wI}*tY_6^Z|~o^U{a4NW;mF@@qYB^~gv5JT zIspTY{kN308@wK-+mf_e*f&?q<769VrnBWsnW3pSeXH zAe`{IrC!kA+*vY&I3Tcw$37;w9T%KK``0P#O7u=v6j2dVs1xTt`JR-2AAK|}zSP}< z8I&sDcRx1Nzh=G=WOzi3PxXQ3QL0Ben;P+?`fbjah0V|d!jd$}0WIAhZP#&J)KQ{Z zgsoV^S$tC&io@6c~;7CEuW8wc7+S^nYEIuVu>&PW5U%@mmridlsG%PHopGEThu6$GZiQn&=p|P z{PuiRFEoyid`2~_rYZuJ1|Z0A#IR*$RcIq@3Mg2D05I;r-SzjO2Y1)svtZ~ein$r~ z9=DshGZw4A$=#RX7?aVzLFPsTS5Oo z6%GI*3fRXmPqyXFsdBcs)uIl&Zq7@05=TR{z%r0JE9=JMf02yjQ#M?20Pvjz&|RHME#YPo8fJ59 z*)wdWu$PyKju8R&h+^lZckx>xa$4vfrqJVZnW6$boT$!IU?yRU$qdpGNijs!q`OCY z_$+Fz_pz``8@+LHhyYC3IZIB?{}N)m`EJVdj(r&t`a^d9Xe$pl9nmDr*x@B4-3d{w zp$KjT7HTS#ywOqRv`8REG`CNM+uJ3-X@O%&S5^hqGWBKv6OUrAqAFQ)x{7=aV@HiI zr)IOwj6w2J)@bzdQ5CP#z**#_?teDv$wSWikAgzb7{C(W=%ApKsSOIWT3laA$`l+0 zy}X*LE8HSSAlR#B%TBf35Rm+xkv@;k>`RNG^BBEQ|c$5WK5rw^1;)iTpvw2xR`Fd2fvM`A9scXJLU^rLpV-h zPCl)mLnB$jX~q~0?~$>YbA(YDQrQ!Ax5z5WgO9Zykf{T2b@RX&+898}^vslChOn~% zHFprxv|rnJ~i%bXl!*S?x*!f_Zg3Lv=Sxj%kHzBo+Qvs#L zb&78it|P9K*@nxI*@lab_QVrgU_gf#A{mCm1VDDYWc#D9-I5S=EVE5Ox+cixYvDZ_ znKW8)4ucIDbJoW6C15drpgLO+H_EcnAgc9-2%22B9Ks(N++%3m@A28U~qb$ z;3}D_M``L_}U(VDit{1mnR*yzTU6>EORa`03Wv&cDdGEJ>t@Hfjn9@gv z^wCvqNJ=W83yVNT?jCyR3br$znd#fU1p155pIa^K8Pn93-v9?mWZc$hf?gE(!Y^riA znrh<%R-t;2wSwoKY>#!&umzrATP&X$40FbZRZvE%Ip7O4J5k+3l!Nga$Vut1rdf;h z4Q)@@3V0E}Bq$$T%tyCEnOpgN1iy#Q(7?p@O}gdrd8MaltCV>bFGN+$ZpiG{4bJE0 z=)}Ik_wf6%39S$$v)s)%IKQ!Cp!}@xg980LN<75xC4gIt%LSY%J-8qY$^VYo-CNIh zpTM;vGf$xWiPZgXs%$xhyfsYceiM24=hL4{UvYJ(%aM3^w3Q=9{h~*i*zwbx)?tSGC zU;RTr_=>B3;QPPtd#C@Gm;bw$y!eHeU6x#W=|varx!}83s@>o99p`=fuCvejAp8&W z4;-O?S&!Y4Tz8}x2ruP>MYYyNrsX^X}J6;itafQFr$JY5$%z zWh>Ouk%A4CF_> zd?sBXn}d4ZA^D~TQ;#Iwk0qoRNjtD*4=J({WH7!8Spw>@$ihnh>67$>^-3sD=GKg% z>`0Nx8ObCgN3Z?T7o+TY6|CjAzMP1CU@f`>Ffo_5UzA$~IW%f5gjY!4(?PRa;Ygp{ zMR8fDJ`k5_Ug|UJGs@=1YYbj@&@~=Q5@+m)+p3GJTltC_RNq@g=w%EDja{hszOT3f zh86_l{(BkHI$h|7b!<&fkX);7i1rtBY!^%Vzw(uJV=7Ec3eL1PqhlQIX^K0Hlf~ur z&zpTa1Frr^mYoyq=^GbEU6u9Km;j=)d8^!YZZgyVW8hVk zkCwHtuxi3(bbu0EUUjHKatK4WRjN3R{x8-;Q+Abbs9YAYi-C2( zyEUx`G$U-rIA$d8ipoSgI-H(sd9>jDF$JnTUJQn)H>+u+aFb2`&XDme#gKq|qe`BK zl|)i#Xk1dfEffgnGtBxM__S}s5T2MWL5=9|+AR{xhgo_LLxIMwL0ML}1P0q_hU6&j z4!Z=bzyuJHIN6#OSA&nc75(9_cR^iwtL(D}^N0f^+SbtVHH5=l+MSv?Ae z)tIwK>#+uhBO$4Nm$2pPi1vge{a>I7_jUOiba$@Q6zIfNe=uW-aJrn;f>JjsmaKq8 zni_#q3OuE1jWtEqqd$$-tMc5V_11c^LVMifsP!6&AlXqJdB864D4NDgMPak_4hV&retft@T^bNmRh zc%e+Qmd0nDr}|v7f3B0HS#A}5VI_GPDAU)eHK~(9DK*d&cn5AQ7hVPm;icr|%jnwz z3aL$5ArmqsUObC~vR^J7l&@_e_`&t^&QU zs$w@g-r@>zCpW%CnK5Yg#t^+nbxPvhZ})y-l|rha)q1(G>Z_B*O%P2i}jmg zp$Fq5BiN)pq!-TO?*|mE#ytkw$1_PMZ;~-#;c`;KEUX-Q;rO=)FtbzSkfxen;5*#B zl3v-lsoZ>6`KdZ9Y{XsY-Q3esJqy)%rEgJ*_g0uU2s2I2;vo1qvxB}Pe#h=#Ie*m( zr=D8Q07*X1{RK(ve-80^JqnEBoAo8I0B27F9K``$BX0LuUA9`md4L7T5m;Rd-v$e6r$g#7 zyT%%{q&dBzxrJ79akQ~H8-cUfoNQ;p$eiXDympxd+MttFe+zrdU~i_VTNp{Wy47P6 zAtu!eQEFiQko}8?96O(xU{{Wa!|i^_mXdC4few#|G4hJQa0uPcJmV z^gO}oPGvKE4tC8TG}+66N9;ag5-gkvm3Z^Jx8w(|gJovdF_O8m;J_u&Itw3W@xwfR zs8)@G6!3>C%NBAm@}l^SY{;+`fG7?_NPtH97CIDe%N=`W-^`eqhd#gMj@h@Rg0yb< zol!BtNZ)fl4vb62euBr$;}O*_1xgkO5p;RhA%0fv4js@3Tu>fn98Za+bc{n`x0kI(3M(qy(JAqD7<_=sfP);CzNggZ7i@=sj`9Hni7+EFqiYTTu{D9|;%v1B(AoIw6 zr4=SB%E&y;M?csbq;(f$wgEKdo?BG2P@p%WyfrnYt$YTZ3_pY~hgXes zu&^54P9e>Y`7tIDY$MGSgg!?V#{73Q1;PPiJw0VcmuNs6rjNURE0lhy#nq|r=v0u9SWE$rPkHc0p{ za)iAcMC8Fp$AD#F)?e#W0Vmie^8k$5H;LB=Q?BIcl|ye57~jMf*lDhXOYx&fMlBQ= zMQ|-IzKRy74%{$g0mZ;dbNTDw3NWuB4E$zL4K|WrCq;b9mB1b_nY&Ioa}bS~-_C`z ztFBP5Le88~ZnpJq~sTc;Z1b58C~%1J#{><3-@Y z*@OMnHDXOe1EK0MH(Xt@EEnQ{V|W;K9$}+;Fv3P!2zAv|-okVaMv_jXA|q1uX-P@{ z(6OW2GyCKHn}}8vmllrTIuplcsogVsW2?jTuic3H^y9Gw6UZ9^Z&N@Xq`tPg;r#Z5 z;3g=A9S4k6(uTH6uyTfAhwz9}8E=^3{Vd)TEeG?`Oy`T=w56CQTS0nBJoCl>nh{{g zbjLCEgRnQCG~4|Ka#qOf3F>pdB+&@5=4>p!o*lKMN7Pp3e#uxVcv_eRutDK4mzMML z;a$uRbcfTB*mtQxv#kG`tr1LSUmu_?Sg`2!1ZwqmnCkT8d0uX_x(8XRHg+_5*IwA2 z#_h7-;vzy!gI(Y!;o(lHe^P78Tz(VvMm<2Dk|*qv*=s$*0T7_Zn0#d$JOQyun?$-) z;UvgOl@28N5gNluZpxp)UVwz<7wMGkGpt8SkQKj}Vn@Ieh<+Vx#R<_Z78xm)p+>ig z&D~I9V|^kNt>Q=iB#)mkjPAbTXK9+Au$py;{lkQ32AfZDg&aW=nsqQ)9KbdpH-mo6 zwve-Jl?;2GF1-vh1WyeC{ag@UrqwO0lb6h12Ydka#avJvg2Hy_DmtqykjH<%oYVfV~*i1dzZ{1d9A!`CDJHpm2{d^aS!8(f(& zy5+dZtqtT=iT%qgPUMPk!;%LUsmG*x2hq?-g+ffT@HDrWsJg;mN_FfX?7R-tA!F)9 zo+Mf74Hqb|9T9deJwoY@T+6^)VtLq+bR)wnl2uq>O8?apY@Dh}eF*ep zWi00(N6W0f;FpAPW0qH@&~om8)lC=Ho>in^iW{op zwepbkf5MF70_O46=zG;?6A|_D7KrFZ1cLEX6S%JrCg}f2o0miKYePqf{P;1c*LJ)} zv!vqfgh28uS+9xuP_(gKjPMjC-DrCY z37Jt9)_tu$Xkh^d?)bP=C`N6KulfxPvp)s~PHV(BFa#wnt*o4}06;YkrQ_YT_Qz)0 z{+z={2ZAGM_d0x=<-**h{o>;b;^Wvu_S>f^n0MOG<+Ig8=7kDCxQyl2TO2cHMXFyN zC8r1#OIHdzXRN9ZJLwdtA>R~x>eb^Tz=OLZX&=6$5n3PQv=p;)K4L4~N)oJDkWtWt zhJ?U%Awj4~CP}>){n18EM2+#K>>mstw}j$iTkENHF6us#DzgyxpQOgG4#iTNuhx3acV!WfE$j#@&o>HuY) z5soW>^unqGLE)b+C%xATLxEh=qr93;OHF=Fp|hBh02K12&10o{4oT{cC@IFDnzJ40 zI3i4qvF(Ls&toEkEXp$?U4kTK>Ygjl6NI$5dHryRt*$ylmThr0cBPA87}~QhwbfQ) zWS34;hyyBod{uCa3XJeuN19K-K9#SLYI!s|A&8s$gdi@%2|<)~4hC%)X`c|pO~}FE z0uLyK>-vG^8#+y{6}B%_mhndHQ86@11|H6j)1ZzyTkSkOB}y&{gK3S=Qa9b)*!XDe z$;ZdUHklTl-nN7=<3d+0Cmm~~k71Sz(v5B4Wrl2za3#S-$Qkj@kx6fjJZ2h71a($6zFM6o(=Gu&cgaXz-1C-wpvB(+aZ~0w}pFhG%_~KL8W! zpl%U6&saA>-98ybu)fg#PA^U91!eb=EsCsDuWZ-Uss_gMg|J&AS>i1OIR*b)^a zzx!mXxNhBEjZ&v(FAm*2&l&M8i?s$aUI~ry;N_0~_I<+3PK^ zDMR@6+8lP4NYz@<)dMhQd-A=(^s6nt<`!%yLr#b+J1n^tIC8jTH6;sr&&UmIUVp%; z^JOjs4ONv7!)1>pA{&i29g3BMeW?=d!=zvgVmI< zw=d`Ayxt^4uN(%?HOJy>{7fiU+k=FVvVAov74nORmjiAARS)gL9FIJlPMr=}Xg+kP z6T%t=Lf|c{&xO*&NK%c?!0;5tE2*Gep9m*PwEgSpEkoCdT*yFRq$U0GR+&ztT`HQT z(MuR~M1nz@d6n%(`pdMhM>q4TIS%eMx*#oXiW%YKMw|i!<>A$M6WVqv)hj$;_4w8fn7bA`!V~7owuYvziquREX zI$fTR+6tlLf-cNx>kyJlh6;&-<51%2z&M#qdWyE40FgYXDAQcRZJdy%R~6mtAg35838i=@%mzW> zDl2{qXEaDi?7v>SNmVFapFs&wZrk5d?P-wvX2HnEb3DNIGZ%ayh3H`50=l+Dfm#9U zyiW^T3wAn9YiE0MM#vzq-DSc;MnE3}5N>5hi5NU1pyeXZ#P#6TlB9zJn$kPwLfXzgN< z;v(o+@Xw^R&?JkE&@0$d#ps2qgN&g_{{%@a6g>JFyFT_+AO6B$|HB&;;U3J(^jM{p z69E}T8_TKt;q2Nf=b%ZmoEg%b{~dmMnlkpu07J!Ajydp87{x!9orT^2f`aN(Xks{R zTxHNRgE{3dVSjw+3#>0*Ih|A85%ov*Y+K6zhIh0GzSkO2rFQ=<3?)NHW`=?m)g$y%MH6n@5y(`&mD~s52H0ye)gU0lR0J~xbtpNg_uA@fvS8h(RjmoS_f%^1Vc4<8~ z{ZMx0tW+v`*)PswKaHl8ZN9PW(M&PO;{U7{PM!=lE67QNsjKe3AU{xn&K1?BN}vO3 z$UI?oo|NolV&ykwG9E#kGy}ZTXxab99bM6IKnt2N7u8@UtG@_lVgi#GCg}VK;1}Gr z_mf>DV4GL#z2c%`kK$J0uPUT5v~;bwt{v!$-|>Aoh$ApxdP@Y5y3D59U9}}fhG%-v z{u~0BHgbnidA7zDM^Bn)xy-_$htqN9roW~$N9!GD>=6JI*euhFW>4IVIg?){%$~e3 zW3#8J>q6{;1l!-Sk$26J1;Gf=VAf;y_`7!YFw-)7wmb>VSTMjwl9WU?;j;?_9;&}w zgp^VVShMJ6;TY+DC+Mu_NHc9(lU&%$^(*`Pm}`!ZjksS8f+yj?>??caH!+W`r4e%7 zp2&12MCtQhA}1&lbzqh>ElsS%OtqEV%WX*3Nnym9seKK1AcrCA+ocZg$p)#|jVZQ7 zvq^N-DSKkLHe8V}4Mx<}8{mGCGOW2st|2)qH>wdT6=*|- zz-)J8&8UiMbgD&trbRU`e-`IkRFZJO+4@uq!Xrs$qU@4r&_lu{IZ9*Lzmbs1>L{gw zds030-yG?-S*KcTb~HMtTA2D@({m{ixqxtgeVPW6P~;D|B&ZvTZ8C;82VA&r4z1*e%E=o8A5 zC(u|$5GZR6wlyt8sPjgFy*w=0M~YQ0AVj@)^G@j)cl;h}W_71^jOw~WS|38H>zc+ z4I1nT1i@H`Ko`}Lv~*8@<}&>sS_k>HkTM6LIW-8)wQ4War?Nz=hQnXtVs0L#H&%XIsYzNjAp7-uF60sC|9eiCZw&eR+yT2E%AZaA|Njn z8FsIg_XZPLyQne@@{))u@+-k~v^31@FEirmSPWjh4>1o?;_LZx=6l4>E<1oB8(;yv zD*GNs2vL1(r)k2Kmea1*lq~Bv$@omOY?RTWLse(jPm4=H zZa~lTZLW(8{FnTDPkMkve;kfr5iRUs;@=zqCcfvW#8o>Ya#2o0*hUu*daKl3P5|czYb4=_I3rzKq2b0s2 zc+?nXiC=HsvWmU8b&JLG-L2cV*VkIcw~7iZ$U$+(Sf1D9a3PhWQ_9K&DEU}9T$n$x zLQRpllLV$UIb0?xorScf99(Q&Q*_==`kPB>uigny=6~9;>SC_@n}O@fY_iqMYE?^> zN{k)+u@ft2=!`bQ>znsge_t+>hA{yr1ieSfHt>#)?ttAxqdP$N;OOpwc=>e-xbtl% z)RCvk!D(4z<<`|ZSC6c&65Xo+t`08!`)+4*ka@zy%BBXufbG{mm+VNA^9*6&_TJAW z4T#@eUw_>}PWT?2Yc0RpT;oqePbv`W91dht5gxA1CFz27Zk-mn^LyCPt4U&j&Zj1} zdk(fiK$u>>Kgg9!!&Cj1DwTV3XlO>$#McS5ua ztD8u>i#RCe!7sL^ixgEskz~+y9t!q~Q0d+QM}Ui$4i)&JYz-6T*6O2g)zU(~hR?Cw z^91rfpI2yVZjXg$=oT?%p>OkM&XneLRkZ3H>U=qkRFadBPQ588A`2VY*OfC$wj!dG zIHuN{Z@p>L_798HOH~)JEUhDxLc(GBW-BGtYWb!%atJ!WWT+ zGJ|JvwbfT=Xw5%`+}pQ*Ow5I@Qpq+}OQP)$tt1GAD>Jv!wshjwQ4c0x-N)?A{RUjFjq`@vW-Cgux zu_Io*#ToGPrnx5_hkK2B(ZdAl8d-H@RLbQTAkms2b8_{#*5Q+l3~#eZQ$ZqkNX+5P*L1mcb&JP%9B0|AdtgDZ1sHa7Qg&9r9&q^6CN7Ur!5h z|4E^(7c)ZJu@d0u)$z5+PQEUgv1Wv@+me?Hx{AZGeI*#*nvRU7L}DHyb5_ye?a8Js zrich*3j#tXYUJe-)^pXzCz3ucvQTJlKTR}K|QJYABocBg^% zmmd-Zk-Fq_0djs-`qkrqs8?n4$|O&kTNlBU3H|;4eJVnR<4AvueyREiorDby#*%=O zlK=5PaT^<{ZbH}>&J3P~K$TYi;eVupzvxg@2i=35I2xrNT?1&6!g3ZY4mL?@G;hUmR!es{4+1qxy5nXqn}5opxI{u7x7$F; zOcw}s{2PS2qPSGAi{df`26BZT?1u6T4TLFdMls`2@F0$YdyOJVz%fN$IOpcDoMG-6 z7tJ7N$Rsy)nZ#u+n}}^Yp@gj?USOb_LDh6@*H*wWU@xCj;FNYhg;Sgnii3BT->nK# zx=E(iZiW1+=~>1pG|a2Mgmn)`2Bl#xHk;5VjI-VPdU;=cRW?`Mcx8=H)kStS|X`jm%$(03jx(JSALf7&mHd2GL?kRnSOwo6;ny{m% zzV7U3CRhpsWvj>hk10nK4)+KYjpTw0xyj{1=H!JNGW>;hreohs;nkctfo)MD_i4W>Y0kr2Pr+{ve8`WG_)33z?*h8aS zZPh=^&IKeCdES;`R=iw^Uj2^Eu;3ud!m^&opd|AEk^{#o>zwL&s*{*fygEcg_rs51 zT|8eQ1337EmwRSkAv?l1YNCiy!v?6U87XMcIi6k;UC^a9ZZ-3k!AEjx~m-MvyKvw79`s1YfGg8OXta7YBnqxG&`%h&wdNfzGSpP*5{T1n8 zHc3Rim0Jx3+jVMP9J2`aZjDiW+ceDQCXkkcV2H^zYHM_$PP-r5OGrj4RHQ>|mk$ zyRAJB9bQ#8ngao>#U;Zhk&FhfD3WH}@GYM8&rME3glxuO&}p*AsuD0aSd|14b8yfH zui{6uaAcH{)&U3Hx;(+)AqKyxQoY89;sx}8M?&HfLkRtaP_c$>q5MEzaAz6Ac81?o zHDS#PRuLrkU@MDHC_p6n-AED|g$4Uo+Or;Y#e%{RrN;^ePaqH5+B18VjDeFn4P8D% z2ghG~j(ppxE!m*-qT~K;69rj;;n7A(So6j@*RG&@)8K`d4u_!d19vGnv6A& ziQv7pzS=8oHh_G`ri0?sDPiH5dBDchG%@TFx~^F$xd1~X{vcd(%n4y-NKlMJM!t-E z=RlMg29`Te7H6EZa#r$D_2kp~vulR)?w3~BMtGve9W49t*9Yqkp*xLLo zY*~ch#P90;cJkWl2@zBzct0!qRL7O1?bQA_aARtJ=tKD!dEn17eTHH1EMQK|Qr7-R zp0!&8oUc*?{*Z@!$mnf6i(ySM8wDs5*d<89g>>r`;33LMxUy`cE5x2G@i=LI?G7;q z{xC#2ubnmnKuNt7PRN)@TXdLnW*pIlog*xk#R5Jxi zky%1=nKO*d)Yr&p^WnN`dS5lYuiSek+QAyNKOOi$?i%O+Pu{!7*>zoYp6792bstqn zQYn^Ha&+#sg5_AU<(KTpZd<2f$!}v4I|(#QL(f0?R3%_JqCf7>*j5>v#FM1^V`dC=lff0pL5TxDwV5Z<XO5b z>_Gxb^zn|FBG`n!3wm1GAPL4Ts7z~-Kb=iR{xq*8{!U9%B)KWPH5vJ{=LC58tBU^B zrb&kDvPzO-9Q{MMf(g&V(~zm<)+H}Z5SJyK&r~NW1Q<@JP#%uJ;nPi=0^@gqL|mmG z4|a_+r7a-zhzH(+4qi8`z-{3=rw3dy^K@) z(f13cB0_5aR0`HC5)7-^HKfTRY|8A&qSiF=V-@)1d01+{QopeMRijVshSYxiWN-Hj zrS^A~+RvXdwZDXn(2YoUpn6t+Ls|VmjNif*IW*>^<&@yhRps>$zEj#0#EG9Fg&2r) z3+u+o)>b2@wLoN2ku9bPku?D_b+S#2Y&kb+^30fQpE0tvPfAmRDYo?HL#)wR)VFN1 z;53DW;-CU*%46QP+6{Ch60r`Cl}<4AtNNFAf5`Lz^1mcBRHHNsqUt*}pW-UPNeo7= zmb)>-cKq80{}?);*wVc!z{`T1+Xip$|KnBOxoz+rJVprVP2qW-?!U>Tx%d#4@I~r! z21-}JKRKZSh}Pul>JfZpF8F_l51`Mqo4N@%!1SBkEYX zRKA8PRPRz@fo!iA6N*sbWj2;fR#&c;&81XxDZ0rD61B=c7=NzY@gVC}cO0Q*ISXlJ zOZqZuu2*nU9S2^lmu{*mMU{OjYdCa}{-V|?^{Es3q`H4X=af~7BJ+ThEJ4I5Wm%t; zmzMXxeZamecEA5-qYcaaJ}*6$YNh|16+M4Gy>0MD-SrxhZ-Ah})i;Qqn#IThpw?@P z;XhAuzLzn2J~fKd-bYsM*3-&)8!gfY_owWBWG&l;>-%?{u6%E5)^pvIgEXy_kTbnX zClrkymZMXM=s`q*p|&U4uf=;%ywQfqKPZU>&Yr=HTn#lm`8p>+27+@1n>d_Zv)JmV zaVgJnvfk}rT;MKhRYygza9LnBEIG*->i-B~frxb|bH--0k(fK>kKQ45$n>_%Up@FN zGm%<#q0nzsJoI}JVI%y_c~?g$1I#~MAqc|MFYWb_VT^;L4%<~up-ee!6zzqgLsF}> z0Xl)#iqEnULidDg);9wWivDDO*Kr44b{;;a;ntI|0+VBJne!Y@RnfOoJRAx>v#H-z zeA>)a>j6uhG~vP}-c$W+J9?{9f9z=I0ZmEh?wwNWp;6pf^L>(nx0wLVyHX@7Q(-05 z6@ca))+CGErOi2GwWtbf+gE1~085Qgnj>b+mQ!siG#Cln7K>1X*v)q-RZF`OHDNeX z*IiKSD;J8UKNAo6gvK7^JnsVm7oo($lU(1&4W zu_u)YXZ(82-T-_G_wH0m6~E*F=%8S0hOWH!9btYo&VDID6DEi1|3Fe#9kt|X(XuAE zm9ECSIA`Vpw2FsX3)!#8P&cy;GxuXn2;E#1nf^4wq+7)FA1*m3uoI`F9n{>UwN3dB zig?i))JpVTT7wt~x1~_EHk5HN5r7e%l~X7Vw1vcrL?vvO z_n)VHx&O!b5(1Qtd9MX(8rK7AH~irI*oTU%{VRz?ls=_#@GJ(D`-~}lhF-Fgn5rpFh)X0|w6v7d7O;}dZDlPLRPlhqDAyh-;2-FeF zc4(wXR^A)6{*EyaOja$}+c_b@QHXNcZ{(NQ*JhYk9lVh#9%D4IOP$pe5jOHL%^@I@ z7NU8h*g?fX0A}pKV%rU9)`_L2AGK9anBMg zAUU*xhm3zo#ts5Rc-K>`tTEshCNn+dYDZwTQlry=SlYPQ(x=TXf{GIu69!*O0|Uitw6< zX1p~hS)PVTjBkMm%-}1R-&r-82M@~j3zVYDTUJznqLXO3bz$YEKT{FaNz}h z=buwnr*FOde7Js!Unx$D%fU%c>fAKif#kU+ykq_|PIr;A?47txA$~i_9sMis((B#X zmtx(b2YMxBh3dxlj!YFk*(8BjI+4D`GzA5!z!{vsFG5jpEmUAYnMky^ia&dn_CBMI z5-8*e8q>5st1hFQx2u`()ze(z`t@YPX1^*84(L8(JM_-Th{r9bTK4iv`zJm3_zixO_cVw89)gl5Q z_e7VD=uDXw(XfO9E`)>v&PgZ$L6mR-gCeshwfBwi&#xinzp*WJt2jvv=Ku7vL5`w5 z(V>?{koxYe{4%p~5iP*Y<}2ms)Lh|)`&g`-i)Nl`Vvq?Ns6h-ex$+Du&OsNnR61Pv z&xSVPPpva#rZ${Zja+Goz_TpNceNJyyM*2OK^8(ychbcErwq+b@$PMwJL9tuSUScb z50_(p;s-S5hs!Y+jACE(u9n=ZBkJo?Yt)^yu|1Iz-<7%3QkKmL8X&xsd{{t)8jMt| z!W+lS-zwXQf1qD^=|~5%%ZaHLLNv4Rl3S+jcYiNQ;7XNX(u!dS(Xu{mYGJ8_=ez!% z4i!rVPb>@jn(yRJ#x=$d&93@EOJ|4CPV+&9(@V;-555o_nBotYL=i8r)v##TU;)t5 z1vcR37xlqy(Xe-AniiN$4iz8zq69=PL!x*j9Ak156QKuglGPd9~7M*VbCj;x$?7)Om_r*=!^@gK zgVEOpRDcVl;nW}?y@2t+tdI$*FPM-j0R+9=;QPb#*mKREqKK;5n_>cbti+rd@6&e2W-S zMxtAnln-4nYZA5iN3qiEZlwv;9wDu;W(&3JbN5Z>?kY| zoAym5hZ3F1CZUTe^|8KHy)5dH`_>sR>eb+FSDKigjKw}3TjMLQPwHzl4Y~0d6312J zlXpoc!ZJV(ro$vXWV)C+%4&_TWpp->mYO|-{Ksp2XUaaFW{oe&b+Uux2Rg=OAezmJ z`J=4~lj4enCVjE^4`!n|(z)4B+{;;l2v~Duq-H6**%tm1pJg$-lDYf0N?xx(4%4Zk3t>70+|TbGb+s$fSf9|z#b@p%mYu!RvwE) z;(X<*Owwv<8rSvvN{yS=QVJ&N^_ErXm5Giqy^aaU0%&4bsGVrJavuphiVxzd07JkDeJ%pk&QR4J8y_FZKczt6J4X+7Un2ZN zx~aKSGU49$NtEq#Eaxab_uphWp2Cp(>DZ*FGA=br%gp?!tUNtR^ZI>Oihk`Zocz>{e`T^3ZST-z=&k6Z5;#LI?TF6I^hjEC3RKb5gKJ7I{Pg z=Notr7`z7DZDdZ{u>nSz_0A4Dm7^=g3mw=RqU<+}Ij-y9I9BU;tKtQMkosfZ6Ldg-6yc_$^vEiUGFT$U zs1MUAxk^+>dyogIsYIL!c-7Yr18T(tv@BIg^*n%UVri0zP~i?**_1S{a+MW~l_*Y> zY)AvvuIva577Qf2;_Z|7sMZ}|*^{JX>JtK-DD=K+Yst_4@&0H%3L6aq-wLwgP z^pu-Mup`C+rV!xv5g7bkQfLWn;K`@NiCpC>DxJUPjeOrT^6?06v-Ne{K?>fZ4s z_?P%%aq=X-^d>k17Gs=E1)PyeEQEwUpAKz=Gb*%Mm4cOMvyZT%-gxRskvQ14@q~CP<@cXoU@1R@x)8 zs`v45O!6Q!dw?T)OSna4t+=ryV_f@RN|iLS8$^pL8bC0DV1RG2SG9||657RDnH4Oo zU7ode$>LJGHd!&zZtCq?h=RFJNfk*NphG()tnIQgTt}M!v|&`Rru`bMMOu6%T>)#x z;;<%mjPqg8kFp;-gV4!6xv&9XoR-wj(+x;D98zwzApvnquIBerK^%>sp&^e%Mo1V9 zjf>-<^_+~#p(%lo$4Zp5Rgj~+SD}Wcaf1vsnx}*?K{=CYHk&ACV*)ijP?L)|NV?~s zNEflOYVo8I^vg;K7m->a#kxw-|4RpnpwTiGHMj!B$MN;j z1SE<`fQ(m*L2o;C*J=T9VynfH>?V2aM8c3f%5bw~WAt!*&gwC)`s%SHyLsaAB)diD zu{{oKd2n@}LO%rBhgF&9Gyv0ap$q`?37bAt|0Vz&3&33|vIu!?c{|eXeA85*U=CDY zlIIUZmonAdIkBu6lC+MvdQ4o(2LaD)C61?v(`R8VbC~IUx^9v~^u~HohQbr(Bc?ce zE1riv_v(3@+}u0yJkIOF@aFyzX(5e@-Zj)abbl}-uZ&M>a)NDb7~^?2AOwHCxuVL5 z8J*)9rE;bP@6M8-=^z$__K%3e?h%R2Inb`ziXW3UI`J&F;?Grj>4{0b^n~=1_ln0} zFyr(}s*3Rmk8hftdWDjwsHvQH)EC#^)b@Jh6$oS(5z+hWg}CJvU!*8@(;Nuzv9$BW>D0|dL( zeRlOo%UwN~bYuF5tw73W!IqM7euSC-Io@q{%yMBMinB6$(XXIje?$b%AVp#ls$Fo z8~3#A<;2b-N|odbT4RK!Tr4{3WTSZE%a#L&g^@4;q|T2l``;*+LBxwBH9N^>??btr zmy(L4B`7aRwoa(;CF?$}2(Pb+ITJdXDx|R*zc#`2iJdCN9IUAGASG$G2w8Xn%%G)<(Z_`uh)lJ@s6c!E?BUN!bh>PYmrHMLl0)P+0!2O~E6H;l5BBBxX05|Egv34I(8ifNV&S73=2#mcFSP}(T&*g z=o)22`vy#@I?E}X#}YKvKjX-z{uHK76I=wAPk<=>F@j0=&p$_<{FT_o?f>fl@C7Dk)ag=?9>{}y@-GVMx)DxK=n5r_$ z(|#o^$*zDE0P-p_FD!_%O&=qRqIf-a2xLNjq$WRJZ$eF~x8=gdHkk8JBp2*Eqm;E3 zm!}pXg`Dw+5T73KyfPLTAp#c(jQicTEv<6%bbY6$)U)5hk7U#gNHsg=P2OFzQr;=x zN&pxB)}PD@C<~a&2WiiZ(D_$Dxn_&fA38Q0@SgYSA!KCJiS*)k~415Zr`=JS4nLGoGd1=Jf6oi$t$d2_DUf2 zUst}ZUqV2D1x<7Xnd~{a=1)kfQd=EEF6>^I3J8iX`Zh>>f*S~ z%hjhiKc7e@e|9fqPeT%tt>+^*!PZsWRtRi=dI;5_31=F+GT$$upcf6xWZ0aa@5gUP z3na8Oyqf38vm`_QFoQzi?4lJxztuq^BGEnM+R-)dd4edt}LqASYJ`ie!C{G3YHSqL^zfYw*^ z<}>9G>c+!uD1=NJDOT0&2=MIXSHp63)9OD+1ejUHhhRvfgw5IS=<@mbX07u`k#Yy6 z@DuRR>;EGIY|++Azn1J-(68`yZn)-qs@hx8gN*-$;WaR{s{0&)ERdl^eAC=;lwYKM zJZAZc7l*eLm_sPB#i8~KoZ-LMLnB6B549kttC790$IW2nA^%-JR}DhW%YT4WA+Qyh}hhvGVO?S+17P?s>4OEjpQgSE2Q^(E)bx4= zMSE)uYUAyNeriycGL}mB1KP}4T3v(_Bcd3EwT zZ$0Ekdut48Lha+*;ShBRsItW)9Sv$+vlbw^bwDhFeu$ zD@VAE?85R|IYLUChHKk3!tEy7mW^<@(XI_^T^o<^vW+%#S*@9TtM`0sHNvgc2)9-^ z+**xrYlXwD)d*j$5x&|q(y|fm*=X1H)Vekv;iVgG=F(a-`4%7HmTH7ssu6CfM!2OK z;g)KITdEN%!5uS5hQzWF<{Rx=UhCR;gqLiznM-QTbH=A+QsS^#V7{&~*g;N*0BlxUVvM|qKYQaq~! zMc&8#^ilzM*DUqUvE6dsQe!d!X7c#$MfQDW-*ja;_`>aq7AB()Wt6m79(`ELZA{h~ zd0?66I8s^@A&abGPk5#b+j*Y`#axC2<~-E#&;5HJ{~C$wP^=Kir}f-Q`_)XxfjdnV`=m&O`XU z;;3n7B|?tIN?;_g5(vn!`qW{gYB2|a`Ey*Z(0u)WYv@$zXs>zF~AXI+L1)^*v1YW))*Ejxgf%p%(|Xnl7s#uw!Ufo8YYb|qWO9(p z`Oee$)f1C0w715fHr`$>T!5=?uJvdq2Rm!huM8J(&B6uegmA%Y>*0de)@-uZ)ra-E z(+umiHJdCyCxi>mWRr|wM0@#bmxl{pW>-;D7;5JzTyRc#Y|729nt^CXrrhkPv~AC+ zY}?6jfq=ct#NAl~=eoiLJ8R&qERl)G$hw-D2;%JW;q9u7_+6C|zpFChcU4CGuF8nt zRSh(R3lx1?Ho{j#KxEEGI9H8ut{UN7HNv@Sgmcvh=c*BgaDjq`%SQN$2#B14kWUB~ zpn;Z;@D&jdIRhb|5H3)Nei;s55do1i5b_D(f|m%0tSemb(gBfmH8T+qIRhad&4IE- zfXwz~IIMY$Ob*vH?t0c9DqO&Ho@RTeP$VlR-Q*hBq+974;6R_znMB$7z0l9~xdu~VCh?W- z?}UD?&o!6|Gl{Qse<$>FeXhY&m`PmQ-`Th+zqY@#@%BPLHK^0N2E=zQjQ9`FHOPJ@ z$t&|+rhH}iol_Zp=TwH@IhElzw&BCu!IURjOBRXwP0Q5JE5ejN1BUJ^+>}29hVCoe zls^N8?kn7sKLdvDE8LVn1BUJ^+?4OSORbrc@~DiCbSufK`ab2|GCHCq@_sFt^549< z&06Z=`aFWH7F`KhpZV+238U9*|DO&k`?Z2YmCq7p3Y2l&8*WxgG>NOMR@gJ1N{I0n zI3FkJb=Hg!Zrl{6y)`0)8*i^>T8Avk#%ROdv{so^D#>DySTGTzHhBii985GV|H7G^hIUh&e*^PG% zOl_-^-?sITAMLGysg1W+i@Jx@(8h=@U2>eaYEWg=oog0#KPyDtNxK}!ck2PTbL+!8 z_cX(*XC&okg{b?PY?2X_nW2+OdM~r9t{KQ&TO3uEUa42so4Ym{br-Ognd;j%8g<`R z(+gv)ysV&MKI=oBtrX~N<(kY^3UszoptF^0GFvIoV5*BpmW^=hMn|}H)e*j|EUGh+ z{uE4giMC}U+_KRTZdrAN7j3kei)zi}VJo?r3WsbmwNM&2{NWnzS`Bb(vVd_O~-XG)n)%J8)2_D!ga-@d$kd=@{IL9`>nbUl~^_( z9$clZwJX&TqYpVB+n97<4Sm?DD~`@-6vssPmiE@rhZ}FNW@835*ci>C57E2Tpk!lm z-Y3Z7Hs;!f^TyLl);63s-d-(ydlq9MhPl#kmW>$i=!$MRf_!e z=GITzn6Fg(CQ_J7WyUT1$*?&I5h>&KPiq4kr<5kD&;>FG5QQD#ci)bD+doTMT>iSG?ihLW9 z>Tk@7Yre@o)t^=+1yaLFr0!|`yozktGI~za!NL4sURHL<M3pd2}|m-)Tj`4i9)QR3gZJSH%VrhY&vpBhIvZUqwn)DkB|SL0^4a zD)sy_)f>31f6;0cNW2wX4ZRo(4s0oDAf$3hb}oJ44xrIy9%M(OH;I=2E3#lgv7VCCyc;7MShN|3u<8zt6Bs&RS61PsAwjSeGGFjsq-)2SoJQ-I$l8Rf&;m?`15sVOzY8 zHpDG2S33Y_?3Ab4f~*bcQ>9YUh9X5a@Nz(9Av)uS)meptYw#VQVBclqX^Liugf!@! z&Dup_d7AxRqAHR(Yo$U*FEe_g2Z5Yb?T1%Z0aj1IvKgN-uvBEJ2ZoGXRjj0u{a@lX zK%v4R0LmCJMlu;^y1^rkl==`WN^ZS#76rN!+Wq zs=mfK>+t;C&a^M&eI?Pc8m~DY^;EP?(gkAEk0dt&G?aH5P47u=2Vz|t8f?(5Dx1C- ziDy9^Lbvcbb&pdm4Xsk$DJVvHFp7C-)1yV3t;piL^srU3dV?Lj9HpUzg;%5KCz))LXK(k z-p#e5;a^e3qmMofKm3i3tp4H)@kAm27h)A>MK{seVRoOrsvS>RTa) zX?oB0rm!w`=yJgj7xFDayRgLzveVe1*Fa5?oiv{rX+59z*~~_>kB?ZZ_&6K0s{-<+ zFf;qjJ%0Z^lvf$F;jt+b@m_VZS)e*)L8zEK`77wXbLAhTCaSR>cfO=Y})MA+a$f$23wA z8- zY88vwWNo!--Bz)<1Y?U8soDokTMQ;Sfd((v4Nf8F29>((gI=y02@VJlSyUoj`fB?q zq_pkWUHmOUz`21Spi4NQ;{qZ3+E5r8Xh^uZF{2$JZ1c43k_OhFCH6N0L$)y;e<^0f zy2>c~5R#qVZ1*BYQpaTnSSCmZxDar_IUP6ms|ZqIRoGPIRF!-G zwQ&~rV`#K2wrwKB>Z`-%vm|E=Fux0WHCzR@j_Z;5bh0Cu>Q zY?|nnBfKOW9(Te~`hjVx^);m8dtQ|JA=zh7iSHlOk@5Y~WZl&zs~vi=>~SkO4|yLR z?4y2HDiu^O;)h6;E~0E-sjMscn?NtqiRw#_l?{5`B|aG4;U%$ERJ2q$w#R5Dc5#Je zW#!=7RqG5IhS7bOr+d6lUPq8PD{DSasdylV{R7Dt8g#@8)IuWE3`9K>G?%cPtaTa+ z5lT)W1xlS@n;*V_&55euqUyM&R(~*59AuQX^^BYP>EJ>{gl&9+>N=~~?1k|fN9Ukl zumz`_Ct#u4UWid;uJ|e4T`{y&`ZKB;_!>POELk@<>*i}Gn6H|VIE@9XeFmD++LD9b zd&C3|3J%tVe85Bl_gZZ0$R}mW=`pY8O$}R=x=;)2dIe=wQGPM{HnpY-sx*ym^S#`7 zBF6f7#>(ykSg=Ppl_v)XL41JE#G%kRb@I^AR?}P%#aNT9L{-V&k)3W^9@9BC-(?T< zVzyDKyRa{c`0eW=N_`*7KSe>x zweSkT2!g5NbO9H{hY`4)@-dB!R7u8<^`RJ($gtc_~p%xfM1zyTYE%RY?c^@M*v0mg<) z2@?cm%71b3pQ9TPSco?>S|yOMujry23hlW9OxW~zjt*lnHk^q0k-theGyqkLKVLmv zL5a&MD1XGwn>8pAhmBf^;K=EOvUg(JsQ+3gm7y6^US=LLFsDs>H19rYss)g6HD931 zRuWl@^w3p0-=-4DexB((8=q530eH}<@B~HR?Ff2~i{FT{k786n2yDrC7@y8Y?B0xZ zfJd`sW$+vK5l|!nk$w;5Fq=(1=d}3XQA~ z&~ka`Nv06WjdX`ia=r4t6eYV(Q4q1LV{LRPAqt3~h{QKXr!cko1aNXx+Su|F`zj-C zdk@Q^@qK$laWGn(-96Y-KFhZuJ)V|il+C4vsQz|^MZUI!L#KB`F`(kBmJd>qwN_u zcHZ<|g^mt09+iC!E}S+)v4`O~7>o`nI#Aa6Hd`5|=D$HM^v7#hgX_aCjEkLusnh3`am&@*Yy5}H%SrL@VAwy$ zo@OJ&6?e50J0_V(6p>DI;aRKkc;0H>J=#=gbhA33?;^ArA@4{>Z z-^+qp!~URei~%jR5jScF_OXpG;1$JS~z`yE7ZTpLKGRlNO3S>i+DJ9?xwUPzcEu&1UZGVx9 z+xVE&jctE%uJC?pt?e(&_AmaZA&rV?mRZ3o&zrRyTADKq!>#Og0jdrUcEN8H=YZ*M z9-LEx44>d(bNM3~?SCF!Ct(#2+x@dk1dhFU$tIB?KS)v$o(lIOf>62*dJvQbNjO*# zlJ-)9l1|g${eq)~1t(=`&_k>rNf`9dzNnjhI99hz?wzk~5-zZcz;suXd%?9)_}}+{ z?)&l!J`gUPdj0>*S1))1IXJI<4H=-EhVzB&G;P~PiE9~3mH(7-ws4=i7ImQ-PwZyrR`F=NHn%Gpt^iD zpXTd)tLv&-Ul0rsuSe0T=xD;F=uo^`w?9?i*6h#ot&VT;gw=uSXOCzP!jqf;40Z3v zr8Tr$i1hLk@n{otVv3xy^ISO@k1mGX{mQM`hfp>_IIw>MKCATjrhG?!aeiy|L2h23 zCwRLULL$%58Q0tDkm+rVTy1e7Pf~i-NA^pIV1Y<~zR zLzfh2P7N1oOvNhLTY=GdPv5f*Aof^KdLC4hHqzF>e-e1fiv40X6x&s5I`QiH$v}q7 zj_Xv8N9|W!q)J69%iZYjG2LvM7fUea@w04iC+kjJT#Sm9h06^^|Ncr_B*b8kvj_q} z${ta9A&!XlgqfC@&&P{b#z%y(IQs*f2bGy}w%wzPYMchp3<5h6;h|Pf6yAmcXE8k5 zjI`Guy6oQ>%6`99a4kK>?5E607+(|1NBv!TR*&gVzeuxRNVI)l&aiw!L_c=31EIvl z$G(V53)RVb+1Y>fDzXGeLT0E~Q|?NZ_ir0)m(&@52maT00K=<6n~*O}xW~GHXrVeZ zx(LmJ?D!D$8b6+0I6@9-j6B~!s>T>FdPhCcWD&NI%)W1deHaUdg@rTsAQ)#CtQ^0Y zj6X~q4P5j0%J^RbJsabd{49Mvy)t?oH&71}gSLSkN)oUGB}f7UnIcm7oG)s>GWz&% zT=Z`moGny-2&YSAB&V};-2lLF@%=(N)Tc*^R9j^L1}KewTL2&63+mY2##+_Bh{b3A zm`|u~HIMe8H~kxHY>3{YufEYDA88^JASoInGI&9JDXS_3Z-XuJHz0MFx~_*6FSR|4 zAt*r`CTFl#UA}o&@#CHBIWz|}Aj=RgjItvTqyf%w1qJM(KaLTEhlnLrUsA+v z+3)RR?HH`Kx%UX<%1?)_HjU7oq>WSNDsqHgj3>$n_b35=70B=;N|22}pkU=}A@$Y} zXILNhhmAB$cJ0wMfw^%M7XDw3-sNusGqz*n9#Yl@K-7mbP<4%f)Sz?>E#-r*dM`F)L;+^PX>@6kW)kxkY-^s{I!aD%ym+5aT#4_7o;kIIn>c z6iLALqN^bY3g-L^7!!O6n!}rytqu+Ei*Cks!2bJStVlH+dXPg=y9I;F{U^%sgSZDP zbb07OZHms8Y0sq6o*sQ_jKdER-0I;6`8XOyE&PDmcOMufnoNWr9wm;*cpw@@TlLT5 zXJ3vNr`y=x{4eHhBX@OmXx_I@hg=SlEO9ac2|H-s=z_4eW+p89xxYkh!_du^G78=s zhQtR%yCg{V@MEF7FUMH@P`ogxD`+-UM@kP7|Az->Y897y2|eA5YhE=*C=XeNJhpQN{P1fPkS`LWIN4CHwuF4!w!RV=B>6#MRt?e zR(oP{Y450~opmJj^w)P4jI*1io8s&iChP1;(@-<;Yd*bz_!QxnLFv^e1_%OcxJZWv zb`rY+gUuYa(>BNYXT3&KPA8~T+b)=H`ZnxUZ?2FFlV=+QZ&=p(RO$J9XilD7`YDdZ0(G&#Q#71KScFwm|=WM{P3!RaI4o#Wl z*?$xP3J>8D@9@Q@+M`#s?b$UL+oB}azTv2$a*Gl>EVn3uTIySr#5a}CmRpqYz*8dB zasCQ52g{;{1Qu$`#!i=~JW+)|k^b39mlJo={znHzE^2RB@lfn?QA(Py{$))^(+i=71 zH_W9w89i{D!lq)F!26|&ss``&mVAEs*GB|jIGBmwqIqP1rsj27o%f77xZ!c zvd#D%;!ocMi;Iy9+nM?B+5=C$ifH) zarqk?z-2O8dq6-`!k@Piv5;&NcS@ooaatx<0Ni(KnuL#>m!3*5PjB2Slf_Eb$UW~kH zHnpX5GV^UKG2Iu8u+E`2=t>^&tynKt#@>k?#2ub6FacB-cFYhe zJP{Rrh2gDL;3?oV_C>rQwcp6TOE+ef{zg1gF?H!}z)s#6d?p}`xg#)7u}RQ#1~C9b zZQw?V6>81TUMyzcj=c>f8TM&YY>Bxm8qhAjP1wd}lQ4#|w-@qj6UaFT>65@hSte2O zLpkdHy>ZcWUIf1&_Pq3Y=t79QXWmFE@?FPy{(o;-ABx}pTI4Ur_{`|<1PkE~T8Z;0 z`+i83E<^=>#~zRa`LMD59g{tW@tfKI0UU5ZMOJ&}Xo%rN#jk%ZDn9TzMmtx$@H-IU zoP9`a&KNV4s10@6h^5$JzNdj}$r3m5kN9Ns&42?4s;h_KMdR^)0%iBg>lih^& z4>iAwg3&h;gvVLw8L+p#bOJ3h~tb8}~!n$MF{l_u*`~>Z+zd6-lIu~t&8(7X@m)|Mq=4ZIpY_i&R)BhocsN6vjrt1l#Rw1j2C)Jf z(W{7k!m2Yt!X>tz`)1m8>&i=>uWK%rSdW}ONT{+zsMX(Vj*fH7emaZIox^g;^t_+V!B;?FTLoYIUPM@+Id&)9X z$>mIa*aJ;u>Q=^(Wf4rGL`6<5?A;Myf(|Uxy6_$0jo8Uf9Zrcf_9TyBr0}{5WAiYn z5(p*rR|4rm(yN&sB}&L!#LFLNB07EG9*-l_VaCG=?J&Y?@kw}R#sb>-SU)5XQed6& zT^V1Tqc=dtsCzKFmSdiei@&wNqutqdtl0MbMSKi}TYM_AiHi=wMmhNR za{z;mS}@{@1sSOk875=+5G@D!>?o(Xt;hx*FRTJCi6Ph(xCDr3lsqpuAHh{86{NJ4 zS-VPN6&FHc73U;YnU4!=OW3^peNAR30*^?Y)BL@F`h5%hDisev0nr2Pk0Y6mEVB5TP8?MhiUc@{V_vM9*D;=`lHR9fNYCC zu|1%SACJZYCQU_{5+S1Kv`$h2&@>Q!(jr+F|D3YsCNl(J zQb~nqmi2-c`~Ba&WL(EGH<7dX>2-H?E3zqi_yGO_+)bg z*+MfO2lEU06q89zy<9wh&AWb3`>HE#l@4D#AHNBiH(NAr;Ae_$)}e9*;Q=*M{%Ua( z5%=LH&2}l7C{||cRG~mUcaqwj7gN6lY3o*6zx86<@4;)j*O<8X;)}cdE+&QUw!+;_ z^Bs;Dhoy^673`+DlP+HTai-I3+ zKD-#-@|~?akDC-1@h}|AIertiYS`J@-TqDa#R4Ev1VN58D=0&7+M@(l;)aC6ly>}e zCcc#{9WP+;4QY{fx}+`3kLmhnfPx&S@R_vyOlkzn)5_@eezCi%w990_;69CvP=-~iusmhh;wb6cy3(H3w$uJIWNbHMay#AizmKpE(U5LUW6VSHhWAD zI)r>((Ra+rkP)_s0OJfqL3Rt4ybg*w+7w+)f@%<0?oN{y=?z%M(@H8%?Uj^Q9v!`; zI9K{@e?IqCNp%oaid|fX_SrcHd9E0MOcz}h+NO1h)M$Bn5{9Dve1zQJLpD6K0KGn} z5ET#qY2@zaW>}D|Lu?w?L^+*zSuHu;u>LmIkkOLRM1O1|-6j$`!jGh7nFWyF6Vd@r zMz_;XMEI~<B89|bd7DlrsfxeVc5^-5ku?3PGx@By|*p#h-p@oa0$ognt zARh0@7c%2$Ln03HZ4_+`4^}AT-Mes<64x9uG)SMWo|!(DZ@;T}(Vr{d(DMMo!QgpQ zKN7Pr1N};#{3Zig_8myXO_~;AEr4~|WCgaB7-E18;$5YSqKo4M7iJ3<=S2XdEBV0v z{vx8f_c+=I838X!Eou87DxqqbfMR4wfGz}0U`He+o0!9IN>1*Yq%93V<0vcXonphF13s9_|i=YW5$H$7FfI|^Ie69us>!qm; zO*ApslV;=D>MITLCV?;!W18p`6EWy8rXeGeeO&4R(nxy63!meYV~_xFz@|(`0dxWS z2PQpFBkPt!&;a}$C=pMKyv;vNmA7e7ZG&^rW5<>qcwzDDe-=yhA;wJi!ObSi%qKFU zhM#RODkzcMiHcW(kx9!QMy=hl*v%t~mljjz=wjuQ{@3nDJxjqR*7atnoS(PoM}ew0 z%Qb#7uq0QAngNeyaUucuLaPNB9z(HVWIbjPqa{mAp?Ae|!uZu{VJVTJiHMH;BEeZz zo99mq!G!PPpcn7{b+hvWqwj&cKmJAde0Ry_d4T{6zGMrpCDVkXB4iJu2l?c?w;dTo zLbf5CE<|ApviOU?j0~B@SM2~a{^$o}w8n(Lc>qC%Nyy#_rn5j9u~I(u2q_nY6SG zRUa!(-Jc4-LtxNSUQNb;KK&aKZFqw3g}vwl@nO0Yy239B5k*%Mqy{RcEMYNQP?HoO zpA~$~h`3(wK*Br}19@7VBHXDV$(y$CSmsq3A=fxRd3oN-HY+Zz$Sn|&U8!#p0(E%W z&s%i%vhXPBvI39NPay3M9~28COflsTUQSYM5ksdpn?5Zg^JG-RV9a1(?8qvI;ZHL= z(Fn5>lTXy9CX`1FW|*4bI|*7GP83EIs|j-xX*oB6sKNxj-T+g@9|11(NW`5nSYJhx zAH!LU1o9}q_E88~2z|IEmpJbImo$x!>mRYC7oswlWau$x8u07I(XzSXG<%gKN3(b~ zF^Q0Bx|on#@fkaph|$?Ih)ViH+(h)D0EWNy+3=Poj`iGAE1!dctKtXsjUQ|~JWU{L zI8Ah3RQ&Mg8~Tq67@%BG@cid|wpn5V?1XtRq5%lIC4|gQe(9A0AfMt_!i(N1GlB@m z-3Jm(4{qh=S}89aL?qd3EknVqPm7g<9F#y1(;Uufs;03oIvdkaN4%F^CSuYnWTOL1 z?(Xz_0x&9R#E+y=>Qv0fOKHRvmqzJW8X+%9a!5*P#K{V2WYn&wUymR5AOu(xz?G6kNSBfGckfr8E|~b~FGs_+$(*S8vq*ETqfYTfgiklN6czrk zf&vxzOH5|){CmH~^9cPMv6vNGi(mUB8q&i_fP*k2_sV!0lImZf9MK-d(x0mr#a2wB ztrkz~5r2w<2%P1UHUoyUaulZnvdo5BJ+1h6J}^J&o1cr}CyWlb6sEZ?zKaQH>jkViBMBG@UX&5vL~i|BJZigd zLO&v*S(tAZo7B&CaesrPPCB|>tV{2up)h3cZ}8g)W7S+G<0Hqz1ww@P&>yzdo-}RS zWJ14^34LUO9#>8<1J^hdID+lF7D`5#Ffzu%9A#S?w5=f3icZVXE}~J}I!&-#lQVfc zdqy79Oz?>e5V-UAe#T_{#a=i__l zzy7rsUu?f=P}}*tQJk#OL&P~JjGbA&tRr&+fK2hs=jEY}(s{9tWB|_22)U9+Cr0VL z-_Fz8a}>UbiqHC^t=mu$tvtOqZ{qzEo2~6i8rAmMj7W1;gN(DvQwc%_15ypLx27b{ zMs_7-&rUk8w}X{c4zV}ldjLZyum#14(xmsr)+Br02YVg@j*`;`c^E@;JG={Z$cFyJ zyRf0}e=w2yh0rkF%)EdUFhsKKtAtLBU@GYy4dHPuPG+1+%g1C8dpT!o`XE`gEDTR; zDnayT+(XE+16(6Tlv@)K<<-OEEH|yf<4_+a!WGhyB&*4mU?@l6ZN-$4hWKBImvKxP z4L?SIp)Q3rolKt^sUTYn`bc`csobn@Rv;gV!Ga%ROp;Ai2QGa zn(QKGzR@94X>?L3)C`~qcK?E}7F5ikJYpi+YBuP8SzWTBo0+vRN>p?J*-LAqi1+j> z9ck!D$~7hqeC`!j>4`jD1m+r?s*FTo{YM)jZ(r|KMl@RKw}H^J*q3cUVS z>Ge0u=k>I$YCxqe(61{NGQ9q#qD@zfrXD4?e#$-n+gbFFCW;qmnCTJBzxN3~;4|MB z-7aSg%U;UIQaNQ}^T=^wfycz7;6~oec6-LxtiZH;jMtQ^nK8fHC=M;cQEBgw(pISl z^$W9QX8!PzGIc)C)jvNvYI*LwurB7w{v`3Z7*B|LG1nkoP0Y|)qA<)ZL1hZd$iswx z?N<2~{X}1ghd{M+QM1^Lq~_DcXUjRnn=%d|&VtQaamX-E59RTmNG(=;0tmz03tgg7 zXeCU-Nzn(Ek-7kWTv&}si-<#iHE<0FJK3g$KWC^ry7B9m}+Fc zkR$<{YJ_Cv|5&*OytdPnYf$H}l?w&aVUMZ~)U`BB1TG|cLJon=0_4TpObCkop^ETb zz*YY)JZ;4cPV-%g8Tfa_?zBJgUFmhMGSs`3H+D?gh?7H>WhQe#WDW0I{0m;SOdv^y zM3b33X_HuEbG)_}HI7Oxm-BS{u+^3w+J}cGlq@I>(E>^PirG~nV|W0GMW#$0t`; z2!NvmPnAtgU}Kx>PW1*T@;#eEhe)tH1UIe_RfN>bso&7*#dO))(10Z;WbiW%kMV%A z1IgWj4T+Lt#yic7r$I;{a0r1Wa2Uoax%0ak>nsNrI@FYIHCDI5DM92NK<0^3Q#a_6 z-p|*(K{5-P&NR7@VhPErC(|r}+AKcsJ_BlV3{(P6rs_^8U|+65*&~czMI&ztVR;48i{7Fv1ZY#*NTIU(iJ0% zR>%vuSbep5?MCmr5(zsVyIAo-!On;ywweumR62!vq5U1hb2V zSbop#+cq^29e)>F^R6Hv3CIO~)}c9GT6mnNXH9m=2*Myo4DZ(OeQ%m1mOuae+QdS8 ziPWgM;8uIgzaxN{ECg_7bMOHot-`2o5bJ=L)fKz`OQ2c+&>ebLg;X_Fm)gW#!3>YJ zQ$@DJ^V`f$NM$4_JC%VpdS99}5?oSh%>aokOaXazYMwq$7`%wd$wJ{_F_zbrNfSSi zH~5Jjm~X$62vSreJZ7Z{L4r6~1IBO)W)nJD6CF0w!uWVHSY3D7H&T5=MwdcPLqMBUh?M~{(J+c&OV}4%<+?IL{D;W^FMohKKBkb{hcPBm3?DKjLw^+bCo$Lw<=5p zX_9AoBQ0;FMI#M$)GWJk7d11qbo?kRYs0Hr=#9J4rUl@nTMnr~xLy4)^^f6i!iR0A-S0GR6iXro!Wwefw)p_Tvg zc)A}aX`|U{w>zCERxnPQtk2K=ng-T4IFD=)Iu|_lNAe!fus(lG7OC#jqj(sLbfTeb zhH#fF@`9AO?hhq;NYCP>u6R~MS=x( z_5ug?fjC@^bd{7@t|!)(@S?MposF8}BHR`ljEfekp}Nqbhim$wPlFVw;rVkC5ocPqs6JH5aFP+|xxHyzl^_8fq0gy;| zO)NtA0ZY0{OjHKqpn~Fz0z9$wkEI^yYsfNlgfr$Wuvx-%5q=<6QBo|OWFA7v27C_r ziSR{QshvD6kb0I4LTg#?y^YeHxewB<5v|_rOTj)b(TIZKlZ2j96fI5WF=|goM6n05 zX`&u?%tJIgkUQuSZku*2pVNdXQ{Jw%k+zNbSqtw}HexYb3+R;LoMH>!kODddDHfWN zDFZs~iGU8P{qn|%QG3;Z&XfW=EIOlfoB}%SdO(MHtTMu)ky@k}-d`Ee!HBK`I!$JT z72MH^TOug+STeC|LADC}#Kc7`Zvqc<2)F z(35=|5%*@JadXNn2AL3pWZnr;&cHNZLCA6Sp&5bKh6a7FIkYga*z?}3dV+Bwg2Be) z>p#OKubhy8T!WE#DU@#D*VlZ;R7{XV1uPiM#JC#E#|7%jaix#;{^0+g1M7Y83{s*~ zp>hxmIpFriPb-T+$&pM`S5SwrR#KDFzm1yW66#6se@!O?1#B3Q1fM6uy7+2#~eP_FU$Cx@5Q%kJSjkf_p9F3+WU1+{)*rF%n>d~@{kvVP|H!|XlP`+li zwf;7hfpZ9x4D%+^ol`-yi2awA?kN3#6A|-@=$kyCh=ghWewvt3A%sWpeA&JoxsIBq3 z9Xm#TyJQ)|!wbckmqsn(A>hUf%2~FDSB&h?`1k=YYMX<1pm_20DZi=R~SK5jEYVwS}1?<(vY#BO9VZnP6?#P0(FKrZkTIcO&&;g|5&D`WV$|A(*bZkX)Mdp$geivUSUWL0y^_ zBJN)sAp;Z96{u&Cod}Ju6Fzfl;b)Rsq$_3g*FFJC%1^+lw2sz_HKrPUw~W3up_uxI z#LosGA;E$eDm_-wx1rhc1a606YV=K5#6xF=$Qvbu-C^X7);F=Uyu;qNAq;@0T1377 zJl!ZmsWg$)De)UUmK#G~ix>XZ$ai{IBkgpPBtHAq(e#c@+2)zq?c2_J)z&S8es8MN zZZ(-oPK!TQa&Zb2aO>@LaW8dXWHa?gk|a!}%2DM(i+IMxmAXZ3lbGr)W?AVGczu|J zc7TXp8>PGm%!qO=7E@XiqV%J}yeXS__>?d4 zRX>IJ&@JmSE!ze88@kTzfqltFA#tEDSm#pcoQCO~3JnTx#2W&@lw3Pk@P!8R@HX_PvpRxW`4XTQZR>P#lxkNP!2nW;66=(o? zicI2DRv%1k5Yhg*WEz=x^!yX9MAy;H1%@jS7Qc+m2)hvUC_Z6_aq)}lQXx4Q+BM&% zMC%qgBP#(}brVnv5RPdZcKIm~*_DWni+^DRLjHDKd{Bq#wnKA&m^Y1CUBS|maKATpxFjSMni+s3dQJ{5o+)qTUGtgfhU zH1ijBNP4%qEK#4FSR=Ks+ERqL_`mHwSL5O@?T~pQd*B}l&Ly3Zx)&Fhs?kkAL;u1< zWrdHpc%AO@a$J1g+Odut(8X?erF`isAeo?z_3Y)>B8G}Ir{eJCg{ zUZtaPYJr%4-{SPHw_& zs>>!op;pNOqp!ewYX}kfq?+Kb&~6cA=Rff>u+hwpdV!WVw#ZWis&}lsr0|IW%oP$) zaM=kkzGT2MxR`)e1UN`O+Cb(fy(c>L=nWAq%bg*{;?x-ahBM(^^L4OnD{3T-MywFH zkJd8MjaFQyH4fRV86uY#YJyEd9aKSBSm0s>s1I&r)Zs|NMa)=G7|Ip4i6JabR=kRZXQ^pHdwk;7FUO4suc)f-;A zrRI7bYOUv?_Ie&tF{_sx-PE#&03BNhI!sWTr1CC@i3p=H#&SbghQbM(I|`Y`n7}o* z!kW)BgR!CK8ykGSxxwdK8+^XK!RM)YRB?g_+L+9^$70s)J21}JsU&aSo2PS+qLRf8 zhbfZ=fE6Y%{{WF;3ABg?n5f-*JZabz1@7TFW$H?DeEz|uhnG$+Eg`2aVZmqo(0u&B zZBlge*F5m3$vAltWG*PDm7~76#;T(xh1IgfMelh38t12MG?WubF(F~$zVzBsE`JZ6 zzp$C@L2QZQ13l4nD)3~?XSFRPhS)WAHm6NGwJ7L z->u(Re=!jenZcUe=VXwZT034aDM_{v-@A{6au!Z6KBNeM*~5bbkw_n~qZ%Orv&XC0 z(C-*xU1P&Az!mSDzv5jIprhve zZ-3z5{l(M#*MFmIeHyMhE&*Z!ReEE{qAPBD$E6rkT|}McQ!Kc$fk^dSAcJP0TV&aW z=kdQL`{Y9Ux5^J|iDzhSMF*t@3Jg`OhO)VvOfP#+1&e)AB=Z>47?4Cm445IS8*NpZ z4nuErC-ldFM~a1jRW`5!^v7AlD-mgk(61nFSNPs&lfx!l(K9m4;-dSue3MTmFX)Mf zshz`~f4>u5Ph}nTi9sM(Z;=SFmz+SnHMyz&p+OwrRmm9nYFgqtMt~!|8Z1-XRJrmI zF(#G^zYWUq94BEq*Scm_sGSc;oje>D1U!Yj4=Aovdt}SAH%bH={^E zFz{%TPe_VOKi4wBUiK5rO%c)@5#Ks5Jv8bQqw&JUTKm=1ZKf8qNdbeS4KfSqu%6w| zeU6#lDPnL?sHh(JZ4>?-Mfr@1CNp8HH-}thQOd9{#2|W@F4Nc5{EzW2h&Q9Wo+Y)L_ptU4ZoW zplz;oLUhiAu#9}ZNQ~38o4Xgp;gb7klk5H{-PSnBGG=nd7BYKe1#xm;-m(N6Gwro@ zM*$X=K173k+xWm3G4Sn!sI)cM*d~xI6wa;~bD{)Eiq5^9^sqqaf$g7ym%<=e zLB|7AP<8k4T_8|>QkV{maGTyu2wn}U1QPyeG;EpbAZEPfZIELEWAlWVhkK0E0)A8r z;%f1!pN$tdVj9YfCIcpyH{HN`Rb+yxRr&%pnVw3}AIeE3!S-!>tGHqjgF+@_gcTFg zAy$l4_EiGKkU=+>H|FSFu4J8;c%k?6iKfc#F`F}3oK5J|j5Mk~1N3Fqq-LO+W<#3V zOnkyPtvKg<)@MOB{Ow>vHr$46l;|@XvQdt;v>|OX8!)z-1*yxj87Ua-^WA1j+BImb zqeLZ(W~SNRQPnU&ymvmi9k@aaAOEL@Kz#)19`+KF2MbaQ73nui)KkcMzp!(wS(zaj zdE(gZPq#ts7%TJ?x}^_XDOgX*N0pLS@W2!`%kguY;+&^81r$3@w#aMA7VWThrr1>` zTjUChBvrD-mWgDGZTXhGePXo5k}cxl<`pYwwkzRcd%oq~e47$3SiY+@HtH0ljkp@8 zT(q${cGx1C_9{6S1KubX(F|@tEGg$g7nkQ;*n^&Nk=uh>L}L%;?co4BtjNb7?TrRv zBdlw9QESEWfhSuGe8mM!H9+T;*Fq`=d`Bd&U%Z!)$E)}y`C9aFmVx<@|IIgxrKH( zPQlA(lM!$;KC&{rfRv?`66$IS0%#)!(eRvnMiz%3dLdq}mxXw_{aK!sXt8I#5U)M( zl*qiI6);xi!wlC|h__u|OBu-0dpEfvuWRf!oRaL%Su_&k8J#xMiL5&Dvdfr1G{8=Aa;8*>8QEu=R(4icm1h8C^?{X{1P>MicUVhS$Jt}? zXc|lQc=2zq(Jq7MlXFbkQ?#Ra&#$r5pfYyJOjKeDUtxx#`26d%%`5hmHjlN2WZlt~ z>}tgq+3Jh>0-E%|@)9fD%(H|+pG_3s8mJ7}P6r11S{qni<<&}-mhSW77i|>|QtgT^ zFwr_aG?V~;;ur1xH5|h+ls27_APFhUpUF0k37!Y9R4q-x{B0$WcTXZTY4+yuL`Bl6&69c2`mu^v;32fx9WA9Psd#22&To}n}3R+@|6RF@YJQIg#av1v`KMNOwk=jDH41m7t5AgUKajI4U62fU$&2pch8fwkpfR zxx6D>6o3DfXs!R$mkZ*EDs&oWx46$nn=Gun)>!3QYxy+;gpFrzbwDT~yw z*5|DWgyjTCR4Qqdl^hwv16@rhBLj;c{F4aIIJB7kw6TSFMkOoyieT-xCw}b@c>(IE zKcRV!$$w(B>)}@FF{q}*U&fkK15b}>zY`=GGNEH7S)fT&2^Oi*dAndiIoPz4=&Xh1 zFcc)`r6GNN5L zEc-X))DbFCswy9)Wn-5CGZ6 zQSZ3*iA9^b339T>V}BdCH-&6y;b1gt(qdL%M%3gI+fJ#Rv&6#aqobuUa8AUvtqV4K z9X?4ZL_Mz?D48qcA6Ch>`*Bz(X?kZ#B-uykH9<+y%^+8LbLa(UY;vUX4B5|0V{I+= z-$Y1g6RXhq*(yrd>U5S}%c}5ACfp|)VpAnH8KU`b*y0g~O_)3ZzN#)FgAVd`3y9=S zKu9n7tAZm15`K;{W>?DE)Ah};7x)~2#gJ zQ%$W~6^x{;f)R@ACbcRUF`ZKt3?(!MjAhT&Ew}m>3V7wu zGlAk&Fl>8?iOglMf>AHEOXq!|Qs_K(v3K6B%z>;-&|g}ac34`O;L5jqa4U15{@Mej zmB|Cktjs~p%3RkH!NG);Ii?GOQxNT#CJ7Z(>k#GqP*t#JTW;$~VCxmXo?kRTgApo=Oz`>Ggi|tp2LL zBB}lI5{VFWJW;i-Foi!NB_zX**j)sR7WeU^miD1T<(s3k`y;g1EeE69;Wok;7|p69 z;VX{tHi-;H8Jn=Nu?l=DHbe5e0x<1?DRoR${hBBgHAskpkJg$%%qENDR#14j!aOf& z%nVE6CG;6;_@r9d#x#nRx^C@@{)u?ZI=ijNya2W>K*~NEQ^x=XVY+p(^HE0VsDPTO`KZ>dCxm3o3t(HB*h=Rhw@X|!2$aT zFyN`;YQq&f#gMi7cH%?eZ|MgNTDIjaK1$i4yuYB%uv0K4MvAtb^yDY>2F%*s&(z}m zOZQ)tHy(fJQLrZ*@VQ6sS7b3X3hn%c<&sj1B9yPM2Ee|RvXa~ivAzRZ1_G2KjJ!EK z6HXV2O>^AT&SBgj)09`J1ZL(rMzt9j->I|NQ4+aHLwFa!naBIVo991LXph?nKN)C8t@S(p`0d%8cSASXcMv(~6f& z)#4=#ZyYTl=d*3Wl5gGu6$V*-&sL~FSk(%ZD;C146pZllXis&NS4UR3B9d4r!zh|N z4sSpJGH=<_BP^AH0$~B$Pz1I%HOcB0gfducm1%MZ%Iuqdyc5o!?yHC1W=RG2H{dowxtzUQIn0alosnjg9oGY^`rVw))AG*rkKN( zajtH=6g`k!#R;5E@L(xHPVEF3O(3C3PVGz;tD+iiSJS0(f?FU-i9wMrXxCT*);8GN zki$QI33SbD1@VQv`8dYPaoyaHt;2&DCq}&hb}dVzS=_Jsm>R;QX@SfsK4K2kE!s^I z3xozQ?Tu8kK?%+^gGOb&EP7IXC=~Xpn>5NE6Ru=p0a2R6V6wch>bp!2C{&sh!qu|p z*zc^uRlTs+y3B;MhAX@?Was&cE4NH393HeR*(pbL_wz__-;I3HrYnrwkhK@1k?;lP z++O;fsP={Ro)a&GVIv~tA3v2>>Ud;!gaPyZY4C_*ay;Vpg2q&6JY+Ix!>CLHDlNsV zZY2t&B`Re?(rrhj`JeR>f|6>4!H~_#m?PvdF+!M=L45;MyT2SQE__L}-{5FV!d)@i zI^j-?R>UReVr+?fJ-RxFteEgo_faqiUVR2&z0@fj?b5i>&y!CLN>* zF$ExSi-dfqDtzQ12a}oS6tV;=Hlr~X$nsla8PSzU4xUS0B(pBj*j!XEHiyy0=CTTx zc`hwu^JUMS&U3N4U8P8lP9u`*o{Ot`oEL@E`H1ALJbY~jXG1cZP zp^(|;9x^={!mN9fO(ZZoq0*WJ{ia^=sebYKFGwycc>rN%vYAN5HXsTc&GJK|nkD~t z7XeZnkgH_?vMASr8U_||!<7`ECO(V-$xTdj8S>5EyAzfMVX~{ZV#*a*Sg)mpmmy5m zGZpRdGK2^jd8Q_7tPCM}Mj%o0jCDBmGK3U3=m%d|#SY3cgdAEK!n7(wsQ0`KpxKiYn73_fXb}(K>SYKGBySch%QA#q@iK(bxD278VO)lgrGSyBydmq1@Ip141%RKZmJj3Tn?B;x)pSW9S|-T(d^wdBl~Y-|xO^&0*Px8a<->N- zQh*<=e-LvQ(t#=!f;tljK|(@pt05%m{du+Sk$Fd<`|e>=Zb05VF(1Ek{*t_DnJ6ML z#k_EO-WxAm%3wNgw1fhDBXyJccF_$#Vx@1an65K+*-f0MCF(dp@0L>DnV-E+(Y=rd zZC$<7)&+vZPH7ckcLmdO)FyX9c391{?9AUEQ&SvVb2%u}mh2Ox%Ka?o` zUYR3S{O8yRz>>Z}9Kzfr#a8*81y&;o3WSghV;MI{CSrXqOt^PtEb#~yL~ukN`D(lO zrCLn@TUnVLGGvd;COt;NN4y}{9s;=2{p2zJNp|2e!2;nw4ftoTLdiGD4`H7lVLx^3 zBVJ0W!IkwDFP+3bEtJ?-g@cx`&-f>?@8w_g8#~VrTAmJyc`UZT74BUrj-VuJux@P4oX6)X`WQhd)NU5lau1En!3GPMl#ETaC zQJe*8r%6q^k#9;|9lT3i(NtMw9NQ4nPz!lerVMB-9XC%gau-^P7YW@=>auaKg>#Hp zX%U*}(Wa^r_5Lccf;I6p?cbkmmWiq2xA z&`}fZ&L)b)X?W;*r`uzSuqeiai>CR9cwZE&PiS)`%cRA*|TN zcuQ;@s5v=laZI~_Iy>r;k&>I;6LJPJJBoEPuAb*M-1a$4YO}x+(XfM7XewxW1UEVL%WMaYy2%*fy zy+aGM?-@!UZH8{LpCjUbI46F^6mb#Vcog|&Dfw@f?MuGJJabr1E3Nm<+rG8YplCXGNIrTi4qDhJ0A0VOUo!gAkqnw*CwT9?8pd=#3=U^9W7k@|JXYd zc+0Bl%-?g)y>Gnly<1fes;DaCxz~za#v+tT5P{HjN<&NYsD|2~G(bO~Bw72O>Dd38RUaph3k%qiFxXZ|!sLx$nJ#0=1LwUo3g| z414dh_u6aPYpuODad4?6I!)G>7u`33srquh9kNy^x14=%r0DuW$&??V=b~UjLVAP! zD`MChx8lu3OKMSSA}omoTL*yyb3o1EWclwn@)+d@K7|Ix`WRK_G9r6Nix;nOyX7IH ze24OjKddRixpa8ih}==Z#q&l>F1Yv*Hl>KuoYfRuVrvQoH%pJr&%JE_^kesb6TS7$ zPaG|sHyXIs(nCfIWLbGQUm5@kN~`E-Q@ilsAr51Y?hVeP-s}z?OLnI411wwI&$@U= zNrW;Tdu+MH?*hLAerI<)cGUAxdn}FdvmB+Y{O}t`VrA3?Di2dGb^uK9eYr)!+88DX zTpsl<272bA3_gmUh4({6S;Uu%+R3J(KtM%VI-5hE6-6Jeo!y!?N-Why8McbTf4!o6 zcoaReRdi4n)i|4iXG&hG&qhm{Jw9Vik2kG|Ozk?(ON;z|*f-~5(MJ5`>X7g{A`Eq$ zDEK4IQ^-h1rM5W(Q`UqONqb{xt~Lh-ViwKqChj|P2rs;l%c>U%q10T2B4zlXR_n_H z1TUs9T*zhm#5czUb~i;o-f4>7z-21RhPG6HU(>^x=GnHU+(n5_IPH(bjNUH^1UM3e zXjhQf%U0rvNlCyR5J1$@Wsm$6wCMR(V0#01%XQ zJ3tW1aYm|;X5neloo=lzI8?q#G}2py8-N8qT#Uw z1X1FO6td2e4(Q_0qv}y9V(nDrKrmxb5a5+N3waL zzRVnQLgDLFfnFTJ7VoR;KLM37=e@<5qT~OOez^LB_wZEKJJ|}lKb{?}Rq(hC8PjD> zIl#GQbTyK9vVpxm(+poAgOrG>b$ zYbpao(eJ8H{R9>$)%1)E&fcEBr^dlrsbOj%WlMYV@}`OKpn9!8@yjGb&oRr21JbC~ z24FaepATM6-}Z5F)n#0qz{Pu&B4uxskUN{l+cXLp9(4q{4k}YeN`7F!%anZLJ3H0y zyi;t5q}wARIF*f?pQAO5ZHz_`sT3vyR&@qfu`?R5^NJz=`T37j)Q?#|o}8WHo*w;3 zt5IU!g_lI^3DWcF=&Vc`s|i;X_6n=>5;rfLD= zxJc$DZ9>7HDv=1z(E*^c*=evTtHnxFfy?T4RZ zB}5RIgL5%>Dr<6INtw$<9FTAwjvgiBGPtBSOL`+*g{x@hZ1zFu=zd$pjtE_f22Y2l zcB+^9ti6awt=@e32fkqg+l57hnJK%yTn7ZK6pBT|;ZzW221p1q>oFrXP-`blLCC74 z9Eg`Nwajhh8pYMrJ}7gbL>42iNESi@wm*nYQ;(+_JqW_9`a?viwALmnT1qyGOg3qVK| zworAo>6L$MjNgCW6LnG}a!9N@gaXosYb#I)_mD0Ewa%hMTH*bXKywS#mH&j0L=>Zq z&W8Bv4E~(_e~LC>)^>!2cM^noZRTwdIaiPyB;8_^y3^WTbgGZxKv;{&xg3)!Cl0x$ zTpN*FZfSTz%fMG01d&@uuy{2N;H<$Qxd&HDD9fW4XZAF!lfh3}8V_}lX=G$ca!QHu z2vx17y)PPaZXnv1J!?Wh&l9|_1)l}F#5p>?=ED3ykk1jrUMunY)7zWQp#w&eu*`zl zM}L~#{9wG}b{^!l+nFI82)DC38mBs-fP^w4B5uYtBgI3A2Ju$EF7<^9J2jwDQcYZf zo}w5CCD9gP09wSrlSvaj%wX6&1!S&;2R)ta*{e_SLuBbR#z<~LRYlfuJdk%@L62!WCRPhTb>Vdj(^Qp;j%AyO`vVZyptSKbd!{zT9-&PMgS_3S!$_@71)Q{ck!)uL zD>_p8fHvw#792Y2utE{)EQp*4y01~EfzFy;1?%B7fjULm2N;lYB-RxTOCkWV52mdK zS;AX{g6S9~t$NBcLf4Fx=ZU6?gG==NLSHn!hyi7N zGoy4M0uwzntL#*tW#`PbPM+n5j3Ui|cs4b%2wnKlWR1Ua4L@90Baa%_OxAe6Yxv>1 z8b#FjtH~PgbqzmUSECy>K0I0DI@j>Sbv1fXS4lxUjcGaITMe`AvB zZi{N&0#rM$zn1DHiN-@8lPinGx(5^Wp;?c&<{C~<(711aTlWs(Wh&OT1U>A zdJ^}Rhc>I;aNXbiQBPXX%&m|lqFyz_&@9_As@Pa6i4)YIL*Z$r2kzu+D={1nt13SB zsh(lF)G#Zr;@owqN~~en>~!^)^;ssa7!Txv%}X0=hGV;ytf`TI=#{nHD zFjlX5$cQDKhY{Z#sYZ}fnETPhm7v4ak0gb5VI9dwy%)^vRNp!lUP5%gw(xhVDKGb# zGE5OJraeDO>!8*flTEd=6}Q`~GtuZ+S|9tfla^5M>s?j&cUp0~o7gqgyA+4gM&~$h zR^0C9a_PKs)4I4_OubFqE}BHd?Y2TL(;DBqKAO1QJAUlX&i3apk_fn3JfU0v5QC_h zzhs)5anOanTHEAiwA7Toa-FRqvbgI`OHHbIsmXgSHDwB{Z6-6PrdnERt|^Coy0OB| zjDuH^RjsAw!GiZ^T6=Ura~XhRyO>PK9i3WW&rOF_widuzd%KVDKH~9(sRM1D5tf}W zT98yyZUZxdISJ0`>ipQzC@LYgpCMvrRcbqslk6*z&Vbr`%Q;A{&YgmRMwai>gyu4U z^PQW~A4`0TWU4rZ8{S|tJcS>EbAhi2xX;oxGS=bIoFzF42Q1AgHjZlKrcgCeK>RDG z7iaR!|5E_&4<9Y)CA~Ny_K7*61ezC9{O+shUQn+1uSZPMSKi1EF$<{TWnCL)+|2j) z8D`Vq>C`$rB}`g#-o{hi2~QPq1A>;Qs%!DovDzvpJY7?+ji)V&CwXQIPY-q~?bIZm zV%Tg}g*I&#@_1;~j%8mKwHis~L}J-S^kV9?LwK;x5#ULzI;nxcS;5?|%b1XN2<&$M zXqZ!jU#yY=Rl!zA*KtoA?_&Tc@^UmHlZTeo8A()MM? z{NZvwk-c8_Fa4vh(=b)3FwzO%qtyY)@lkBFJ$d{BwT#yE48y}0^xhQ- z50JQY-K$$gFh*OQSoeaIt<>$aPO7V+jL~wx>NQV3h{AdF195vdcOOB zWLHzARWEmn6xV8tB_AnbOP_g{R;7j7lvzxJnf*>RLYV>&#*4+&i7&Upgo82eD6Ct(Mhp6rN?LOr{Z3!{u2L1g+yICt>|@pgow6|5o%GyW zi#M%Q-?k$;ho4n*V%Ks|SCh}>c9*)5zB|$cp)8ZwIMSPY3dhf)pmHR1u-}t2L;HEuK6#K={@=NQT9usWOm_Nni*yq zFk?+q-l;wp>yM)Pa%XjME-4~eCcqWdTeYwh1Yh&dd_$+kU4`3T7RvGIa)^!U^H(sX zGF`4c$*%facz1+-Sltb9@2d@|iq(xrFUq|cFf0fP2ly?H)H!O7WO%{tcX^kw8s{unu8?1Sf{*cx6XILqeb{t}aBw zx?Tdp!8Q%N2)BkYQFxem?btEo`2QOD>iB;!s*eAsr8@qfXT<;4C|Ae-yTE&7g&8Yr zZFKW_r)jZM_71@hM4!=_ZL?oxk}`!}X+}IsI8BU_ojMiN$S9jJ>QSRFws#*KQWqw6 zAEYkuNkxCT3r3?!8Ya*jt_xV$LXm>Zxrr?lSsR3C_Sa}{Wk4_!(fWOz)Q9))@!re! z2-+I&A<=Amd-D8eLoPvz0#tl^AdCrW;0$<;1vD~7&>MwT49=!tRtsQ`mhFH^S!)5O zyOv@sUX;}-O$$RiN_Jpwm zN6)o6Y-9W)&Chr*!_+}gd;-5Z;-~{UfSBmVt}{hk*@Mrw@HL6c(_>f=YyrJX6reYB zM^~+(N}Fs>hW`RbgeO)}pTMDvOaMs`nyHTl<>IR>Dizf;!BA%go2$dpru$GH!W-DO`CGwH2b4ig^@Q+YaEA~aDm&Fk2<7=1-xIV^QhW<52)}GPnfS+ zEJ%iu6rjnQ2Kd(yK`ai(6p)sNZ3@uBs6_#M%S*#HA*7`tDcaUA4clDu`&k--0!AU7 zriK1PsEcd^3PJWEs_7o3U%>@}!}!(i{6#>mii}d7R9>e#pQLBBB~QBwIDINHo~lY7 zFf?))GXkkI|E<}%F_w+5lF^U&P5OfFcCsd%-NQ#^+hqNj3hW~kuX^_D!1klLc;g3{ zmc7+H3;{X%44^6Fo>L}McX`-{F+DG1u)71LWLG(MRf*Vk^Kh^7Z?XaN)N$)F(YK%oTjarxY}MFEtb6ZNMatvQktcE=BhY40K6i?AVTgfe@;@6(MZwz?_QK7X+N{?boGKjTb`NTU6GXk#md#5tb+b2ctW0n4AZZn-q6A2>!TXyt z+f|DcfN`TG68E@iq*+n|iO3@#sZHOB9(DoxlksgU{(=dHBXstovb{=?xw0FMhrUop znGu~$JQxpBlo|I#nQ7OHp$<=c9*GzgQ^Ni87 zWt907fdni@73epb(-FVGlOU{fFB|N(H3&;>(&G_%eV5bm0<4b67(+mD33mDO3Vuy| zNU1Joe~p2J#!Uh>Mr_PJjW^8KS&F6Z-Veh>b}n@U7%f`)131$2c>>YYg4HA-wKwKJ zq2z9G<T{Y5_ZKRQfWV5Z5us2NWBL)RC0r>Pxm<_y)o&t&EQ%`dzcuUtLBsEkq zpZ9lG1~1R)UwQ?Au#X7^nQ8VNfP&I9=pZu(*kM;B+@$O17?~KRX4_flz{>Q|=|h@k zO)?3viJ_KrQRpojrm**ihuX>*GCxLbGWR;_&X~&|vuwtp`7~9PG8U;vio(25r{0*4 zT_{M9y_!_1BC7*(eUQK0_|Y3YKvXi1nx;Lod=Ekap_qL|Jz$wZESxs#h0#IySd&Yd zdLoId%P(c>6*g>cG?_b$Y;>1RE>?WPad*U^252+Ny_S4AOhN zq+^DXi1+?c8r|o#h6Q6S5$GP#HZ&D2R<-%mkAVaWX`o{J6_+kSpF-JDr!raB66IT8 z82sw?`D%u*`(>mI=s@#Q^D@*t={~aLBbB=IpU-WIX%s)cC4!`TBIFB`fL_)O*!ypJ9>GYeb5LRS$K^YZH_q)*|oDkz;&S zUli=uEculU%C3&IShLc3b>yVgcQrEAKu@@y7B?J(s-T0XRbO3ir%WCryS z*j1xoX7jh?lL{sa|8B^8v6F5Mv2Jy9D45+w!Ngu0XTo<|@*SUkpucvyf@juqbE!5$ z6-{*)hbhT|1DFnO->FSj#H~VDk%2Ym#1L5wjxQw$skdfBaI&>D8-mkvw`eVFgiuoJ z;64Vt)kfP|nhn8e;Ts!**OY6kb>HXWH#zNW0%VATN9ib(E+PmVpPK*9)`NuB1=def z2s4yqtDN{mkn@ubVUb66is53uPqes)7eu~^FWLLp4}OsB=avnyFdMt7D>Laf-Rh#J z+bk|VK)XDaHBhF=-mpWPYa8RdJ1R|a3?mgrVmEaa81cN0Baz4^y=wK{?-eJbC4nY< z$-igQ^yQpnnmIk5;lN27Vx(lS7bzg&??0U4t38c`tn?5nBk`!!J1_UODC9r18RP83TnD?hha8lFXaR5Ph*(BsNaa zLyTRF9lX#IO5egzMI|M-)Iks`X~t^BxktQ8}n z6we4HIm3S9BQYNMJ=rNM#rScwMp1Ol6o4xjBRo@K>Nv zB5E{ADf)9g!$QQ(|>?UXUtZTOku{lZ9>3k2RoW5bh`;b$K?5F3L$9EB#)4U zAO(pHcp7G}poKA|W}X>3M+PD_V0mMDfv@$<*RXI6K@OTcC~&n0bj;AW7DMZ`7#d8P zgB85e*N<-LOSk%ry~^smtV(pg%7!c}MK+dh6Jq*buls^?xB9f=5zByB4KJ3=92~-{ zlVxV9!EP%|;QUyk$X?q*(J@^Z`kuZ<+W!C%TT)qkIB1e#9H}p}#(}4)-?0I}+@Tlu zHj&ASC{i_3&?xD>3)NajqUnDFu~rL3C>9}C-`zi6+gW1j$I=faV+E4(ho_;OBRH4Uwu2w_ z296ag+}ZhW9j4==5Be{pEcSjn0DX81vv5(O=wC=VCRJFD)-dXWugNt#RoOM0#m=VK zbUcM?Rsks0GjE~1w*G3 zl0#nj<{~(%zR@ZE3ZcL))lmjfEjot_0)`Tv^<%BuSF9D=e{Bk1YWcML)!d4EB9!Cc z4Ou9I3^+hcyMB=%gL`OkzaWc03L>v{n9bE0FNyL}u1x(Zhw6e}T$0Nl$`MLjAeMN? z30UP)mjfMo+(Zg+PW!R0h=|fjYr9t*1&JwcnuQx;6Lp9Vp)(174sl|2A=~b7z!7=| zf-O_{<5!1#ooN^hwR0HKt={u37PA6Cj2$=}$l{zcY=kwKm< zg(98M5w%|il$ZrGK#4`e#eAuwq(O3jkkg^eF?FL?3K*Q^BIFP@cGkQ{L_yqQPJrZK z{==UAhn_6?W)4%?850&4^|?!o75?TI`X=s4`wYVzhy@M}*D)|1ekS~fvNtK<(oS@> zKY8*}PabqkNi9Q@?k4?*awW(j*&I{QlOtW_CjEyl*ETfuZm&PRH}jT6<1)dww4!j$~TZNh2IP1y?2+Zec-9QIX*8x4wvswdmwCWbn z7435{pgSNDM}UE@_6_vuI&2{UeR=}u(+2_ibRE5rfbKK;MvATxzQI&9IX^I<*N_I1 zJH_5)Be6DXWw%~gi|?ST2(_T66tN@MbSBovBOSmi%wpYIhnx7aK12$Sbo&sgI#hWa zu|t9POh)W{f4*oRG}s^ryc)xgt@@zA7*QG|v2XE*NSHPQ|G!C=|1V9u^(zY!qR6d2 zV9B%IDl{e1|54%Fvy-R`lTh9vZP0^l&M#^(I)CppPl!gUUoI=v`Z20cY zZ>Bl|n0kYw6r?ox(fO;lOu8a2&pF5o<#(Do7)rX2teP{Cr$zj{CpltM zX@gkWNNydIe>~#@Y)LtQ9*%(Idul5QHwBu-Ve?XZA}ckW3bklON)ZiBlbZ!OcUr7)LDeE(wQpCBvqDgx1FdZ1gh@sgicaxW1Ez zWlmG^9mha%)~ut)Sw%L<{haiOpkR2~OdLfEQ={2!vhWXnu_Vw^4H{YUh#s=V*?R$G z7WRD8eDxh?-{KG=z~sOjL~BYrZ4_ev8yq>uhddJe6}hhI;mJG6caHp!cbMd!`6{!) zFGEPoQw|^>Ak+kx*Ab5`A)zivG7DltP@+x6`~gz4IjN3)v}9gWu6=+|+XZw;30+#@ zwl=(KoF0TIqEl_IzV_)3>!ss$jYnukRz;6J)7TLfpeimM4PRs!dr6lmOse?WuCDk7}$x*SO zjgbgK8Mr82D0$W_>jnlQ5S<($VH_jEU`Wrwd2p&Mb+@CRGxQVcE-lvTE>A+;&BnA% z58JfO4d;o3!dI)iewNM?Nke2}cuJ&Y#HEhrfS|x+q!Q%S_rAR=A{in*j@{kajR~&_ z)9E@)hX*N4hkL?wY{igknzS5F_Tlc;$v*P5s}$31QzBrdY#(%Jnb1dP`@m&RwhuUs zCQM7h5vJyp>LVxBhsxUHSWXeY14|$lSFSpAcksX?3yaHiwTUTZ8OH}S$YzMlgEOb- zm&_?i!EwXd`yt#iM%J-+x9`N%nHW~Bxr1{U6Q#L3G|EWG6u_piScK*dnv0zOKRGeg z1jLL0!d;G6u-=RuVyd)@ZW<;L?@+*i)tVRt<;Dg+4Iiw-mRo!<|W6(gOfaV0EY1Y1)l+h?sKZb7nso}UE-IGI#CTaCV_?S8pQfqJ$-@DvL%FfK+ zFp>U~knI#w6>y%>7AXOoNT&P2(L47)N5|3dV0q;M*wg5_7z{}nfga-#BkE!>P{3i# zUu3dW3uveF5)|+P#gD)jIL)(kdK-jiaOjj0b8w7QSHds+B}_=#MM-W`HBT}Yj_1?D z5Rros17Et#VumvUjxw|@g^R1MNOTOv?}r{_CGJ+=-2=)WGZc+7h;1(GS2TVHUDmTd|@BtF^NwBt`&SJMK?n>Aaf3ThN$UXndpA^W}07Gx&KTN^%xoU;YR z*&thftr>|qu_|B}U8sU+(V{sRB6e16^=jDqcO%t+TiMf=q1z3$RBa>+2Ab6Glm~bwt!++SljtBNk)1M8gmq06Z5CT!su|=-~_mMa$yxX$51$w`fXxY zOi}NOp?+84_%bjMUfeP;upO{%U_f%nu)vQHGZ_{joCBs@85Yz=V_5KFZN#!%`=YyE z+KP8l2)q2BXzL)qH~AMkLuSsY24Iu#)RGC=^~^jdEfE+iox9s4qty?r9q9zdFzIvx zJ)XV&5)BT#VU_;J#;1%;+apqJk0{B{E`F%V5m>TT9_XE;4c`_s#xJ!(p7;^%^DzoU zbS@xb%vu}o&W{#adBb8C6-v)og)BQL`>4*n$<12jGB#*cb5HCM5*B=G#-TTS96m^h zxHybF3;-0?f=J?45(1fJ6^mgPmOvCgus6UAxv>LG zu!A+_+Q#BGH@Lm}uhx&Ooo`~cHPW<#=VJ#msOI)`s5j_LIYxIb!_&b<*W0t;=w<|d zAs`0h2JGSp0ytBU$9f6(L$g!L{x(sM8LL{i$-O>*uuRsJ_W6cdsZaVjWSI!Dme@nG zrr=UxwZX(2+F4j#+E8p;Qw~WBZdp?_*<msp-oYu$N~S5gWtk}&C1Bp&Yr6MDPLO5-j?8s4e;6UPXv#XD=)%(`Y3k)SDpgE&f|GrTh#=1x4x z7xQW9OWE*FCRu%-$NKW>V$sQR+RsRfq1*$I=;74`bLuc=GZ-|zykKrr==1Owsuk5Y zH~}J8ph}?@>dWJ$r^8*(tuA_|&myn%q&j|hC!QY9F?k9Oxb@b@ZA&nuwslEM`k8Dy zr$lu;kGBz7b0^vQ@@i`Y{Yt04&94~<2Oo_N)L8RP2XVYwU}R;kU&d2ZhoAf?@L1&N z?~6?z5-h2DyCC@o`k+1sX$h?JVBMWCCll4uDeugJH{%!ly&B}$o$q5iUrgUg!ztri zt`qLhVJhF=^_f_Jlbb7_>&ZeLz7uGRM_q7>lK62~C`2oHb>&N3%%M5bWSd#`xg(%O z4-=$Hv&TD?RTu{#R0=T~xc<-b6~PD%;j>&xO8Objc>1Y3_YS_NZD4Nj{ZDqFJk>QG z43_+Sb5@AQ#YxIx2>eTV@7Qn6u@F*2SbQCosl(ls!Mn1uOjQZ_U|i#3YGC7%G>^%? zsGd&b;NV26pc08{ z{`gUQ?{Uw29sLu>-22%6eU3Z)_?;*GNX`mO)Uobl|3LQm>&d zZ1t?C~FHqXJ5$vHv7Bmi`fm?m$JXl{=xrl%x=uSoP8zx$Lyx;tJ&AGr{!PI zZqB}u{ZsbOoNo8D{9D<-WZ%xdll7jK-@@%J*>|&BvhQUF^2hV<3HcN8fj%vNa{iS3 zsrdz5$yUQc<3m~h0$-DNfa|B`lAu#Zc9b!FN*sg@AsB18+=WJjT~TZLY&(q7n8b6e zc1Y2`#W7HOp~&SvHF#H{=lTfRLWMQMl3h)|z|H__J}DdF5_uTxmv5qQ!kYE-m^kL= z!{|8n^1P1ES$)l|ZJetzXTv~s)^5(mfKJBEhwUOHUH*!mh@W#DLFX79RLeIWDupLL zfeEqs#9b-IHwLdG_$59O#=rE5IQ6=aGQ|!w+GU9X`;JB9UD0se_QQt)nFfN5QCj2B z(H8tjP-&0qY;<9!?n2S(!l#ixl$xavX_Q5Kl!ZrGcR@$K^rH*vNm{;sn*PxhK?eY; zBem7#2~gOS4O_`Mf2uuwI^2c8&GDBun!Nxm z9nzQV&k-=>%AuFG>$zdfuCy<;obbc1=@}ivc~&8^MzM zqD+3m0ZX{>SkS&-qetrXs~`iu_h2ewJD@E}_D9s{0wI2I@$!xKEC5;{G$RZbR?^xA z(=Z#;KnSd+0gI{DjkEi6QV&ui0I#7M=!xzG>H&@20uS*j8^GA3D=?s9IoM%bq1wFa zGua3TmCq4XxTtc_liP`Wul5kpl_MH+2#d}@iyfVKMdfa8eduP%X2!6)X0HFh~(sN+M$^6&+ojZ76{lf)e)uB^I+1_C-L6j}fqaeu9!B zZbAK$93sBS92$>R0FmGaCHq8qrK|F`V#o=wy2aYxSJ>v zMx|XFwg&O?q)7G(*pKUM707{{7z4A8nM9;2UTI(msq~6kUbbT~4n*a!n7P4w3P^!1 zHOhfC3yb&=^BCDwtCB4mq?fp+GY^KTwp7n^L3Ar;#%qC}>SLWnJJn1p2KOS|1u1S@YR(CAG{h{Q zi|Lvl4`-f+M8?f<7;u6;Mb73%u(w-Mn*>ZOc1vn+a40I|3cy0y=uzBAbV8wx&~%BG zD&3(Wv>*4*3d649ED8hCEQ8RVg>B!EZf*226|RFwD|s!L)^V+^T9Z7u)!N%%09!(OR~jDi*^vTpTf z&cD&(Z@&Lz<1|v40d)FL(w*Yww2JFL(eLI~!x9;5R-5)0DgvmGk{4@L9w55f5&&rsOh@< zw(i_OTGZc9@cI{jp-Tqb)EiM(XK-QBXU~#`q<;>c;+cQN&c11W)6oPD{yOh}(;uoo z`_H~x#%t~JX7b=ur~glSA?;P%g0UOrSrp#i;{K`s+^Kqlobl2jo6=c{jBjO|fOkO#wKpuMA&>ZuTgG zaS}9vJ_YFEoti;iaRzIQU^qaWZN*eehJ>YE9k!6M=Gv)aC-6xzP^Rq0Y_vr>jc0E& zu2!{BZXp{x)&)v(U@PBLH(q|Pa>?C5TU6a6JJ*1qr&4z&d>%dVUF|d>{eqLch>h@4 zJ`rr#g)~l<7Ll-{DR&C4jG8`y3dUx-2hxnxNAz=+(fC&ml-8XcfT$ac4|OO% zzxwj_aasqBhkE0( zUvb%gblHf~t;>FFUAzD2vNySGG12b&KHTK8Uv*isO}6^*iFNIM)n&itvb~A2*E-O- z-QTZm*AA&!PewX=ilgWt@bcZ! z>>4WA^f?+-ayT?l|LDI+1!kA1RF}12fA_j!P+V~T7`2cw>nixDp$XViQWZY#3dOn# zA6)kZN~*#qT)}zsC!n?d3zSrazjg(u)t{*F;dNi2q$+&U6(Vr)-2U?V0 z5bOo|<<;eHanuLP)=aPcIm2lTOSrsvK~2k}P4b2oYMDL+;ltxN77FN1)SBL)79#~7 zM|Oe*hyo_6tox9>)a{4EP3pEH?WkC8(#CzVQ|VsD;z89t*}D#^H^sP|v@FbMBTLUT&mXp^=@jDeDBF+2k$j~x$(SgR0z0F=T@TjpNd z)f4OFLxD1N_f97Lg8<$7`VhT-xC#A^iUmz=DwhQmA(WlVSJactJmm{{gJD&{_IjPu zT~GWv$h1KpkSW$f#uMM}@H)s?gcb0rdh*l0sqq*mKSb{}#`eQ{j1q<(pX~tywvj+G zZ>t9=X3ca%h^z6mzS9qZUyIuBFXphhD3fYV~ecEg}p|ol}8` zl49-dwdZ3b6g$`?sbZQW5U$12FbZ9nC=&+6@rB?hwt*J!i9JIN_SXzEVZV8giIWZL z;ypg$dNzoY1C3L$VnT2S$I3Npt`&JE%R{U+CeGXF8oYiTVTxPHZeDXLW z>`A%2s$LC@77E|S7aLCXZxI-FT}*JP0ER?c4G<|*6>2Ini&(=9gM?O@T~47{8E)n3 z=9?m^q4-;5eUO}-xvU)Uf3_N2_Sna=>1}uzM1Q_E#dFl#VS}SI3y1B`&fEXpTfX7Rk&H90pAyLd!!N*yC^seI{|Bmv3%tO#}6&tQmkT>4=Xap^lsV)iZ_{m6!K>4zyU z{jl;!&MS8)E}aZL*MF(&RgI+LI4&I?>yx(`UXyLViA&eAr;ba{>$r3;->c`-8voH( zII!Y{wK$uMOV>k1!yI<;_h zm{uVpjts8XA*TQz+@5mWeX_$m6=jdaLw)^|rxHTg>69g3 z3mN$!_0s-ZZE9`4ICO49WIDan>c!jOrrX(h%1z{*DRI?F0jS&3dWV5v_NFgdbd9*x z!i!}W;lRR&xC$~s&=0R}o#EnR|8z%oW-pwgWbF&j8uzPiL9mP#z1bu09Yp<8?6s0Mn zvZp)}9=KMD(j+lL)KZk@nsO)s0x%Pib`8&8y1)Op{r#XBpkT`J9*>%I72nTQwRBFom9*p9OruU}y?v{&1dHj@ z_;ABRgJsm(5SC*;(%MrpWYu`v`{r7iJp{Vmc=wFM;a0Tl76p<^CsCl5o-nJm6v%p_ zrodTJJ&h?)Np)0ZMoC|bk?q@>_%Q`S-6m}jR*+}H$et+>HWkw{EJRG$JJ{7_UC}nb*G&vyb$KzhFT&rEDmR z)r~3}?cIFS3tov%I5l6rLoy@%id$LJbv?zW_BzlI5UDxcZkXDPgtIi_)Vi@;AF`Z! zXUHHv$NsG8bE=y^^=i~>+(q#7tM!g6*^iO{C>8bg0jQvp!V(~m?C7u zx2GStgXUp=eH2H}7?k60Y4&(rE<#;!2*fRBt)d)==0LEcGR_6mF>$gFk`X^_b6d(S z>_4Dw_7p(K+$fTmZ3ukg2SXVctqAJg)#-noPRq(E_R#5n&38MoU&79LZnNSF7o{wA zs}g!&b&;dj7df^ma+8a6DH091HML?3pj-LJ^jXEbcKToO-SUc}U}dr#ti1&xIbhm^jMw1;ss z&;Q~E&2WOGb~kU_jL5YBnw04{MO9p9NSpcUwRSQ{0q6=w z##D8q?YBOsxSWwbk!zJ=7n*{c6jL0k19Pf|pvmf{Oi4zU&Ot&^P+m2*-1vk?x|hpW zU(GmNgg1DpkzNou?!xYmXO!n7SaZy}p+ENCkVBwzZ#s^%MaQhq&-ee%vl+&7Cd&P- zr+@JLqW`z?zGcvlOa5kq7Zm+3=sgvT?{!7DGWeaM|M{l%@=8k5h1-eA3vELq%e1wt!1R(^!s&GyAjQj{VNbp|e{fsx!S}*Uv2^w&Z_W zOrh9bHrydAl?qA;!;ZHyQR1@s;bG`)J03gSF<+A8cH$+~Yb}we4s~EIEv^{dT&=Pu z4RNleX0j4z8glr2@^Z(;Y~FVElI@}+{Cw2`Nh66;k&a^s1RPo5 zMQ5ghVpcdg`rwq+5 zN9G(2U06Gpba)Pmj-6HwKvHtEHb6L>XCoaR#@N6oB{!R^HqbkNVA8cu-k325KzzKY z=zlgns)Y#7O`d+n#ETT{_CM{*+Vl4*-vspf>oAt^S@IGEQtv;O+O6wGEKcmLYDjMh&55Bm;psqg+Oy=y*yO-TphdWW*i=wJk#iFE095yT~4$ zfhBO*ed_TLl4XG^4doj5p9OojvOYHKvADR2eJ=~BonolYpgr~Dgw$6G6J$g;ZwHbm zieC~f1RKC!04#gB%vAw*tB;!Il8~4ZNpES}1^sqHqT&f+SR~MJ3u2+Y#HG=M9UxP^ z>x)cAd;%UmcyAFWYH%P2V4(-k|Lv??7@Vl3Cas^~z+s;#?~qG4(E!zZn6ocWY{<)^ zS_dCzK_1OK!|L0TwHO){qeriUe5tpUBPuu zf~qcFI3_=VTb?fS!{<&uuEY6k3{BB)q#z^1hD3|Rk|3&luX|Sb!;!xp(SjD)$3}~L z>0$Sg@YqjFOgT8QD}_z*%G!@y3u$18)RLkmI4bBc8+@K8vMSK%9v%@-HuwUMP`0q| z+&x|pb{f%vbog#;9UC2X@8T59Qc7jS<~^lK0?rue$_p-b_f8RvptREfC9D^vN(Cj? z^&6g3P7l)=S)QO%m>>a;-I1axA{XG~v>ILfYZ(ZdVR%y^T$}0S6!Hf8*LPN6Nd>Lw z=L}vRdrW>h%>&{Gi@_syL+g_)Krxwv%|!&TAw1Ie7If?saJ(XR`~z$tVd>4E2O`rQ z*vq2aEeVi?I>wQ5p0FOLA8UYxvi&lb>=6%D2h{Q;0uHc=OG!7n18PX2)5V3Dqr{DC1UdZEB&@yty`OX`{#NK zH9I2$oM7-$CK|CLmh@+-UB%L~==O|9*`!w<4a|-Z%uW&$p{kJv#L++A>{}H`!Jd~D z@htuhUhbF!w~nM!Krl-o9Q!&D5gkhUp)4Uj>#SRS?>En(H_VAUfeYlBsdRyuSZK?L3`u0;DgA0>Ek_+al0NEi% z{MM4BmMpc(AB@-#Wt3|0t#0s!)L{Mowp*@Sq$?VO;BL6lrV@DrjU@Nj)0{ry&Imu= z68Pcds=#cQjLFQ;mw~O3y8jk;s*FMUORf1i&}GJ=^H;ds9=L_(h`2~Tx~{mQd0$@W z8+6N|`t>BiGAt#+q^ia!q)9G-wq}_Q2}Xb7&j9~!UwIh1il^)L-|Wj;F?ths`h4mP zS03)*75Z|tqt1z{=?2M+xI@>vh?nYnL2dmaG-L8CPdyd~Du*M;25ND~zPN|Z075c# zz#}*mxoV|C6C`9N6^~e8h&ePNMPp{F8rTSDsyjdW97F~>pg>;1jr`0PhC4X8wP zMRVxrHP`~*gnz%n6a9v|6MN}|u{b`b!|3a)`inW@yM9)GQ4v4&v-q}c1$>*qRnHPD zINqPuM^V8y2kKtI6Wj>0j;#HRAnI^IB|Dy0A`B`NNEv zbjWsIDOi?SB?Lr@Nw$i#F@$qi`&k%`E6z!`qh-dy=CVHu`E@6KPF280qzqwA)@ITv zil`8B7dOqkjW5g~usHc9U*Ye^!8~D3G)7>#g}OT7w&PYWS%&L}$4%*r)E3|D^3AIE zK!0`?ea0Bo|HCw9z$8P;WrU;XGMA9$CVEt?RLNvWG?ps+){MiJK;Y{X5PkKb>A?D7 zB#$GMX+hT!B7r|>9x{xI520fF2m_%YJ5gA~hZYm}J9WQP{7?72>PRa-T6H@j^APuD@RdA) z3hSFFKt?!_Pk1Z}5UbLM8w$t^hUT6~_cTIsSED|Nj!g)b*`@#oX9!JGGopZKMifB0 z_!b4^+FCJE1cf>gU-E5>0(jhfS`;8cfdXdMQGgX0!Mu@+2k^#7%(0i0i441Uj-wu~e~8vKDfc~NTs zX)5?mynBV;mGBZ#p9kQ%O0Qp@+B7L^(q85VHS2$AYPpdNFG=P1%l59g_5SbrNh#iB zwxC8{JkiLDnnqw3di_Ek+?FOIShpC{#YO*jR13&@45s42B`qGhzQPOqU1+!4f4(mb z#pn5w0g^4W(|@k-Qfzqtx9dA=!WX7HFy{F!e~79*$FCT4yb4V$RMh8sN}fGgfPuT) zbRR*i7M?``!9ZvigPIZh*ChE?BH}eg|Cv!tcdv~R#tQ8jYn~ha)(6%2(^KQeg0s>1 z9yJc7_=8%_jJyi;w*=G_Pc9F{5!ELLN?bNoz4>0;kOJvM)K4C8Uqq zX6sMUe_9$)qx%XVZN;~dpcfVW3n-k#a0AYIy`p-TdIFy6CIg}L^pYacH*Do1x)h4} zQ`{CJJXlv+^^9A2a_U&U97-r#BSaXZ0x>Qt`cF!w(>@J)S=Va@OQ|RNn>7hO!FLHm zg);j1Ym5Hl{ro^i*9^3(UMD5M(fFFRnJWIF$9}+dy~c~W_3F;u3AR2ieZI5-ePsXM z!Ic@t@i1^{hPC098JlUeMn9ila|7A|?7|aDoES z?ek1BY5b2>wXq{fX#c<*2}iSB=cF<3haXW8I#7S`6>%y4*pgAQoN zRu|OWf0R{9<}U1RcX5vhudEb$z_F@)mae=M)f$MzuAT+CkO6wPVrh66$BNAD>VS)( zC(wi8R^55m=H3n_zz2&1DU~2rUMWV$a{-#>Fsu5X%!ZsotIsb~c#YBIP<5C+w4iUS+h}eybDE-AE-hzR@;~LVqr>*+PZ{n2{waMc{y_9|?#E$QJBS!N zomk;wp2y?Nf;jrPkBBj1H2oS_EUaAWMzsR3p-3zx;6rD&;RPtu7v;}lj<)i#9fPA4 zFoUr}pe9iQf{Vw8oyh3f@J_grZUgW#b$A|O7Y30wx=XE;mxBjLLje@?#X@bqK=k>@ z1&D>|-btqe*XovZ4);`b(H=PA7^#H%8=)0blh7(=Bt{}npki8Z6H%R?_QJn9}Jmq&eDoGhoWdudUB z$>>o%=?UaP)feacXX`UkS|qrWJ{w9nUl_dJ66M!bCKPlQ8gPd6{MSr8ysO2yv^f`z zx-@EC;0=s2mKu+64I1$`3%9hs)LDFwNmi*Y2U!u)<-OOL&It&UZeLSSc~gg zxXbCKx$ZS{-D~DLo!1ONd$r)_s-EkB3q-+dDO<~$ELh8GZ~@x@m^8S%=CA>(daCio z>Ydpp%QW>6V1JzT$@OCm*NYuJHH6-1IRDS|PG7O3u-@RSGO>*0jZvH=0VKMyYBSr6 zbha7cY%@Y_TdvF1*bEmDKxWfGL04(U$S`{f;T`h2IoC=Wl{QUc-B%Db&+!2elPZNd zy)I`0dzC1oqY=t8;2}?gh>@1nx57(M!NtzhU}siqLKh@h=Z8DYaZ`_>(N6zYRgCq& zDGLJg^eFVuR3PTv0Pzyxp4Q$x0WsXXv1hy(#!x~KH(i*jh{EONb5ROt3Ep_WgyP9qzx3c!bqIw7ggT;{lA){ zxUa2gh&nLjscJ7J)1| zN{_!|*FGTB8Mk6dHXxx<#m0jQ=h-zVwAf#QFug<}hevhq$aaDY7AY(jEYg|2T!C8= z`KwwCRzo!%X(7W091GB?uDUF%UUqrR9YuBw-fWigP^*@K7Cu!Au+9J%y9CeRhjUU- z;fM9~N&IBTXQ#W%b_~X+k2oqj-Re{WN9m`p_u&y*4Qn18>c@(`ru*CgoMPUgS5cXv zK2`mMIjC*@!d;E0x<>%c%XAmjE@E{)JX5tPAQ_?5vg$Dxcz;t*_$=dErZWsp6^8S0 zGw6Fb2(7%oOImpt3nM`bZtPh_Z4(L%L!ydOpLtj`MiXufZ4K!uO`J$Io@wou{vGHt zF1yrlYg;s^6Z~gM*SODUKr%fgj~GbjAGjZ75 zR&@b;0c7H6bV0_?c%8VsW?5#z2|eb45z7S!G{e_`91zFz>o7X|l_ZUkW`ZK@?!v_I z=%~>vN6{ePfuL+?s_Yao8$iiz4Bi4@k|e(0!Y{=9X*~*0rA$L2zYy(NV42hc-|vVg z>FE~XV^5M;o>dBsjShr1@YbUL^DUHW=(VBwHKoUc_&J8E{x?;GoV|?V+_(`FsSd3xQVrV zBTXkU|cMh>?1e+D>2w**VBTvwlJjMX+ydMCXNVL*W6B-c_!&q1Tbd?Wb zYE*8w^$^~rW+YxN;RD_NPe%o683Xmr{~Y}syTk&2B!ht9D+R7vU%t5`2=YKiGNBNt z(@kbF%D#a9IW-2phX?D^H#xxsm(jTb_e1}|>H*~3?f)lT)ke9W(hc7n>zRC&NA6|} z>rV}$2dQAvA3%zocw;WH(-mrh@VTk2r9Fg(mLe7Nc0avhBh;!t8)Vl&SCBmM~AKHhWGL3^0g zE;ax@-fBXNd(3uqD~d_M#|(e%^*mVFclK|ja~BijCH44qm&(&jjulq`6Lf66AM;jPQeso@E{k*}n);Psh+r6tp2dHp5~DUXQ{oy!jkowNDe-|6Fu zL*sL@EaM8PC6&-iGCkiPgi#qxB#yK8 zd>Ori2jQ{;%-3Wxk)29^VHD!ZgSQp^2ZqSeYC1i6!1#%6DD?R4MV|=MFrk>`^T*~D zUfe%k;P8-IXEq--PTrtKrl#(FmS$6DO z9qJT-%R{0V$A|)Ber}d_&Pb2pDwqYyyroiGIfVtKYu=$0us@;ZN{&ySYjLGnxDw&0 zieZ(G3V}EA$!S-xvQOrs|S+cU2F8h4GKi)1f#Fo6k zQ0f@x6EIy#A}H<|J2iqi1v(#{0-a@OjX-C0l-@Pr%XChi(R^Qxf6|d-j>+8(fq~(> zc=3UE(RvEi-6JA)G;|6LesIv`Df}qJ`k4F-L}K@m3MV2+d^FJDJcgMP(L6&4bONOr zJdcpOk`#y)mY=#3%g>5c#KwhAnzSd2_OsP|jwrMytuuUEMKDx#P9;9oujC!x{PC`U^ zWAs^eW8HCx-0Ejp{&!2;)l13Rh5Ww!6@ghZN zdrN7vgidZ$Xn?ub+7OO2J9vMgmidxa(=lwAli)Mo-l!(EpDdZ$s79hTg%VkxOK2|a zhO1M{A{vxNgou+%fir%#cuIf4m1_&eJ3(1v+KWL=gDZB_MUJ=Ix<~SBQ~E56jy&D(`WT`QDeqT!#4`D zvGO6l%PWVIZ&ETGvN2P){+=j@oRaLb<>7Kt-c6~CY46%1D&^tScctXMOS{(=TkbpU zy5ArJ1w^q}d-KxnwZ-a(xqFR4!1eorD+VgK4#3qEB|*0dk+msibCY;1X|qb}+~oY& zxhi}U5avl;pa~Z}FDF70FCSb&RvH6p+X}a%CBVn6+8MWVtHJ0t-;^lTdL6C$Lp`lI8 z_h`vMfup`maZ6CsvUcQ`+oj{NcYmqbTHUX&ypPpFNeR*2{sKPu9E}`+thZAjI@U+ z3zcBN%0B4?1MfJoJ}{`R_>Gf(3Vbnw#D#O1pJ;bZ ztlBUr!Pc+upvNpjPSieluu>~MqN;W%g!gp(^-Kqk&f$B?t)#u~rwdM`ozK;c;@eB)w@{G zZLWqVW1#KO#^+h_4`LS`wY1$uwUn63wIsz}`aEtV#W3U6T+DFe?hP^wM4q?U2tc|p zA9}X9e;3~DO@hQGmJ*$=$aqCpJivW0D(dTg{ZwX!w-NtL9|RZlJ;cKnAv?>X{cj&phAjjGZ(d_uR35xVCo3eJV6nG)PyEU zmB_)88L1MBsG}0iA1wln*khqr^Ynxj^nf46p*7m3q@cJJy5^%D7r{$T3N%eKU5l-_ z3n-KOaomOO#JHv03o>3VGUL>3GjAvFQCTtX4a$aq87KH?ANJ@(Rw;Q^SrAgxnMhNm z2huCw6bZL7ZkQY`<`z+pj_|SZfJ2^9aQbGSnz&eQ8f;Ml7O(b@zWc-|g|J)7t=g0Z zh>`nS%IS2oAK~6?m#QS`ah6@B5%>4$j>X4NH~-PE5)&HN04b##RFBsJRmE4WA*jYr zrs{6%1XmxwJYM(7Co5r*7bAZ`7x^CJqK25P)LSb{COH>Ri}lkuC}=sx?p?=Xf?GQT&H!1xI%FB4BPMH^n?*VVF{ieM|(zNu(01Qg(MnhIc2Usb&E7%Y= zZU&mqtJ2G-fP~9RgJFa+1+@9|13+VMeCU^3@C}T;2LcD8eVLzauzBVVMa?`{*Rh$K zt|Bej$1FKOaja3Bk%_^knPtGa%oFSkgFj~3rti;jOawpBGntfFg{ujBex+SdSxk)@ zwp@i^_z4lQRx3F)sWr+_OO>Eps5324l!+YrW~dlsYM;Y$(D2rv;RO~cq~_XEuTcg8 zhalz6Ye^Y{2eSCq(<1(BlQQ`6!_J8~LBopX5#}cH-7fM4aHu>$FUWWMZICa4g~OsD zUo2~he4T!67Wd&g^2MPnjHgm;o8w1%B%bDEBOr;FX<~bjuc=Q<`>kuqS50{DP>Wa~ z3-Jp%E@M;YEX!ok|2pzbc~9l@hfQf$6HH zylwI=OupN-RN8=iS)=sJ&13S-9t2gh9;y<sm5j;#*7q#>qUX!ZWqRp83BcvDvdH z7+M*x63K57$pgfW{v?v$atBG?5_@(uy%EVfn-sWm5R%`*GE_`qOOU)N79U=@aJxue zSy{D@TgJZ)C3YhD+mzVY8rGBibV%%E$_xUz{UpETAS93K*)O*qoaB?1=M}e)v_Lu5 z(n<6*FIsm>QOqwQHVR1Y5>O@*yH}{$keDu#_dX;k_CL{!y?hB}=lf3>j263b!eC&H8i|5i`~b;?w#ar2&(wmIA+{7; zSv{Z^%n0J01Zj;!qGHWmU@REr_4V$R`l@WM9DfX27qGng?bElC!b?Uuz8O+S2@6=O z-SLD4v+HErj76%f7-GigYpW1Nq%jt+*Kt->O;Ow?Ra1EGhO$i-Q-nn%;=B#jv}f67 zC)zG$$U&Rz^zZ4lZA32TTEiMLxE_BhqM+g{WcJ*#8ZGm-c1=0*4822(8NdZ-by{f<}xZ6KUSM z0ZAMw^Xs-yLOBm7gi>d;xru_o%F@KZY?e-in+Ai(WDE?Cx5*Vb4q({~b57AK*vU|z zWwFGnq!<{pP?inY`V<4R$egHM4#C*nj)7sx(Tag7bO^$tVqh?vNM7?YVqm~&$H2IE zO$-bpa12a(nqpwKgz?<=VRwm)B65OAp7ZgM7E=slbKDNM8Y#E2pvWKasG;qLVG-t( zym0%=s{lt1B@|^8HyDHcYwTL%f;(4AF50r!< zVX22jec3EpcDc@I5R^z9DQB73!Xj%`pW+aG8RHkkYBhXHvab|9G-RNW6 zQr?26{fTmX&){05S1cTX`3Nr+%tPs^wYar?mV=$(g(9b^>H^H1Bm&nk2(uveN%k8D z7lF!C7)k%c$0cC3T^oX-h2j=16m>8ZZmlC#b6fSMn;Y`1sn5hX__LzFM@5dPF8M~T zh>Yg(-SwCUgFi3&Kc=sWYWc&aN}k-UetTun-#z)3C;vf2AFEL~4q5FNAVT z=M39&a%&{_k`qOtw#*JVLqG>Nz%JC6gb9Gk9B)=iRaZJB0Sny;{o->`LAT+zW5$0GNm6+9I3n)K#CZr-iQ zEvl#vZEJLV1Yis=0 z>I%Bw;Q|f>^Q69%a1hD4e(HzADQUDM;6+CB~sw*?j zSdcOj)-YSuL9gZkAsSb*rad4xDx|+%Xh%{~HI|i|{A{U;cnva2U?rk+5QOmaWO*ML zt>AVRKfFAXpSff5hsV#ufaS~I55yH8wuG;j(M~iX7hlvrEq+dkpOd0Kv{?P+MXCPQ z>eF9mX&E7THN=mN@<&Jcy_Em#3*b@UfWzDzy}3keyBDN9FIVCeSa(+E+tGEM9cSy8 zyDoRm6RuVp4oX0r0KRdEr;OW3omo;&YntFg2hfK2d877D%~pRzZ_S=~tRs`1^hv-P z{3+qZEPHy@v+PcP8}e@}0Y+a@nB>+(#P)wc5jd@x^=8NEv}^>^+>bpUx|?)ad&%uu zX#?u?sj1ea%i84#)4S02UIy1Xqysa=Atd^r9(y|^3St!U(_ZM1g}aK&c2|Mpd*X~h za29}yPdl5>s-y`#_a+4=)Vh^S^k%&Ho(Dsn?#$hd*$7U10%0hLS=yAzkroKq4U$qq zMNAqz0xl#KUM{+Vtaf)2TGYC8F9d;N2Lg4Q7YirUE z%xdlT=$*o2HZ`9sBX1~;NI;O%_zC$$US1#aF;%_jI&dX;2^~^ao~i1J<{3jRATaA{ zdG~x_mB`=Q#J|N>s^ELM*yd6-v_0oaO1ocXb-IMlX@yM&%`^Cc0#8S5zeHh@4;DUu zm^Gxl&kzMOMoTQ@mEHTuj*gsg19kmVqW(!#xZ*{q%Ia*?Csc##U>G0s+LYEs_Blr6 ztN40#BOiEQ#wKMJyl25-8K}F2T}fR!nj&vKJY4b7VxrP~@aw`OEVMB$S2{B)J)BC{ zUdNXn*7O5rB;uxL$m1jcmvp^G;GuX66STBX0xznt0uUpLz&2!|RI8+$M&3>o$R;bN zhe}~dH5znP?C^nGd%(3V;wivg;D{vFMMc?#W7@P)!GOz>LL zA1;UGQtj$YF)B+fg75KmlHl!%b*=F!DeB}>HA(O;*IMm^xQ!R-&oZV-AV#wm=vc>>?+G2By$(apJhz@N-_*8R=CI%zYx!wyid|;JX8roZYd2 zN!U%@~G8)=v3w(6@NWd_A|-*g=@FOHBCJ!$oj6k}bHIC&k%Yxo@&t)${h zjErvekgGmCpnb$n90z3;zkn)nLo$D@BX+1CF9 z!4wH$Mtr}Fkyt~=egJ3OE}19MoL95p(-bf#8g&;yzV=yJb<>NbyJhF#4k>~Dt3M{_ zJ0OYCGz)5qG)rrkZyLXh3iK3Y!9Z;#dbB-M5JFx<2NxqwWC6QoUgb z->TmT>#P7V;FjuR>#$XyX;dGJtTY2-%pBvTXbb93Di01b2F9_W+ItEcd0RIuTRnU= z?5Gth@{c<5whsX*C@Qw+PE{Y`?B<2MQuTLjEXBY-O|+2?Q!YZyZk&MzErK3f?j_IThysXyF$eiKrH^m-eh! za*ETK*hjN0Rb*h*NhJlM%j7 zYe7J&chAwhlm~xUG_uHPLqkG=w6dh*V9K6oY(~0*a`9B6fd;#$%k2_e2HSKfZ~->h zmUBkXwGj!j)fdNI64pN4q>a$!CbU}7BxxqSvQw8gc|F31&CB#od1RPpec558QI}&T zI!set7ak_kpHtk~icX&F%)9O;>UxwqsT+i1e+xz2*aID&iVqf}mvnC?pe!Q{qTXhZgzb6%6p^Z_)~Tu1r0(c)ZQZeddv(YDc(Eua z@@5$Uw`nbc6>yg@f9lANY>ynMqiK^t+y z(4YwHZXw9$k{~aj1HoD|41eYb!YLPLh6*3uV+SxK1{S2v|wssZd%XvvfTBvoo}UkXzuyGSd`RQHg&yYp;b&v?**OEaD|> z9lI)}nE$X)mKf>aBM_$!XAG|9j|YDdtLujifSFbVm6GHOsSx?G%TXs+umas9loIHW ziPCYgVY7QiC@;kkjK7Pt(>NeRTQ`QdXoe++wVe4O&}dcmh(R z^#xM1$UbE4bfJaTwlyKg)@Y})b*$4)H`{`8OnwP5&q4*3M4X8ES@hG3ywMf~b#vM~ z3}UKBUb@(5(^$B-iK#15GLrWE;Wp+&^iCwFb?N{Of);><#^eJYfNq+_9>tU824950 zzGj_I#aQKo4N2>@5fnx3;D=`6P?^wrXRI|gT5p`*dgxlO)mF_GSSW)M)+E~(fCPJL z7_uZGn5$Vuah3k&veQCVBCCwEG7it;!$Jl(M^b~kjk*aK>GT?{o1ki*g%lQ`xtEGy zzYOeFHaWXux%@x8y$`fy)m`U#{@j1>-TPkMDhjAj6>{!PsgFrjsLmiTfcnns3KV~$ z7!!%ESx&kqvxa_;R;sAZIBTk?M;3{gL}f6tlume2#o08#1wRn z>BxBMT(ufSz?6t0avXr~TcQXChz5#i%Rx{qj3RT|)D>hlKeg`ziYNVN;}m7V_u)R$ zDqY^?4K5%Db`R0UUE0MFjO)9wUDGct?9!2Wqb;Hn_dfEhL{DBQc>XGWsNnJdx=X^( zAwc#{4xq5rU2Py?NV^TS#*e9dU#MeGs6)Y@V1fkr=ROfXMnS3!*O19CMX|;|%JI)%VL^Qu)jY(> zyCh!~c$2o0`G6{kOTk=Dyr_tCueniFCMbBcjIdQe&4La)8)v zYqOxUNVZoVi%~02${)BM7NAWM*vxo=yHrjzIL85TxZ_gu!Uh4HX3#kXz(@J26mp`T zxeXS8U;M9O`!WE)zQV2ng;C812P0w^#d|Rv5n%KxbkBtD%4_Nr<&l&c{n?VmKHyXkc$Dk7tO-EOXR zrE=5j%H^6^*$Bnj-n!y2l4=u-7?C&29&qT0h};2#1p8m0YhZ<~!GId4o@5JRbEakp z8-Ouus~Hld@(f{VV20wp4$sh1#2Pa|v$3ZAoZgjk0d6dSh?U0>8_#nCm||MEixTac?U3PnuRY8HJ56Kj}83g3h& z!q^NZnsS4QHHagH=TwZ0)$C>Gg(Hk@V&d6Q_y#6!n5U3=Vbgi);1q`;((g>eW-dYe6gfcO#qRW*RgMAKY zvQmc*V81eXg4zV^uj!NW6^lM0Cr3aTAG+WJ-N+(MnyYD&Em{^aYq~Tia-pQj6LL|V zV=B^9A^x2CZp>O-ocp6vIko8?x-^<|WMOP2AHH1BwYRdl&ecS{&dD=6Sq1jau+D=r z1aDH%-?Qo9LRgXo=Qr4qSG4e)fEwh;u!-}STjQ9QXRZZH$<{` z9myV;r}o!Z0k`6tlI&!hz`VuZ7;bAD)5@NiaN9kNaNE2Jw>`fKw`B{@^M~8!4~#E7 z`6HMG6-+BVz5LvNYF(5kk*A`+s5V)X~(D)FGaYmLTrWX89^p> zxGlt(7*$sAo@UH#=0F&mv9ro7vBB`5X~edF6O$!BIjH0fM=UUfSFnO(=0e!39cVU+ z0rVc zv9t!~2V}&=3Em3cLiM5EC4=)U<8g0%H60y(l3Wpb5@^MKn$WFEpR1aj2#9D5?Uz=> zffM*gp|AnGR=Kn$a8~d$ZIhy2K`_8C?7I$ZT{SXBuSo*d-4tSF)jM}RtQrK=N8EqR z-(i=CoKF&=tX*gjaCcS4aL^Wf2%0Ef?=MVKyGW?WBvZ%LH=>=om3Ws6nE?u+;x`-bv z=mTw#si!qWC-QWkKH%5m<<}K7za8k?7Q~8KbvgcV{$0&7n5LJ0-r%e)(hKYLyk0An zplBP3|J97^);)+B?x_x%rblRdVAsI}TG&!XhVUNvsWPk;y7#_nTYm)DI5AM}B@^t( zAd%5Sj%bz9#~AoEQ7expG9j8n0#NSQahjFC3R%YB9+7v6PSE|9KC0XBG-s-m%>#Og zfDyGAgHDaW-5QOUsi?;Woye37fgXYsi`Y8fvDV#8#oZ0&ReJlv3qrAbUJx35z2108 zwf$m0eI1wg{am(sAW4Ef6YH3=2TF%oT;*kYynOIU>jh)E4kS0ABk1v?f1RzqnkU%E zxqIxl8iig~VlqK8Nlj=Tor9qi=N0EIWy?t6p#dH&WzRsdpx3;E@c7ALQ-EGkNJQXq zIY88rv_c@0G#P?xKb;mus4M#c?-w`^V1;5-d6)ysD5>-Enk7S|OkTdzCUR5I38+UzxT>?U@R(s-y}DTDKxI<=c%SU=lP|c zb^UVx?s$I}zx2;urxbh+Fe&ev$2(Nej?Nl5&sv_U%F1`{U_GNxFg&^Av*P9Udr@Y6 zUSsPQY4M8HQL0*>CB(fTgaiweBF|$_nl1C0TRK!E<B-JY77=w6p?1!Q}GMKLifLUDEI=SMc)5RK@OO=QO>q;}V++DBk%eTl!xM%X0W8 zSr{4$XaooXxtRgZyhl?|d!KX|NrJeyV~!h|-&3R#a`&NP?~WfnosONN#2=QaMB;r# zO4fz|=*Qw~*GF}F7xN75tMp87>`Vd9MBLV$v~vb)vhBf}KJBZdZ#SiK(urouHLYH0 z!w*L&C<}5EB=V^wUtex;QXH}$~Ebs7>_4&7}?|9FBzu)W6_0t|tR9pPh?smIb+U?KJ z&$FN;z-T7sg&=^-0w7$tdOjDQ5BD@4_Ns^fXUbE5sPb4Vr*6Nd+p40r%gN?cq&lw` zm@ubbWqFT5oW8i+q@tHi)$`TqYR_-HYzzw|Er)Wcn(U$~zz>{jzA zc&#nwNt(eGjq>}(oGJ$gwsveME zJoI2#^+4+%8I2x^ckna3syw$pqHmB_kSy(gpfjgYPXDEBSZcI4YH8q_11EnUr&u&4 zWaA&nMk$MrzjmdD5i&ketrS5)ye=*GU%k-g=Xc2Ilk)qQmt$oBF%QX4YK&aTaZYC&nQGqMh8&6-H0L5DkR*s z(|vm{rPwfMcjsZhQOZ0EBUx!6^!d~aUwIBE0_7eokp?p!J&Et00xxr2K%cD z(wHKM^fRy7=q)g(qn6f0ukub|7Tv^86*@>a(0trUI@k;Aneduh3Vc($*Cc^57s}5h zywkK@y?~UNm2D|h+QznEv&UepC6m^V7s4cxq{!b>FRydfYuiF>V375F7%y(QW}#HJ zU@iJU2O3q=ykp4)8YM(wimACJSr``WAOSE^oCA5(tHrtpLLzfrLOvMj@Mp+l2O_=} z_CfOl^yBbYI_`KLC}{1NQFr?9#9?|Wy}e!~x5w)f>Ft3&%(0jVXk-m)t!OF4 zIpRQuwZ&cncJn6@EIpToKeL#jbgHz!a3&HW1J9(_(5-H{pC5S$M~f@zsKbg^t(q<4 zsQ1Ht64#YbN-;QL&wi;#K(C8EeV#zePjFkc;8v#g%YiMuXl#r#4o*{O9I#Q^!*)7`%*S~<(EJ4o}cf=;`;JxQhrg%7e4f_RHpot zJZfS0>L*$7?eNi8^ie4J^i%Ko6)r*7HYFLj4wxyQ{`|kd;jBy~jH=TwKi;ecs+ngw zy1`WC^po+=J_91utKD}3i#GbOf6&+-W*tuA(8n>jL43T(fz}yV0il6Tro#_s7X*6D zAy&uBJ^yU@A#kN%e(*uf#;H*!Oad^h|6YgJ;7U+B=G#ygIpQySM|?xK7TxS;{R z3Ukwr!%6(}k48y$d$Hqv@xf#N@V{qrcRWbR6+(r>pHux&hb|>$k0r6=p`!EAhh9$y zJ5`AjKjb?mM}Kk*STs{~F3aIqT4@?Y`S7#J(IP$OdnmzIpUaM3nacRXLROLsMnunk z;lIhH1r==>#p(vu*H8VRic}3g^~r?F`6P903p{L0MSEe?hHUM z(=v~+sBs!BrfnptaTcywlhT!SAX>stI3~c2i=`>~z1^$?$ECGl9Da z>08?cd-meNo^1>4qACrrXVYM}>cJ!OCB{8nJ%euu3IJ_^j+ePoH)mzW zp%y&BA< zUdRrhN`oz$R$!mBGJmENGg?+EO%u88ti!)2gb-ocGFu3Q$$=g(DMCzV3z;EIru@V< zTj-LIdN$b6^0GBrU}`ZDfEMDv;)!$auk1LaT+mWV%71$?IRG&DAjrri zkgl9!BcSld*aNnG3j}>1;bSuTd>qLPDkVV#eol@OD(HF7V^S(%uuOgF@K;0Q7A}Sd zVBJ9&;NRrrO7;f6BGUh(|CryH#j!)6eOPmK{iOsZ=u$WMe-!YdlMKM zm%D*)|B7VZ>>qKc$gYt{$G!+r2x*=LrXU!Ke%_=XxeRZTAYUa6=SfHyo=gImDc1~O z=4L$;ytF7|!f-zeMm&t;KT&qo?p)BAyZv|P-C7T@-mHbm#~G2SELqlYDkFWRdzJYu z>L5y7{UkeHq_^Ehp!!dgPyMaafdvnbRX!!$`Ty8m(^Zv7*wQA@6d(PH3l^R`#8p|E z@B8!A8)K#Q`)!!lJHm}xO;y#^%16>F@BVgZDwkqOD+?mC$Wu(V4hNz&veuk^YoQNs zqYt1mK|aNt73U5huvbq#LPcPdlpvr)Kf?K_(rG1c)>rg7>1oPM@zk>(h%i3wcRinj z{?BC_W}r;hVz}jI~J3r-7X%FrY#)t$(EA z(yY_rKkj1%=Q*7T=9Brg#a5DKiQboZojxzx)4{MsaRh(^h3t30N=83=ibf~LevRKa1fCRlV-+sIVMSV|X=34(>D>WXB<4+Ts|-6YaE4PBh>E1!~? zDTQ|JV`ebuT%2AA^zwsAp;@IH2UIH{DDMe#AtQd)|JeL|gDl8YAS1!;jO&pQbJDRb z%4+pNWwxuBEF&=*=qBi?v|I_N@!Btk$&t z>H=k(HJ+5e?m{A>M6lvCT}9%!p=HZv`Je?B4U*`EP?-)>o>>1|6Jc-Ek+>H{zM`{* zfxFc(a0{JEt;3%@I%Z*&?IRpNWr&6anm<5ttlP23foeiGj9F&!aJQB8T^ zw!umdat}&W)seFngsq7Ld=;BN-4MKKk4KHh9$Ykh_>mf+dT# z1RHbNcqzjwy;h?`{2}}Q#r&ww2ifP?2=kv<1P!!CHb7_iAO}NH2%+M z{CJQ;-Sc6D^BN(^M5af`D0!q2cHN3Z7jS=_EIA68TJHpH$!u+1EJN?G?#`8a4ab!l=m>X;bzDAb2TUgk53}s3?+`zV#=fv=L_EQpEXlnS)Y(ou78u z?)M)VY~qOs)>V%6g)BhY`LVQ>lwXYL#>%f^=$X&b_(#6{y!_XQkt~y5`N40}5Z(|> zqvw_%{}gU)dqnt&zMEe8_J4^vM7Xiu^xgD=?*^9kW42`>SxoPc_OLW zYWye6pupK zUfdU|hMju|4?`tnz+u51Rj7JYAxjLjqp0>pgiTSw_nHF*aR$*}7r?@ZK7257t|u)@ zcGJ2y!By)Wde<0z2;aj?t7@=sQb!>rLX!KQRm63G&s)v5U0dukCz8gIK!J6Np;DqX zMu;H@bq$-t^|a_-KQga6dL=B#*M*w^ZP@r-O|5-_KlusEI&OioYYrqLKm z-W-oOoW>I-nAr{iEzR-7Q1URInR3nXG(Gv-+M?0)%L3WYMmeht&mbe?TXY1i zq&n=8D3_2Uj7{sFcE|vo;+zB;Ks}HKghVKAKr@d8;hn0uF;+0eRS<(IDJ>LnFN0YS z_qI(jR^f$u5Eh@9g7CbO1vsj9$>r=llO4 zO|g+dpmXYcvU>~vuYNy!(0P=MF-+X~J-WPVXO@sw4ffpc|4l0of;+s1xNjd^9{MkO zBM#o(%SHFKaLVMGtGVpG7UFvw7i7GW(vMD)$QP5!nz&9znH=j0{AW;cnL+tCA2yd6 z)LdrNk3RZ=IZfbd1=xteCK>)w>db`BC!$OT*7_F+O~VL6LyX`fKn*BphTG-0UoI#} zb>S7A#;z=yFBh-Eyjy`zUkRJX|E_tn$ZTYB}@CxBH`| zBxpcPkaNB)XzWz1e_9Z0%8FO3GZBjwieqeyv@HhWG;uhMILt@JVXBZo(QN^goY;r=kWK_k&+v%42Iv~ z*)H|Nloz}ZY+MTEoTN4&mG!R@k!_Y282obvNFwMv&+Fdzls&d{*llpK=*px`9_mQ~?51j`FchhBMT1q=s-4t| z%GcJaTuXX5>*KKgf$(6r92?5)TGB)2j3G`uS;~Jc5dFQIG$%4m!+C=ls-e$s70uU3 zI#vdh1XWQd6a&R-5Oxb(6VxlQ3YTm+4u4^*Mm@0~O?oX{H9N8`VWioSx|YT~jkZc+FVv5iFRi-O|7qe}r^BN{7>H~;DU8KL-|q3FVkf4^=-#6R`Ao}qhtMK6PB6FF z%CPA$auHv$vTmBe7!MHTk&q=IpukB*gZ5BfsaQiqkq&lOWl4D_P0CDkmm-Qt zA4v{l`QRndD*H@AL()xQo7&>9gCz%)PlM>9g6bQ3zkU`KQN*tIqRa6GglJ55zLV{z zk;Ay^nEEGYA#_rG6fdj($^zB1D4&(LUlSu#EHGjE)H21P0ie)sU~c0%=}Ss+T*@>+ z--mm(OmLZmlPW+^gmJw`xDw(_glE7DO;5sk365~Pxii)XYv?frt1$6^#-6I;b~i$kPd7qS!A$|0yxts|9iZ8X&;%C)G$}o>eF1PH6ahh53c=L2y;Z#8JU3?boogUW1YI-1qAeJ~X^Kw3$~Q4BT>8;EffgOkOM=Z&La z_hg8pXzXLGX}jzr6>V=yg} zJ%$&tM0zAIpE`CnUcMG|cY~L&Oz<}F21A92skYYgFYCoimBG*p9`xUtCP7EYi1rJ5 zCDcvW@@XBAcr^kBHpuKeS_-E!9j(@}$}yj1gp+ zd@~&d*lTEJI@pB3lBondjX2gWlnV7r`aH`zsKC%K59wBnhB=AzrMap)d^b|na2vyP zSV}M*mVHo!I}gPepu4XJ%&hk~Y5HOKlKzp2S!x=n6dDn2Meh1* zdx@xkQJEmr!bj6Sv@Kbxf#yXb=*sakRwoMO>*ax*r$|l`uRNbyBGI;lovF-64dZGjdMs`0_beXXdhoM+!wpgD>pNRMOe#9Ggb^f>=; zJjr_RdeWB``PC{1@{TjM*lzAO%bI|u@HF?8>FA{Z^mMS$jAmt&g$C8Up@y-VuVDOQ zqQ|D4W?2KqQslrykwh?Vg5XV4mtC2$4@GMWcjnZQvWe({QiQQOn*+fmnZGrJSmvds z;wO*7@<;9fq%EunHmZYaqMIS4--hn7>7a9TNjRj>f!5K6^n@2jvQ6c>-m@a3#C*^f zw8pJ)(_=7=j*GGTgpgo}^fPD?(r>5NI5lULY9Y3%yK4^#^hFVWO}H9PO8UJ zJR=1sr<4{pyiY9?-W*5l)gud!?N(TQ!>ht}d2j0Wh`ltKNR2r4oE7Qb;4ft1dC-n4 zA)MQFsVTQ1*&6z)DThD$3yBhvx%(GDe2ZKG^y)>Tzr%lz%>@nenRahR;nW@^ER%ht z4zsHA6b%7LzHWtUJX~Fq37P-P!KfE)N+GTZxB-$9zDpTEw0lg)>?b`= zqTGC$6522xT=VQY@Dpn<^Ff#KiSSZlkYM*DnU-{lS`t(ly9215aD{-- zT(|3EgCKnPdg*A`&eFm3!pf3@M4&-T5?D8Ljp9lgwW2z4*phNwB-hcN9ZS$sBNz-@ zv%=`hU;7@+Tvv($OSwzR`*VUHcnM(8FDJmEX#s~Fw^Bz18SAY96jaYs)nExi0G!8i z4Q30~ho4Vjp6o)N5Y2F=@1DdF+3FAwi!P0cwzyiYvU=0-`J_k2-Q9BA zM8kVEYwC;`I1XVN<)68|N^^#m3shLa!>fP*w{-Ts&{aw%e#8a%c^D{A(eH>;Al`OlImMi==-_E5yPUySoK~- zA;}W!hY$PTt;_cN_oow20(%D2{Rw9DOdw(~*|PpJ>g{;0(~0Lgi=JzFNQS$>spz>* z%MX9lrrxynDR|dmT6?Y?8o87m(TJ9hj(~I;yd+uw-|Xo(XiOEXgqaIUqkQZw=A)(g zIl?zuBjN6FwmiI0GE25x-t!yGgw6aJ*6oZu(IPP5+&cU6xOtD?hlou*93I73hNtAY z|LG`>VjlF4@$)%{Q0-->LHTEQyy>X;<_)Y4fL8sj`E~hB-jG{*l|}fQc_kq}Bc`*Z zStSrY86gM*=yd*-520W1zMK{$dVgYoH zcakdD#>C3YN|aFct!FxSLCH%H>2esG5+j3c*v0fvQ0-p(3#GLC?9RyD|zK_H}3D^{^7z`EfPFJcB zz$=m;<({86mLK_u66HYAkl8*8$Nlv*lza;VnY%1MRAeiU-SNMz_b$r|Ua(_QF*x*0 zKX=O`j)S@J=y8qfsi)xfK#6SR!^fZp;Yq&X30-QGdHXMfugt8;iNWQ zYGsjamSm55!ZY^BmI7q==<)K?;oKO4ShYR)a#qgY{uV_q;ld#%hhWy#7GVzZWKpx5 z*OU}>k3ydzxun8HlzviM;Z}$LF&!t1y;kBs=KT1TvC27H0u+U<{t&Vbk{IjT9InyL z5F2e+-y|WXij6iBi2P<1R_N^{vokjYMtgx1f(ptFzgGp;vltkSC@AkXod6_dx7i6! zrNJeuP_=sT!slvHpV2pb4O?xF=d6Wh>N=VRIHG3EFYFP?i!t-yhH^bSHhdfqc_qMd zfXF-dT)lU=qP3#3Vj?nCs0wHyvm$n#44+6x%%fO1j|QGtYk=YguN$*u-k`>)PUw^j zzr?C>kh;GV=E*Jn*I{W<3vImp-%=CRl_WnzG?jQ0q>p{Ue88hU#D}vOO>K-ysb&Bu z3XYML@*uEMR;XC1UX>5Nj}YzQ{|lXx3%J6}IQ(RKfriaugLw)>!`lKj=EEt$o;N=*)v0M(<+7-+@6a@@h-{XvoJ)i*34W`u9x z*P5UwzNxbM?v>S7w8D3J^5B|p$y9t!p=U@D)4!PrFIe&zPN=I zWqv}~v2aM0n+k*~Lytq6BApb6D4Icq;3h?e{~X~E%aYM=#muYxfZH$c_s{V6%9lP%H-*CV+ZC~4B$5Xa1wj(L46?Tl53qQ~* zp*j42Wbg2sY$ns?8dReHOt-0KG`#2mLmg_xnirGJ%AOBlYHkv@+Jmsa z%H=WfyepRnN_5EOG536)cNYCZ$c@N%pLb_P9 z>__E@67gqx-RnCDKv7Lj&Ca73K&GCfEnf&OUMWoE4KeU`2yhO_hWIhu==fL+5RT?# zujF{H{H8W^B@TCpnN<4IP#3nVBhYCbIKW+wT?LWwdF*^M&`0Un2K0jqN|cj+vM1MM z4?uwb95<;){Id!47j0V{59R7vgw9~DRop}Ec;c*a%j6u4lhQ`jAkmj}J^fmQ2`1 zjG27wgDCy6ib@{vR~*=?LrF0;WRi14qGS@u`X>{bPJ{Xo zYBL2b3+*8gbE274McAB5-$d?^IsaLa92K!+0NB(#F#AF&MJgh`%Df4bN|-5sLz5H@ zB$93y=~|KP?Y|9tYY@iz+Wy=ib<6Gx3rPqmTIR2lEfJy@J-Wo4vI#u|AUQ3`Liw;Y z(DI*03k|_FB|d(qdF_<#Yd!q(JqW{XMqs?jb(&iTGxeF#FbhuG(he?#wg4@xp2X?{ zOwmnjkgH^1j^*8zHZ&RHz6$O-;%e7Y7j8(XBn09h>!)#Y6gysXNq zpnx7Mxp9BnaQK}e*rrRkBU7qT9^){$ zL>LyYdB^P`lDVMLOtke`3t8X1Qb1kikhu z`Lqjiuu8VnGz}*C7W6Czue^3)j@CMpcdV+8-*zX@Mmr+RjQ?~rEpsJO%Tkh-eC4|| zWK9jWYP8aJzx<=8STOpRH^y_swe>w%`k#C5f5e{u*wbM>ECI8xe&K)pH7HA7>@0su z8+giRZl}b%Mtr~ijSNGJh^k#F;`-4i(un&jc9?VnuN`y&_=5~8sCmG{hjrf-#IUVU zn+idfLtHUY)J6H>hZArI15Usl64A23zkKfYqeqw?7rlfZom^P{A0JmyOh+o34=9=v zvas_g3xa|LQyU@6IwO@=AQ^y+*|~#=riz@7KnV$vZmXbdUw zf?>G}4_GrA8ThG~z_81m@5ElbfP?`Eb5sT}rT+9HBDkJ-^1Qbt%~R<6ps%u_X0+i? zh{a3$Aw*D_m&rWZtB`24NWU5wiHM^R6?&o{YN|Gp+shOdSdG4vW4m!HO|?;1UuqC^ zxDyLc3To-NR?S>pLc`)qlgB0%LfD_8K5VelYUf);Z}CBm_6z05P90@#gu%lL#R`)V z8IBwsAgHGD5TuL`WJPEgJ}VnDA~hr>u@6jISI0y%HyamC4zH0;;bO>b6fN($0uPtb zM>)>mdOU!R_ zee3`1;s5$Y=hl3$$qPeFQ`ksdKZhr-!|`|ETuDcqg(IE^A_q@r`R>yx(8HLVG8AN9 z@HDyRm`I^$s{&yekX(`++T&}Vgw-Mj5|13!@Iqmr%tNu~SlD(!(B1!hv|Mi;laraI zYG{;)8vcm6${%rY<&HR{K~g*htPH0DR(6XyJ}@3`8nB|A@h~h7GAV{9i`^T%5pxZ< zK-{d+tGp5Yi8>y`8DK8LjhGl}t_oYx!`ZMEJp*FXVJmtFzA@T~Golad6dWufhQvB1 z8b=wA`beztDs0;ABccY%-^Y?w6&lo62m>z*PoXDjocf@JkaUbAjx%jrw$YiS za$1PjC1`vbgRnbRdSG18LHySGS!7D**mK_D=!ZHi25F(5PKr(TlFKnW9Tuat^mm`m z##Ew)Pc|GhrxHQ{AKxPM=ta$8oWa7A&1`DpiWeMK1s`$Pnam}t0lLd`8SLQ|90jL^ zUZfnB3>niDBlw9B18TU8LA#&buZRvT3jP=8cu6S4q?QI2kG5r==ueDFBo}3k&oQ&V zZhKeMd}D9}NFZj6BK#3i3h;+Z#wKYIA$#|DzVwcDSmo-7s7~2o=M@}L4!lhr_*jvw zPQ(MYd^+j**-*$yEoU?S@*EZ>3JF`C>9J(6wK4w?n2pT+GNS^L1yDH55M%Cd?v9M- zC?Uu-%tX!65PmT+?#*vu+-rDkw1Z$$Rf(N;vb?Ir#bFK=x%|A<)90g?ofknbd(B1G zz;9{!JsIrsBrXcKIM4X^&&Wt?6DdxMjBY{6N6bvV7Ky~j?O95(RmPmGdzur z+XAL2e!zm|SRKQ9vAKA}Ag7;caD zE;MK_ikIX9>Pz|~j`mhqI7)=5QGN@w=wT^^4=2~{l`c&t7zh)`kIkP=>zyvehvsr=y>9^OWe~j2l5SAuBdM5#XN01lgO1uGSD+?l7vJxcf?ROWw>Npr z6CK7mfzHbLn_{qa`SJY9na@7-Yo~wr-#_>ji&tGHea;2HGF7lV^A~Ubj~#WwOTFgB z&6(U5^={52owAjZru_SxdLSd=dj%L%Du>SAe}1$m`9#}|y9ddS z&TO%~F3s-M=2)mE%SHVde<%@Zhako|HlUXvQQq|@$?(fE zI%<=k{DoiPpKIDIm@AS6#<-|&CFh3Xzxw4^oKD8#Vy@&OF3oG$$EWGKqjx1Kw9v+> z1UL(n@EF!ue?(0{9N+Y*;g8Csrivd=3A@tHBSdf*PaER{I2W%uyLxAJ%|WHTcwIf} zt%fU1dSY7blEq$}PXxezuAN|OzBpe}E7VAr%r(Yw)Ue|G^3IS) z3(w=uu-X}m=TQiNLx+jcMhxbLh(I$*7kCW#iSXYW+?t7w$+$0GzmDtseT|~cML<~U z5o>=MIfnnK9oa|^9{4I-&|F#+S-4$3sBg;m`r#2Ch@;=-evZzO1zO2|cG^uZiSbD5 z)C!X111t0IIH`yG^v|Bv2TqNLE9>`s`SW=Ze}8E2X@apikaTCqSbadwRF?I90R$;h zI;YWTe>tZUD-l{W?fP_QmfaNz4qN@46Ml4>_jy+&JNQ|+B7qd?9Y}^Se?`*4nSm#0 z<QgIdL(BmC`5pb(b!Xz0B5*34)RKu3k zO3vCISLsfwsVVmCP=xa9cRk94Nf(JoGqd=K6=h{k5K4<(!aGm-gh^{Gc|FuKf=7<* zMG<9LBM5=k%n`dzOLm3qy&~~aBgqZffG|4~9}BV`0P{bujKy9J-6FdvKXh4s7ZyRS zIRdC8;a!kXO^w(Nte3b)fyc?CB$Vmx>`AYBr*tYJrI{welEk$KMN8){`AFrq%qYa6 zw#%1Ynmx>KU1iu*u!A=blb@E^T*94yfxi-gU?b&aNDeOxW*8l71gU0dgJN)TiYbMh zcO2R@D0Uo7M&i<{;Qp=02#>i& zxdC1L#%&ho*bAIT*y2R)GCIQ2KdfFLn>k_KQk2Bi$)G91-gRa0;IwH3%1aHjMOS9D zV9xdQ5g0GSQodZYwO4H4xQz}~yi9b9?F7&)vhLBpUF zcEwR56jb>=8hR`!Ii0#V(NDEkrDAoeYhR-$6p`rg4C%pwgMb~g1&h?O`_ zcr5O`UjMf`Eo`1KF-9el2)BTXb{h&tMj?8`%ri+Gb-{rz9?^H^OX{v zR7$k_G^0f88K^L=MC&0em+n`L=)cf_Z(5L5bL#;+?JkC^j3Ev*X$qpU`%8wb~isW@vxV#pmx0Hy1 z>grH^wNzgf^_62anJCc~e?edB#a!X7DZwfwb^1}mc&FcVzLV0w1Lbt(!|uO z4n3?UGcP6)kJC1IFQUNO*l3|cFLFK851bdw>v_)}Xor4A@G7RdTmjw(prLtr6&Xr7 zQj;sR9**KtojQn%l_nyq{-M-E!Vwmo*MS;H&LH$=c3!gO68&EravOL6ja+h~so-YJ z!}UD5TaoRH)z*1b zY}rowA6aNF`Pv~^9npqI5dKP^Eujoq^$b)p9N%g`AM9MF1%B)US60qB?#RkHWa(=Q zp;qG}RAW)X7XMHe2w;D~CXdmUsQ{T=Svdzd0a$dhQZd`OT#v)STjNFDPglo#d2{F4 zVxSEM^l%R*UK@869`^n8GRV@H5ka>dh>M6x52oV*D@NlP(GFg7<@#kTvh^X>9hZ}L zj&V=|&mxV3SyOePWM*qq)uCO)jgvS#)=*=!;3L3Z5KaMb=Kv7WsIi7QPlq3>Qqvtw zUR7rD{m8=bnS0VvYU&mDFU!qTlj4O}r{ggj^4RZ6X~mU!nQaVXJvrvfc@%64v=sqEc;0n zPyfOuRS2!BJ~MqW+HI>U{${f(Fz#+$h3HoRgJT>vyB3c?57x-%3MQzK|KSKYrdbJd zVN46i=;=JAgo5)-Wb5d7Cjik@jb+gerfeV!!s6a&flEVll?!M$duw^s(ei3J_!j z`%0gc>e*tIj6l8-y~7gCKWy^TmL4{=Le_N8{}{^De=KE~)Z9(I(PwnG4~V?m+V&&( z0R3h^Ec6cNDA%}9eXYRxZsAN7j&8$B@8@W_`vm1;@fhHQE=g$=c@lYG#YXx(HKp0WSJP8~`L@=m_X2dVDXs1bqpDs5X~v795Q{L3yHHqr8`y>nK+P zRmPlfn5ibodBmlaoCkhQ0UiIqn##4_!Y8sm45%-yrOzN4yPa`IWUswozSFb(Q|-mC zcjcRoR=rX8<=8}^Qpd_iY(DM(a(lzs9A*`AKC0tGlW7nJsaXuWC5BDUWg=$bi8&EZ zM}C43!ihv%=O?ht93*CTW(bz`ahM(DjKc8EHko|0VD}b z2+fc-o<^ym4wmM?cyV&VA!V7>UQ4>6t5&eI=xq1NUvQ?owpb+XjepWCJj>hdmc(5r z@vtTZMo}SnJ-K5?y^sdLv-y;59MkX1uO#YI^#z)Vdc_X41SG?#a4sYShR zMvYJvNq4hD|k{{Ygg6w1IQy&|2vu=fOQ~^-938!Rqjr*&=1F zQ){)^HklN}m$v$A;}qcstof4j#-SjD;kR|5Px*Vv)r2%a@cla5>~&6H&ZK4v#_-*p z{mn}c`sJ6@NNC{GG>|H^=jq9_&l0tRgYIDBV~)z-PbAof87sd|F`Z(|+sr-u!}ylN zj*{{l;ceL-r7GbQm&#AkgoN%~C7w_TEOvG6A8*$F#o5|F)2#g~vG%-K`ya#-uKlkj z-?!X5waxsn-Y0E`;nyAb^rQnVMpkB__Aokuht8Iau4V6gco_imyS$tafN7O~5t`m? zCeX4rnbusPGMP=>(6=sA0j}0@TQ3117m=QUy zs@fYf(keY8&Dt9?(t>6&o7BG5jI>J6Nces-BLW&TQn&qlGeYefW<=7OXT)NrQEf6K zaxJsa?Qqp?na+yH|G+-^XOfbpLJ zG1Lv=qyjh8K9$$|ZD?P}B&f}HtV70wCz9B$PciNC%~mt>xe2P0sY2~eIs}S%m3kdM zUA+tasaCMp$k*N9PUvr#laJG1Je*;bd=arcFZF)5(;Z=~CS$hKBu6d(bJgiTp6N7$ zn2?Vr+;}TA9+uc2(0GT&-SNM2<9a{axU#y&shkF-4(E=boPJ@<+^oCV*>;z{y-;_v zpaN}#RccBRCm0Iic$NkVo8m`$VTL6&Ya=+6s$bmr!vG-y8>g1G(#&=e({4Y-# z+$Ywz+tm~@B)RRfWdt%Z4-z~~j^tH^lVDW-PA8n>9pwbf#*w!whR zea{TrGr(}P*Gr)pw8=s5R42- z{pz|(fuT+2WBKP@f;ck8jl5kdEb5^8-|a}K$^yaWF@#$ES%Oh^Ka&y zz)edmhFuDg*HHmH{x=*Xv0ms@yQ<;7{FzSo%vVO1sds){Q0o}h*d_d+bZs-PEp3wmIG ze)-3LYJ^G3ixk;GyJ%o4dB?jmt-$_C@7`72VR#ISYl0Uvc??S)>QNeqnHBZjGs8M7 zQlm3mG&0bE=EgFSfCyS`-iAHly{yry1~>t`vuk8`R3g_YV$ z8yqu3vYIE<{DItP2tDQ`7zn0qGWX|96Z?cQ=1D0``~Od;VYdnD6)AAk$YZ26p&F85 zsfV~4fe^at5OJ=a+NS%%Ua`uswAFEm4fjXEiA6#b+F;NvP%8r>(aAFs<6s3cemqhr zb^;awk=)a@eS#Ig%i#nsCuYw|9X2ka7W7{X2!mj4hQGX4c!>@48Y|thpy%SGRPiJf zQ#JeMe&&1lO;ks^bg5n?!@o{L%R8!NdN{PHeug*7j}Mx_&OjxBn$6d$ITRex7U)A@ znj=K^P=J>CGFZQSN@$uUl$t&r6bZ0IpLfg^#Y0m&7rR-S@JCkJWO!4QIx(`S$M{fw zL|F)jZwk%Zj3O5?qXK6fTL^+dO+DCUTTXrI)5Zd{CueH5T!kLy*TV&3=%J47nhrgb zrxY6knk?3K1!KEpm;;Ug2%8w#?vabMY39U zd~H0(Dbf1i5-pN?vumov6j*E)TbXgFw0%)r0OQWC`XL5KdEMZZ<)8d~^!5I$-{HxylzRhJ`CUlC43?ZR zv8>WyJ#`Odo z)H9t6fz5I4O07>s1EgQXuomLVVeXM=xVnlf!gW_6tBQ2j4MFL>)hp9o+;lHaa>zpO zIJ~*{)?;H18`plj-dfrDaURLOreL->B>B6)ts(8NhEz-qpKZ*$yZ{C7gaMMrjLd|r zv~q0fRY)*lVBJ7g$*6AuDj^Ut%1fG1s1>rtiSmCDTJ-knoN7w!8e<&P#sPdP#uK(X zz>b*v<$SsPclRiJF+zmev3=b!jBNF}7Naux8VToSyd-&F)z>#bbO2P*A>x~_5YiRa z3A;woq%#V+!!?8w^Qh`out-e6NxoLiXf{2g8T%>vGX7@)-vQ4dDI{tCj#gkMb<9_J zx6R`PUbl*3*dgM0Wzi=Qj7eznIAebGNc4e3i2nEn(H0_Z?V!;48C*Hm8PiN7$~goz zQ}EunRVmd~2#Ur)9uTa#F*3;}kym^+*|{ZhJ-xlhG?U_SpKHD$&MbRi+}8X>ioYOYv|CByn?VTE&^^;q2yCJ!68aII|FTrH27era^_4tWl6c>|uv4qbbtq)3SB1ld_>th5AD4 z2UH`gym?YK=5ykblrEE@C>asw@aghE3HvSYuD1e62XE~jfO4j zqMolJiF9TQ*TLj9K|7!+$;3f@VW`0hBGm~PTd>tGrdpnDB)WysZ9}%`O&rGRXFCf*NzI2e)XF6(H|w7<6;6XXO>1!0c>9rrMa*?*HHIW=?o>kXJIfMsF6Deg{@dNyAb$pho=rlfvOq<*gGo-BHb_rrZL2`O$yyfPT}-?5Xk0l1pfOOUQe z{onog4MsVk^|XiY6;TpwET2_upX4V+vLPUtvk7oT=N6zFV0+&y5cciYlPGFnCPLVx zgd!>dFd4EC9!XE(Kvf95kHTUy1b2y@-%4&}*)b8uNhzsbc&xdr9WsxyAo)YpJ)3Z- zhs*M@i_^CH!BQx{mtAHi-r@Gy6~4N zBd7r5Lju-)fPoQ-9eQ;4$CVNcfDE5WV^6I;<5p!Ng_s6^z?Fv$O2nqB$%l;W8KcljoiMa{4Q9hZm%Qj zaXim8GPrEnu2X)PmDd=>>18^6I|uqIJ$$0d3hLukc?x$~@DjeNzAN8OEUrEmT;YE( zCZ7hu{pHGgkS}(Uls|K#N)Xoi!|+AoFC5Aczqr87=%67^ytVKt97v-0)yn@u2!cQ$^ z*-PCfQ?WM~fPt5Ip$=&;ixrTES3J_DD5?mfCIDWoslMX%a>yX^(8V#K#sh54=E+@V zm4gCZJE6!`nKQSq6eoz6)M4d{HBlBzT99#GS+{lBl?tH<&J)BhtIKa>cI7;jmZsjp zr=&VK;30NR0+Zkm1Lv@aRm{WL@Eu~##R83yEkXiFpWe%PS!tJ8xNoQ_FFl$>%D(uc zXoObn5TRRW6#U03d@LathrT;x{jq%0+NN1 zOvXVOVT5w-F$7_&2AW^5;~jZUhNL3DUbgz{kBtyq6+P6|6P*D`gx=oq+_mKJ(F+bh z(F=_0ddaaCywD{NbVvt;<#m{>`g_ZqwdU zu(W0lTH)tOSE0hY0g}F-1&E5hbQ$SphVAUS6_x`HF#4g=q z=druT3+X*fLc!$(8zuGzDk6|aikr9-)A*=BfT9hhHD0p#OV$cq2%tz!3-%yQHBA2m zj8Q~Qj>CcX-PWne0&i}A-ByrcbNefm?$PW~H|Psgqv#ynCgFsgv5wxX492e!45cm# zl=T#4@OMp-pc;6YL|-xIoAsj|4gR^9r>{XjxE`T?BSI0dhvDdy8{8gf zD_u1QB9IE{&Ww9-dpB7qwJ(?5#xP#Qw0UXkod3Y-J+7)-aw0~oB8Xdqa%J4StXt5@vA6IeKkci=H;ECU(qz;2oETH2^kq^wHT zsj!mva%?{gIGUzfH;3j2Am38pj87m=B)QtZAjPE zkSlG?g$;8>Cz&6;6=Ownm=m-94M6J&4mtGW0l&JAI{zVhv~tZiKzp1K)fz_oc~h zeD3nDj}x5S2~*6quli@6&pY7AMy+|T`;?`QL5G!(L>(7$ppmT1s9doI*oqYvF^nkC z11)9z;abWve}VBpVzQJ;PlASrGQ?A@WQ@Eb20G!HPJ@|ZhFqgYz4<5$8xEI?!#NSg z9>w$mU=ql(s>FjZ-h&}TaICLqt5U5bH4&Y3928^NRxOU8%b)|>H6Ay!hyf*U6 z292pvur*M6kg7s_4*G-c0flInZ(9d2o4vSms~7Lk3;8QTRY1j61$0(J(ip)y($r?h z$Ix!+<2){swF+pG+bc2-AJZ|k)JMM%RBnSVdIzUS9xZV=G3WDuSdqj{%F~Rtide(X zi$1*of<6GTQ&G=O`7fU^_3TWjXDd?Aj?8PFVA5~(ug6hsq74G>8>6K%FB(I^EL3K1PfwQ-_xH`**gRyW6S_t!xojnfql-Z zWy^YUGxOx_ZP02`*Xq$*@RD#RnO%w)u|#d{aua>Zl^dGhrqCJ=$~3iPuxy&-OF-ZvI=&(F|KT6maaggEY41Z!I+kVkxvU2Ktjfp4hTaA zP!=7;G7D2^t^Dz?{qMj1b02u}LpMQIOdtb+5wSsNNMK`7DRh$|$1(|2Y^tA-tIe6h zr3tw=RJPbo*+>TOO}A5ccc}ROZ54*Jcq<@txX){%ggDD8m7Q_oFfN!8b@bj8>tBd` zkfYt~*Rv3XwE_AxL?g^h(K!L+?azix^luLAn_32A))pwkCG2$~$u2^iRd7F>Ov_(m6%I3 zpT>E@3+;?cXhzNh9gPVa2$)FfZrHLkBI5}5B7JdPtb>P{zy5xc9q6xi3Pa^qxZHag z^rz_d|E#mq67gio%PT&)6LfSgAJXxBB^^r(W}lk2wJx3sK>HCb8Ob{yY(i>uao5}r zwZA+vSv`=sL~&$@M)bsG;2UEf!v=4!9xcU3F#hV%Asz`I*zYBGJ1e7lb9sD&HyU%? z2-L3L5ZLCLImO3pW)@)kqii9Ua^D3;0_jK)1^c!{$YysfdU1Y zbnJS*XE|gnn3V+6me-kA6*UlznK|Dp??lwqZy`I~5_}nt)`eD62I_?!Ycgt!>#$r+ zh4^NVji-iuYuwc`>&HdOmzpUeBBd*FNE;wwp~Ap4Ld+}(R|0{?$Pc-Q+C?9E#%;q> z`m+7P%~+ys=gy-b4HxYPPKb@@^oq7bS&FPlc?}Bje9%pL{im`{t$MPkD6Oxd7^X6* zSfYnx3W4{OJ~CqdiIl`eTIR^ONq>K?Ju>$1c@Ljk_UT5h(L0a z%i_#%3G&W#Fo#-kUFi!#N10q?;Q?2n*IY(l1+o;)%F9s*w~-uPRc1)v06y2`)>9`b zyy4>_>zm#6STxcq4=p8VlWMAfhW3<~OU6V@&6@`_^yKA2_&Qm1Hze(DdYxb%W}UF~ z8k1gXFBb!yxVeHB&?*s`)-!-6ogK06I3yCV7U6J0-de~kg7bG`lb5kA)t9y^`3rv? zR9zT>{S8{uwP8TEx*j4Uv%+j(F~uwPYR{Ye61EvoTbT8r&1l)@{g0i0e!WKP;4nWi z8#LlfJ%=$q#n!^s{)CApYP1Uf5*mOo5CIV%H{~THDj76FdgJ3a@65(57jR9Ek{%=g z%f+ks!E*5$;iRxZ!o(qqnqc(sr?k)_qP<3A3^rjXWkfzblaP@DQrR~rW_1=30 zUE*x1F0tZQmsf?W(0loTTIG{+FD(f&At=HSMw+;JWkeW-`Vh)3ug&_47$+6A4krH) zPVnvYs4hz-wc~f$1{p3^5dO(7_qLyT_WzR0Qtz(UKi9^BM^q4ng-6#>blf|3Y^+S8 zX!Fm?2vc{h@9j2!ug z_>K*gukcyTGo%5)&jU{q6n(3QY3aG!HoOfot^VDhZWhDDF$&kPB3a7r1DK*dG zO0;_wbF6(ug)m&EXd9&q_-i!r==eXDYA-HPEJ@gQv^|JHUp3zKT5wQh$FM)safCqv zDS0*kTg%Z}iNd1;=n<&sX^%c|Qs!aRZ zy=RJrlc?%CeG0sbORiI#NBX9)H0_^tTsI@a@!LYdCTn*`PS8M3EcjA4oxXhdYznnP zfs*zu!kfq#bA%s6zQg?NzA{}=GdGT)BQomZpIg8fM^z0gvG$H13jDmIH^x!`f?>9eaRo9&?xy=;X!u*T~MT>H#q%vaxHb znFF6V-ig$dZy_}`bKpal)wg71&y3eGG&*5@3mq-F3*ke0Mlbr9Fhi76qq!X3%gO?iR zTw>*$1*vFsy);_~QS|gJ5*M3)XBcmA=mxyELpQ?#-s2CuW&-F%ia6+=y$LsmZ&Lvo z>DkWUS?3!g2M=Qb(0hiLM(=tmM~|WpZ<(o5Up#M>!7V(~-xhyTOYu|*uTdxJUh0eI ztunZcXR6HjlOlq+m&dgzrvR6i`iiVho>&3So=1*2=YfbA5ID@zv!Hg1toFqED5U=V zS^1y88;YWEddNWoT)9P$nJR<0hN>aCzp&gC{hEz0gH*;5LCwy{vS@m9iPsaGV`#N@ zr#Ar!l%!`T1U0{L*=G5O+y%5-}%!zRCFN{!?=E{;6y3Bt@&X>GEvd zAbb^%1oOSY96A|}u^m-l+1!OEK@CgVQnGt{WmD(D0)6;I0YEQMy?A%3bh*9$hoMvv zmC*DaL(^lY2v{gXBp@<|Ggf$1h-1sOY@z>RN8%K|hdGF0)%S3Y9QIM)!&bzP;(cT| z`5}{=#=5|_WQq~_lDJVWW>$SCj+BdS)(_k;M6Q0|o-MD{_lzJ%WUB7P>PQ=|(YL^G z4O9R4$jKr*m|P`N3FSQmtLF#a+}5w+_>dH|s$ubYe2S33)8(0`H~8t1_!M)QYmygR z-@3XtX?imWAi^T*cmo0guXzmB5}A`w;NH1!>Qo@S2BTk~`T|hwjnp7mQviTh_rL{b z%j6!gC}h2U4_M?;s_sKJb!y^o`H94_3c4H~=lChIh9kqvCi$32P^zP9_&bEqw}Z~?0m#8-KH3c}wfwlKBKfEM$UZ@M0}tpp*8WJ#SFafcPt0kR2odv0(q7j6bUK z0O4Z^U+22H8RJ$a4~YPhUL)LwXviFd4nTC`Ez~bXYLtQ?lz$8F0pjp~ptFbchOeSW z?Pk0`65wTFyg3B==mVgG1?d*PV$ZDyekAOFwTGx(KKV6=08mpX_uaBm3X&_W6Sre* z4>4|aB^)VmIiOcxo~%-%9X4+1VK8jT?_`Xjab0Qp=mJBfuc+F)N8MV4z);b!b!N4# zbIW-C`6)}MVuaYbHNR;*{{TxTx^RxGW*%SeYz|*QI59rz%p#Rl{u71vH};X#Mo-yX ztI+*~{{i7DE z?smC*RXHi0M^-EVOU^m0O8z~7+K zX$Bms3RP*%Qes~2}}_2M0R0dmEvXgP*0(U60h;7x%J$a0p_ zJ_tncJtxb6~4rI?@k< z<+v~1fQSRU>SIoYxp6Q5_StI5WUEY%#g`7>&9cW~Gtf>`WZ=jzRki)@O5Zd58Cbok7)xasdB;Txd-`sIbxw@o?r@OTvv{cJWE2s4 zCr+JK#0nA(5{Kf-Mj3qz9VzC2L~-)d{S?V*UrShoNIrn*(p!BGE1~zYKvKPipgxN< zDprx0L1A$F%tSH?F&H2)l4Td~_$gMSb3!O;;#P%~u{xPJD5xHAN|g<;s;I#50%7Y$ zyBcH&nhwq#=8+g!r`#{#T7@eLgz7t}tn#`jiLm{RUA}qq$20*lX zxX9N=xte1FluJQQAQ71b5t&@{Y9SJtZlG72y|{C$FHEnxbycv_&FGaB1O^Xahz}vG zD3B^mo)3Iro<*BW0=9)FLIDi;OycDZ28%nGfD*cu$W_2?Efv&kWL}{e_$TF4*g?S< z(f!1ZT@C5G3QG#V!I5wM97&we!q$HCesi&~6cA9Q4IzI?@crJbr**(I(6hs+A}u5u zAr7~dhtIF{&tuY6_~k!VjJOog%HtWiweZaFM4FaAvB27ZE+aGB@_HSC6AoKhGsBud4-V4Ew{;lXMW z#&?WzE&z3~NZ5r|2y4RAu*~0d0&}0PX1eE0-afHuj0e$pq70e^JKK63^Y zW0_b>_pc9VxDPAj52&|#bDwZmv&GWIB#|wH!X0&m6hr#h7|Tw4=rIxy*!={_7^5|E zp`*!~6U~GCB7kWTI0~!Comd*VNRt;(yAyIUOT<*gQN9N~h-30OWx^*U0**<9gw7Vg zea<6M1pWa(W!8glaKnEMB+cmh%(Uo{04rpdWRZZo=K@54tb76EY>`=*{7E1`Q~?dw z&pZ-rXjwB;?MAH;0N^_)D;(KI50OC!*UJaAmoW+@VB!tBwpAb&{0EewQ zEK45FR4Cnp@3lE#4@pfP8Asr$YJI>#8qi*$7vc@$sur*Oqk{I5N(mt2T?A)!SK235 zzWuG|p6mWF-*;C!Clp&*E2>5JG?1L+7?HVjI>!ho(hSL&-gvH44?A0JJnt(c2M%$v zSlkej(>xcNr4&MP<|lUdT02$qm3I1f-gwR^8`>%Dfq?U#2VjlgRj6d)pOiN%tb~A5 z3S1P>!y6=3c@LRQ3{`Bvs_p@Ji08vOy2{+h->+0QWa&4(<49p9u?6?lyogXzX-2!$ zv|pG-0eIN#T;~K;?kILad6`vCRp1;BR^LK#4j8agr*XpeG&3vO?ex23 z$k2wpwC#y)EB1O2-{zrDR*aI`LRK(ir45#S4sQ-J;k4>Wpih>X9-d z<+o8#w5zw2DEN555+uiwrkr_pNo-)Vh3TKFka%uk=gf%{lyc@vWq&60ZsIxE!f6zk z$jUl@0I*u5vQwu)wvg^l;d_i^AD$IPVlr%YF=u8ce#DO49Ok3QqIuAfxLf`IV%I1sL{ zOC6&C&dGU1-AcaF(PJzEznwZ{HUJy@7z@!EcFl9qOrJp^2webZ*U*XnL0mwv$ycZU zJe7$7@LkCz`F$!O&z4M)0)f3UIx&$=g&9uIsQg}?p;e1FEO@$!s|}4faxqJFfK4K0 zZ9u|&Bq3I27tHj)TBbm?h}7Um7y_LrqY6ifcS>KxDKV#R1F(|R(#UW*TR<3y81<%` zFkMt539BqJVwgKh0Ncc2XL}jA&9Y)N70!(pPD3b#TW4<9ki6-_*7N-+X^hM(5WfY( zezR=3AU|X655MKmJ7K#-a*=-ilJdoK>rU@RQjEjbu%eBbqIqR3!UT-z#d@%>HJMwG*{p~;S{sHzZAVB!a9a19DeY3xfv z$@i3p&rCMENc+=Y0zCL(GLT=Va>Q=2ISFD4z@};&Y^V*K*=B8oY|hk%%s(|MP<`9A z)qwAX9X#H@2D*(phQ7q;?#gaFPas zwVhC%{-5Skn+F1J$$Q6m5XnFeqx`DIz<-v9Wnalyk3$YjxKvKP7e$^^MJ`WRbIo<5mVO=S>iniHjjLC`ax32}U(fm+mE%U3MWr&m~6--b>x( z@|bWnWQNEDWKSipm0n3D_03cn=B6r>Z&fCrl)<6Cc|G{;s(RX6l_8*^D%07jOlMN2 zyHy#s6Nh?8J37@HCZ1QolVwVR5BB5c%gjnHNZ?^cD+7=Lcx0!#R^|vyq7XMwReop6 zP*m}0N|Hcki^Xv!zgv#?0na4(FUhTSy=?h5N>~IcZHp8(yGL1e)%Ts} zac|vQ_ui_$-CdGO-7R$Pp@0IqqXv4Uw$KW7dW2|%2-v}ZZ6-?-vnEJ zO@S9AXfE#LFn5A*l+5>AlCmcaxWEZ&yekmQld* zXH!a;luh5C@-CCvoUUkFM%(8sB4sun|8IHi4OEjlrdR%lHK_}b=&Xi-8-kh0m|kmr zs%IhVNrN2?scXtW>gqBPH+GhR)YWAodh9F%sjJIG4B1&mzFXp=bT=Z&&N7g?x=h5A zon;_(q0IJ`BA+^K1vJ>udnBNPVDXoO4!4m|ftk}*Ka;DU5+;QFS0r2F`dfFwsm_9- zGG>66AX(gBL~-x~R{mC;`Tz4-Yn`2o=ta2iC+!YLaMpSV4S5N9&nB;9m95^yeTnxb z)$=zw!MMzP!LUHYyJG28pT&`dj}cJ_Ve zr}e?NbA5M2fxG2)WB+rvyUnp)Xs`foxUcm5E_RW$eG}$kN8cB!5O}Z~+$T-n_kjEM zPj`j8`hM4rzK3?V!Jfqh{3G1y`#t3|igDfdop8?`tH4w}Dcph5PPp&cn92{0o=V?PtR{Jogxl|M^orLQS14okOOP`p|J zWnn*Nq||*yh2q0rU3sK<7StQ_4Mb(Y2j>g_dHGR3)kg=9(yfCENSE>BplmhID#lgm zMwAVoHS8Qiv*#B_#2}u{4|`|FS)9aDT`M-;{wo}p<{kW{;#vS&aJFaI!N>V&%`lK` zT=1fJzS0(rw9l|6D;rOtmD;$d%3}2>-<7blqgd5eiEgXPErzsuR3!FXIa3rmSND{M ziX#v|fWeXB&&J{Xxy2fJ127U$(^i$em3E$W%h9r|e8g;tU3Dg}t5H!(I~}lDUL5Bv z^273#r-8D1+ud8NT^~nIUpO;B8#QdubAuQ)Le>p8NM+b@;|*eoth?b&#*MG^j1wC4 zX||=(@usJnJl^1xO0r5G;H@;;tei^MuR*0^Lie8S?(vAZrfj}}MjPs6;c95m$NrZtKd~gw5Eu5v-3KBQ-dzztvnREw+R zO)}b}QD+xmfVTj^P#Ablio<8it3iByY?H$kgiTWKJ+fL}Ssa=jE}p3q$v4ZXZS=BA zbRp(oL?-D98BNRLnJW2A886~T)zYh$dg9(dp%}6L#45C@&CeC{6UUtBNb*CLVW z&XB))u0c)Fm0^mmqN7aE;g=RyGBsg_c`!dW+veqPJug@7GA~!`Ixn##kO5O{T1wmn-Xe*{#v-^K#``&+4vilbSB81Hig~%ZtY_wm7QVq!^lS*n z3TdkrG$Bf;2-TSKL#Up%KRF5uVS$RF5IRpDFZa#aYB3Jt75Kn`^zBCA!FHP%1n)$J zj`xTPJ=ooAbSQC?Pvl6au6-reKho9(HWX2KD&|DTD2wEmk$+$gAfov{2bP05$V}V6 z@nX=jHsiShq30R$Wo7k~aP_U2_sSWI3U-95SJf}Dz>;28e^WJeU zn|-}|mCGiIn?o+1_#?#49v2ojlWI)lbrd&|H8J0Wk!rZ!F+>ufFhq`~eR{*VxJKa- zGrBpOu-L>@O3^yn;X0XJUA;5r5j|2IMw^7#9yWGeE5d!1Y91BW;$5VxD`iW&7BFeUT^gI|T1e=SZ@`tqP+%*POC2H<7l?4xEUCj7;f z(Ii@VAFnu4kRm97%E*O@fs90Cuq{5sejY*&5s)0N2)*I4-U|5v_N2H%3F{`sGuR|0 z$Z}mjadHR6HCoMEj}*_@7Bj+B;{u?;D$x8Ikv2*_?;UY6oq%cdQlv1MugT39w&}(Q z4+ukvnvavB$uCm|->;qpj?mpOA@nRD!!s;tP|E+CGUTA|q{4`^;2I{c@JfedNQ9V4 zigDk#jxSsEG&bKJdf;_Xm#uQv&bBa7YY*^7^*8jW(0OYT2E95glp!UlK!JBUgb9P5 zP-}YHvhv&-We7bsd6Xx56#KQijv`ren|inNvwE4vwsY;CAxxc|0U3uDz=VYlhSyz{ zq`fdtHLnGnxH@IXYLNQm|5qeOLbf=ifr20*6L8ZjI6x3_| zoa3`F*f5Jq=*m2DHT2bptC-qVi7f_FKGj4U5KkZjM0&&|@))<#QaE8fi2Ku83OLFr zeZ7;B)sgWjZP;P7jfp282HSHQe$X4S&N7VVA<-MExOo^x{REqg(${&88OqPFtEW1VbUjSa*8^Uwh!_cZ^GpO3&ce+bc z#Plh_Ix8u!Ymu*2&Y$KULYYG?n|lWvHt`_?s0;6#Wd1r^lY4^dLhFe5*Jrm&(s%H? zfA8Ry)%d3Hb65CbzP*ur#%qyl`2z~o;#%QJjl*s_k@ax_STkdKE_dFhPC52W32 zSUhujJZ1*8An^atrWJS_{Q^SN3y-yb%IXUXhwjUTo0X}o8{nUkQ1G?*rIxGnz9_St zj@}RfW*h$KjR{FOu<{zJa+jsq1#)_KPo=5dfa_jyj-O1qm@c3P{G2KmP9&&qlKHh0 zLft46>qYI#tY;dA=>{fz@2gfye40a3fUW3>wg&W7q$Rnw0(2ip2>rVaz+)W5v7^l4 zruZ)TaKIw>k%95s3Wt8&6OL-baWQP8$U3D?&aw=I3H~cwrPbdf(5X2?kjm*F8z3`? z3cbOG%qCDKBlq)Y8_GMVo<9!f2M%^WKd_Tkz~=|z{?$k+K06QxFyY)N<_mnXqXCf_ z;`x8!OhD<;i$2azz?%pMb&8)m4W3|(Uxc7BKCal-BAP3tTmgb>B@~)l9TLctql{{U zNE1E&N4bskjXMSJGwI3vfPmT((1i5wWR~vYK?U6Tlqri|SX6%JEu7ug(=w)PQrd|i zAS?HFVkr~WFm!%0ODIJ`*Ed6atNxo{kBL+RAo7&APOBe(Pj6<=A9hgV4b&s-4bTr- zFyAu9c}+0#O*YH-<#^%I?A9wSMOKwJbiv5&8@kesw4)2MB-Kx z{0?I731V8bGW!jV@KKOt`^tzB{S%V$AI-XM`gSz{j8_$hiEFvPakhLK9EyEei%0DlM2qT|F-{ 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

fQ%*MQI{VN>U3fv|01Qo7jOG1oMwQ{;S!gzYe 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≈n1eEGM6?(gjd)OLGKsO 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�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
=f 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 z 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 literal 0 HcmV?d00001