From 4eb5190863fdf037f6402e4943ce827d613191ac Mon Sep 17 00:00:00 2001 From: veryCrunchy Date: Mon, 28 Sep 2026 00:22:20 +0200 Subject: [PATCH 1/6] fix(admin): cache permissions and hide unauthorized administration --- ADAPTER_ARCHITECTURE.md | 20 ++ .../cached-administration-permissions.md | 7 + tools/kotlin-file-size-baseline.txt | 2 +- .../app/AccountSettingsScreen.kt | 2 + .../nextcloudnative/app/AdminAppManagement.kt | 6 +- .../nextcloudnative/app/AdminAppsScreen.kt | 121 +++++++++++ .../app/AdministrationAccessComposition.kt | 46 ++++ .../app/AdministrationAccessRepository.kt | 66 ++++++ .../nextcloudnative/app/NextcloudNativeApp.kt | 133 +----------- .../nextcloudnative/app/SettingsWorkspace.kt | 2 + .../app/AdministrationAccessRepositoryTest.kt | 197 ++++++++++++++++++ .../app/SettingsWorkspaceTest.kt | 16 ++ .../AdministrationAccessCompositionTest.kt | 105 ++++++++++ 13 files changed, 597 insertions(+), 126 deletions(-) create mode 100644 changes/unreleased/cached-administration-permissions.md create mode 100644 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt create mode 100644 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt create mode 100644 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt create mode 100644 ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepositoryTest.kt create mode 100644 ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt diff --git a/ADAPTER_ARCHITECTURE.md b/ADAPTER_ARCHITECTURE.md index 2f81ca4d9..800d4478e 100644 --- a/ADAPTER_ARCHITECTURE.md +++ b/ADAPTER_ARCHITECTURE.md @@ -156,6 +156,26 @@ Stored Login Flow app passwords must not be treated as primary passwords for strict administrator confirmation. The client must not collect or retain a primary account password to bypass that boundary. +### Administration visibility + +`AdministrationAccessRepository` owns session-scoped, in-memory permission +evidence from the existing read-only administrator catalog contract. It reuses +that catalog for the Server apps screen and caches both allowed and denied +results for five minutes using a monotonic clock. Opening Settings checks the +cache; while Settings or Server apps remains open, expired evidence is refreshed. +No permission result survives logout, account replacement, or process restart. +Both catalog request paths use `ForceNetwork` so revalidation cannot renew access +from the transport's persisted response cache. + +Administration, its installed-workspace summary, and the Server apps route +require fresh successful evidence. Unknown, expired, denied, malformed, and +unavailable results hide those surfaces, including restored navigation. An +explicit refresh removes old access before requesting new evidence. Concurrent +checks share the cached result, and cancellation cannot publish a late success. +The ordinary Apps workspace remains available to regular users. Cached visibility +never authorizes a mutation; strict operations still use authenticated browser +handoff and server-side authorization. + ## Error and cancellation rules Errors must retain enough structured context to support recovery and safe diff --git a/changes/unreleased/cached-administration-permissions.md b/changes/unreleased/cached-administration-permissions.md new file mode 100644 index 000000000..c1beaa998 --- /dev/null +++ b/changes/unreleased/cached-administration-permissions.md @@ -0,0 +1,7 @@ +category: fix +issue: 187 +pull: none +platforms: android, desktop +user-facing: yes + +Hide Administration and Server apps unless the signed-in account has freshly verified access. Cache permission checks for five minutes within the session, and prevent stale responses or restored navigation from exposing admin controls. diff --git a/tools/kotlin-file-size-baseline.txt b/tools/kotlin-file-size-baseline.txt index 66d03f066..a1c411f47 100644 --- a/tools/kotlin-file-size-baseline.txt +++ b/tools/kotlin-file-size-baseline.txt @@ -23,7 +23,7 @@ ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NativeDeckBoardSurface. ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NativeDeckRelationDialogs.kt|1234 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NativeDeckScreen.kt|1883 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudMediaViewer.kt|1331 -ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt|12313 +ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt|12200 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNotes.kt|1693 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudPhotoEditor.kt|808 ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudPlatform.kt|1716 diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt index ef6e2d7ec..6d21d3bc7 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt @@ -27,6 +27,7 @@ internal fun SettingsScreen( themePreference: ThemePreference, platformCapabilityRefreshRequest: Long, onThemePreferenceChanged: (ThemePreference) -> Unit, + canAdminister: Boolean, onAdminApps: () -> Unit, onOfflineCenter: () -> Unit, onTransfers: () -> Unit, @@ -61,6 +62,7 @@ internal fun SettingsScreen( isDesktop = isDesktop, hasDeviceSettings = platformCapabilities.isNotEmpty(), hasDesktopAppSettings = hasDesktopAppSettings, + canAdminister = canAdminister, ) val selectedSection = selectedSectionName?.let { restoredName -> resolveSettingsWorkspaceSection(restoredName, visibleSections) diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt index fd7ec88fe..5760f2949 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt @@ -104,6 +104,7 @@ suspend fun loadNativeAppCatalog( queryParameters = mapOf("details" to "true", "format" to "json"), ocsApiRequest = true, maximumResponseBytes = APP_CATALOG_RESPONSE_LIMIT_BYTES, + cachePolicy = NextcloudApiCachePolicy.ForceNetwork, ), ) when (appStoreResponse.status) { @@ -309,6 +310,7 @@ private fun legacyAppListRequest(filter: String): NextcloudApiRequest = Nextclou relativePath = PROVISIONING_APPS_PATH, queryParameters = mapOf("filter" to filter, "format" to "json"), ocsApiRequest = true, + cachePolicy = NextcloudApiCachePolicy.ForceNetwork, ) private fun appStoreMutationRequest( @@ -379,9 +381,9 @@ private fun NextcloudApiResponse.ocsDataOrNull(): JsonElement? { val ocs = root["ocs"] as? JsonObject ?: return null val meta = ocs["meta"] as? JsonObject ?: return null val statusCode = (meta["statuscode"] as? JsonPrimitive)?.contentOrNull?.toIntOrNull() - if (statusCode != null && statusCode !in setOf(100, 200)) return null + if (statusCode !in setOf(100, 200)) return null val statusValue = (meta["status"] as? JsonPrimitive)?.contentOrNull - if (statusValue != null && statusValue != "ok") return null + if (statusValue != "ok") return null return ocs["data"] } diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt new file mode 100644 index 000000000..3b08824b8 --- /dev/null +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt @@ -0,0 +1,121 @@ +package dev.obiente.nextcloudnative.app + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier + +@Composable +internal fun AdminAppsScreen( + access: AdministrationAccessController, + onContinueInBrowser: () -> Unit, + serverInfo: NextcloudServerInfo?, + onOpenApp: (NextcloudAppEntry) -> Unit, + onBack: () -> Unit, +) { + var search by remember { mutableStateOf("") } + var catalogFilter by remember { mutableStateOf(NativeAppCatalogFilter.All) } + var pendingLifecycleAction by remember(access.state.result) { + mutableStateOf?>(null) + } + if (!access.canAdminister) { + if (access.state.checking) { + LoadingMessage("Checking administrator access...") + } else { + LaunchedEffect(access.state) { onBack() } + } + return + } + + Column(modifier = Modifier.fillMaxSize().safeDrawingPadding()) { + ScreenHeader( + title = "Server apps", + subtitle = "Administrator app management", + onBack = onBack, + ) + when (val result = access.state.result) { + null -> LoadingMessage("Loading administrator app catalog...") + is NativeAppCatalogResult.Available -> NativeAppCatalogSurface( + catalog = result.catalog, + query = search, + filter = catalogFilter, + onQueryChanged = { search = it }, + onFilterChanged = { catalogFilter = it }, + onOpenInstalledApp = { managed -> + serverInfo?.apps?.firstOrNull { app -> app.id == managed.id }?.let(onOpenApp) + }, + onLifecycleAction = { app, action -> + if (access.canAdminister) pendingLifecycleAction = app to action + }, + ) + NativeAppCatalogResult.Forbidden -> ErrorMessage( + "This account does not have permission to manage server apps.", + onRetry = access.refresh, + ) + NativeAppCatalogResult.Unavailable -> ErrorMessage( + "Administrator app management is unavailable on this server.", + onRetry = access.refresh, + ) + is NativeAppCatalogResult.InvalidResponse -> ErrorMessage( + result.reason, + onRetry = access.refresh, + ) + } + } + + pendingLifecycleAction?.let { (app, action) -> + AlertDialog( + onDismissRequest = { pendingLifecycleAction = null }, + title = { Text("${action.uiLabel()} ${app.name}?") }, + text = { + Text( + when (action) { + NativeAppLifecycleAction.InstallAndEnable -> + "This downloads server-side code and enables the app for users." + NativeAppLifecycleAction.Enable -> + "This activates the app and may add navigation, jobs, and integrations for users." + NativeAppLifecycleAction.Disable -> + "This makes the app and its integrations unavailable until an administrator enables it again." + NativeAppLifecycleAction.Update -> + "The server may enter maintenance mode while the app package is updated. Do not interrupt it." + NativeAppLifecycleAction.Uninstall -> + "This removes the app package. App data retention depends on the app and is not guaranteed." + } + "\n\nNextcloud requires administrator password confirmation. Continue in the authenticated server administration page.", + ) + }, + dismissButton = { + TextButton(onClick = { pendingLifecycleAction = null }) { Text("Cancel") } + }, + confirmButton = { + Button( + onClick = { + pendingLifecycleAction = null + if (access.canAdminister) { + onContinueInBrowser() + access.refresh() + } + }, + colors = if (action == NativeAppLifecycleAction.Uninstall) { + ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error) + } else { + ButtonDefaults.buttonColors() + }, + ) { + Text("Continue in browser") + } + }, + ) + } +} diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt new file mode 100644 index 000000000..0a3424d5e --- /dev/null +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt @@ -0,0 +1,46 @@ +package dev.obiente.nextcloudnative.app + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.key +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.rememberUpdatedState +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch + +internal class AdministrationAccessController( + val state: AdministrationAccessState, + private val permissionCheck: () -> Boolean, + val refresh: () -> Unit, +) { + val canAdminister: Boolean get() = permissionCheck() +} + +@Composable +internal fun rememberAdministrationAccess( + session: NextcloudSession, + refreshRequest: Long, + active: Boolean, + execute: suspend (NextcloudApiRequest) -> NextcloudApiResponse, +): AdministrationAccessController = key(session) { + val repository = remember { AdministrationAccessRepository() } + val currentExecute by rememberUpdatedState(execute) + val state by repository.state.collectAsState() + val scope = rememberCoroutineScope() + DisposableEffect(repository) { onDispose { repository.retire() } } + LaunchedEffect(repository, refreshRequest, active) { + while (active && isActive) { + repository.refresh { request -> currentExecute(request) } + val age = repository.state.value.checkedAt?.elapsedNow() ?: AdministrationAccessTtl + delay((AdministrationAccessTtl - age).coerceAtLeast(kotlin.time.Duration.ZERO)) + } + } + AdministrationAccessController(state, permissionCheck = { repository.state.value.canAdminister }) { + scope.launch { repository.refresh(force = true) { currentExecute(it) } } + } +} diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt new file mode 100644 index 000000000..7491ff6ec --- /dev/null +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt @@ -0,0 +1,66 @@ +package dev.obiente.nextcloudnative.app + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.currentCoroutineContext +import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlin.time.Duration.Companion.minutes +import kotlin.time.TimeMark +import kotlin.time.TimeSource + +internal data class AdministrationAccessState( + val result: NativeAppCatalogResult? = null, + val checking: Boolean = false, + val checkedAt: TimeMark? = null, + val retired: Boolean = false, +) { + val canAdminister: Boolean + get() = isFresh && (result as? NativeAppCatalogResult.Available)?.catalog?.administratorAuthorized == true + + val isFresh: Boolean + get() = checkedAt?.elapsedNow()?.let { it >= kotlin.time.Duration.ZERO && it < AdministrationAccessTtl } == true +} + +internal val AdministrationAccessTtl = 5.minutes + +/** + * One instance per authenticated session. Nothing is persisted or shared between accounts. + * The verified read-only catalog doubles as permission evidence and the management screen cache. + */ +internal class AdministrationAccessRepository(private val timeSource: TimeSource = TimeSource.Monotonic) { + private val mutableState = MutableStateFlow(AdministrationAccessState()) + val state = mutableState.asStateFlow() + private val mutex = Mutex() + + fun retire() { + mutableState.value = AdministrationAccessState(retired = true) + } + + suspend fun refresh( + force: Boolean = false, + execute: suspend (NextcloudApiRequest) -> NextcloudApiResponse, + ) = mutex.withLock { + val previous = mutableState.value + if (previous.retired || (!force && previous.isFresh)) return@withLock + // Expired or explicitly refreshed permission must not leave old admin controls actionable. + val checking = AdministrationAccessState(checking = true) + if (!mutableState.compareAndSet(previous, checking)) return@withLock + try { + val result = loadNativeAppCatalog(execute) + currentCoroutineContext().ensureActive() + mutableState.compareAndSet(checking, AdministrationAccessState(result = result, checkedAt = timeSource.markNow())) + } catch (cancelled: CancellationException) { + mutableState.compareAndSet(checking, AdministrationAccessState()) + throw cancelled + } catch (_: Exception) { + // Transport fault boundary: no account data or exception text enters the UI/cache. + mutableState.compareAndSet(checking, AdministrationAccessState( + result = NativeAppCatalogResult.Unavailable, + checkedAt = timeSource.markNow(), + )) + } + } +} diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt index 881a3f103..6c3aec295 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt @@ -1219,6 +1219,10 @@ private fun AuthenticatedApp( session.loginName, stateSaver = enumSaver(), ) { mutableStateOf(NextcloudDestination.Home) } + val administration = rememberAdministrationAccess( + session, platformCapabilityRefreshRequest, + active = destination == NextcloudDestination.Settings || screen == Screen.AdminApps, + ) { services.executeNextcloudApi(session, it) } var serverInfo by remember(session) { mutableStateOf(null) } var lastOpenedAppId by remember(session) { mutableStateOf(services.loadLastOpenedAppId()) } val appPinsStorage = rememberAccountHomeWorkspaceStorage(session) @@ -2151,7 +2155,8 @@ private fun AuthenticatedApp( themePreference = themePreference, platformCapabilityRefreshRequest = platformCapabilityRefreshRequest, onThemePreferenceChanged = onThemePreferenceChanged, - onAdminApps = { screen = Screen.AdminApps }, + canAdminister = administration.canAdminister, + onAdminApps = { if (administration.canAdminister) screen = Screen.AdminApps }, onOfflineCenter = { if (presentation == NextcloudPresentation.Desktop) { screen = Screen.Root @@ -2323,8 +2328,10 @@ private fun AuthenticatedApp( modifier = Modifier.fillMaxSize().safeDrawingPadding(), ) Screen.AdminApps -> AdminAppsScreen( - services = services, - session = session, + access = administration, + onContinueInBrowser = { + services.openExternalUrl(session.serverUrl.trimEnd('/') + "/index.php/settings/apps") + }, serverInfo = serverInfo, onOpenApp = { openApp(it, NextcloudDestination.Settings) }, onBack = ::navigateBack, @@ -2682,126 +2689,6 @@ private fun AppsScreen( ) } -@Composable -private fun AdminAppsScreen( - services: NextcloudPlatformServices, - session: NextcloudSession, - serverInfo: NextcloudServerInfo?, - onOpenApp: (NextcloudAppEntry) -> Unit, - onBack: () -> Unit, -) { - var search by remember { mutableStateOf("") } - var catalogFilter by remember { mutableStateOf(NativeAppCatalogFilter.All) } - var catalogResult by remember(session) { mutableStateOf(null) } - var catalogAttempt by remember(session) { mutableStateOf(0) } - var catalogRefreshing by remember(session) { mutableStateOf(false) } - var catalogRefreshError by remember(session) { mutableStateOf(null) } - var pendingLifecycleAction by remember { - mutableStateOf?>(null) - } - LaunchedEffect(session, catalogAttempt) { - val retained = catalogResult - catalogRefreshing = retained != null - catalogRefreshError = null - val loaded = runCatching { - loadNativeAppCatalog { request -> services.executeNextcloudApi(session, request) } - }.getOrElse { - NativeAppCatalogResult.InvalidResponse("The administrator app catalog could not be loaded.") - } - if (retained is NativeAppCatalogResult.Available && loaded !is NativeAppCatalogResult.Available) { - catalogRefreshError = when (loaded) { - NativeAppCatalogResult.Forbidden -> "This account no longer has permission to refresh server apps." - NativeAppCatalogResult.Unavailable -> "Administrator app management is currently unavailable." - is NativeAppCatalogResult.InvalidResponse -> loaded.reason - is NativeAppCatalogResult.Available -> error("Handled above") - } - } else { - catalogResult = loaded - } - catalogRefreshing = false - } - - Column(modifier = Modifier.fillMaxSize().safeDrawingPadding()) { - ScreenHeader( - title = "Server apps", - subtitle = "Administrator app management", - onBack = onBack, - ) - if (catalogRefreshing) LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) - catalogRefreshError?.let { message -> - RetainedRefreshError(message = message, onRetry = { catalogAttempt += 1 }) - } - when (val result = catalogResult) { - null -> LoadingMessage("Loading administrator app catalog...") - is NativeAppCatalogResult.Available -> NativeAppCatalogSurface( - catalog = result.catalog, - query = search, - filter = catalogFilter, - onQueryChanged = { search = it }, - onFilterChanged = { catalogFilter = it }, - onOpenInstalledApp = { managed -> - serverInfo?.apps?.firstOrNull { app -> app.id == managed.id }?.let(onOpenApp) - }, - onLifecycleAction = { app, action -> pendingLifecycleAction = app to action }, - ) - NativeAppCatalogResult.Forbidden -> ErrorMessage( - "This account does not have permission to manage server apps.", - onRetry = { catalogAttempt += 1 }, - ) - NativeAppCatalogResult.Unavailable -> ErrorMessage( - "Administrator app management is unavailable on this server.", - onRetry = { catalogAttempt += 1 }, - ) - is NativeAppCatalogResult.InvalidResponse -> ErrorMessage( - result.reason, - onRetry = { catalogAttempt += 1 }, - ) - } - } - - pendingLifecycleAction?.let { (app, action) -> - AlertDialog( - onDismissRequest = { pendingLifecycleAction = null }, - title = { Text("${action.uiLabel()} ${app.name}?") }, - text = { - Text( - when (action) { - NativeAppLifecycleAction.InstallAndEnable -> - "This downloads server-side code and enables the app for users." - NativeAppLifecycleAction.Enable -> - "This activates the app and may add navigation, jobs, and integrations for users." - NativeAppLifecycleAction.Disable -> - "This makes the app and its integrations unavailable until an administrator enables it again." - NativeAppLifecycleAction.Update -> - "The server may enter maintenance mode while the app package is updated. Do not interrupt it." - NativeAppLifecycleAction.Uninstall -> - "This removes the app package. App data retention depends on the app and is not guaranteed." - } + "\n\nNextcloud requires administrator password confirmation. Continue in the authenticated server administration page.", - ) - }, - dismissButton = { - TextButton(onClick = { pendingLifecycleAction = null }) { Text("Cancel") } - }, - confirmButton = { - Button( - onClick = { - pendingLifecycleAction = null - services.openExternalUrl(session.serverUrl.trimEnd('/') + "/index.php/settings/apps") - catalogAttempt += 1 - }, - colors = if (action == NativeAppLifecycleAction.Uninstall) { - ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error) - } else { - ButtonDefaults.buttonColors() - }, - ) { - Text("Continue in browser") - } - }, - ) - } -} - @Composable private fun AppInfoScreen( services: NextcloudPlatformServices, diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspace.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspace.kt index 67703cd46..2b0849f52 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspace.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspace.kt @@ -73,8 +73,10 @@ internal fun visibleSettingsSections( isDesktop: Boolean, hasDeviceSettings: Boolean, hasDesktopAppSettings: Boolean = isDesktop, + canAdminister: Boolean = false, ): List = SettingsWorkspaceSection.entries.filter { section -> when (section) { + SettingsWorkspaceSection.Administration -> canAdminister SettingsWorkspaceSection.DesktopApp -> isDesktop && hasDesktopAppSettings SettingsWorkspaceSection.NotificationsAndDevice -> hasDeviceSettings else -> true diff --git a/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepositoryTest.kt b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepositoryTest.kt new file mode 100644 index 000000000..03bc05e7a --- /dev/null +++ b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepositoryTest.kt @@ -0,0 +1,197 @@ +package dev.obiente.nextcloudnative.app + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.async +import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertIs +import kotlin.test.assertNull +import kotlin.test.assertTrue +import kotlin.time.Duration.Companion.minutes +import kotlin.time.TestTimeSource + +class AdministrationAccessRepositoryTest { + @Test + fun unknownAndOtherAccountsNeverInheritAccess(): Unit = runBlocking { + val admin = AdministrationAccessRepository() + val regular = AdministrationAccessRepository() + assertFalse(admin.state.value.canAdminister) + admin.refresh { allowedResponse() } + assertTrue(admin.state.value.canAdminister) + assertFalse(regular.state.value.canAdminister) + regular.refresh { response(status = 403) } + assertFalse(regular.state.value.canAdminister) + assertTrue(admin.state.value.canAdminister) + } + + @Test + fun successfulCatalogIsReusedUntilItsExactExpiry(): Unit = runBlocking { + val clock = TestTimeSource() + val repository = AdministrationAccessRepository(clock) + var calls = 0 + val execute: suspend (NextcloudApiRequest) -> NextcloudApiResponse = { request -> + assertEquals(NextcloudApiMethod.GET, request.method) + assertEquals(NextcloudApiCachePolicy.ForceNetwork, request.cachePolicy) + calls++ + allowedResponse() + } + repository.refresh(execute = execute) + repeat(3) { repository.refresh(execute = execute) } + assertEquals(1, calls) + clock += 5.minutes + assertFalse(repository.state.value.canAdminister) + repository.refresh(execute = execute) + assertEquals(2, calls) + assertTrue(repository.state.value.canAdminister) + } + + @Test + fun legacyPermissionEvidenceAlsoBypassesTransportCaches(): Unit = runBlocking { + val repository = AdministrationAccessRepository() + var calls = 0 + repository.refresh { request -> + assertEquals(NextcloudApiMethod.GET, request.method) + assertEquals(NextcloudApiCachePolicy.ForceNetwork, request.cachePolicy) + calls++ + if (calls == 1) response(status = 404) else response( + body = """{"ocs":{"meta":{"status":"ok","statuscode":100},"data":{"apps":[]}}}""", + ) + } + assertEquals(3, calls) + assertTrue(repository.state.value.canAdminister) + } + + @Test + fun deniedResultsAreCachedAndPromotionIsDiscoveredAfterExpiry(): Unit = runBlocking { + val clock = TestTimeSource() + val repository = AdministrationAccessRepository(clock) + var calls = 0 + repeat(3) { + repository.refresh { calls++; response(status = 403) } + } + assertEquals(1, calls) + assertFalse(repository.state.value.canAdminister) + clock += 5.minutes + repository.refresh { allowedResponse() } + assertTrue(repository.state.value.canAdminister) + } + + @Test + fun expiredOrExplicitlyRefreshedAccessIsHiddenBeforeNetworkCompletion(): Unit = runBlocking { + for (force in listOf(false, true)) { + val clock = TestTimeSource() + val repository = AdministrationAccessRepository(clock) + repository.refresh { allowedResponse() } + if (!force) clock += 5.minutes + val pending = CompletableDeferred() + val request = async(start = CoroutineStart.UNDISPATCHED) { + repository.refresh(force) { pending.await() } + } + assertTrue(repository.state.value.checking) + assertFalse(repository.state.value.canAdminister) + pending.complete(response(status = 403)) + request.await() + assertIs(repository.state.value.result) + assertFalse(repository.state.value.canAdminister) + } + } + + @Test + fun concurrentChecksPerformOneRead(): Unit = runBlocking { + val repository = AdministrationAccessRepository() + val pending = CompletableDeferred() + var calls = 0 + val first = async(start = CoroutineStart.UNDISPATCHED) { + repository.refresh { calls++; pending.await() } + } + val second = async(start = CoroutineStart.UNDISPATCHED) { + repository.refresh { calls++; allowedResponse() } + } + pending.complete(allowedResponse()) + first.await() + second.await() + assertEquals(1, calls) + assertTrue(repository.state.value.canAdminister) + } + + @Test + fun cancellationCannotBecomeCachedSuccessEvenIfTransportSwallowsIt(): Unit = runBlocking { + val repository = AdministrationAccessRepository() + val pending = CompletableDeferred() + val job = launch(start = CoroutineStart.UNDISPATCHED) { + repository.refresh { + try { + pending.await() + } catch (_: CancellationException) { + // Simulate an incorrectly cancellation-swallowing platform boundary. + } + allowedResponse() + } + } + job.cancelAndJoin() + assertFalse(repository.state.value.canAdminister) + assertFalse(repository.state.value.checking) + assertNull(repository.state.value.result) + repository.refresh { response(status = 403) } + assertIs(repository.state.value.result) + } + + @Test + fun retiredAccountRejectsLateCompletionAndFurtherChecks(): Unit = runBlocking { + val repository = AdministrationAccessRepository() + val pending = CompletableDeferred() + val request = async(start = CoroutineStart.UNDISPATCHED) { + repository.refresh { pending.await() } + } + repository.retire() + pending.complete(allowedResponse()) + request.await() + repository.refresh { error("Retired accounts must not make requests") } + assertTrue(repository.state.value.retired) + assertFalse(repository.state.value.canAdminister) + assertNull(repository.state.value.result) + } + + @Test + fun failedRefreshNeverRetainsEarlierPermission(): Unit = runBlocking { + val repository = AdministrationAccessRepository() + repository.refresh { allowedResponse() } + repository.refresh(force = true) { error("Synthetic transport failure") } + assertFalse(repository.state.value.canAdminister) + assertIs(repository.state.value.result) + } + + @Test + fun deniedUnavailableAndMalformedCatalogsCannotGrantAccess(): Unit = runBlocking { + val responses = listOf( + response(status = 401), response(status = 403), response(status = 503), + response(body = "not json"), response(body = "{}"), + response(body = """{"ocs":{"meta":{},"data":[]}}"""), + response(body = """{"ocs":{"meta":{"status":"failure","statuscode":403},"data":[]}}"""), + response(body = """{"ocs":{"meta":{"status":"ok","statuscode":200},"data":{}}}"""), + allowedResponse().copy(contentType = "text/html"), + ) + for (response in responses) { + val repository = AdministrationAccessRepository() + repository.refresh { response } + assertFalse(repository.state.value.canAdminister) + } + } + + private fun allowedResponse() = response( + body = """{"ocs":{"meta":{"status":"ok","statuscode":200},"data":[]}}""", + ) + + private fun response(status: Int = 200, body: String = "{}") = NextcloudApiResponse( + status = status, + body = body.encodeToByteArray(), + contentType = "application/json", + etag = null, + ) +} diff --git a/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspaceTest.kt b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspaceTest.kt index 222c7c390..d04b4c6b1 100644 --- a/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspaceTest.kt +++ b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspaceTest.kt @@ -7,6 +7,22 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue class SettingsWorkspaceTest { + @Test + fun administrationRequiresPermissionOnBothLayouts() { + for (desktop in listOf(false, true)) { + val regular = visibleSettingsSections(isDesktop = desktop, hasDeviceSettings = true) + assertFalse(SettingsWorkspaceSection.Administration in regular) + val admin = visibleSettingsSections( + isDesktop = desktop, hasDeviceSettings = true, canAdminister = true, + ) + assertTrue(SettingsWorkspaceSection.Administration in admin) + assertEquals( + SettingsWorkspaceSection.Account, + resolveSettingsWorkspaceSection("Administration", regular), + ) + } + } + @Test fun `width below 600 uses compact category and detail flow`() { val compact = resolveSettingsWorkspaceLayout(599) diff --git a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt new file mode 100644 index 000000000..be1368955 --- /dev/null +++ b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt @@ -0,0 +1,105 @@ +package dev.obiente.nextcloudnative.app + +import androidx.compose.runtime.AbstractApplier +import androidx.compose.runtime.BroadcastFrameClock +import androidx.compose.runtime.Composition +import androidx.compose.runtime.Recomposer +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshots.Snapshot +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import kotlinx.coroutines.yield +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class AdministrationAccessCompositionTest { + @Test + fun settingsReusesCacheAndAccountSwitchNeverRendersPreviousPermission() = runBlocking { + val frameClock = BroadcastFrameClock() + val recomposer = Recomposer(coroutineContext + frameClock) + val recomposerJob = launch(frameClock, start = CoroutineStart.UNDISPATCHED) { + recomposer.runRecomposeAndApplyChanges() + } + val composition = Composition(EmptyUnitApplier(), recomposer) + var frameTime = 0L + suspend fun advance() { + yield() + Snapshot.sendApplyNotifications() + yield() + frameClock.sendFrame(frameTime++) + recomposer.awaitIdle() + } + var session by mutableStateOf(NextcloudSession( + serverUrl = "https://permissions.example.test", loginName = "admin", appPassword = "synthetic", + )) + var active by mutableStateOf(true) + var denyAdmin = false + var calls = 0 + var rendered: AdministrationAccessController? = null + val regularRenders = mutableListOf() + try { + composition.setContent { + val account = session.loginName + val access = rememberAdministrationAccess(session, refreshRequest = 0, active = active) { + calls++ + NextcloudApiResponse( + status = if (account == "admin" && !denyAdmin) 200 else 403, + contentType = "application/json", etag = null, + body = """{"ocs":{"meta":{"status":"ok","statuscode":200},"data":[]}}""".encodeToByteArray(), + ) + } + rendered = access + if (account == "regular") regularRenders += access.state.canAdminister + } + withTimeout(5_000) { + while (rendered?.state?.canAdminister != true) advance() + } + assertEquals(1, calls) + active = false + advance() + active = true + advance() + assertEquals(1, calls) + assertTrue(requireNotNull(rendered).state.canAdminister) + + denyAdmin = true + val staleController = requireNotNull(rendered) + requireNotNull(rendered).refresh() + withTimeout(5_000) { + while (rendered?.state?.result != NativeAppCatalogResult.Forbidden) advance() + } + assertFalse(requireNotNull(rendered).state.canAdminister) + assertFalse(staleController.canAdminister) + + denyAdmin = false + requireNotNull(rendered).refresh() + withTimeout(5_000) { + while (rendered?.state?.canAdminister != true) advance() + } + session = session.copy(loginName = "regular") + withTimeout(5_000) { + while (regularRenders.isEmpty() || rendered?.state?.result != NativeAppCatalogResult.Forbidden) advance() + } + assertTrue(regularRenders.isNotEmpty()) + assertTrue(regularRenders.none { it }) + } finally { + composition.dispose() + recomposer.close() + recomposerJob.join() + } + } + + private class EmptyUnitApplier : AbstractApplier(Unit) { + override fun insertTopDown(index: Int, instance: Unit) = Unit + override fun insertBottomUp(index: Int, instance: Unit) = Unit + override fun remove(index: Int, count: Int) = Unit + override fun move(from: Int, to: Int, count: Int) = Unit + override fun onClear() = Unit + } +} From 6b25bcb06f92e6203a6d55d5fba40667c58cc4fb Mon Sep 17 00:00:00 2001 From: "obiente-automations[bot]" <311907242+obiente-automations[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:28:15 +0000 Subject: [PATCH 2/6] chore(website): refresh marketing captures --- .../public/screenshots/capture-manifest.json | 22 +++++++++++------- .../desktop-startup-settings-light.png | Bin 102903 -> 98335 bytes .../screenshots/desktop-startup-settings.png | Bin 103033 -> 98377 bytes ...desktop-getting-started-settings-light.png | Bin 102903 -> 98335 bytes ...guide-desktop-getting-started-settings.png | Bin 103033 -> 98377 bytes 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/website/public/screenshots/capture-manifest.json b/website/public/screenshots/capture-manifest.json index b9efda13a..2d47127e6 100644 --- a/website/public/screenshots/capture-manifest.json +++ b/website/public/screenshots/capture-manifest.json @@ -22,6 +22,9 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivitySemantics.kt", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityWorkspace.kt", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppCoroutineResult.kt", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppNavigationState.kt", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppUpdateChannels.kt", @@ -448,13 +451,16 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountHomeWorkspaceStorage.kt": "5e0fa144df65840d15882c7da1dac19041083a302ced40578d07747f8ec7d828", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountPrivateMemoryCleanup.kt": "35c13216a14662f9bc2b47cee36b29f9d7d8602373b937536fcc5cc01da67e4f", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountPrivateMemoryLifecycle.kt": "09053be8a8739289395cd079d9eff473df53f5eb87305bb6609f4dabefe86bb2", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt": "f59c5befeabd5986b2a12cdaa62bbe71faaebd52c007616fc7a1e7d43046c5ea", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt": "da3a3320f79c5b9cd0926ce9a9a5017bfea40e1de04515d3101c280449bad521", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountWorkspaceMemoryCaches.kt": "b987eb0ae9d1c30ecbda65a753aaf469b836394aca42c68c63e406a067a8a653", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityFilters.kt": "569265895b9442292c043f5ecbe2cdd55a9da6761a77b19b5f81fff34e999a10", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityHistoryPresentation.kt": "88f25cd079f7d7fc1553f8969818740816e2788542b70377ea11f64201c44474", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivitySemantics.kt": "625e281281f28e5a2d0497626efc882f4fb2b5e778fcbdcac34425c853f83730", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityWorkspace.kt": "79a2ba91cee7ed17441f4b0bcc781eb7bfa8c5eb90a1717233df96794c56a61c", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt": "b11fbc2c93ab17a20f123c8bde25a993c612ffb1b1525329a7e341952fefbf7d", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt": "a82f5b173075a98e0c3bd544b90de08c1d3dc291a0e7329ce00822aa0584abd3", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt": "e3c493e9168c206cda82d539bfea111f61da0b6cc1c585879db8d765f393a4b0", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt": "ef689066029776407a9782f302b4a5101439f16e5d3c67180738a234487c336b", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt": "c9343041d0ce159bd97494fa7036c98d8140b089decd0d84b63dd5bf2a35a1a3", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppCoroutineResult.kt": "a0d6f140ffa50d1def77e0734b4ceae63855eed9766e2f3f82e82f2307ddc8f7", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppNavigationState.kt": "115b9a0b5d360fae4f0738d9e16e1077d969ca4bb5d3c136401d7156adde431c", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppUpdateChannels.kt": "f8aef5ec39978ef0d80ff6cbab00a9a4af34d73c2f3a759eb483a5cadfb8170a", @@ -660,7 +666,7 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudLinkRouting.kt": "4f2c26b7f76b9edd9af33da676f83298a02cb571cd10f4bc1f41a73a42eb5e47", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudMediaViewer.kt": "fb424bf8979ac292ef30daba64e905e6f5123066cda793aa0244907e11b465c9", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudMediaViewerActions.kt": "48aaed6948d1423113d300cc3ab86d244ab76e8225e24988e9855edf74553944", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt": "db61c541cebc01d632557d71dec7dd9d1b3b5fa65f8533add7610d675a44669c", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt": "ac90c1365b665491a5f467f5d3da1793e46f81d436d964f22d468deb9e4cf769", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNotes.kt": "29b0b80824eeb2d154f52a9eacc10bd4d7068b7eca3bd9427aec67903bf6ee0d", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNotesCache.kt": "aa9ec330c3a569e2bc9948858ddde1d939358069d38fbd7a0319b1ecc3baa363", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudPeople.kt": "cff910ea2cc77211ef81779c49ee0c957851f2b4a3ed32b857b12ded1cee643b", @@ -713,7 +719,7 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/RetainedContentNotice.kt": "77bcf477e60d7e3022abea07ada109c92e57b4a3c2dd57e61de7bdf53d242b4f", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ServerCertificateReviewDialog.kt": "f7c4d2489596788486893ed746eb762060b5080f64dae5659eca8b48feabf0ea", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SettingsSectionContent.kt": "3ce0895751bc569843ffabfcdae6ca11c68b4c700a954cb5e1370391cd87e472", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspace.kt": "040e1226c31e0e04b8a0fb13c2d85305d62c218eb08c1a23cd6be9fa11d7bd29", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SettingsWorkspace.kt": "377027a31cba2a1d1dd5e90490b7c26e6e8cd068c793835e159effc3f65c507d", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SupportDiagnostics.kt": "ae9e2daa635332327b296ec5bce8da09ef32aa5249b6b1f8e029b73fa224f31a", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SupportDiagnosticsDisclosure.kt": "248523efc8721ef405f5f000ba3c518db5d6ed4d5129cbbd418b431f19e29ed1", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/SupportDiagnosticsSettings.kt": "f851adbdd10d8549f4ad1678c192430bac3e27f12fe89e26c430e66bf0b42ae9", @@ -2394,7 +2400,7 @@ "purpose": "state-coverage", "platform": "desktop", "viewport": "wide", - "sha256": "316347fb81c3bfd5db96facb92fd3708ed7445beeaaef077cfc5fee2f2f94e2c" + "sha256": "3d10e6ccc9f92a6262d0364bf26aecd98a911236bf1e1130d634079bc16ed30e" }, { "scenario": "desktop-startup-settings-light", @@ -2410,7 +2416,7 @@ "purpose": "state-coverage", "platform": "desktop", "viewport": "wide", - "sha256": "853c1bbad08d3c3b7a8fdd9409950ceb88b35af5576af442f67145d28ae9267e" + "sha256": "c21f4553b8afc45a75d34aeb948da843d09658750d85728efbd003330d7af4c9" }, { "scenario": "tables-insights-desktop", @@ -4062,7 +4068,7 @@ "purpose": "showcase", "platform": "desktop", "viewport": "wide", - "sha256": "316347fb81c3bfd5db96facb92fd3708ed7445beeaaef077cfc5fee2f2f94e2c" + "sha256": "3d10e6ccc9f92a6262d0364bf26aecd98a911236bf1e1130d634079bc16ed30e" }, { "scenario": "guide-desktop-getting-started-settings-light", @@ -4078,7 +4084,7 @@ "purpose": "showcase", "platform": "desktop", "viewport": "wide", - "sha256": "853c1bbad08d3c3b7a8fdd9409950ceb88b35af5576af442f67145d28ae9267e" + "sha256": "c21f4553b8afc45a75d34aeb948da843d09658750d85728efbd003330d7af4c9" }, { "scenario": "guide-android-offline-files-browse", diff --git a/website/public/screenshots/desktop-startup-settings-light.png b/website/public/screenshots/desktop-startup-settings-light.png index 1b80d9e631676f8c31b54ac75285ca3aeb50d6ed..44ea306abe915dcf2b72857170fa8774d4fad7a1 100644 GIT binary patch delta 18319 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

F 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 GqyGnI2`PjC diff --git a/website/public/screenshots/desktop-startup-settings.png b/website/public/screenshots/desktop-startup-settings.png index f37413272bf86fd63a3bcabb1425120d6d881713..c22898368d60301af6f799c10c1bd3ae4c061ff3 100644 GIT binary patch delta 18884 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 HJPrCk&lH>Z diff --git a/website/public/screenshots/guide-desktop-getting-started-settings-light.png b/website/public/screenshots/guide-desktop-getting-started-settings-light.png index 1b80d9e631676f8c31b54ac75285ca3aeb50d6ed..44ea306abe915dcf2b72857170fa8774d4fad7a1 100644 GIT binary patch delta 18319 zcmc(`2UJsQw>FBRq9S0~f=ClZ5oyw;MnRO0(mP7;2%(oO+$y+1dM6Z70qIKbK@pG= zg0#>>3z1#|ganfOEAH+0{r8S@?>*;?asIo;$OvO)t@+M(ws+2FP6+Q$uk&*t{??V(C-n@@ZkFpM6-h2Nzj!?m zKON6}L78ce|y@Cq}Z+fmew8$+x(B5qoR+ z7tMYs8nxLrj81~W-Z%X*-*R%rnvwa!J4jYCB{a2b`hY8Q>%t8_o``Pw5CA|4HM$`V zXLm3TooltoxhUbibSUC*xmb2Ht_`}*qtj!iGV;icw#ba@ds4B_XHC)ifSStmv(FKhCUAKm0r z=MFvm>kYevG@EshDikiDpYO2Bzysb6p6lYQ!mv=*h?g~^iNsU<1^G2{jcXO}`Op0# zH(qG;XP|`5w}+w%79l@W6Zo+C`J7&(yzDi|6lk^iM?fWlPrdN7*sIvKWfXKHlw~pQ z#U4su7XpWSG%Lz`)RtbQrxCIiv|gekg(>>G#CzS)&d9{~A#SS3kadFgEacQHMry|(Dg$v9bs4jbZE@uGIIQ+||5Xj$c+ne5)roDTrCg*f&Z(c3LpmPR2T1YHGp z4A6y@N0P zs;i~c6WnXZuY$&7r=x(Csh?@89H?;zICQVm_P1HxzfAuVL*D+*%7gzB!QDqQB2~7f z?0bS|dI|p1yyl+Ofvii@rS-_#5er2bOMm;a22#VS{}dB=(|p9lcGykYXOOR}gQF}* zQ$#@&ZQ*Y#(tOx0B=cm9)9)t>M8e3>&=3~%Ew*B+uMzi7Q>5n$!#WNqJVsl-h4r+A z15yN~8&OnL6lv9eO;-udD2m|49P~A?S6NU4*9mjQo(p}AJl!mQ6CxNZ+l&6J6b6mF zfx~Liq>D@~4mWhO<3%jT1!?5e6N-UG5!*+oG?1ND|G7j?-~4`a|GZ&a?1Y! zIsZS28QlN>kJfjW{+Ip#=R(y#QYm5^YMsBKV;K4|PPNfb?^pC=tvk+om+?Ezm*`ri z-M;(^bN^wy`@f48`2UV~2DLk3SZ`TvZER9T#z6mQQoeU$BOUcxyN%eeVY>lalmIKE zz#pe0kAjQ09vyslWM@^D$=OM$P|iS2UtfPwQp&!s6M;4`&eL{}{z_x<)7>gHx~ZX| zr1V{YNg%c77PIij+|NlJdivwT!}%svmuZnaEX8n3@hv6jp-~0;+TtZ_vmI=h+0jj-}KquQelEiFm~ z*?tdkIV8?)7Fkoub>-7qa8Ow_fUAzLwzyYa{C(27tNm~Y2;0Ar6Lx$ z15j|M%KJq-#^uxhbY7H{& zvu(v(P5-h|_&kG^Myhp*NXTIv_(7%K*5E)LTa z5LW*3c+1hC@g3(ekBAN2_xCaCg+ob$I%GusR~)t6xIBAoHCP3@bv@N_D0l-&xI>tt z-j(xTPkK(z5VF3-C`y8gQ1JG$v)>X2JzL+t;gT1r1RRiks%+K?T>jI-6B~7|Wr*2) zaBHYFU?Y^^NKgdgXurfN?(JK2I`n3ySE7iv(o=3doX`4s1D6XOGh)eeFRiiZjyXMr z1ym&t4+Y7=eC-}Gi$Yp6@a(Siv>l!^a7ZlBf9NCX4I$7yhBCHQPYH)-OuXSH!$?fP zr6e)ijzu>9!(09ss5Q*%Yk9?NhYEB@tkbbK?K8Amam%>Ct}Qyk0X;?N(-dvaG`0>_ zB%e5=p+tH3Cyf3Cwy+?(>p4V067ErB4+9p*3d?f_Lk?Wt%g zIdUReX7Y+?^P#u&WPsD2{N_w=hLme|N7@}{JxWLyb}Se*rGG1wqBIb^{@L7b!Z-DB z4%fMu%$9?E7bTJ)Sl%F4j@WX55hnD#=T3Fv^36SvnDrK%L@0(!>J|gQ>Eq;waZkdf_cDCw{%l0f#9||6>ZU(=Z9S<6%hv@K6p5u^_8leKVv?{> zQi(#2n7gO_0Y{8XZlWhryH^e3lZTL`k+Wl%;c~E``@2wK~R@Q1=*x zxy?h$jy@EnNWjKFD2WH8>1W4jOoV{O{Y2)25B|!F0b{ z(~oe|iifdoh^ZQ6r$(M$S^Zvvn~WRWXJuUKg|UU$N(p(bX=l3!>2751JG}ad{HX-^ z^tH9hdGH23gGf#%H*ghtnWJLv?LB97&6>sh@bGY`2VBa?TG*4BC)*YcXAIu?iWAgi)#HpuOJHf@ib}bh4CcbtXJ( z-AOx3Sx0*IP^6V|I00g%N*=Y%qOy1LfSf-4Syc2Ch%QI_UsIbv>Z5D&f%kowQOaZ;h6+?RfJhXrozZG7pM(oNDkz z9&E%CwI&4g3-UY9N6Ap9>+$@d4t;6qKi*?d%<^j)pyT9W!tT{C0gL7m_RB+y(xIds z4@!N0{taAa;DZj`v^1nN<^~&;I3Ou0*()`Ta2?E5iJ%Enf$~kCUEa?EwBhNJ&!i$G zxxs&hQV2CD`22ZmKKQnxV(?zCGNbU0^$MuQ)Ww_?mlZwIKIc5YmKs5~bjWI7e{Fwz z8Q0qdnr{+-%LcwE{VF~}?1eVzf;J-s7oIb4XKcV;DQ|nSN}#Zw074$19w?4Inb)qQ zJb*7OntSx1052PnhW!NUXu11Djj2o5bqVL~q(#&Xt+X_-I)&xC7sPN$z`nj*#5ne5 zZgmBYS8Eg2r@U9R(O4wf%8lYVDs3)PTL=^tWvqlK1_{OIaP1~q08`2J8x#h7KZKjo zn?@}|f&xwqUT+rFh2Y)%#=Q>ekIvg{;XVBi_SPi47ruvpzD6ZKC(7V{j+DCQYY{&f z@xbo1t&(`s6@&fuh+mF;b);#u#hW#Njy%u9lhL@*EQ)~OS3@=nL*uDgfL>uz1UKoS zNd0Q0TQk;yT20Pnpx&;X^sy|f->$HLV(r184qxPdczAPy=>TPZ-@wq&J~hk#yDxew zji%1cSx;OzhiA5{W)#)4{i5-AWbI^11Z7LDBZey#?%7gJH1YNI^_#NCSp*Rc*~M(` z-_XfOGPVko(uY(Z1xSPWy6|lNoDjJS{Ms6pmT(`_{mO~(!vbmgRBNSO=rR;^aU{NI z!=AL$=TcmnpefoYz7frx1%fTt-akY@tO;Jx!^SsP+c2ev1JDfz8)VR z_gNiX!mN88I%6;(+c0eMm_HRfE`tefjYy+0r?y?lV3{#0TXthr0!lf~me&H)VTP>E zl+<@DBRdI`&{~VY;bGaG&1(|Dd#m7K+)eB{7ZJLihE0ObBWoAyaXGqhX?Jm-L2aO7 zUCtE+g@a|kTRqW17S{x^Pc}5lC@>ot8CgX0XT?FXfyaJRp&L6(Q}Pdab`yyWu^c4` zj|Z{bS=V9|Ajh9xd-mQSc2$`3mB zWtTIi5BA5^VuJYf3$)3xz*^)h8P6kJh%VMsW+F{B z`8ViK?D#VvUOErv+b?|ghkkhl^yQ^mjJ~sF0W-CH9e4(}rcgXER_TasSn=$Q<1KFd zg-UEP8I>Nh<^k@kOoDr2Boa}vT@~bm>Yt-|`FbLVxn(ed3NB3+>W^4^X00~0F?;+< z!a`nDX9(X3OR;5SequHDCkR1=>B2F>cOo@@rQCO~{|Dd$_{+cRum4=lWgz;K@e<^z zjR&P?ik-L~ERfu7T4SBF+BCK3tZ$5-T#TOGSXgBgLFFE7#J7Y7^$k<8#+dJ10C0sT z9-h&n=(r`#>BCmhkvCcQ%o3JgYk3sBobJVYnn^)jJ zAuF~c=@a=R9Fg65#+b}m&seqESB-XPuG&65MONK2;jD%GWe!c* zgFk!pjg8@<{ur^TM!&B8zY+&WNB7lvi;BHTU7h(L=Sw)NUMzY#!O-|}nzZ|P?;s(- z^;=`0=gxsFag?W^rpBSnmY}q+mL0N~v(#Uv7Us2{Gwa@TnFo}DbIt_NT#a_4)Z_FNw`Z>D!t#+(S z9&%;+xkFArPhI}Jk7&-f`J5KR#irrwi*$@3uT29B@%%aJ9lGDU3bNsYI&wFpq=wlg{6b)%9YCNgUIv1SkZ@SscJ=5> z^O_$t5OHktjj(I;ZAt#I5!)jrGZkMrSWqyi%xE9s-jbRZB$TbEukTTZ?NcD2j0dY- zQ+>?qqS$}AIp)c5>FiajAZ+v@v72MS2C zk&XMopAB?r2%g#R#cj06+-MFG8RJv}vO7BTVo2?tgZ-m%U?sV_OJ38nR3sQ(L^bbg za0hOub9(hFIS_a(6W~I(>(Cyr(!Ygmt zUFc;ROef>Z zS2yYLLr`jOPdO6`#SFPJEM+LWqMK?TzdqF~PP4!LaF>fmc24&YP=)+tA>hIdo$lkQ zmhc+)<%+M~WPJa7-GxnhLPh~}GL(9aUEU*v`5<%8(6D{T2-r3RLP>$dXNx6179T@n zNIxh%7vDA9Ldeb*fG7gkw3)5{8My)-irs^|s%~+#VY=R8Q?v_o7_Y03nD{6HV8^U6yDg|^@^IWpUol+^83(o(KGE-K;QFARxOngF!nFc@%M$T6nxV{al+?Wyoym%SFAn?q z4J_kmQBbs*^dM#V^L=UR`U%;2bSHKvF&4SR&jatvl3R>8SWmggAOdHz3KAA=-u~f& zd6*p_&7!nzw>RO68yXq0^9vnT&@-8F6I_mNj4BXog6G4Iu#|@&V9F zc(HY1d*pSzsrO$X;9>Q#?V+eYr^NaTzAlJ$P$_ZrTbKSoe}CMtF?Z62+b5%GZn0aI za{j$nry3X68Mt){4K%75R7P5bpfEJS-dB zsYo*^UkgroI$rIZn0$hz_XM!QOpFb+3bqX>Dk`r0x=n_zY5Vi3!*(Ys;juh*C_<$L z)n191Fl;FMlc8}TMSi`HN~Y*Kr%CXG2P?c-+tyY9qO`Zbr;gLf+9t2n_P&eiZ3eb9 zUZnJldd)+Z)7d^`dZ+O8L*O1w>ui*Dj?zXWk;c6gPUu|W(nu+wxpzpZ0pUa1aX>rJ zb(D59!K~RX!d>QIl8xk!81A2>)E;biMwNGiQ957S(vq~dlwRXLE?G+?2d46=gW7|G z(#e!E=1@S(j@P&+3Ws|nF^V)wbB))cW}ee$)b3s)Q|c^$l`H|7nSPn(4kWZO?N}X@RE9s6bqZJl9uhrz~FBmGrh+Hmqw~JQ`RQr=lOM{L5HQ; zWzlWhk=5-(pN~ZuweA=5QJJL;{TjkUWk`i;!DJ1*@3dZSN!_NDMBw%tpQQmSUhpNg z1cPKo{BX-hI~s|9cdLN^TD$7kA@lZX5!=pji_KoL?Anh;aoavO|9NOtxqITZk#Wg` zvW71fIjMSyddq*jw%F;#K(_{g9u}jCn+N3$Wq;BZ?{^XEzt}IaID{K|2(161MD4tc zq|`mwMdlF86(4g@u_hMmLk;dmMVKn)@wKv%D+?p5} z`FOkPD&W4-s}A0zGt+68dEt)EH%iXEc$LHL=vzUUqRA z0MTweeOadHXaT9@spI=Rg|}Gs^ewZ1A{$;+!ED-kCapzm-`;|#db^FDzPswL7G*0s z`FaA4)_>HQ6mDVg39T1{4kU$p3q)h{ljg3!+(hUlD;F`g53v^MCE6^X9{vr>+bkIr zP9_Op$I|sZ^n5=KDQL>(c?;|USiOV~HIKA#%5Z~=ho66SPKC==^$OFm;cq-M1VX}D zr3)sLwzMTAiYMP*qH$7HM+4q_qSMC>Jl`{!-0fD+mmGF$rk?E}_Hebs% zqqMvKH29U3fKaBr_x8AO3|U$49#fR3$|o?}v74?}daLbu|5w>vcn+ zFb_3#-`tDhGQSidkj(hDM_J_G$UL@Y<~0N#G4dOj2eEvSF-KOj>wlXWsD6 zo*10GMQf3S^U4)k0#@&7ga@%Ex?@{yg*_-o!oqzv}O zsS62wqRm?mI^IyP^au~iFl^L3B<-zc5jtYJ1lurL32!(cN~u#Jw&AgyvoXLgMyt-3 zdNamYXN4MN2h7%IZg)Zl5XKu#l)eeD+A+1CIjx>BY;-9JXB{fr1`D`L+Fi|(dC-&< za=aE>H(Mr;Pd(V^S?c7>5y_GZyi5~WSb4G$+g%80bue)56;AwgRXWfbF|!{QRiLD? zD1EO6>J?)Z2^J2$8R^)AJ>&_Mk?#K8k(>ewEhSKlRZ7TRDb2}P*6ltx6cjC}$(QaS zte_7~;SCKwW*==M+u!}3332v4va=zg08y{N0e7}JZWER;oHHpJ<@n>u-tfK(wl(s-r0a94vMzSFf#P#=?QdFDOFATB-b(9 ziM4_JG7--vyx)TsNKiIvYbT1@s|!Fiq^(vakVkyLZdBhsUX{IJngl)G5BL1^SQ@}Q zxu(lYQ}br^(DKoryGGU$A|?Ws6^L^pp@{QP>J#mS6hD*Cnn==Oz55 z7gh$7hJb88V_hE=TPgeO;5QD0^!Tjy^AZ$EPO#wFoCLmNw`$Xbg@(#Lq_6*UJik?d zl5W#x2rO`Mqmr;EzgTdvo&zm!QgE~);S{{5w3o)~p?%HU+h=%W#ezc7%!S3J_-}uQg#6*-{Sj-`x}?43Pq0)6*4SA9mm$R0%Yc#q8_d!toY^1;}L;UVDN8rDgmd}7w*KLn%8 z0{5_~;xJ&~gAX;JCl!Z^@%&e&@DM@ufqMN;zAn)BE49kAmoUY; z33l}@p@RtjjV9@kfP@b{oogf3cynu)N#?b2+|c`2WUQ`|m^`QVBR`CvNzLdpVBTkC z;JW(u97j2>oMk!(lv9-3Z9BCDyJZjs+bV%9v|9T0gxRNb*-SNFS2wcudNy9|4(DTU zvan6~;26to>WVd_%uDsANl8Skwmii9vrE82%9?gldNZX2*T!p*YlNx9>#U}d{G5IP za#gN58>O}PYQQ0}MM|Y3njcVa@HM^TT5{)3wUku0H*I@Qo;xLbA{wb%oe6yU`P#Y( zI~!B{Z5a0W*=rB^)UAS7N}FVD?x(B`I+pnnl=i--at9;72x3$4BH!01n0xGHrqZJL zGVK7{dHp zMRnGVX+?GM;ua+^7e}>hdmC|7+0eM=13MD#Cs<5c>O;%9H60LHetqn0)@hcpcZ6gn zeI1oDW!n;&|4~luQPP_z(cYZ0`dfzWHZAzI>O?+<^=e5>8|G(CNPl>}aw^p4+f1e>#Cnx(3VOBX)L@5wFuL9r8X8jUFCcwQS6@ zF1KP=^wZMF>)0__eIFM%kW^^uu#^oYqieL`v8T-roe)3u2KhxrN&wP+Wq8LxY7woU zrqRRFiw8vk(z>ors|1H@!-4#@)8tg77Xw#wB8*cfI!M}z5k;Xg!!74ly z=4Sx*o*Od#+p&ScLye{_o`_8EZ@N%?Jx-=J*nS^Awmw6@y$$!wN9k!6l&!xXZjRWf zMgeTx2i5-5-Q_5Ge%I0_mj?f}l+W{>xS|Qq9;=D9IB8$^in)p&`$XT79?w3AXyvkF zo^foRc;NU@lZ1;w%s91mLEqfLBBX71sd+(_Z>V!l$<#J=&B zkX+ZvkQdS3`(6Bt3s6*FT(WT=R1`oYsq5$4#h3A{DUwlWtDY>D$(-lpgS=3la^VAcblS#le&rO>twk{Q2rFeOsItWuVlc`5KOcuXy?eM<3Wo?OpCLgop^4`-w z{U0>Lw-RqiQCrl|WlPlydh1t0ju_pg$9JEmO&}_*xi%hcAb?g6ej0y48+6v^RDX?q z(gAPJM<&aA-Sf@;S0R(~7@Swhf8r%o_28db6IHtZZSKTI-N3iVfX$5ecdiRQt(_}3 zJneO|RKqvYS^uNa$zQzPZ$Ce$oFHQ8d+SW8T56HB)jit%yHSNd&tsPj@@yZUWGcM} zblPMgG-%JiRW&>W%OW-xy_>A!rOtlc%S^&$Y09j(M)EClAN-Ts3s(uK6N*$A3xy5xpr5si+?r^aXY0{^8_#RSxBeKc?w1COl3sNIs1gMzoLmrTrMhKb z)PpY%u|^hZ8x}FvO#Z^Zo_s0v*gC@4Zcvcs$7=U09}X!s<))Q+|MSC%!0*A&`@6=o zS8++F(+5qo3N6&?Gn2a2dDTD1{c&2|FgJ62Ie*9~dFnBZr!b>;!zcQ&-r~id)5e(E z4_!-|sI0~gq@Bn0%g^5@dJm*2FKZeK@Hy)bCe;jU3;Z!@@$0qYg@ztq#ENs%x+;q$ zR;<6`m=3`DZ}(s-C3<8`ZsLq0pZP9?AHD}EB?b_!Nw7gh@+yAJ2F|q&&N7D-;zIxw zk6mSHjg0v(a>Rimy>ah^!d=7ku}4}&{Vu#A5F*8~+bF}ZTB{24`*}lvHSv#xEW)(n z!G`}6>9t_9zWpVxoXmpEUbmYLL7|2eHn=yCxeYq(=m2?p3R$CLYddezd6|Qwa*1`q z;d9;r_M1Lza8AnHZ3!m3@aYer~H$$I_b#(F_!Gu~8-0IL(Fw>LGj3eFy+ z(-x=0mm41I*T&k7XV$-%i)NTiW+F}H@T@{^wu8XGAvUR7+gVM&=(M`8A+J=sa*=C- zw4tH8nCwhMutO9@#$k|x0Nj;y3kA}Z3gon{y#;o_E}&znXK8u_PpDfNiYH)mcJ;O! zd}nFcwG4#`!Ix$}+osx2aJA%kdVW%mxwBl?MBbA}cIr~wWQjk{J#<{HW7&RxEe1Th zOLIVAmWqbq=UWbVx@|NGJrHh~PZguaCjMn=yT(-6sRS@A{OHWy|6r8|PScDf zk2xg@SB@D?;L81{vi8=-;lEmvts$-;WFE0==u9%$Z?eLyKsTSS*dtyTX%{qP^a@Dk z<>$v4BoDeO8(Jv)MTn%phGFF9=MdAddLM1y= z!Lg%WHww_K4efCUoTtNSEj^Eh-I@^pc_xX#<)QlV)E=zC#o`L|dgJ29Yp|q;JiygX z%Jzr)aRuUzge+;)+HUUKU&Qqej(nAfJ^au{&$umyzH;*`Bd-6&UJq?3tW|{>_42O^ ziG1K7PWItyowY-{QgbCfrpx0pF7Z^x?HD0l2Jl#4lEj zjya0{@N$^-$fwfU-g6OLnS6z=gEt~L{p=pR;Y_BPbGW&OcI%i zcvQSf{}tqVYe6&(kV%G|ew%1F!JCSUqYuw}l$fM}HAqhMlQMJ`O4V1Yjng~GccX4k zn%@&@xSu+?JMO_QH`DY-q&swmSN?-Lyr?(ZQo~kXzomNYylFw*Ls-Sv@0lb$RIkg; z{IUjtcF~GFulh_1nI!Gm_IY6DUf|4^h>9Mai9B<3nX?cQAbWoWTK4rk>WCvvq;U@7 zlgWK8a2Qb??Dq6othF?5g4Gc!omS7w|MYBI4T|bw7~vtB}ysBx24%g&d=he z`ao{zK}r31QQ$$=IS0m8s_RDIeDTM1r5K>EcQQDUqvFrEZZ65HcOTzB_s7Nir(eGl zW+}U3W-;*&_*h-qGr#S$6*$yz(Y$mnyl(bS#=5soUQeScqErjRl5QPUzp@}A0nLV- zKd=1A`qVeR{ZNEelhwks1hg-6wwK3R2X^i1-&gg(+v|5~^0{h~9VmV(moecloll+; z<4!uEL^*cH-s=WGGKT(k(2O_?*6(tHbN`qshX!yYt>y51zAy*!Wh4KE@v|%UhJ0TK zg!h|y>$B61Mk=jzUux^(XIjilwSHe$_fkMq%lX;}<+1yF;! zN?+@*p(dAPB_t%4eJ0CZJ37E{{`bz#-5JJx_p&VgdaFkUz|1PlHE!EChejRYV9YPj#~uwIRDYIbo)b_d@=?>8M_1y_jAbM=ncQP;6FojF@spQnM&kr(93<{He+pCPFW ziR{pmCxKI0XXj1cWxtS0>G6<_j4EII5^X6>cYAAhwvJgcwzKuFUBo+-{GKJpME5hg z9mx7W%D%MQPH5E9qL^9e^zE@qU-GcKC0hOP>PwRasd$!|NR$M@M&s#C9yoc`3O>)K2FJ)Mf7&A*j=Fj&stjG4JC}Op(?W;hQS_hmdG}7nTvsN_z87QZd{wt{9%`wfMTXqX%@H&H?}E%z5XsP#Ck{=uP%;-rVXt%x={bKl)x?RMT(Io@ zE`~m){nGaxiz(-Sn-Y)di{t(4%!aqWw$5F!QKp|54zF>$&d=ITXWtcPcXp1Q0e$)F z*{j(q-6uZ$dA9uBv4>}m9h2tczx)Nt<+e!;ETMUA^jy zl`;T2J4{B)SfNfmJ+AjHROHSSUp8wSc^SKM@2r{lHD+h!!z$kMcjIclJrnDgo7f(| zT=*fD>CE+0JZvgX{sXmY7ZTO@z)2-B$g<{1)xTAB|GuAU+gg}kQABG_`KM#K*DsnV zo9|}Xi`-NFv3QcXLoQA{tu<~(MbBAN{1d?UB91kF+YbZF5)vJJDh#_E!U6NdT-AOq z7VgCNZqxKP&5So-)Os)fvXz-*^Vvyy&9kjYhEj$ni;?(x{31izvmUk&^f!eWUz@1> zH2?bH%ggYY2d^NNas(dSirHlEa>3?1nH1?XxSqH|}@Y~po z>O;z+JbVc9PX30L9p%sKX4<<#tWjG#A0Gap6!nj5s3rb*a>VCbG51k65ex0JW;QV@ zyUL=R z5?xbE$fdT}fP|qGkvDIA99rj(5ToFR+4z?+IpTYfdmjdP3zM$z2;1LlT?Xnn&3@ci zeATe>dx@)8AxF!3r~`p$4m`)s9C()jrxTmc)-tW^Jjt@&lNU*O86}K(1ivQ_)Z?phIs*( zp{Lo-MXSngjVfVeV@mB$aR)D}roi@OO-;S}DA-5LOXGiaX2Z^PdR>yWxkTr$74UN1 zQr>HBD>MMm;T?47wZSh6SGhfIef9o9e~~?-QHe!+75hefD!gs-tLnG;^h{txG#&Be z6u3@8`Z?Q$*H1YIsxQzXT1XCkmz97d0a3(X)hV#f9h=b^id2VFsr~X!Z6M)A;1gl` zn2omn=bal>Q<{Sgo6`|^b-qN-(1oXOIK|$8oZf&?FKecRp6KY`NVCcm|H#vE$trN( zGNFr4(75y|wy4|*-Ei^R!!z?^g`S_bd!$yUDr8eL{Z9l}JC!91|E(2J{{tr_o#@ss zecx0*-_jNZEwjDb`FVB9`>YD^BlWed8lQ^Ixd^=IhUSp(rGZ)B{L)JXfg!iB5+5fz zExhcFg`TLW+`1UYEcBB30Ck#(g9xjn*we?cpYqaL>$r662ti@<7-R!DV@z2Lk#@h8 z|Mp6(sBw9z8y-nwQc!RPP8(auWrR*t&yvSpO_E#ZC;iA5ApsPEQf4QPYKGijDR1@S zT+g{fl%LRnQKZDh#q0bJt4pjJW8^8~@e`B-jR%=>X)9D8(dJl_wptFE1g#sFo>_R( zjjvY97?Vi~r?C43mWeW3 zzggw%ATKj}I?EKbin%DmN!a|x&0Ax=)M@;cgKAf8f=5>8-%GyMKH8kQf+OqB$J36K@E_2mQL)!DmOd(tT(>Jqw@G=M2t6wY$kOwd;>CQc+ zqhaYAsM!oJw$FfnadRCoXXnv~+ptjdJ9ALuj+{p|eXFW<^jcpkaIydG{jVjD>Zq_> z;b!s@RGww0Hl?a>u+08o;JMMZ_1#<1jm~TSoRkP#w0w%I4kZ%CFx_^F%K^Xq;*93JY}2>|1I(JRw^v5 zbYtvF*H6WMnwttM7e!=#v0Uffl=1%Z3egtb@bbuL|3L7QBM+IH=pbi4KW}g2Jr{nd zbA}=1dmHbOl*bppNQBMb^%H6xdKv%oyGVY6?YUQ<*-&(+z|H$_h9A6zQszAzD zI!F-aRrg`7BliZ)?tm$w^ z6M46;Oy%q`v*CY5^5~c7ODAS8fA8895W$bKB6Y0&*y&!#VR~M%QBGsbgs{&mSJ;p8 z2%X@3@q#z~w3@}lJW)k*A5)-u7JAAaend?k88@M;GV;Ov z(D-(BdLZ__ajXjLnN^gAhKq&mH~gr9fq`jfpzY&xNXDW+m)(!l|ISQbOTu()*f~*+V-D-^h^-xI>p!^_C>Bo7eQeyAlhE=j&}dV7fEP ze~G)9*cSm>9LU&y=R^EYug!Z>HUTq4aEMKCwbWve7;kKoBY96dHv*T-K{Z`(`>K|>v@GOwY$BQjSBg% zab9EX?*r!23$?PhZ`I2p>kj9j#nsNk6~_^B!FN~`w>YoEYx`R)T|2Cv>0o1Uj|*7l z|H4__V2v6mQiTTbc$r{7ck+btt+Y_WA(K7~Ki*t&Jj2nOWDH=AT{%ggB5Zw++R{vS z=Kv8dP9!=Xu7^|G%rqxPf+hC8#w%>C8t5pru#}qByfy4$^%(`Mt%BT7@UtwVGQX-G zZlyGSNA|t*+{iwhZzK91? zdz3=-A~CQ8u&53%3AjN=KG?IdeJlo!HS-kuWVAE~d+%)~%DV2WD-b7(-!ytCu&1-{ z$dlA!QnG!z7BzCUf}&(TXc0beqF_A z6VY#UTWX;5CY(MafZ_dg!gaQfJ;GM7+wT&6+2{MsaUY8}if0Y{N3RzCS{THqKAFOVM z{jOuqor@33r8E1TjNiY%tXfL%RP6ueuS3Zp`_Jf#lg+=EljQPMhb@1iH#=4JUH6`) zQG-~J((m8YlI2#zj9U4&^`BJJ|Dp!aNY>ac$B~DW!bTLL4*7GRR(aKbHTb-%Kgv_)PMX}s zJhp#m#CNn8eh*sio=EO1Wjb~A87G77AJTtG8aA5w%{OxEj3~d3RQY{mNy^qJV8(_q zzW#olCI%PGKAeJRF7t*=cRcCl5f4)MEe1)hMu89qWBI6k!{JBOO583O?%Mzx}X1BCw8?^ z$>YD>{pwXco(R}@~TI39nQtM((4nQ6pMe5XT z9on2uR$B(Ym5m<#(XC7B1G&1~@i12@+EZ|!8EjPj8`LDZvN`x<+;ig_I5Wn>ab+vqbFD^XN8ihO-2N_L4zP2y z!0vk^r7m2&YP&WWZB%#gu7egjQSBMbuJ>^$lR8^qy`{C4Wp{uMI*`q#i?V6Tv70am zV3V}}?4`?&&_Hd>eBir#MeeJ9ARE8a>SBkrp@&wv!y{-!v)$+%iDBO^U2r10(pE16 z-&R*P!iJResXhU`tjuXx2Y@k?W|vv?T3@86kiME@-@m}2wjSHzyU5`Uzyl;BbL4s* z&&S62UAIoED{aR8CbxmnEfM4t%27&6f7$HMymM5p(l~wR-tOw?8GXEM26}o8LqJHm zJ3%BfJbXSPv-WVbzr+M!WGs$-`wlY+?c?i93$3sk>g$>I2J9x5-=UDm;a`&6yQp7Y zC{(|o)8Yern(($l{lmJT7{;8qvgKu+6m__U%I~>UiqXT}-67u!>wIyHCZHf8K0aH} zm7GaL*SpN@Oq0?NtBsdMCYE13kCv@Lp) z2QxcV>7YPLh_9jfUd7Kw>lJ*f(Y!hdN!eV-j1w8f-o9VWfy22*SlHOas%`kT`&!$L z%%sHmIy`U|c3uV1M$sM)G8b3ZFSHf*gEHiNw!^FLGo$W?VUdA>LiTjw(ro&*5(Gnq z8Q8Y~jTMDWvl6X~%8S`^qUQ>(>l16y$hz8Es~tcV%Sr9<>zj9ifatCmX~MevLS&ahu-0Wb-;6C1Qz1Gf%pzCtk=pNCt-MJW_*h z)QK0fs8vYh&-3fO-ItIt+fU7)&^g#F88KAuC@G)3Q{lEXQMiJGKeDgwyof}`X8|0+ zt?4m11Vf)xb9fwg31?nD3=8^PpS#9o4hPT-6`p&%o55o#c~f>()*~C#!};)wOFSqFcG z)u1+k*uabCfTlFbz_8b+2l`${U++LwI(9ml4bl^P5=C<46RMCU$%;($f`5j25r}5C zw+9CW2ajqRDk>E*Bx{@pbaOlObqRW`7So>F>bA;8sk*q7@12BEol62mpFLDv*Ljp< z5DnZW%ZYOEZ1md2AJKnJqT4R?Z)`N)IcsI46!a2q%Smc_09!i)tXqm7k#X9*3`LF< zs!rCV3kY>n+2xxP@O3-Y+ou>HCv#%%tB^6XI7adS>-)RKqp0Ns8nrwLY}<)?buRNB^~fK1Torq}T}A63NKWADUBoBm zXV39SPx3Lbg7e(BsXE(>Er(X!msVEb&p1Tg2dzEVHwlLGOoSSEmhmV>ot|H=icUhZ zbe|47tC*ZkBaQC!-u@iXVLFi3EWNb8kdZDGv>IoTJOHrJ%nVHoH+3TC)4zYfbUD}% z*qo}-wGZ{wgt2HSWdsm(j*e;)2W!vF9P_NUt}HICWvy{7zdmB2;X${p;Sz9o4p!O` zlHZ44Zu^T6s-c(#QH`OcF0Ym8lAw@~QRm)+bIn7XKN8)o6ebbJ!6AmxvS~Le$VL~{ zWdY9e^pP^xaCX%&&T=-~>WEp7v^OU!BZ7m2sXVJcy{PAv@jVrNw0(9=2MzW+kl^mqKF6g!rEjruUq-xri@7vE zKQEjd9-I3kge>1SL7J-qr4`2BlcHN;g8-$fEGJihiFsx}F%lA8s6|&djd=79r?YEN zH6ki8F+b)yf#xBCa>?Cy7O7h!_GkIwRZBIHT8~%C4d+Pl%`s;%1d0G{E80JahYNI` zX*`ZgfbChxSks5*HR>93Fm6vRWH=r zGDMNybrdJ(wHpclhDAgTNG)~7sN2{i^4dI}m*9RqqJ z2o0F!*4EYpfky+R;u?sD3_*vEQj~O$Xf+bm?;O`OVQJi1pfRFY6uO7REUPA72$~o1UKC zW>b*;QkRVEd&1EnYWmmBKjh;%O%U{oacTB#0HV}P2EFNNXBT%^0BoW-cRN?|2xh1= z9!ud`Z#M!rD(nWAq7gzOG?Ms%G=n8#V!8#d2X#&H{1rPgvWiZdJxSzIlb*qPv^C&go09&Ai5R3#7S*umbS;lpbHU^HEm#x#+ znZF#Z`h8?Oj_b?kml#A;S1CV`C952VT+A#~p=;h>k1&&YDW@jN!2uoUH)#WPHU062 z<1Cs#Y`fENNkSleRi1kqNn+G_ZnnDl#;vlJ9%{$id!X}Np z_R|?VDvx?h7!(rK$Dh)ne441p`26DWsRa;yeGe^;`%QAxa@>eeTQkXlxKrt4W6zI| zJvr}yq(MD{Mzk8$W}R$c;LU}q&^~;qdc+D%OM8aPs_`;{P^%z(U|{emEHDOF`HMf~ zI>8@y9>$bll6{q5Y9;D}IFYcV{;@1RV{C5!x`~0M^$PS(KWkgF%r&@vS0Fcf#Z1r< zX%oGRYxaG3BMpaC{0|L(z2^|TIUw{NDNz=Uw4%Ad7IK~$DhOPtR4!rPI(q8yXB4F7 zGlc9bWn1^KR0?oZySMjInc9MxL+h*N_Gh1t=g zlBl-(DRphGg{Semr!^Q;$ zsDJ)KGN52#_#9uBJd|D;K~+kOKSaeRM{jzfe^9q6T90?4ypCHNcTuR3HLew+IYWOO z$3V`wQn8EOuQ?aLk7{SD;0|e+J&;;`c;Ex2KZKn=UJ5O1T#_Ik{6AA(?+Xt^4_?@~ z)%`Rt^YLw1TKk14&1z0Gn*`jYUiWjbz>>cp=AX6hdsJ0+t}Nw!u?G;9YzbB~>1Mc0 z25KZ3#%kLaWL8>5m9&<-``D#AtjPW>81Z?jNSSGT znIRaD?CHA);>t*(;-e7(D62fzVES68rTiHW??fuAGk*=lIHMu~;O@FUq(apB!TJ<& z!*;A(GC6r`q6+;HOf+&8d+~7@wZxn3XVS8|Mp)QrB#-wzt@@lBV7*;j(&r(^bJjd| zO49IAdsy=?r9cgWJcZ5th|CJ|N~_-k6;95M${(D5jfWOB|LRke)j%G~3&G-}v#+D9 z;F9Zs6&`D3wiBg*DwHXYnTR;Ou|cR~xK)Z~_CoJ)I6ognUd06N8v&2k*JII*5dKV0 zF*Z#JiF91z9rctpq5PMR0H}(KT>Z@HqON`|VIl5P^Kh9pxrH}?@M`Q&X^T`HEH~=H zuc@wn-5M`XcJ@8;#J1IIB?wuz@|ef?aSS)Ub!QV^>vn!l&m1asFerVz%i8h?K~eXE?-ku!z4&=z_r3Y z^6}fbdU0w|c8^YGtL$j5bs%v>W{RJFmY=U+SJNvD+lg9PAvdX9qlO8Y-u6B)uJfb< zinf!aK$@g`KJ?{}5*=rq`s z1>E+Kkq%2za+1ma;l~M$h%y4oSZI%meACE>i!wk1q=g<1=N5PdM>DZ+1t}y8FxYSV z;NHR;IguA4B=yv`Z{$*lh>A`|Dn8?VIJo#V=4X6FSOW4BucM8y@IMt3-WLq?NUGo-W_U=wg61d>P>d?Jk^ad zry3`4&71(xL&(H1r)6fEW?7i7F6KEi>*c08*F~LLsrNUY2bPuluCCrxhwJs!sEmVN z89z{xylP|QO>>(mZyX^xAa(QR%^qhfwL(S`xO(fmAg1!?;R=a@8Q@L`I_CVO->RVYgVNW5%V}dD!GRM9}X+ zAtd`+s%1OXO*?J|uA|e|PpO42g#CPVL&W%A*iEN@LJsBUFTr_V4|y9Rhu7h?&J!sK zb-LMpi`63)P{6j{hBKjzS}SlN;C|6~scjgq-AvkD$&@cKIf0_*PEO0G&QlK5_;s{E zWO}*@YI9M5jC0Wv#CNjknhJ;W%2v4C7tY3ir!MSsm$A1FvmVkKx1Y)@KgcRq4H>#g1e2&PW_1br&3^{tklRL3d!>O#9&l$fls`9Ex&P8F zfezr(kR}V-uJN!+D!dJWoLdMYWsVIa_KbW!^O|r@)ua-l_FZslp}M9UUNAH!B+l zbGx*`QOWH+;7iQnuU`mr0+HNKSSRwRgG-M7QmMX*d;)Wu9lrU6BCCS;_(;KIzJ2IVwUYD?`_FqrBQgc{fZ^j?F{ULt>Lq$iu)1Ht z#LfeTZr~C%bKJW3Q7v&!&aUe3aI7tKw?U3wF22(>pgY_GgVL>=>wb7;(3@Y7ljrU4f_j&Lt+4HX-*N3y?9~i$_aas8*6hEq5#P$VK1E~0 zJ6Sl)C-9(raHQ-_z3e z^9{qFjsMRbKI2>Xe?CAU;>nje<<<4%8t8GZuCI5l_5J+_kpu(v-_N(7{l^Aho%8;q zqyG^9mktK!|1WU;uj2#wZ%OaJ&&QSgA^*)?{IBzIIsd;-oBs2B0RK{L`p+v9@Sio9 z|NIjFKUa9Q|Nrky0Qi5WdVe$z_*Xfy|H8f)HRw|UhMz+%_A%ZOvadEj{6hmWS6OF^ z!Hq$B^&4brdhG2#l;qV7%qu(u%=#YPxPl$PVF3^Qum2tW;O)Qj=Kq1gz`yx^YdiN< z2Y%BkA=9!+Sh7*fw9yI^1bw$`oE6^63Lj@J8>fxzXi2@AXs)tj7$Qi=roTqY`-1Yx z$7wsw_-RD>dWwDlaZO$AlP6chs@a_A{3|CnWn|=Int#1&d7~GVY@`~{&92C&8P{D9 zaQ#aE#J8UM5WEKS;+81x?-p~sj{Foda!}ZGj~m|=op${IoIYsY+UKX?I8R9aL@r49 z3PTb{?)*m4@7-mMFRe9i204H2N1}M z;^pC6Ws{qNZX4A$2e&_b2VL-!R$3-|Y3%yF++@Yjvb!CYNjG2`P5mVq_!`xjHBs(Y@#C|X;gJf8TqM)1OVeDp5lnNla)2D`g91ydX=K0m#nKK~y{kebfner$xtb6a zRn_5@j+_ebUW4m@70^9OxCA?}+k9}|&~JFilFMax(Xu;%OEpV2#wptU^{fIG)nb<`18&3C!7ooFxR`R~rJ^x>4ney$^$H4wX0);8F5Q@FwV+h`g&Tu5CLg{$vtaPn=Q8Mya%RR(rL7j4} zO7+7nl7W3vF4v=WW#6N3LS!OH*KWh=mrZPjUzVmojmt%sVeNbLZjqh#dkZ?uDP`~G z4Voh*Of$3Pj}3bFx8ZL%@cLVWV}QgZYQO!GARL_aJw-9FK&H}k(QCbvilOtwJ=;rk zME>I9B5p$V<;(WUo@N5R{(;%(u3ru>BPwlY(<*Is@?Q5pj>vR0^vME$vF;?ezv#fv z?LJdcEJ#BmS=7KOnL)@(>lt4O7P_^;)|afCj>P$wa7{P#>elkyz5uWrAnMW5S3Ov+|pOemOBy~ zu^q@v3#FKX-&|-K8nK;3{bpEj8ftt0DH3IxVz9fn=NwRmP8qg>joU=G+Bj}`3Y#ob zxNZ(WTi?A?N7#_Mt^q^JP3O@({xfA3DO9%odh!X}8cMHH1zl~nL5FJ-&*L2`==Pcc z{T5q2%gIbcYa0XHs_g>RvKM%+TSL!?STw@x>gt%)7>mF zcOi$>lT_k{4e_aSsb48Z`QqfP`cfN{H__$M?79bGC_dYn^p=+AJT^+`Xaoxdcx$@jUBx$HI}&+79DoIX~S>y{_m&rHt(E zq2dl2o#Gva22Q7P(A}I>t$2EPF!D3Lh-?ZUe6aZ2 zJDn0ISmpLu9ztKx4EJ;Q@&8aar%*zX$w`>;?jwfM>0(=R6uWZ+`lTK);lc z2}<_K7yHF^89u=HyTxB6;_nAmb#xk?V3+Pizt+fbF`?uV=CEr3t9aR!h1BP5Cs@gV z!mX9w{(?1CZtD|5k%{!UfZJ5Lp_CVX!8gDzhOKEq>z+hULHDitP)Z>L^$J^ic~)x* zvnC=JY{3|)MUjILp7JeXR;Os~LJg6Th6KM@K|m6WXlgEUpYbX9bC1Y1#AjELF!)5R zYhAjD@#69_dlRO172a{3AW>(Grj<@UG3yyq8@y3A;6uK7Hxi7ME=eNp3W504{WZ=j z_GFzE{4- z!$%Y;qa~8wcn@~Y#70<@9`0$}K_C#j2M0B4RBe37{)U8Xg%m`iq8QxYA5vjI`U13^ zpDIPqUw&-7n0NL)oqi6wWy`+c-u1?bio~S`@53R`L4w4UvNAJsU!bhWo*uQ@oVv89 zdEO$n9Nn6Ba(CC<1I)v6FW#Y?^xBL|a$UQmQA?u>>J47Q6d_q~IDE#}I;!#5E&Vbq ze3y{q@fi!(^$HCk8yN-H#_h4{K*XZ+9CR52i0QgGBQypdAD?_YfAX8F!~iTCMa3r0 zSHtdKpxy5BIrA_rMYGd_F}4lOpLWFZ8_?~w0iLoHn8xA~zY6=65XWy>iqLDwe}-jP zZ97_Qw$2-Zc1x$1KMKH!z*#zU=~Wg<=ysFcoRGu6PEy^~@`Jv!w>S7|vX>F8_=9Z2 zRm-qj?yio?>!DGITh zSV!{)EzHXBX0+k|=p_(PqZgK&7Oae_OGqf|`C`Jb-|DW)Gq+{{R$U_2fU|R)u-Cs! zd1_tOO3%*EhiaxXn6=YAqWvNwRm)9Vbv8fo=YmisOspveIgCgPOc2gpU{G8iEMn-g zssI6`uF*DKy!GLJELW?=BT*IAL2gH+9;KM?i!9k_r6vP?E|@e0e>zhcNxp8Nw0fZv zHdIB$snjpFM!YRFB?pSy1GCXptqRNj=XA2~Uv~$v#d987G>Gok$hkg!YI8DQmj}Xw>a%TiAUc}@BFL~W zUw)5@Yq6aiZE7w#@R$3JipnQ7DDmW9hDYzvt%b129M^*>Pq6bt7VJ0aP^)y>yly*P zq6r)ei#(-7FI5dYm1ymcz&R`jEA=lY!}BglaoZHiZ8#;cY>_=Dq9o5LVvy6UdHSm} zrI%~)c+XEK-xnt|_p(NG_g-d8rm24Y1G>nL#e%(gt_Gre6uGy)D4!g4-DD=A%HB0= z_T2j$Bp+;nu_Kv^DqpLyoOTVE&+^F1&VgUnUw7lgE(!w4MRLKyRovz=9&&o+On{bO z$(qlmTg77bjbu>hr$O@O^e^^+3wf}_=XDrqKU5(p3&SIDPF8(PtL17v+P5;R0CWtEype1hDzSC; z^r&8cBglgqEMmEQ5r=?UwW4zgY*u13q_zi}@cJ(#1J!fPc~)vP5qiTX@{=furnV&b zcM%a`LZxEy%0ttVSktEoOADJxYe%iQU0$adMcfC4cbyzdz{D?V=6uoG_u_&aY?~Mu z(!S;L%Q$KSKM)`rEz0;oFjM5b!eKRX)*960r7n8B2Y0R`28+(j3DXE_683&X0}fc- zOF6rB#Myjh(Ei@BJREw@Ti(!|_??7x7LV^MEqLMHx*1JtJ65V{XJ?nMT#-)9ru{o? z(`KqvQk^Bb+v#k7{1&)Zi?>tCBEJ|77Js2;6ai@THQ?%s`>Tv_o;?ksx&z9-fI=be zqj83%tzU?nVm}8sx<+#);nG8;+9v0vE-(YiUA^eavdMeTBjyo$ux*t17+3`|Fh~vx zlkJ1SZ{jj*v}pJCj!HW^YH}rcFZ*N`Xavgy5ThqKNe`#h;wbRJgaU3>_5)0F_}h8` zGsTui;2q2Tk0f9bI&CpZ4LWeh<)^m3EU#W8L25f$p*XnAI>hoWxxZ51y8_+E+3+;C zseqk0gj`JO1Lj%WRSzf#>@q7}>jO7_MB2U~y{n(|#IDoEv$`(NxMlz>R|H=d*?S&3 zq1EX1?lH%UwN@LXE~|Ns4jQN(b{D(Qxe4vq?b*&U!b)l6y`vF4Lyam0kJR{7qS>DY zm#xOW`o(DwQVY0Az&c@H!W8{3QGNAtmnARP*QoX;av#~{ZGUb7iqdi0(zB+8(DgR1 z*+?mN4U!c%^0H;Nk;Zq@nd_5wXP(m>`B;)jO7N$`{SJzu~&(LAC=EK&Vgvi(1w zUa7I&$xs$Bh9 z(=LZm-fbQ^exk|00m3B}@o1FD>B$M>1yUV5zZh&5frUr0Qg5H_?)}y{gR%5@Icg%9 zg$tf%I|pAoVgY+9NZ4QGz5WFOots*B0>In1zU}k4ZaO)u2!ei#%R-e2&e=&Qo^WB< zP`=N-(tCk@wm%WRQf@tq(S7O}$4n)ZcAY?Pa(A)yLa}|6Z_ka&=_Q|y7#n>2`|ZES z^ev-hFuwt-iIDZRl5So*CO2w2ixqM^228R)PY9P883vrqB=t9 zh4*88runZG!;R#X8$%O#y2IO_>@J)0WUQ>BA(b+%PEIAYuYZJzvC#7xfF&R8$kBCB zNgm@qKiJ55M%@90(%JB}Btd6|oZdv$xB;WM9ux|t0csex?SVv+2sM+YCP^F{ zAAt{tl>P`cgCbL|)^bD9-b&rUQs`yrmv%FRe~~pfG(^?Qs}?-hWCoHA5C4v|SX@~z z1nY1WKHb~k5&yEIczln97D^}ame6r07ojJw}xk!Qca8(P|ZJ& zYr!gg^43=fsIXHU%ge$ML;VL?4qo^pdKd%Cpq_ZAy1Y;$kC#MXxFL04W;gst$ zK43Lce$mu;NRL{#>fHE1#(6?>e0rMa9(DlslrWQ1W#_{>*Eho&qu{~8f>i+bB**^x zP_ zQv+;TQ_oWxsVQu$*#k&;-23kdY~Xu(dghuWEQ7Oom0DPI>sLQ-e&Nfg87$?x1xKVB zOR2+k%qYb?Uu=Iq*SWwxSIbt*1>^3&d7sX|sU~Z5qAlEkhv`E<_HOQ3@|HlpMcKGr zo_<2dw>eDrxPRAr^{4X+xNN;L5BSsQ0h;lvYySbv^4}oK|LfrIUUeLEb(C-(w*?it z?5rK`(qBtR#5dQ3Jo}IraiNooz~h9e2M=G*hnmHgpYw^Rmwie`D5qdt#cJ_nM_o;E zhU_e42A=GV6tvrC6-1bF{$8wPMA8mvM8tp!sv`h9Nbcj{7@io*uYkip)iyBqoVK%u zY%U?QE0?Tx2rr&ZI`J$nooLS4M3|}wVqtmK*5=9A2zIV4BY1%&E0z?Nrr0YNCO%^% zBd6dv)p?URm`)mXFLKb-eT>xTVHjt^&)r>zZe{(;1l)EKOu!%f?-Ou78|?C6*f!s_ z-N(!HS45qHji6EEa_!iQ9njvXD;CAsIiL9Ra@L9i28sJW<*x=V-dn(Y9SPNdf4F;n z_YS=EaoMMTfXOw@eNC;04z5P;-w3xfhY0)wDm6JWFHYV<{4cO9K`NVhS^bp0*?jNC zn@O$?dHN-1_s9<%)c=^g3--LzhL^8C(!pK;TqbL=yk#QZPg(B$7eB`%EV~R7K_-@q*MmepC|}?8XE`7oKVtc-W{Zy{u~zw|aamH{2!D61o`HHH^-m2TUZ|YA11uB#`&-SJugOn;VtU^D zCm7!Pzcd&!GT$ZqdH*l7{=&%6o2k-%7kQOiqPmw)!w@Fx zK37R0#;%`ks8KY~Mq?0@5=LN8bH%cMolNqrRKBe#1e>>8o`gp=*f-#M)Z#dtuP2rA z*+c*0vXR}uYnMr6B)jnXXVR=o(x$)ffUu&~-j@DEwR0d6&?x#{blT*w7GaLwE#uvs z$ZA=ng>k6Mgdm61_pakPyZC{}H4U4o)MY%f&eoIBoh{K~Lj*g5nVM=#czJ7?KILo% zJcHGL`YXmQK~Hx73y1Gj5t%cTLU8pAdO@$<_c9-%`s~+7k(1h7u4g|jVXOvvy)N5% zq$z+;wwOYSipM7inhCapcTRW9ODj-}=IyOG zP5n6V^+xTUZs%G~<0N8~Puq<$%qpsZ%yMD(v61sAcfFAJxb^q6GX>k#gG{H6_zHS# z#0E5>5ylJi`yO@pI%Q^M20qs10BxS>Z#38lzEF_6g$`>n-)hhu*MDXC_A#@(vN9{7 z6t;4SFxMFa>F{a&

F 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 GqyGnI2`PjC diff --git a/website/public/screenshots/guide-desktop-getting-started-settings.png b/website/public/screenshots/guide-desktop-getting-started-settings.png index f37413272bf86fd63a3bcabb1425120d6d881713..c22898368d60301af6f799c10c1bd3ae4c061ff3 100644 GIT binary patch delta 18884 zcmc({2UJsAw>AuV6bphL6hxX8q$5?j%0Z+{2WcW89h6X{BpVB$BE`^aL@CmH4FnJb zsX=-P1O!42p$13-`F40;&-;Gk{{Q#i?;rP$yGO<#?CiDXTyxF(%$4kA9B&Ug9#l?$ zT?R<7G@6i^!Y0BKx44g7QM}@n5qc@<)z;+4tMwy(XM@{9-kxIpD^mZ%yOw(^;=Ekld$h=xv^SB33_Sf7G6>M zO(So1T@B#zaiFI?9#<;OcE`lnm{&awy7W$AV`^U$<1u?b*{(urNW;j;C|Q&g4%ExN zW?=4cb}3vw`3G%~QrTGGqky$(H9qx&7n7rA5WIKUCO3JOlqZTd&{e1$Dbejv^ra}i zK7K|E9@9A|WLkVVnpd~odl;LrDN^0baulFVQ~YKukWSI@M{(S+l$6xs&oUEdXXi=Z zmFTS=dBQBNVIs*#3g73Oh%$q8OL=}<$7&#y>LDFD*?!Kn;dF6#g8!_uwuC}av>*A(o&+Z)hJP(b~Zr9m6qA!sIl+2Fu+Cw?- zrI@3{33>I6P6Sm*-o3#x4Ms{#0j7B*W(ul27p^ck5bB8!CQrxuVqnO+?V<6SgI12s zfqt}I$1FcVerKn_7r5s$`8*T@K|}Y5>wE&zG%9O}dfQI5BmB{Pb3@66oiXjvkDx2> zqIr4M<1F1rueU!J&u2^+ph01?3nDy!xZAt=y9391HLnE%I`E}jA9c8AjjVcKz1q&!YQOx9 zbwEz0c8;M&&>}@FOgc{lzjVZYH5Gbn4OZy);Jm071i__ zew~F6g$%!+W7yGIRF~vZRPSEm+Q$lE#rV;Yd}%mlK|auh@9{N71JV7O-(s&DL0pqLrJn~f)r`7 z))pq=zcsVBA#L4JAcKvXw|;SJ0_okIQUiGeb1bgen3zGhZV z3FU?j7@VZ>5y)GJFbzso1Y7lzI9%cT%(6nh7$1mL z;B?K6RiJ7^AkRL}trDHdmWoj0L19yab?>N5e2yGIm8ukcZgS}I+z+uE8+d*SRGd5T z45ucw&ag4esf8Q^P$4VFo|0WFx`{j`zOvE0;XCJPE2b-_cXL1H1s6hEG~}ajayj|= zroWWJwYB|l@7gw6m-{D-cHfxNp8;Rs{x>#|28x1o;EVlPPf6uDtGu)s8naD<|D?U4 zd-w;vL)c?9`_}{D^z<-BR`Ty4bua6!b-Qg1Z zYa2+vT%>y``vlFi33+P@2eC#S2I#=b(N~A=F6iEgPltDIzM;EBd+Pt!4Z{jzP^Lcr zg$uDc`R?%@OG}1EM#$4^C!GLiS1nr==p~M219xYQ8Vln?4<46feEL(Ty7RcN26F6? zQRpi}W24N{Tmh-YsOve_ir`QWg4`QRe7BEJ! z>1P&tYg|@N(9-5RE&`H4g>G0H+qsNxHl-$pS(Pek!L%7a4W7Srhun16(R^&M+~hFW zJ<_(J_iFEOaE$KKrakgV6a3%ayJG1chn@Qo@J8>WQ>Q=WjSqemDZh(53^N6pKrvly zZij%TW7zLO!T*dqZ*nXBZ7y86z%FO^P(UzO9QLbaU~sU;oHjKb;wmk|X=`hv{4jcc zYdz+h!=2QWJW=G$NX%wr;P$7Z`g(dRbE|bTJ~f*j!*e;IgzgJ~92HwxKgH~T?>CF})+F!MNP9n#@3OMXN@fr7e;AlEQkOA~_G zRARn@IB6YZ#eODS`p2zMK5`$&L)(0@PN9az z#yE#;sz4a)Ah6045pNBZ(pA{=vI=km@)JwX4-O2>`Z}bQue+BXKxm7(v3&Q;u+c@$v{%wRXbR2G-iDbmv%srb>{o!q9z{ly`2 zRrXm!egDYFZn|5oHz6*kKWjeM#bdV!r38V@@8_T$lzNX4lBo?Y$M5A5+C!2Sp$x1^Z* z#y3sTxeT6E67bTNiet-uI!jsxwNji}iL&tIaAP8@6b@8z^b= zN{tJzb{hOBvplc5=NdhE&fHpFpka5Aun`MDce*-@P;nPbE~Z)4``Z&&Mr#((@pJIb zA`LiaHFk2;1EJW5bSN5-8JH(=c&Mw`sxVF$(t!5~!XU#S#&vRe9$}UVVIRhF> zOcb|&1Y3*l-xw%EKb;CXkj1z0IRsBPmp=RXS%J74&0ewCYUc8~yQ`F{4~0S_fZegG zO|td=y+ey@%O};Ls-K{IDOHoe@J{dR2Dq>cR`Lr^fH-iQ`kC>P_& za~bdZv<+X`t`x93kg6h|w{9AAI{14} z)!x@|<>GD$G%9MkIV96Ilt~?aM#fasqd`$3-U2okKo~|JWd@X!Xj;#I14*bgfZHuh z-Id)aeqHvs>03&`^!J+SEc1;m2{iO^s`SK*W((MMMa|axyuKoAsq8aqee`v#0`Y6U zSfFWP9j?~G=ev|yK!H?uq3%PPXb)O_H&)6-XDMYs@}P;OnI6rm95>@grxx^*U1J0b z_m=;}0}_Ed^~`qL+tTg49N}G}0O<>-@7DC*cXo$^HdrW+=VNaF-Jh7iPPaYWEw#YM z$t5#<8I(yPyJ$VdS|0+k+|gxLwpl?4lu_3= zv5qIe$QkB6(777`XWwUEpv+-Nq144#p z+H`+J>g=n+?FvNm(~L~~WLhxK$)ec?Z4t7I%*x%VzS!YDSget8Aa;Z~5+>x33IXoI zX{wv$Ta=~_zo5nlQmc!zrjUHq;dfsjpA9oN-Djl94dI{(J?1s9!zE$Av~|PXS|lEV zJ<2?fIZcfbbt~BeT&ZO|h!h_qBiTi@Y*@zfBaev+eIuhpnaPx&8>65s`cTCEyh3>& zM}#j9?cqo5>ny6M<5mJ(9R&mh%g7?~xSBTZA2erSr5KQ^qF-!pUb>eM5jr)a29pZSvju&A_s%jEuqS-JCnXjlT z^l*Hjs>%;m*5*}`($d1LNO`bDsJFu?MzD?;*-P|DDxX212cruCk{G zX=^bxT!u3-Po!o6OXQG&J-Nh@T&jhb6h>?>Oe$_tZ#W((Z?Xw#wGr{=lgt;313Q=3 z0Z^T4YGmWBo_iac`_9BQs6^aeMPM`i)_H^}GdJSrI^_w864Ym~<4h}vYfQ2WP+OR3 z@=ws;r>ihH^oL7#Z4FzayQ?t7^cf057BZien=76iIku}jRJNzmQ{wpZo7ZYz$s82i zI?ym4xVdTfC~h)NOB}9DP7{Ehj=&xqU@ZLFgJp?7R3L*D!}HyMnGN|aZC|E;ctaXd z0k|ySq=|Bu*}PSh4)xCvZl7Kgahtvj3%~7cY9+QsJzC=F%E*T?yJnilTpX)_7+ZVK zDIByI5M0Q!Al&kLd$@fu`{1^&BH7hv5;h)ZYYVFC$T~|Y&~0pPw~F!e+Ygs1{RS%X z!5-UYRRi__1%Wzsc9(%7pIy&RYnR`|Wuj0A(7WUYm(A?X!XG;09?65omN%I90p*Zg z8+YV>;Y!80i0tauW(m9APhR+;8)Z*>_8#o4gWUECkygvRvfg1HIQV zmyuqg2kg?+yD_^*pZSw@;9e{zY(-`>uV1JAoVB9kJF+D$%93}8R}XyMtM`V!Px5#+ z!V;B%yYBV-5!8_#wuS>son7Ma=C*C57U*=WUM$YVDMnBSW!WgV^719GCcD<%z3*14 zw^}zp$#}7sYTW~QirTEO^<211&i?#a94LF*-H}%mzSnq5GgDvsQVpzf{OPi!jEw!a zmUdY}Bw+PR+8|4(Q?m$_Bn2*4X3}%{&%upgHtUY>@dq~oR!R*bNkcBYCOeoa-k(O?>fGjlI~la`)6zqAc-AoHF(j|xC_$O;nv!PLg|z-x4_K#n*ZsiZK0^hLYawqDrYZW*HifFqn>ZY#8?_bY=XT+~NVn6pA}gy^D@{&#-r`xw z?@?|~Pcwbm9(i@tRKIcxoM*}!Iv{*oAchgdKR{7j{Vz%Jh4H5^DtMWq>L!SbgL%3F z8W$3!q0S=6*^x43?zi|_+PG~?hoyRo9XF& z#QTi!3l^0=lJi+j$!ZO$+iOjh-C2?7$6!(nbmSH1JY~Vx_V#w77|f!O(s{$l(a|wB z07i2L@_CZ`aYKuoq%on>JS-1P^^x{~7OPn?APEvBR`Iv?G zcYClCkS!4yd;!vUm%(9T8@P{4XCUm%9@d({=1cTjD`pa#z56>L*o+?*H8P4#RC3ek zT(2i8Ue;BRmb)f{**!|edNo^{Tj?fA^5^B(lE`DO&iKI)*f6kicyOGFJ7sSZXTREz|Ku=!D*?G<-&9?z z+rPS&;fXmnV>ebLbmw!j)3o4$egKlIuXiL$-h&z-J>nQmeUVl%WG2JHr}F|k4~<`r zuX@_$coL!f0PF|BygJYZdS)MSxGaq4rglzIk#&CeSK-PInov)p75Tv8qbFUBGd0y` z;#&N{;%Bg4l;?0)5Xes5Xx>RBzpng49b|gk0T=Lc?bWeO18bA`G@#x;Q>87!Zzf#k z(O5Tvsw3x%FEzzpQ3=V+$>G;kSRZL9XkQIjO;se0@x{g(`Tbh|={GmW7Qc(iuR8bv z!U*#*JZUjWNn>7%8>><)rQ|ffHB%ca1&E@$YuH_ zRX42_Hxjy16*~bTn&t(ebEMDRQTC$N`z^dAi@*5MyHYcZ8ug2x*ua#b!4?!MN;zeF z{DxdxVZcgk;Y98HhNcJ%TY|&kB&DP)>XfGgsL4r5NkaK~ouaz?&o?GnIhAiOzA-d3 zw3|K7VLy)d{jpr6YwoJL{^{;(38!BzS_ma6unIg4pzZ6o@55FImLf8u2Pi`gdn2Qy zBvz_IroMmxE4BUy=*=aiWNyrP!e^(zehc;BX!LcUcK21>G76U~xPg(-by(}Q8Knlj z7I(pQ(R5VP3o5EWwHUGpnBd&$Cd|J38Hq~|<^Hj;&yb-RFEZ-2DO?KnaIy^rGIMJI z0T5zX90vBZl5VGG(zIT4XLX`moaUu=Q*xapO!P$@C?mHLB|*<3GA@dDcJ9xF#8c4k z`1l9~4=3%b6#G!Np$g9kiecUp?ro`M-`>W0{@k0ln`Ce$uMK^W0ge4!PGO-A=%PgG zrc&}tJ9618M&k%B!ttlIo>(j)e;8BvQaK|2 zI+Uri-WQvAy=M0nL;_5>sU9(XWaoeMQD8d=-ct(ajwysLMZOJ9@O1w2OyUSWknM>YR z$6j^ri7kKu2op}u&Rs996%{&nc%s0dkYynPJi99(Q2LYiOJ8BFC9iH;`AA8Lt#x9x z9IpZ!PBW*$zNSMOa4`Cvq?0OlW2P;#7(uhek-*{V3itdzuJF zw&gIW5(H-s`YLwmz`x*jgM&kkveJ*I8p}PfO1_f^I|_Rvwu{J>QjiNzTu*AUa6`Fv zZeE_jI7%9fk=N!s-;74=i~D&f;{sM|ui07$c$YjU)RPOhR?D=QK)a8D zYo#ji%UJs2+YW%$s(pOx3NU2?`KGSi1*X}!R*r)t(6DJ?fRRJ`sv6f$IB4W^2LY=+ z8O$T&qzz4KjOEUVV8BX+$JpQim_=XlK&_LWQT=WiHkl8^Y~%kPp_ zWdw}4oF~GWd#fMoSv9Oo)_FHKhw&^7@LjMZWf|&aK0rVet2p6S=4ZN-WdOy*Dp1Am z(#SbV#4Vj#(0B8WQ+y1W-fYktOqcHDF80%?7!*dtYGxXGnHleDY2XFQx*`O#EO&@z zK1JKnMEv<<;NT!>+nnRQbE;<&y?4r1zX4*)s}2TM1HBt4Ly_#d$64Q^JfQ|pmF1+g zPjiTqn{Ks#^H&9NZGi4m_f7BR!77TLoZ+z0sPi0CDl)UQH zoMgy0b{WD#<90~jln!+H*+6=sPH_4eP-8Sfu=*@b4CU|NU)4o9Hr2%>2V3^C#v~_~ zIUXqd6LmH`uh>ZOgBY@p(Lv4~PGtOo&eGkzLmu)pt6jsSAGv(e=g%>hR1Rb9)>X|Bj~yJ$ zDa=tfGO9q*A);DaLnH@=Gjr0fba!j>-{6ncI7OSeQD1Lx>}VW#szTc--$TQ8|Ee$D zsT3F5oW+txHxF9|bgKWM6XCe6_^A`07d@7nktL9sv;<^m9A`p|P@Ek#mN=qoTkZ60 zHBNKmo$@&Bxfis$#s;U~DUOF|OWBLG$ z>Jp9DJ9+$G$GmECuP%<>jZGI`7@eMwJ#_m88O4&h79tJEc}Q^M>9JS(-;w0v_)h!p zw0S=nosVZ4HXh$(A4>p9W(?KQO1)3s=P%wd$q^}6{U^$wQB7Cd3S#`f8w2ky^sf2Y z9`*!)UJbA*pg9BK-Y7#fN-e|{I$p)5Z4g*TKfc^w^1N}JFO1S zMgU5AMdh9%vSem<8Jl|{VD%7qs%q}`&IfD2zNI&PZ_dnN&che8>U6jyC4(^wy844L z7ZCm%`XOlBmQiWx7Q)0GlbseIjU_Mg`vnZ;UvDRf)?GHS1T1yr_ZZCFGGjqRW)?)L z?NdbquPhf-7~fakn{DF;2$nwG?&BT^d;cAEFpI_2Z|YdV@PmOf83a*1DgXu*QSxe~ zIn1|d&(FRqAr7re85=gR#zsl>$Rg*;NTiT~VVNvc`p@XYCRre^yoQcct-`DcxA55> ztii7$#l3nzeMr82%iOipiD@!`z__A(nT1!kBRJkFsTs8$&d4ox*_Kc12hp0Mf3PFp zHa}9tom8aYx7BtD2>_r^Z!tl^neg&2@EV>0)M-X5|LoIv`x z?B(l%<$!;fu*B1E)!!SI-|@XTLetzJbUt`;N?Fq1%lM+Wq%sA;(pO+!W$}E%x@?`a zJnw*2=2xeQ=EFrfp@!WiX2<|FkWW`(Q;RriUlj=KuQi*K0E^`O1{etECJckQ1Wb+l z=Y}5$z*p5xK2LV@Y~&7jT7&A$Dk-^Tkfqy6TNaYLTDgJJ6j}O{w9Kd8qp4hch~(sBTpI_jum$L!WM@rTu7qBqRFe( zQ21;NOGEtj@FQB<142)hSqe4&;I-by9ne>v z1D=@C!A?R;H!H_00+sxhVrJ`OyV|%tO-aPX=(aR}adh2U;PGvqC=X6QJGpW~R8D`k zLl33~6bmS-stKqAuWoYEbJ`)QER>QW?Z#@rLOL^0AL4FVYnSbYN@+L9eu`;%w>Vhl zK%DTdikrbIY<$hH+~`PbczoB&A3sPFpb7(%vn&ehj-1y_c1znk&4w!^6FN^9)xqnk zJPuE9-Enb_R=)QFdoA+1`qKtB9Mh`u%^6;88rlfIUKGI<{hX!Ep`~|P9WGloe;rWg z4&0iiI%62P{jP&tnN*GjhNV1Pc|Pif#6!BfW#&T6J=Ecxb!a6}`kLIA6y?~g{run= zwqzzVx4GEO@7>a!9zF7W$safq( zp}<@dSdAc+_nyONTQx;Bu>dI3>DuMF^tSsB;YP;lAf^K&ElYS}o0%P&y@xv&l}XPv zsUoTJeCjyS1VjU6d#rBP>K~^Xd&dOEeyO_2dD_766+i$8k|w+l{J zk$5rnsZJW^3eV6S79kMFA2(C|S9lJ7&F{?-fcRT8Z4M(-K$Gmci#3{`4<@Q!>WZ+3 zU*{;Svg(na8I~n{uy&}3HPL}HE>vOoi2K$r_7Lgon3_%a^?HBegGl#@z8Zt z9Yu=!$U(2|7jt7vzV_}aY#MDZcc-q%?rhy@#t+cZ@dVP&5=eNivNv>Oakx&YA6Dj% zERz9qdg#^_>+ZV&_*78KG5b@m)!|_Wo=&jMXamT1KQ_=QsIx0Pz5}17Xo{%AF`JD? z&D_4ndUm|SqN85EKFD*s4WAuL_UNgQ!KO_3j$CQu@_$h|V%N`z{Iy|d)L>qymi9tH zw4Su|1e*4On5dh79D?iKdw}ok?glF$KsOaW!6bVVt3(=ct!?^|U$f-QF8Ayq>UrPJ zCZ$u5S^!A?z*$Nto;!a-L* zyPV@g5hO8*GW(&QZJGM~gGE3p=m?AF_N8PdVrn*VS-GX+mU4h^`{U3@hxDv(b>--8EXa2}ZBQu}sbTh4ngcySa1M`u6H$ ze^Hk{l%YFx7*-GtR)I>Ea=tySgaUy>5jzTljq)usHj5|;-F-9SxNT&hcf(QfV(NyU z_eug~7x>U$M%7cREaw2j+X01KCh=sUSSv;0hW8n7bvTx~{y9>S$eQd57xk#IpG>%Q z4QvZ*4i{RMX%UnX#i9Obfy6{wL6_`St!K<$@txvz4rFmtMNfCQe7Y9+5M2o;XADH*B>>m8DaxvYvaX5>6t&&J2jsg19?Zob+5`hu zR>_uE>&K^q&TLRvX9&TVHXewDw1vlnR-&|`x3~9V17?GEmanBfS`kl+=Xdg)A%dTH zK$Jvby-R`?vX2w3mHMp!ML|ZcI87Kel+$nOt~&f0v%=RKfoVh%u*^OJ?B$EuIdTJ} zMFmm|3s1nxEtb~#Zg!7MU$m8(Q}BhpdY54ZYM-X;%t{&PLO!rZ_oI~ri^6&0>Gw(Y zuf2!5i|@YP1pC{<^VMMWB!Lf?>GP=J17L*_1cj32h%4+KJ7D;A&1&b6>??t)lX z0?Pp(u={<{%w>CUvmW&8G@o1_KHt0x;#-TiG zvH4=Ij#>5V{;PFV)b;jckNQ}_BIGLM`D zwzm%PP&bY5*>m@@>y;EOkzVcTWS*!VE_wU0twls92N7p3(O2M7MGFvSkcvSAGrdFx zZs_&wRKKijcA73Y8jQ`da`M9@@spKCnnQoEsy(Ud}mlH_kYiBt$rMH zga0Fa736<*%qx27p7}oyy=c5Y{b_zU(_;A3x89JLT_|Cbb3GxeN3f5Y|i! z9SueK>lZEvFcsuu22$!2l{5V+Cuv-M@;0hyy_{JSrk`ew*jh}{4|O&QHP*N4jjEHC z$;>MKXH}5<2mosz1Bf_Or^D!iI+(#%$~jr5>U(F>Dj!c3+tT7&W&=?|u39-I>WBSv zQ|H`A0gd{$5b>hb3FWEiRBH_yy*nIF44%^7{9o0~V3|$pzx>~hIUJ(5om2f|Damkn zAgeT2F7v&<#svZnH;2Q4^&DSMB4ycxU;HN|kv- zLlJHTv>%Kbqsax?vN6vx)Dfv)`z0hGszEkd)qsO}6ZlwmdER1_>goAR*z_y(cK5_D zP3xZcDy(c3=7r@dYNj$0nq~la8;=>8%*z99TsEyVI&_-(;m3M2y;jB)2l39VIcZd-Zp@$#xCag4D5q!?0fJe*VY2=+j<5D(O^5n(%HqC_EiK5g^#bw8TbzKJwR*{ z%{}Hq`C!Y?wo6OP1}4^s*4E>?ax}Jjm&UZ{EOWnVWfv;yn^o-I=nhyX%Py@A8i>T| zn;B_X8W;%V!n1ImNd`Iw9kL5woBL6p#T^jP=VL`1RdFZ~Ff|yhHuY4YPZ*f( zp*s`Fze@PyT_C$3^D;kwj=|~6YR`FgsOM^A#t3Mt*Tm#@WaQ?E^WRY8hCCFJ3rHN0 zic}9ZB51;CC+G}@-TfShXL^R&Ca5*dAg&ACsZ1Uy}1$ z*{z?KYB`ym)@1WK0vF4Mmsj9YB}J&)=cNY1{-ir6`Yp=l z+QMX+3@_vERK4#Baite&X{_gdUx3qDWDdjQpci_lIUNid%?{en-akM$F>;mg1?xqY zU-;$6dOO5&_;y!f6mI>wVB^uw%CD7y_r}jc+$|ABxq!Y`#BCCr*UA8U5R0ySw9-ED zvYyd*N)4hno4Pv7#=4;XdqL+u9(UQ`>McpJP!K(G=R0Ql`~`f=_iO$i83V7TX~Tm| z2Y5kS_6S`@rX8^?n+KFApH=+Za~L`Nu2vpP6l)P@O}`-SwOgYFU7Z(tM3l24u&rO! zdm>wt;hf7Mr88cdC}k^GPsUrBhuBhIhW@G*A=FF6LYWn+b;yf^hR&@WY=Porjy8t| z((8-%xQ~!E(a2{*F|sHQ*19Y2?$qmN?!4HCuE7_5q2C?!1DZ!1u>1V@vD8e2aJmOo z@x&2C1D0fBT)3MQcjJZyWMA7~|F7RyMpKexP^D0qsRDD*nbQ$=vui3P3MY=dw!OS6 zyW9GBwe+ix^NaH3DY^Oak3pu9eANN27b>Hh*TQtJ@!_Jhj_=z1K(&=m-yw5mO+xjF>`p$FU!Q_?8hAJ43?D@NpbaY9v9 zc>OB(YU|ig$%{H2WR6Gu zN!zn?b4yPDwnt8VbaJesjio@D(H+WVHtd_*?8&`MB^Fr|}YZiZ7 z{Ufoe9e?Xw=k~kpK>8qgk4<*jC9MyqKQ^|?gj^PjNl=J8Qi(qsHg8~H`Sa^~h|Po1 zU%_64(d5+e@=QxIlNPk>K=Yt>XXQJ81LXpTfWQlzjsASob*YBi>ymP@K-`dvxuxX< zxQM?5VlgWV=E3Shc~%80`1NC9SASon`!2O~W2J9fo>YV)W4xLnu7QG$&xPcaUDr`N za-zP8567Q2W02LewNI{AhEM->6?eXsGOc*EzLoCmvh2I@R=E^^693A;*h?|;tLCG` za0y#m+{$;)uj+tn(0x?YGvWv4#eNUwl0XBCy3li@>QrVp{%Cio5G@QJn zqqD+LG%>PS87IaFexoC!xcDuoAo-SMA)t+&3VSbR^C?^Px1#)YDWm;}<8au}D(v{e zM4tSW5Xyr$l1et;aC3dGyB4y(3K7d|$cFQ9U`Fn`Oi236lhs?I$}_mU`_m&+cpt&_ zRTjUETh(?0ivw?z{3_dWCt2&F@okmD7NYMFI?~P%mdxOqZRs@=3pVo;n{}G+1WYj|6{lj(jaPJBe(SUOK>aCw@mUFxt&}P~*`+ zT+GjOTRzUVRuekm-{QV{#!kklEsd=}{;a&lW5#81{y;`RpgV5jYl<&hLqqx-YCS3; z<*W9c1mT}H99Ij&OBmTAxf{PO?|ea180dcRLoc+2#I4^nof;k5Ax@kHnWal0uXhn# zB{rLx6AliL=ULex8;cHlhJZzvG9rL@DA^~nvRkWF7#| zlEewoqk*-L)6!z_L2T>02tAWxmwA2dkhlN5Bu^XbwfCIKRh?F?(oug~_bsma;{*Kq zD1&y3_Zbw|pOLa302^C6MPH#|%t&1MoUQAc_5(ePEuhlD=gg@v{_Pg4QG3*sTte@* z5*bF9*@v5Fe)*|q9g^==EZ;g>U3&waX5f=h6kcDT$6Va z)umQ|Q@7U>P&YqvX(d;tnxS0Z@!tD~Hqf2;^Gs)0k}E^`+->g&6~UIa$F?6&Nyi3= z8Q*vb+`3(;+EV&9fa&hzn;(#WM9_2OzCP>vTFocB%%0tq;a7yp!1IwPVndb3N8IJ; zb?|IBb~mv7iAdd+0RGMIIPwv1)qkwlc%rab?7HOf@sKy`G8~WT_0Zp>SdGuS3f&u@ z8e!ej3;p2nc8pc8jo1EF_;BS~czVaqI-sKRc5f1;niQth>VU!9p1&9NPl-M#E1tMs za&EY(>04VA!M_5*@kt!dLU(Sw)m!Mp%MU!i~`C@0>}l zerM1nKi(uCYiYguaqGFoiF+y$4$)Uy(55fw|6o@+&(JBp%WLl3eDO4ksp|vMZPPb6 zc@nGB)2mi*rU5o<;uqALhrbQiPE&G}X`!)*{G{=F7~@^X2Mi&-t{NZC^q+XOQW6?& z@A|;p^rdPCv$_LgPGi)mdyj69PL0`Zl-bLDXhH{33%JnORr3s4vA8DYBf)>mqR&;* zj4ri310@wzQ9bhJ<&_hkuythmn=9J@ql~q$jBkX{!wx~*|r-TT-;wK9^L*I>mL zS;`OFElIa!2j0}_9&-=1AAG+M)Fvq>@atuRi>e^xoN7rgR56*CU8_Hje(4Gq2eVOjnlm*ki z_zMuE{8qwq=ROt`wL9OjWlXd?^YaB~(1kqfBV`POupoT%6}AgO-WPns6YrG|tI)Oh zYfTja7Qqh0Ux0}f^Q5aUyLG%sLA~8vT{63$6GLBOl-Jlqp!AMOS|XhQ z7r-28j0G-gkA4o;3Z&RXC{CY;RbpSZ{E{^^He4G~*(rN59Z2LZ=3(IR`6D(q)(b!R z+EAc9Mx6ybG{LNa+-XGHy>RM)XhAoP=vpy;q8|0cKN+|KZ^zlMudlExcv2O&8Jx^g zpp#<$J9uW+uB2P3ZQOMPzr*~4m9($`i@zRv?<6X5X3Hk?vhPJ5fd*68eT))bwL^#6QMShb91f1Im zN4_ro?tQeU#}fH`Wu0$*B|7r?o~lZsBIJ039B}iT=*H_|<<$&>(M)Z5cS`>t=EcOI zmjIr`GtQ*sadXiSo(G6&k?zRu`ezw~ZxC3^HN zY}CYB>>%Qn1#J2u%Bu3imk3!D(H}3r+QEj1e?A(_Cbs;AS#~BLVp`#O!z6-o#sC|b zdRL9he0<2;Qf_7Jow9}BN#98ymU`0G{8V$~SD9AZNae&H%UZy51_48B1E@Hwdh+we zMwR6X`RSPc#l8ah84sT33X_OmV2y#EoT*W1YOFA^>_}*^P>Xk;*!!-YJ(M<_M_AQ@ zkxmxY+1(x-9Aspddlhe;&|=SK)wpCN$X-6W|L%8ye9&K->`&Leq(RZT6hyJIH;l!! zA7xnuu02K0%8Bp>RnPrd!Wj}S_jckHGH2KBY%Byo%f3#tYx$98ic*a_9#|Zhd^u3Ee6#NI7Acd!aykIm2Ne~Lih+vX9XHbWm4-`M?|D*#xNy_!>*QwXO0ChhV&)Jq)Ud|z^o2YemH&6j`e7SS@ zCxEUWErux;)$JV_{tA*^QKUK{ZqNvSp-`5 zh;735v?OClI|~mVqsk=UAh37rn0M>ikV{dNMkbg?{|N%m3Ear-9GM;~C|SaGj3FN| zMk0xRuq(PdiJ-m>re%lXffw5q^~(4bN@ zncPEN>dfpykZ-|wRltll|544WQJ!u(ThrSfOu?$E{<(j z^v@fyV}?hOye0e(c8(&v1S~l$$f!uS;r+dq+KS{>V>7e6%c(wvGCeQcMHskzZZmMF zOl-T#N^8c)47$X#pzSBBRx4CHjjPkz-p^UPN%JiKXb&Ie=F82Kffn60oe!nId-2!p zh&1QlmB>c`{|2eZ`0dS=!3%S<7b+Sn%jlozL=Mwc6DG;*a$A9cwqkZi9oi~R1d5qH zHXkv~=%a53-e^sly3cUfTzqJ$7tti?>}nLt@uR(ae^PpIFg7Npyl~UZ-HO}Aq^NbL z%p1YgR!~6C73ooHrLFzBr*MKoAutsT#~1OP2y{mRPLiGRP$L3C_x7AuZeH%qn>U{{ z!WcFVkkqGBHm^sZ1bWJT9EVv+AbTh$>^hlQ!LGl~{7iDRae?pCx%Wl%HwE0)Ki9&< ztfRl;CUU4WYb8&*++aERJ}hiG(6|J}iQRD;FH~{knr9V$q;FJXR_*a2?a^-m03V-z zo3uLq=W!*Dp+erW63#Z6CyG|nJZMTBnU}&fJW^e$Ex`3>8JC4Ei`_kA-3RM)EjioY z=C$P7Ln`u4Hh=m#lOzQ>UO40VEyv;P`qgrm;g4`*?`9mRrkZ4()Db8eTI`lQqaznC zb|P_eT?^D=aG9eJ1U=o>%3wT@Dm^Z1L0mjS91EcPF8l}{ACC??%9Oj0OnH%VTC^Sx zy4G`lDA^-m9qJA#s&{R!RJxU!6Hs71*2FaNWgDTK2(p#xGZ|dZu+o-dCb6CI z{YUAkIwy97fS^E{=KC;G!_``8SxP+N)Ivz{pI!wY}3@R9NhUIE05 z7V`pk&qe`ShVVl5$8N@}pKs~6U*d+YaYrccF&^iZduvx361vJ|o!$K_c++pa#^Ltf zho%(o)noaV_3s%7Tqekwy*V~M$kubdjm>M3>7Sn{hOr8NRrKx1$mVw%Ov)=lzVza4 zHZQ90YHThQ-GNv}`rv&ti^Y&Cq$YA3gy`42+YJ8xMr)~1$8do?W~AXcZggJ4rBxDi zqZzJ0?}1TY)PYec@|~_ii#wEji{w!S;&zXTYW<51^Ge}qVRN0R*+`iW^pA(scs2+? zy;ZGwY1?5G4lm&_1ZLH#&Su}KUcJ`gF{zJpAuY!fGJ{GJ! zWZ+Hk=KMx4)K_AbGHn6$oAxc9M|6?i##<%i^BMiliZj?t-)s1|Kh!=ddWl>Ta$hn{ zO^7dIyWmkvFv7A$#D;@4=Af`=-sU1aS3OF@kX~T0SSq}pOkdc5J2jMVmD#>~vfb5K zg3>VEVw)uS?~*U=;S>u#}gFBM8iLo zqx%|y+}bN88Ga|WS2wI7$<3GdwKS$ne`~|r2NE;Rr)C?TuNPlQ`s25?opU;CZgBbU zaaYG*0Y@DF{_xx=@A*5w%b&Mze@OqFq8q#T#f)X|q+?fE;r88sio>pLFkvNoTK-e4 z=sU-|KS{qQ-00u5{iC<_O_Jj|;hR|DfxkZ}Z9WBjpnF6g{X^GQ(W&L%rvln896y7G zUE;hGdMe>B*q@hJcsZ<>U;lF%KbV%=PJC)Qd;BG@xgA3sw3Wl4cl0dj5zp_9@sVux zu&}a|$tt_N#l&!vrm;OGg7@XoN6`@{!Re#*I$(0y> z>4ZS&y?qDqcjrIresjM&^Ud5j3)VV0*=Lt`@3-vdd3RcTF7Kyb_9?|<6abvm=SCXW zE#-t0F8WGd3G4P;O@Xe~e#mAa47^TC^h-u%iiM57@ z@dyN>zfhTb|L_nsq6i#W)$AO9m1Yj1?(Qsz+gf60=nHlmj*E0$eUi{b@8 z#&ily_1O!1Pk(3xHtsbLoVQ`uMeoz;yNwmF*o?An4QCF$e0`A_dSE;ju+*EAwzEPs zP)aemIGrKyar9MopwQM9)AgcCJ}ac!2~$kQt(RMS2uL~av=3i1s#`x`amMy)QSn># zHb)zz{rWoy9K|3C^SUeXV}GkjkkgKWad{WbEsA?kwjIewP}R*$MW+q*N?LcXY)12` z)CTP;ua6_8HW^hC$N5abRM;O4@)n~hj+rw;)JkIOztSj=x+VSm{i_=P5wR!Gphqsb z@N|y@YNO!_Mf7397)d$QU%+LKNZ?0BdBH8lswuvg9zgvF$+}O9@GGdhtoSjQDdme~q(__2gHz zZS2568@G5@#jWN!^nsP{{ZQH-U!jr`>(1uvl0YFqylq9ImB$Czlk1fe9vbTsySjSw;H2F>-E&?( z0$>GzsuqIRd&jEb=g;Q|ew&f}2{Dvq&rwpT(E?YMRskU)S00QV7}&B!4|FB~+1@Dr zvpK#&Et>9oX#?9jz>cJ&bP}|&np+>irttx|P|B@tN$YX6-e~#iZ=I{Ns?L^!z1#0E z!jLbacn{=Rc*5z(YGe8^M@b9I!@zGEpp5uBky_i%N=bjY>=3f}CC90pH4l~LMyYwM zs5PYl^`8;ojH<+a;Mf8367Nn?_l<1VE}VlPbv0bza(v`b2k)zD%zS4`*zyu3gye+qbvd0wXErfk075jc{~g zZcky|*?;DZ1k`%LMTZpG%VLZG0C4J5NhOTBc6T@Vzu6Kw9j_a&%dSIzS^Jo)S-@1% zl3sf#Jy#^6yWr`xlG`Oto3(0sn$6Ftll}bj{c4xvYBDaZ``pUhWwxWw+`YV~V;MOH17w6&Q=Al1qSelX84FQQ9-i-p6pHI~k`= z=7PS5*0`{9Z%KVX-qVlMJaGzvK|y^#GUQ?O0NysPM-Nf@dP)k~E1RVB;)NYWndN}C zE&BBBv)Z*9LUOKrSBZn?U!!Muk6M`3i{0$q-Q8JFT1h($YF+|H5+_e*COlW8jJB6X z6uIlx{ox0j2BDuk)-P=@kHFw?xSSHSCxszkd+?BM@!NN4tpl&~HIGApc3c9OQIF0B!h^0f*ixkn4^u*RnYrvY6L#pU%m8EH;rLyXv%BcMOk0AH&HepV5{l(#dRZLhplWW;`ceQ&3TK%SC$3(n{kXeHVGrbz?84> zE{*}Z!KwQ)4z8DAn4i`ZV%a?tDv#Kh>&Po7E+3pWY1{6_7RnyZ^;;4ECE= zqxP9~B+IR^sXafUM&9x_z)zW{F4##Z(pYfQhNK zV|=B2$noUIB~3t(9SVhhba35mE?pVhC*t*5ymK)3Jc$qjp@%@9K2f*$agj#U>!n18 zK{9CXPgczI>kN&mcZrD?3j+vl^y8nLY;0{s413M2mQ+M*Mqw8huvwLRZkl`f68QV3 z!Blw`bFE0ofzp4Q{W;q1h14`BF5y5FK0WYmiO(Vr{*H+vgif@`0Oew%Iqngxp5st< zZNc>jJx52-4Omz7)G6C;uWn9qI#~>4e?}(EoUY&*SD206VHu7>tiP1opwUydu&{_4 zRf^|@##Pw#sY%nSrCq+hh5OROrj=SLe&lpyeW)j2nTR`qinTbDO(OoYUT1AIswogxdFlGjwdrgjIHa$`%as*3jJ!vCoqX4Yi09z!iLc>~2#H*4?DK(o#?Y+(|0 zgZVmHm`QJDDBFAzJknjGF;IvuZG_Jv*JSf%!J(s{^S;A(L^?hJ@n*xH$m=)lQ!w|mqEGKIEB4}QJqI#j?3`bK$2zhhw3@-Wu*jw+ z<|h2bB(u|GFaQV)3DM}eFEh6?H+Nw8Gl-lUT;pCiEgCTo^%O(Hn2@ihufACE$N9eV z?N77R1ijm%`p}1_Ci#ByQMnr1lpeP2aTYyRX@PqOxlhKch3(eDqL6!j+*E%=x=VlI z4Wu$yo6nL3U}9p@1EU`*e(S-ncbL^vq%Og7bfIaJ?#k{Pv#{-4n0l=oY=vmFaMBg0 zYB$Uy#*x1mXQW|}ck(Hu&iwjoPxE!HjlYmHM9N}0BL146sQ$H)=AFB|?I1Job z<=}pOiPs0!y8mU-X{v~i1-P!b1P4tiKe5@J?-#{uN zs5B+}tlH2zz(Y+e;VdOj)}dB`^Co%8#8SUsPq1sbojXTz z^G_Z0RJSDYEAvRU0ZHKdcTyheii}^3&<6R7#vbB38xI1{qwBDaE6I3c&Q>}6wGXH5 zhYoj}l%BhabL}9W)t#hbkHK}H{N_(}5Fs$qKfi-Op3#F{8mq|FEG($m-!R*+WCXWN zc|Jb9B!AS&hvOB|4Tvj^tAMLF-`t@S(3F~%rdLQrw$WjC0<3q}hvq#C7ItuS>>J3_ z5 zWMyO~_D+YNS5=|RMpl!uHS0cG3|S}Vgfp`-G08=;Y4%}0sEvICxa{kent3Kzmuj~uUqTX=?C$Py?X^uS zXzzyw*%nL@wvD?H+jFlT_Vu+1=)@BQ;p%;v@OwfD6pdfjFrG+vPO?0GFOyO)qQjP@ z`OM=K&#m!x)(vhA-86kqSx=W$^$u-klah=#4I45erGS0GNZD$tw(}CJ5UUJc#syL; zPiP4`38}^$nrFEyZqZ$olTVh1P($#omxMa4|Jdi~*zILEDs}DR8pu|WWeSH<3FP+_ zXAm($#XPRRNPE^15gV1;{9&z~$chKk)8wDy5NT2TvOu^9NHSG8RDDNFk=q)X*U~Yr z_vlg20kE{G9P#B#GI66~|J1ufSedq>R)NOKaIIPiP`SXPD)c}3L13MlXDFHl@dG_9NDWXen=D2KW-xQ$P-P%(1BaDokFUr$MIEXzO zxahpxKVFtvEjK{9G_Y{b-P4o((IXWi^7ft+ZvX|$Qo?t}49X_zCxS7xcClMxx$XE* z{A*{^S-Dz7zzZ2`Oq6h8VPeuQtX)SR5PSVBZi^XeGw9W>&)nCs)C>fzbm=CRPBN%8{7 zEv2>UyVv)~#}c5=eOoyO=|oAVHsajewps-? z9@~+(wCheZ`D_O?5F{k(`kdP3JxBY1#8QF4v(}~gD06QSmn9@PHRdBjclZtl7RnqN zZbN$y%JM)*N6vdtwh+l}3+J;PZXC#Z`E}aEaZCQ-BreCIJNaYoP(CMggsxha4%o}o zhueR7{kk(FFQYIi37vRUCGNJ$x4%!SvVg2Db~**L(9ajR%B79sYtoc7_1Up^$>5zTFfmKI;j&EG3#D@ENwxewB?Qf>Y;@j_opQNaBC9{-tVt zuvcHvUn4{1SNf))hYxGf8$AOnvrw$6sxtr8$Ne0^F;A73d|G@MN<(;k9PDBdJUEuu zGUfIIxg4(sIXMNnet-@IA1dhzR(*THZ);v;h7sI{3+(TcbvS*B0}+kFPQB{9SN9}@ z5^g|Mzx(>>ZrYAiYTO8rZj0tr4~nuTxqFupTJ13xc(OO+3hkv6DbMpPgd@_6@DKZI z%_Jf@HT5ldwDe9~Hwz3ItO>V$*~+ruIS z|F3OPR|i|dn{?SD@7zYVS@Gw|w7C#+=xI0z&aTX)iHf`Hdf%YF0+VwJ6^7iP` z)~nGFi}B2NfC5u^zKsn}T*nB?GrHOdTVR$%mEnxlz)JoSr)4^m_c!m45K2h#tNH_j zGV>W*kC_hQfpl{sy^o=qQc}M9o+eK-R|@q%y4IrY?mYuT+-#K@Q#KII3a}w$P)-!g z_sJhZg%Q z2gRnDld0TTduEj}!H?+DMQr)Uw}jf6gc4LSJWrO!%AzxYV?R)CmfiKr&2_)K-(s3M@RMl5)S&~tRnkcLYW_WC(X_cXvNtQSk)qGfMB#IIL&pyC&04)s zUuVFgKPpt2Hu4$^r!qIU9?C`0(C{##i8)l*X^AUFVS`;&{reo-ghTu|$~D)kfsIXz z=LKjgBN=HV?A1+Lqtr552Nui(-1n5RIh!aY@1sD;_9j#(}L=l@*qJPWUq-YDX9OniTZ?uYyh`ylBk@5Lie0} zw0i1OR?;0#1X4NDf-jO;S$`lGri@0*I8FchOr?`1m>^6Fm!hSmCFHmhfmCks=_R~! zCBooyDj}QZ_wBSutacaq zY2L#C3Skf5(~iTjr`$wGD?{84HWw&lF?6_K{lQ61J6R$+%(pD6AG?tuD~hM^lG8yR1ROskNT2<^zEba$n{IHijHZ*{?@GKJqdAv7P7P-To4A zuS8jn4h9R9vp$M(nx3@}cE>V+iwOoQQuEMI*TBN;#~DiDWug7qmb?#ZYTD(-@TfZc zIQ|07(8Oat_zx1$1(lp8+6nVvQRYhnmOhP&Ul;?%k?#nkNGYpzu2b^$%_xg9WcB6j zvD<5xzPdqt=SH%ITSmlPaD;0sx%@0{A*jxj7i%F*C40 zLPr;k(?#v*^=I3En4lKhK%RU$3sTDJkloc~d6iScvu~$ONNAh`rOxVwFhX~JinIm& z^2LYX9%bs-d^W5W5KsE(`NyAr8}|iG$@%r_O8IYy9UyP@9nXhT@Xs>=BQQ2Rza){8 z|2Y8vPx1c*e*XvU|M!J~|9~6#_oe^$7e417Apapp@qe-(XYK#5OYi@`Jb-f==Ktgn z|HBdfl|SS!9rRz`k3a4Ids^zhtRKMty`}eOUV#4+E&m^{)4%ioe@z9>+W)Un0mF`* zkH`3}FTB6eKl+@-@@Eqa@}Ca6A(y%@8vj{v5Qv@ae>1^8_rM+U-{<~kyZZC%?!TIF z5XU*c{wE9P4~wO=7$b(QfX@vbdSn6u;0|T%(r<&;%JOR3xr*lI{6Z@(;O;i?yqiAM z;nsMiYKSaN+A2>ERp)Q?WO*>~k9H%9aTpOE8SkXWBnPs&;N?Rd#)((jV*J?^eN_Bq zcpbl43742yT!~`GSk%NT5nMVSl4LoL=q>)34xm*nnSSbVm^6oJ$p#4vlRGJ?abVKQr^~%HWuXp=pVhN!!KN*X3-Y_oY}_S;sif zdjqKqnyn`727@*a!=DeW^-!ur3tojuW?lWORPcc?*~>tS75|O{${7PXbdKJM6)L`6 zlzD}vWhl*1poyZ}$lQ zE(z2#w>r5o^15V?++w4-iIU!&I#AKVYo+7wsrGeCmN%!D}#Zsx`}ma zKO)lp-*1m2qM}^d_%9KXfiRm8(4kW_3mk~v$eKyqbI6~pl)(zvOtH2YDrKqJXyj!o z9_T7x143^8japoTsfm*}K^_$oF0PhAIOn|BtWqm{Fzz(9X>k93*PDUDI`g$}=n*;> zNwc)n)i;Tc3eowq5hM)_4Q3uE3tEq1xyDy>jIa8wjHHG(0-1LJW+n4k$F6LrSFF(9 z@AUzE2MJ$eI**5&j0Te7G+OOsAeYE6UiIwy5@wG4S+=?)^uYrr^YO+G%1zu$Xm6|u zQR((>LarJrGmxA;Q?sci&4svJ{oR4{9A+wqT@$(3Q z6+iHsIWdY+O!y6utncOWMLcoMkCwJuRyKr2)6e1i#`ZSM%d5r|E}WZ!6fH`+ zytB$#_XAy=F;eP=AO z*BNA7kXuS~ZOR5YM+73g3>zv&Xg>I~jFNwW^^k7ZiXRZ$Uw-b*H)SOC*OH9E9K47Z zZz+o*5e;-NLh;@WxOU$>E;pRv97T?nYDKa|47E0FZVdq9QPI(6QS*y~8EKUK*?Fvw z(Wp7`-og-fO;GY>63fX4*E|%0qLJMo;GcFMj*i{w*gY`+ejk?m;z?oM(QAKnsKh}L zpk4MRGXb^pW}`HQ@Y=QKuJG9sWp;x^(SuiGZUwp}8hXOzYNz62dJ7`umT7HYzs6R) z`YI|qHc)Ni2$I;UAYm9am_M3)OhBATRVed3Tw(M*P9pnvGX1`rr#ym^FF&g-+Gx8z zKIz2Ez(A*bwL4lZ6UvmM8Hz-t7iZuD+x>S!*&aQD8g%Vx$VU})qq~a~u>JW^29QE~ zYub^JHQf+oz9xOl2;~-itT5;MZmaJ|CRWT9Z84PF(znfBJZwdIawI=ecba^*SO;>| zQ(4Y+zj@oi>yp#+zQ$M)z%XiuLch*FD0jdzH#3-OF`Rg!=fjlr_Bycl5g4^yGarRIePP;k0)tzslOwGV>GIP{s!W3>5fa}S&?EIVs1A<{R=xh>Xa z>K{PAe>X8H8CFM`@&PnLa9uht(R=k?W@%j}BaQXr(j9SpgK5OXXOhbEvJ3lh<4B<9 z2C+neYa^TknhQ&d%~eO=dhLSg*9SReUXKj|Z4^8_&wH+wl&8Jcdx6Va$fTMv$K?5A z5XXsPgt5@&gP9Q6nNzQOP;iR7-*IXk|JjW|AY)y?nT#ex#f7Pyx!P6|l(P7(hmnP5 zURfZC4N^wLlQayjd9bue3QyS~SfLH4RsmT;on4PJ2S1mRej%dpyO^ zq*wUvU2E&>ui2WrT!f=#GKQ$~<_bH*xwfRC0jBw*OGDV1Cgr6z*2fXd%CxncAP#Z} z7-q6*uteLSb;^b--Sh5u#>3uKJM$J9aFcR`8L$uKJ8lQnd30=#fP3qbVMZw1%VeM4 z-et^>1)VClbp+N~TRWB`ipt;~H;5h>R2@ueH#Dw09S4n#kMm(llwk$hCg3*f&-G1@ z0pxdz-USTgL(@cX3r=!O;TXVnbRb7d8V*N~RNG|i9HUia0{3#DX_sSn>)S_nL`Z2< zK%hO4Y~7KDUA-vzwhdwIDI)9(BON#Q(4mjdZRF6@R2G;81+t-CXVw5)*OW-TKG`+> z{4~vP^5~(?3TnIOXG@=Yt~yj~{}%(rd<`rv0p*fsHQZ}4Sos+MQ#Ib~2f`}i7q~T% z`jG<`DnVgPfR1t#XXA4vCDjQpapbQ1=H8mqvAn35*w*&X_4i%p?LO{PV+kGQsrTBQfO0bESa-G)#)$!*p!A>>oPvIIBU zy6!{sV?fw`BV8(%zxT{BNC5had z5I&VPfOM7zF;~S$3tf4jVY@*sm~Nm^*z!;#PJNM}Sp!>&44#z+11tpjrpn-SxeXYPkj#A&I~N zRIkcIFL-Ha26GTCn4oH*O*!@WeB?M`AzDc~VFz{TB=;wG#61j@Z@4qI9g}e%%NQJ2 zk*}|CXrXz=51TGuSC^7X)j;mA*dD@qGpT~EY0Y&ZKzE3};5pIv`Awe#EmEz$SC#PvYY{MMxiE~@k$8j+TviVy8f zC8=F9<~zibY*QnAnsL?JRJl5#`r3P&$|J{3oleJ80_K^|6k}O!PmZeLE4hRD+9|c3 zE@oetfs>=9v4X4%^3hQN0a>c52tIK% zc2DhGuK2p-LT1H?`l;?iI&ZeDK2`wykLv(aIkUFfDpZYr1Ziyyiybj<$uHTSx!!lwjhw$`Se+~u_P-1auro0zgAp=-B(Ov zI!w#nj6dVl5zFp~6IdJ>$kRHY261MP75Cd(|Fs(dUO3%~#9A2IO9u40y)>(1WdYPT zP>rF7k{vqY*&zui%LC(QT$SLUh{dsKwUX)@+H>C{)Wok22|8;O<)B30WbB<(983=t z@{?QYFGJPTh=Pex`H^)T11b21AlFIByZ0!PO;7tOnDnuvnD^`NUTqA>ubR3~$#-1^ zbtA!;Kc-Z|DGAuYjWa+kCcl=b_NkV+bXf3NjcwUB<-oF#_wOs23F1yA?e(hNdPv31 z8ee~1OxSH|v3k@tRb<()VFHGJn34CTRt15PZ03zaYEE-nIn|ys)b{LufQm-$fR^@9Ct{azCV~#6i+v@Ap_BX~W{c*Ji zZ?KucBQ@r=+G4*n5~`j0Kv7r>d_l79eR0 zuBOp)E0CZu8OU0NfH1q7;h{9F%;UP^$;Ku}a8H`6!5sIC7mn~f{(7N+`g@+SOtP-9dJ~Ypd@>+%M{L`k+%%&Y&Dtiv{)&fdVU7!x#b(EStmIJt+!XUTolIx=mBmN zgTy9E*djsVF2`w@UW|9~RzpLh#qkKARyFz^!4LHk7rkJ&sRt_)Rnnv7)+!$nc&*Xg zNwH;baxyz~nvHo{mP{i-L$r=~Ktf?Z0!soxe72WG^vV=}3_1X@ODdj^Ww!^pm5ulJ z85m{_@+-&0L_w}qymn*cE~bmL70mI9iVm$Pw;BsWS~hWwt0TQ+I^y|dhIoc|rg}jF zkV{kF#>PfYQE}iCMoqoSfz*%JHZr9Ev~uMIaoevBZ?NfATUA3wUYCQ++q{P@0`u(3 z5%B{?#@rXcloSG77PcS_!Op)^j5Mgrtl2+7O%FGX%9=6U@7)d-c0A*t&e{Merh(M` z&DpuRv|HStA_fra<^D;cDPVF?uCZj!mWiuiUoA+!+tr4A5-d=b@Gwx6)@DgJVUGme zOE7jw4uMWMDN9Z5JgL)Cps+Z{K>*0_6O&F1QMP_blw9<65E0Ul%uyv|AY2`GeQ(|eo)+2$X%7Wiofa)-L(hbLL@J$eF?o*@2_9%r=K zxLrKj$LrSo;>@rK2}@oJXLg!hdlJc|rg3s|0%qR(6OwY};}h&; zVW~)+HKwwZ&RisD!ivGP+6W8f+Bsd5){8mMds3_I#F@s|fBlko5KaJ7iMgSsnkI$g>#8Oc)y*o5jrK$VKKoM}WyO>Z!&)fh60S zCrA4*wjy5TyXS#`9bMZxX}2HIVXj&)HecL&N4`!%<) zu-a#ve6U58tsbYytVG=x3uEsKzC}k@IF543)(M@km`o}8QLkL3!4=I0dv-6h95HOH z>L6DGyxjnXZ%pgmc7C?;c{*JGGI$Fr4QuE$lVzUORSC_e1Viv&- zz!Q1SW%pa$+U( zW$yiX5y9v=oiHb3D)$c-`tZX47+F4V>i-K^2Jzp2g?|k@FhpxBBQH+yrH!|DW^Ih` zb3W2~R3fm{i&()Z&$8Zk6bEA3H3FTI*vE1|dFezC_?dV*nNLvugNo@g$ZAT)iH@sV zy&(FrFk0l{nfoi5jK{sYDnv+;DQ1(D!OLF(M@G7$`UH2WRy`lE^=@fPNImZ?{ZMlc zWF#g&w{rWiiU?q^Ife^`tLd#ODrLog{7Q1!VPrXQ^40@S)!gZd#4v;v$zKGp%0I`a zux?XHxYFI&x~$lB;zIFDtrVhJ{+&|Z2l_!>s-u5G@6jK1rVyMEF$s6tVzwH|9~=*$ zhZZwWXz3gOB3vw0*LZ!Q>Q>jEtOE$7I0yty#W*9EE>zw8@1E7$Wc@qP)JZrZ79r*L zR+n)g>V8(=lk*9KgmJb%yO9|0rl>?vu@gX796CR-!u(ieqQO~$A(`8 z>AHU|gyOg6iB#U-~Xn{T-s2Ag$bUagv)e{am~=%O&~Bp7j%j$KFfHYq{z zXHHh=Rn6DKgnv(^2>poFyAz|JD(B#f2)|>@uVrlS7#*D*RN?!)?fMHnhK09Boc90%d3Evs9e8iv z5lc?cw?SmVHi}wjr`v>cu|s z?xHMzm7zFciaj}DU({ryO*-Rk{A>O;b>6~w({KgN@SMMbDGp8ni)fUn|B3@8{={&V zstaH|A5)m(HTkr7rG;Rzq>hXFk~Xh+CVvHtW1Lj~A~nWDGrfk&0y|!p9Vo)1<7QhN z|H07>UqP%hswHjy4MewktqWQC&L&Txrje%{tCWD1BPqTMgFJ;Q{E^8U9sXTR*Z_6lk7}Dh-*L4thTvCisP-Js` zz$b70fG@gOL2*pwW`xX+BL6Uj=@*gRL`OJqE%^4a++~8xo?>*ww01bJu6_9GE(cJv z(6;a#Q6AaN8pa4koc-|;-~(^YZ=tFszYGJvYq(&a9hO^DRYVu+Hu&z6d0c*Q{(X+$ zh~b6BJZ|)RvCG8fV{pgmr(Bgwa$U)Pt15dTqHr|?nIKY9?m@FFzD19jA1DTfZOlzUu&+dEDmD4puU&LH#VPc+Pj8|=yV=jFA*%D4M258dO zY;w)F$H^AbioGJ>XtVFiPU^164Wyfdizpu-Qxrb?JKiJ~PA;DbPhjzd{|$;CTf-$R zY%Hm{X2cU73)blE`p@~gwUj<0I8^kc#14yq*Mj!t?bWWDOGG(cCc};u<9ExOXg|e0 zOldhza@u-C?K%5-xj%&=M?G+98|&^me~s&ShmX$u)O(k*F*;N%Y7}=Y)MwUVadfm4 z#GQf`Z^}lkS{>!1#Q|Aw@5BS$33iq9VfHdB1ra543m;NLXiw_t+z$2^vX^?^32iPo zuALC94TLMD7VEgqbLxKcCKmfC6m1~ag&U6%v!#`V@4P@CZnIad<(CL~|G1>M1n#(y z@ty~m2$JZBuHU^Jszg^t$}@}(Z_w@Em8EeJtaq7w#}CYr1}8aNO}?$aA^u)#bKdGe zuMpkJ{^FnBXn?&jpb!WVug%??5J0A;rut5bA6z+HsTGi@o*#v@>lB5dVYOA5kyZN> z0d(gcG+c0h(WuJ!=ZD7QIE&NT-Aovi-Lx~Io^>H%bkDtlOONXG*sq>=p>#$$*)a=9 zXj#~-sW5)DE4FpBt9I+Y1bXMt%VM<_uX6i<4sY#9o|`B86d6H6{F*H)&}^A&msvE#@>$;9oV_!4iVeV9 z>@_!o+YJa{P;Fd4?b}8AGF4Udl`4QvJ;C2ZvKJn1EZKhDrIj`x$R*w0){5fLX$-Cy zZv_`s?et$2uzt*md+^@%WEzfktlxfb*!=x)h2Yz8R${CFb?11m388qq&X{bfd17eCs~s`!3o5F*KT;pazeL&4K+Z&?EOE*~M9%%X({~@jphNPtCf8wTvUnC;ueBF7pUuruP!cFIBHPgi{vg&ntrJ9|utV|(J=p87poZRJ} zy-l?cu@GtE171FWihpe^$S8)#Ti7Z;j`Oc_jH(8CU7h+hq>ulqqw!&dSp{vo*2BJxq6V7C{s=dciqX7#`a;aW#RhPW|#e57V&&85%=`3F1nU4%t^nM zf&Ir21F?N$w$?T`lQBWsy>VN}8<_5oWIflp5&|0FXV)3z+aZqcljg+TrZ7DG52+vM zPMk=L47?-HRIX$4^vTSLNk#^wzkhHID|^!1AB1m517qFB|zwESK7 z?Fz`Rsu?B7vWV5)G}+^bo-}wXIHpU@o(!Wkxsb(lO_3%aa+kwX%x}_iVJa(oN<7Cf_mEAY-L$?h1bNw5c*B&EWBHt%*5lHdI->#a@=CLB=ff_wQrkxtB(t3QXNPmAU?IfHWXa# z9)2A68rbU=15axf+k3X(Q7%Gy&|uU9i+g!M{ktq_jvXA^{>II}|JdfoMaXopp`D6~ z;f#H%7uvA+UB5<0M=qb`O9M4&cP)zg0NmAYNbf_{YWs}6fZ*y)7qr_*jzX+(OmVO3 z&S+(>?q4rb9!XYl;b6yeb#4#~{A6tc=(@DB;-8sRAltu)1<`$~j!^^8=X}+h%$+z| z3K7BR48-jdO)|u_U9fB7#@RYd60Fuq$Wl98X^Y}E8?Ux#ZEG6__4&*wfo>=@v)upP z&M^u8!Olzy3O98;x7t_jY$;r7+01E;6yL?l6HV*nR`m_sg}=P!}}mF?_bPV%5$M668LQ-gPk8FAMtR`b)p2 z!tLs?Rg_Hv>UPtkO>(X+i+`p>u?(CNaBjob!u&VI&i zDpK=9s;G3pHAB$A#fdiRJPS2l+QLLcMm{qB2FV0EzCabNt!KKTIdq;eMVeN;#UFP4 z^$LfZX|oaGR*HVf!NW~-w0)4{02%j5Le-RQ?f(1e{zIA7Sk3y8iS zwXOVIW;x{WvxV712AdXBJI%n?W`ZqWEXqOLU(h&sj~UA#4sZ5 ztS3HjgYe9fqlhUL*c8^m!-e+s1r;8Af5l^=qHTON1js7Z5daesMk{N*=Ge$;7J|0Z znZ8~ONDpnkO?}o(I`QGth~Imz^W3`4M}C((5x`$HPP>wD;h#v*@l82IxTUER*?+;^ zR_;&l%yrDsq}{_cCG2HSC*saKJn}4-+XpEyi_m6VRXl&!nxUieg0O>2MpUz>+Igwb z=bM+h`LqyLofJ{pVT^GBvH5rI{VAPpojQC0ScLpO-e&yDEgG)v%NSxfT$Rb$}x?2+H!(6v0l$CY4QF2}Gks=a*5mT>P1zHiYz0p;m0 zj3FO4+#QC6fsLyCe+jXps3ZySWF8c-at2Y_ z64oLoPmdTnJsf$yc+yw0WiEGLl6gQ98F4$4|9aw(l6WNJn}$mZ)KX#Jq<6(6^;Bio zeHI{KFqDcIBq51lPQ?uq@E=}r;4WVdf>!G~ldWS=ei61Oci z!+-7rTr8_ zbF;fT^?FV}LA{p1wiF`$!>xtu_pjkk)8CW3eVd-<;>8>Y!pDiQSB3C`;HssW-D!fz z=U_7x9y<<5j#KR59BIBm3Bs6tNlLR&NA?Nu1n-^8sCPKTquEAUtLn8-ft;-(R#6 zJ?IHXwgRJo3aq{(mIm#IjF_Q3g(kddyR6r1Gho}9>z*jjq;Z`p-j|$I?Adu@EsgU2BQq)Z_BOqy5dj;a~HGVV5~m|zZ_>h~@yqnj&On+>IZ=B=UJ5<+wF%#7f@ z+{I1ldYyc~Nbw={z50a*F(mtp_o^NzGnKs!a20Y6KL+Z3KcvFz<`Q)V?_>rFou=Ml z;gVC)B>x<0w6pJJwnJR^<5v=0a|(k1Z;cZI!049#EmGA z0XYcx0|o$SlLj*~^0i80P2{5?MGg&wAh0Wq9W1EPIk#?%)}L1>CBYhQy}u5V+)!cP zfGV(&-wt^6gwi5aGzX=6RJ>~+eAwSv6G4xYkMMk}aol(_eG@#~dfP_?9cO?18@dNNJ#l?aARoV81?7kAD(Ai@DRJZraiwZI_~LY6z8mlo9$f%DpKgLK?P%d zX9b^m@4^T#f4Y#IeVTT(97WQUq+;;oaHq7};7H4|sUZ-K_VbzQ>dh1pJAN6YSTx>dB@DAx61*d92)p z$$E!7XLfb4K%TWQoBksMuu67r;GsIks7u`#1;d#oGoQEk2e-ptXupsYbDtgw%gUqt zv9QGI8ZMVrc_2GSlBL#feN8%zae9MprK4lA=9BuB7(GA^I{D}bH)Mw~VJ^Pc*(cn- zcJd9PZ?njJ4Zk-=YGd13k#bj}%}#wMf4bI>$PK_ucZ_i80ljNlNpRFg4nDDIH2N6x z%Y5O~V>uHylnZ0;tX(T^Tww{R+U?Yd-8#-hKfbVx52nD}N)|e}vh3-9pNe>4v<+yGnU`IC#up=*Y z@7@M(2}CSjxkK1{4;p6I(mbW>GLF6$y90qVzyJnPDHKBL3jLkSr(ah&*SmPAA!-wF z>}0t+wqwYBrc9H?w$I;4S=29(-+FH|iFUuR$z};I)6j5@y7-U)0CBpFU8+qiL5$#( zqMV%eBfIWbnM#R2Ke=XkWR*fX9h+{Nj;ohM_fAC0o}f>_!}9v%!EQ607p4VA!G$C}-LGy$wdZAMXfVbBOl~k^6*jC@xK9AElCw7RE-zlO(X1)kQuSjPrZqQM_ zqVS9Hak_nzMC!RDHBqYG$NP{f4{vix-WQ-X+P9kUL;VL zt4psUgy((KA1l&(Bc3J;KLa7jHvP723&LBKd)~1qD@(>~W&Wu|s zYqqf_8T*p#YnCDVJ|2u|h(VZ!7|USB`oDYV_xb!^{9gXv-Jk2lb)D3|O2=cLNFc)m+f&a(}{=<^V@&>1d z>)0vG5qhjFa;%|K)|)Y?{w^kLq|eF739Jk?zkb-ma)K$44WImiCyxEb9X$+90!p!1D>&K1goz~St7U^z9Woq9Z9 zLhNNb^|X8=^)CzY0%Agj$Ltr^vWGa^ncLsR@XON7HAI5Ml8kl3g><__*>dEO5TUSR zqu4pUlboUlxz2Wsuo&^F-P^@qbESpj5AA1lhu0%|fjI?)?9``s%qFSEf|uI58N*y# z6f^TJRRAsBnAgUFoZ9qwxIRKknD3HxR&sSg@RV|Qf_ywlmupR_>!3HB2rNAsI| zshA!N(0>-Sa74JSAC>Lh$KYC{S=;otr4Yw2$CK z+i0)ZOxl9V#DCxhbJ0NYK!wzi1s>P%^Y?mU`p6(RKUs!V*LIC3SQvktr6rKf^W>#= zaVhF{>^Dz$aZ4LE5|jh>l_)zUdwze=b=08oU0`5@)Z(p_nBz=AbU}gORcr}PV()Oh z@z`cCjf>2-bX-_@r41u^rb-Ojg{FJn-f}-KF+cIybWR1j6Ckc_6E%Cs0}IhANc^?DYx4>mZnH^IR%FChUVe5m*pY^| zQ35R6j#BJ?%E2wzm1ku@Cxy>(RxigZr}=oWYI%*n`iS1^BD(F)g{jMKer}?dS%~uY z-GA3qdZ39CW;!;Rc0Da*`G7Y6iuIVG`nvg_?2~NAK*87o_Ih{r5%m=V&!*BRbaRIL z;NF+L37g!P$10~suH77LEEk2WY_>700+eQqu%6=F+X`_>N$b21^@C`wo1?`~+Oq)a z71Yj*tjD(kZU@|_>5Lt+<-pH(llY?xdxFymGY|*KMHinA974lt=ZXud!xyDXg`;%; zp!dX|$qc+EJ%KvO3&d`V^E%c6tc$r%dgn|%h(i)}C%Nue2%4axyXUz8<><&R^_Z0i zsKuW`^%=pl7Eg4k1RiS^#f?69AMXY0V%oOOH*cI{Us{!2Gu|Ny%1>*z@|pE+n(vAD zONLamn(8&m#B%kIgAM9U0e4ju@8upg_1a)QG{B}-=tTp@)BNU{7Aid9>&O$-y;csF zk$*ae!9AYepTiXVya%)oTDB_917GQu#({bvP^I!n7mcvtqM^20XrnQI?03>YWAJt4tqv zSfKnGrd0wwk3(FR6r^oOqR~cVD1z1^+o`au@N{Kabu)zEhRq?uV6fJ+7p101qJne3 zgre>ADpIrvN7=5S%~MWf`Vs8iI1HA-Sox{^;yB?8Ll!wpOn>-tf=F08L>I=Ht+-Xr z0DP6J3#p3Z$nop(ruJkseGiJ*;hts4^b_LHghIm8m(ihuZWpY!(^xg6OpU6U3sE7g z6WoEaO};T>Dd%i3sfN`~ts;)WOO4Xtvk=P}szT`ZWYP09HM)AT($A*zP2L3Xz3kRG z3DZwcC&sE8_In}@svloY$o=?{!$^Jg3}6yZT&n4)u-Ulm#aG7*HZPejF;W{yic$+> zVBcp2sQs_nT(t)GN8f*cQ0YQXM>a%+l&`IISdH2)QrEvn-$2T&_PatLs`B#+U|PjN zIy$HF(~CG+)q_5ZZkvieluAeexxt|6F{7jW0R1a(tKC|hS(TfTMB){z4vHNsaOS#o zh1Z^!Ko=jFcS^-yGiySpe0H~?H^$a;7^x};vsG373NlWM+v*a&t=3xPeS@oH zKJ}z2^0My9n=x(7JN&>{;&e!w7BosP^YwLMPgi};KWDRE_aS6ykm*>csKO@aocl^#Oap3)sW^U$#Bp2an4w;$YhurQY0{gH+7S4A=dV{iiPqO^c{C^>-@^ zgg$h;Otza|4@kU~CoW~5pRpHhd(dGUt%$@H-oNVDqY~*DrM3$2Y_pxwzRcRq!-MP( zFlO-AT4L1ngZ98sMb50n>oir%S`u0Ge$npJ7g($VsTP*k-(fcN@f0Kf+SyI@d`ql* z49h!p+fAFL@Y@f|7A(*X<6Z)~wpS$|?@oryTb*hzx^=F`!NDG?SYp!9EzOXrD3Wl? z*Yt=`xS|czU1GfuW@SHGoa?FcsHId`LvneGm2PXoU;W}=sX9nbIOf&9mMf74%eZ?JrRdW$4OHwM zUQz;sW~S6~H~w@(p_zGwRA_Ir6pdD@Gm6zuG}Z=J`|3?axX;d%rR=yEk2A=kXmJ)8_$kI)0ryCJ zW7Xkw8cJMPd{E=2) zuqrJibBAUndrt;LfCqczQwd=CqjZ{%A}Evm0b1$iv-#E=?_M%pX*V7PhDc}81o}vI z2`TaEmfn&~oD>3N(kpEHrjp|fGd?w>%CO=+r=C8nk;=JUv;4E3pt-x8!RRwnCd=>J z#~fd2uVZGXB!^vmQ0H^9;BLy7`lYga#2=sn-_9Vp>b#1qo14Gr0|EXsHjcUaDQ(al z0gY#vCv+a9(GN}uYL-?AA_IpKPvBXy;WJF5x=xbQ1n8o&oe${Q2(F_Z(1Ug>aVc@j zJVTWV5H|zt;!EvPl8!Rm0x5Vu4jXf|F##++13!HYr{bgTMe`HB!A4W#sC+~?~f zcc8031fLT!F5=(^ehcnOX~4W4yK46ITmZ=B(?n~@GoFuPo%4}BCn7!`}ya_KN5x=$F?7+av8t+g@l&UJS-zz*?m zwt%tmKj`7p*y~+9ryUD3OdbrSWX^B}0R=kd(5(wzQ7Y?BSnPZF`A%6pTa~o~jv>*W zsyN|>VKCoXaxVRwwqw|F5CeP*u@44#z)Xjz!GFtiESu_ejoyzdDiZl{#3PF^Y2Dwd zeS_8DYKOSqh{weCj>cl1H6BZWol#^wg00YUN|a0&T*{$V@(5q5Bv-=Hqi2xr7#FVJ z+zJr;|H@H*$Io{vWC9N(C$LH-;tG3u9K>}r`+(lyGY$bgSzX~4j zJ87}Fku^aPJy08Rh=WuN?$;1k2*cUR|hG<9|i z!-jt!gzeflhA$752tW#y&S)IDBV@{(|77V4%>I|dyMnR4cTLPg$!w9o>c8}K47H1I HJPrCk&lH>Z From f9b3816d409b95c08f136370a6a228fc34ed4ef3 Mon Sep 17 00:00:00 2001 From: veryCrunchy Date: Mon, 28 Sep 2026 01:05:02 +0200 Subject: [PATCH 3/6] fix(admin): stop hidden polling and preserve permission recovery --- ADAPTER_ARCHITECTURE.md | 9 ++- .../nextcloudnative/app/AdminAppsScreen.kt | 58 ++++++++------ .../app/AdministrationAccessComposition.kt | 4 + .../nextcloudnative/app/NextcloudNativeApp.kt | 2 +- .../app/AdminAppsContentTest.kt | 47 ++++++++++++ .../app/AdministrationNavigationTest.kt | 32 ++++++++ .../app/AdminAppsScreenRecoveryTest.kt | 75 +++++++++++++++++++ .../AdministrationAccessCompositionTest.kt | 19 +++-- 8 files changed, 213 insertions(+), 33 deletions(-) create mode 100644 ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsContentTest.kt create mode 100644 ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationNavigationTest.kt create mode 100644 ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreenRecoveryTest.kt diff --git a/ADAPTER_ARCHITECTURE.md b/ADAPTER_ARCHITECTURE.md index 800d4478e..0731393c0 100644 --- a/ADAPTER_ARCHITECTURE.md +++ b/ADAPTER_ARCHITECTURE.md @@ -162,14 +162,17 @@ primary account password to bypass that boundary. evidence from the existing read-only administrator catalog contract. It reuses that catalog for the Server apps screen and caches both allowed and denied results for five minutes using a monotonic clock. Opening Settings checks the -cache; while Settings or Server apps remains open, expired evidence is refreshed. +cache; while the root Settings screen or Server apps is visible, expired evidence +is refreshed. Opening a child screen from Settings stops automatic polling. No permission result survives logout, account replacement, or process restart. Both catalog request paths use `ForceNetwork` so revalidation cannot renew access from the transport's persisted response cache. -Administration, its installed-workspace summary, and the Server apps route +Administration, its installed-workspace summary, and the Server apps catalog require fresh successful evidence. Unknown, expired, denied, malformed, and -unavailable results hide those surfaces, including restored navigation. An +unavailable results hide those surfaces, including restored navigation. The +Server apps route keeps a loading or typed failure view with retry and Back +instead of navigating away silently when permission revalidation fails. An explicit refresh removes old access before requesting new evidence. Concurrent checks share the cached result, and cancellation cannot publish a late success. The ordinary Apps workspace remains available to regular users. Cached visibility diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt index 3b08824b8..98676a5dd 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt @@ -10,13 +10,38 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +internal sealed interface AdminAppsContent { + data object Checking : AdminAppsContent + data class Catalog(val catalog: NativeAppCatalog) : AdminAppsContent + enum class Failure(val message: String) : AdminAppsContent { + Forbidden("This account does not have permission to manage server apps. You can return to Settings."), + Unavailable("Administrator access could not be verified. Try again, or return to Settings."), + InvalidResponse("The server returned an unexpected response while checking administrator access. Try again, or return to Settings."), + Expired("Administrator access needs to be checked again before server apps can be shown."), + } +} + +internal fun adminAppsContent(state: AdministrationAccessState, canAdminister: Boolean): AdminAppsContent { + if (state.checking) return AdminAppsContent.Checking + return when (val result = state.result) { + null -> AdminAppsContent.Checking + is NativeAppCatalogResult.Available -> if (canAdminister && state.canAdminister) { + AdminAppsContent.Catalog(result.catalog) + } else { + AdminAppsContent.Failure.Expired + } + NativeAppCatalogResult.Forbidden -> AdminAppsContent.Failure.Forbidden + NativeAppCatalogResult.Unavailable -> AdminAppsContent.Failure.Unavailable + is NativeAppCatalogResult.InvalidResponse -> AdminAppsContent.Failure.InvalidResponse + } +} + @Composable internal fun AdminAppsScreen( access: AdministrationAccessController, @@ -30,14 +55,7 @@ internal fun AdminAppsScreen( var pendingLifecycleAction by remember(access.state.result) { mutableStateOf?>(null) } - if (!access.canAdminister) { - if (access.state.checking) { - LoadingMessage("Checking administrator access...") - } else { - LaunchedEffect(access.state) { onBack() } - } - return - } + val content = adminAppsContent(access.state, access.canAdminister) Column(modifier = Modifier.fillMaxSize().safeDrawingPadding()) { ScreenHeader( @@ -45,10 +63,10 @@ internal fun AdminAppsScreen( subtitle = "Administrator app management", onBack = onBack, ) - when (val result = access.state.result) { - null -> LoadingMessage("Loading administrator app catalog...") - is NativeAppCatalogResult.Available -> NativeAppCatalogSurface( - catalog = result.catalog, + when (content) { + AdminAppsContent.Checking -> LoadingMessage("Checking administrator access...") + is AdminAppsContent.Catalog -> NativeAppCatalogSurface( + catalog = content.catalog, query = search, filter = catalogFilter, onQueryChanged = { search = it }, @@ -60,22 +78,14 @@ internal fun AdminAppsScreen( if (access.canAdminister) pendingLifecycleAction = app to action }, ) - NativeAppCatalogResult.Forbidden -> ErrorMessage( - "This account does not have permission to manage server apps.", - onRetry = access.refresh, - ) - NativeAppCatalogResult.Unavailable -> ErrorMessage( - "Administrator app management is unavailable on this server.", - onRetry = access.refresh, - ) - is NativeAppCatalogResult.InvalidResponse -> ErrorMessage( - result.reason, + is AdminAppsContent.Failure -> ErrorMessage( + content.message, onRetry = access.refresh, ) } } - pendingLifecycleAction?.let { (app, action) -> + pendingLifecycleAction?.takeIf { content is AdminAppsContent.Catalog }?.let { (app, action) -> AlertDialog( onDismissRequest = { pendingLifecycleAction = null }, title = { Text("${action.uiLabel()} ${app.name}?") }, diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt index 0a3424d5e..288da29c7 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt @@ -9,10 +9,14 @@ import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState +import dev.obiente.nextcloudnative.app.design.NextcloudDestination import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +internal fun administrationAccessPollingActive(screen: Screen, destination: NextcloudDestination): Boolean = + screen == Screen.AdminApps || (screen == Screen.Root && destination == NextcloudDestination.Settings) + internal class AdministrationAccessController( val state: AdministrationAccessState, private val permissionCheck: () -> Boolean, diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt index 6c3aec295..25e5bf747 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt @@ -1221,7 +1221,7 @@ private fun AuthenticatedApp( ) { mutableStateOf(NextcloudDestination.Home) } val administration = rememberAdministrationAccess( session, platformCapabilityRefreshRequest, - active = destination == NextcloudDestination.Settings || screen == Screen.AdminApps, + active = administrationAccessPollingActive(screen, destination), ) { services.executeNextcloudApi(session, it) } var serverInfo by remember(session) { mutableStateOf(null) } var lastOpenedAppId by remember(session) { mutableStateOf(services.loadLastOpenedAppId()) } diff --git a/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsContentTest.kt b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsContentTest.kt new file mode 100644 index 000000000..393cb1969 --- /dev/null +++ b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsContentTest.kt @@ -0,0 +1,47 @@ +package dev.obiente.nextcloudnative.app + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.time.Duration.Companion.minutes +import kotlin.time.TestTimeSource + +class AdminAppsContentTest { + @Test + fun failuresRemainVisibleWithoutExposingTheCatalog() { + val cases = listOf( + NativeAppCatalogResult.Forbidden to AdminAppsContent.Failure.Forbidden, + NativeAppCatalogResult.Unavailable to AdminAppsContent.Failure.Unavailable, + NativeAppCatalogResult.InvalidResponse("Synthetic invalid response") to AdminAppsContent.Failure.InvalidResponse, + ) + for ((result, expected) in cases) { + assertEquals(expected, adminAppsContent(AdministrationAccessState(result = result), canAdminister = false)) + } + } + + @Test + fun checkingAndRestoredUnknownStateNeverShowCatalogControls() { + assertEquals(AdminAppsContent.Checking, adminAppsContent(AdministrationAccessState(), false)) + assertEquals( + AdminAppsContent.Checking, + adminAppsContent(AdministrationAccessState(checking = true), false), + ) + } + + @Test + fun expiredOrRevokedLiveAccessCannotRenderACachedCatalog() { + val clock = TestTimeSource() + val state = AdministrationAccessState( + result = NativeAppCatalogResult.Available(NativeAppCatalog( + contract = NativeAppCatalogContract.ProvisioningOcsV1, + apps = emptyList(), administratorAuthorized = true, + includesAvailableApps = false, includesUpdateAvailability = false, + )), + checkedAt = clock.markNow(), + ) + assertIs(adminAppsContent(state, true)) + assertEquals(AdminAppsContent.Failure.Expired, adminAppsContent(state, false)) + clock += 5.minutes + assertEquals(AdminAppsContent.Failure.Expired, adminAppsContent(state, true)) + } +} diff --git a/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationNavigationTest.kt b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationNavigationTest.kt new file mode 100644 index 000000000..d5d55418f --- /dev/null +++ b/ui/src/commonTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationNavigationTest.kt @@ -0,0 +1,32 @@ +package dev.obiente.nextcloudnative.app + +import dev.obiente.nextcloudnative.app.design.NextcloudDestination +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class AdministrationNavigationTest { + @Test + fun onlyVisibleSettingsOrServerAppsPollPermissions() { + for (destination in NextcloudDestination.entries) { + assertEquals( + destination == NextcloudDestination.Settings, + administrationAccessPollingActive(Screen.Root, destination), + ) + assertTrue(administrationAccessPollingActive(Screen.AdminApps, destination)) + } + } + + @Test + fun settingsChildScreensDoNotPollWithRetainedSettingsDestination() { + val screens = listOf( + Screen.OfflineCenter, Screen.Transfers, Screen.ProjectNews, + Screen.Files(""), Screen.Media, Screen.Notes, + Screen.AppInfo(NextcloudAppEntry("sample_app", "Sample app", null)), + ) + for (screen in screens) { + assertFalse(administrationAccessPollingActive(screen, NextcloudDestination.Settings)) + } + } +} diff --git a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreenRecoveryTest.kt b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreenRecoveryTest.kt new file mode 100644 index 000000000..79d40b16d --- /dev/null +++ b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreenRecoveryTest.kt @@ -0,0 +1,75 @@ +package dev.obiente.nextcloudnative.app + +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.CompositionLocalProvider +import dev.obiente.nextcloudnative.app.design.LocalNextcloudWorkspaceCapabilities +import dev.obiente.nextcloudnative.app.design.NextcloudWorkspaceCapabilities +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue +import kotlin.time.TimeSource + +class AdminAppsScreenRecoveryTest { + @Test + fun failedRevalidationKeepsRecoveryControlsWithoutNavigatingAway() { + val failures = listOf( + NativeAppCatalogResult.Forbidden to AdminAppsContent.Failure.Forbidden, + NativeAppCatalogResult.Unavailable to AdminAppsContent.Failure.Unavailable, + NativeAppCatalogResult.InvalidResponse("Synthetic invalid response") to AdminAppsContent.Failure.InvalidResponse, + ) + for ((width, height) in listOf(390 to 844, 1280 to 800)) { + for ((result, expected) in failures) { + val allowed = AdministrationAccessState( + result = NativeAppCatalogResult.Available(NativeAppCatalog( + contract = NativeAppCatalogContract.ProvisioningOcsV1, + apps = listOf(NativeManagedApp("sample_app", "Sample app", installed = true, enabled = true)), + administratorAuthorized = true, + includesAvailableApps = false, includesUpdateAvailability = false, + )), + checkedAt = TimeSource.Monotonic.markNow(), + ) + val state = mutableStateOf(allowed) + var backCalls = 0 + var retries = 0 + val desktop = width >= 900 + nativeSceneTest(width, height, content = { + CompositionLocalProvider(LocalNextcloudWorkspaceCapabilities provides + NextcloudWorkspaceCapabilities(desktop, desktop, desktop) + ) { + AdminAppsScreen( + access = AdministrationAccessController( + state.value, permissionCheck = { state.value.canAdminister }, refresh = { retries++ }, + ), + onContinueInBrowser = { error("A failed check must never open administration") }, + serverInfo = null, + onOpenApp = {}, + onBack = { backCalls++ }, + ) + } + }) { + assertTrue(has("Sample app")) + state.value = AdministrationAccessState(checking = true) + settle() + assertFalse(has("Sample app")) + assertEquals(0, backCalls) + state.value = AdministrationAccessState(result = result) + settle() + assertTrue(has(expected.message)) + assertFalse(has("Sample app")) + assertFalse(has("Find an app")) + assertEquals(0, backCalls) + capture("admin-revalidation-$width-${expected.name.lowercase()}") + click("Back") + assertEquals(1, backCalls) + click("Try again") + assertEquals(1, retries) + state.value = allowed + settle() + assertTrue(has("Sample app")) + assertEquals(1, backCalls) + } + } + } + } +} diff --git a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt index be1368955..e69df5a10 100644 --- a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt +++ b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt @@ -8,7 +8,10 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.Snapshot +import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout @@ -28,11 +31,16 @@ class AdministrationAccessCompositionTest { } val composition = Composition(EmptyUnitApplier(), recomposer) var frameTime = 0L - suspend fun advance() { + val frames = launch { + while (isActive) { + Snapshot.sendApplyNotifications() + frameClock.sendFrame(frameTime++) + delay(1) + } + } + suspend fun advance() = withTimeout(5_000) { yield() Snapshot.sendApplyNotifications() - yield() - frameClock.sendFrame(frameTime++) recomposer.awaitIdle() } var session by mutableStateOf(NextcloudSession( @@ -89,9 +97,10 @@ class AdministrationAccessCompositionTest { assertTrue(regularRenders.isNotEmpty()) assertTrue(regularRenders.none { it }) } finally { + frames.cancelAndJoin() composition.dispose() - recomposer.close() - recomposerJob.join() + recomposer.cancel() + recomposerJob.cancelAndJoin() } } From 2a8658d541d1a13320ce1524a89bdfce0f8a18d5 Mon Sep 17 00:00:00 2001 From: "obiente-automations[bot]" <311907242+obiente-automations[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:11:09 +0000 Subject: [PATCH 4/6] chore(website): refresh marketing captures --- website/public/screenshots/capture-manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/public/screenshots/capture-manifest.json b/website/public/screenshots/capture-manifest.json index 2d47127e6..97aa2e4bc 100644 --- a/website/public/screenshots/capture-manifest.json +++ b/website/public/screenshots/capture-manifest.json @@ -458,8 +458,8 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivitySemantics.kt": "625e281281f28e5a2d0497626efc882f4fb2b5e778fcbdcac34425c853f83730", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityWorkspace.kt": "79a2ba91cee7ed17441f4b0bcc781eb7bfa8c5eb90a1717233df96794c56a61c", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt": "a82f5b173075a98e0c3bd544b90de08c1d3dc291a0e7329ce00822aa0584abd3", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt": "e3c493e9168c206cda82d539bfea111f61da0b6cc1c585879db8d765f393a4b0", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt": "ef689066029776407a9782f302b4a5101439f16e5d3c67180738a234487c336b", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt": "22c6a8d16faca6d0c3c94273dd05ffad27f9592805c9daf2e79dbab9a141d229", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt": "20ec6dc0998a90a8e3d7b8357e80bebd57498487afbba61226609659c6be9e78", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt": "c9343041d0ce159bd97494fa7036c98d8140b089decd0d84b63dd5bf2a35a1a3", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppCoroutineResult.kt": "a0d6f140ffa50d1def77e0734b4ceae63855eed9766e2f3f82e82f2307ddc8f7", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppNavigationState.kt": "115b9a0b5d360fae4f0738d9e16e1077d969ca4bb5d3c136401d7156adde431c", @@ -666,7 +666,7 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudLinkRouting.kt": "4f2c26b7f76b9edd9af33da676f83298a02cb571cd10f4bc1f41a73a42eb5e47", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudMediaViewer.kt": "fb424bf8979ac292ef30daba64e905e6f5123066cda793aa0244907e11b465c9", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudMediaViewerActions.kt": "48aaed6948d1423113d300cc3ab86d244ab76e8225e24988e9855edf74553944", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt": "ac90c1365b665491a5f467f5d3da1793e46f81d436d964f22d468deb9e4cf769", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNativeApp.kt": "96c1edf4c68256a6e0e33ccd2ab0c7d1ed3fb512eba0444334a07b2da711488e", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNotes.kt": "29b0b80824eeb2d154f52a9eacc10bd4d7068b7eca3bd9427aec67903bf6ee0d", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudNotesCache.kt": "aa9ec330c3a569e2bc9948858ddde1d939358069d38fbd7a0319b1ecc3baa363", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/NextcloudPeople.kt": "cff910ea2cc77211ef81779c49ee0c957851f2b4a3ed32b857b12ded1cee643b", From 471cfd7401bef46cd902cdc336f5c7753f12ce69 Mon Sep 17 00:00:00 2001 From: veryCrunchy Date: Mon, 28 Sep 2026 01:43:58 +0200 Subject: [PATCH 5/6] fix(admin): pause hidden polling and retain settings selection --- ADAPTER_ARCHITECTURE.md | 4 + .../obiente/nextcloudnative/MainActivity.kt | 46 ++++++++---- .../app/AccountSettingsScreen.kt | 29 ++++++-- .../app/AdministrationAccessComposition.kt | 20 +++-- .../nextcloudnative/nativeui/preview/Main.kt | 8 ++ .../AdministrationAccessCompositionTest.kt | 5 ++ .../AdministrationSettingsSelectionTest.kt | 74 +++++++++++++++++++ .../app/AdministrationVisibilityTest.kt | 40 ++++++++++ 8 files changed, 198 insertions(+), 28 deletions(-) create mode 100644 ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationSettingsSelectionTest.kt create mode 100644 ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationVisibilityTest.kt diff --git a/ADAPTER_ARCHITECTURE.md b/ADAPTER_ARCHITECTURE.md index 0731393c0..7feebf0ac 100644 --- a/ADAPTER_ARCHITECTURE.md +++ b/ADAPTER_ARCHITECTURE.md @@ -164,6 +164,10 @@ that catalog for the Server apps screen and caches both allowed and denied results for five minutes using a monotonic clock. Opening Settings checks the cache; while the root Settings screen or Server apps is visible, expired evidence is refreshed. Opening a child screen from Settings stops automatic polling. +Polling also stops when Android leaves the started lifecycle or the desktop +window is hidden or minimized. Returning to a visible screen reuses fresh +evidence or revalidates expired evidence. Settings retains the requested section +while Administration is hidden during a check, without rendering its controls. No permission result survives logout, account replacement, or process restart. Both catalog request paths use `ForceNetwork` so revalidation cannot renew access from the transport's persisted response cache. diff --git a/androidApp/src/main/kotlin/dev/obiente/nextcloudnative/MainActivity.kt b/androidApp/src/main/kotlin/dev/obiente/nextcloudnative/MainActivity.kt index e72970704..365c48315 100644 --- a/androidApp/src/main/kotlin/dev/obiente/nextcloudnative/MainActivity.kt +++ b/androidApp/src/main/kotlin/dev/obiente/nextcloudnative/MainActivity.kt @@ -8,6 +8,7 @@ import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableLongStateOf @@ -18,12 +19,15 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalConfiguration +import dev.obiente.nextcloudnative.app.LocalAppWindowVisibility +import kotlinx.coroutines.flow.MutableStateFlow import dev.obiente.nextcloudnative.app.NextcloudNativeApp import dev.obiente.nextcloudnative.app.NextcloudNativeLinkRequest import dev.obiente.nextcloudnative.app.ThemePreference import java.util.UUID class MainActivity : ComponentActivity() { + private val windowVisibility = MutableStateFlow(false) private var appUpdateReviewRequest by mutableLongStateOf(0L) private var lastAppUpdateReviewEventId: Long? = null private var platformCapabilityRefreshRequest by mutableLongStateOf(0L) @@ -131,24 +135,36 @@ class MainActivity : ComponentActivity() { window.decorView.setBackgroundColor(background.toArgb()) } - NextcloudNativeApp( - services = services, - appUpdateReviewRequest = appUpdateReviewRequest, - platformCapabilityRefreshRequest = platformCapabilityRefreshRequest, - linkRequest = incomingLinkRequests.firstOrNull(), - onLinkRequestHandled = { sequence -> - if (incomingLinkRequests.firstOrNull()?.sequence == sequence) { - incomingLinkRequests.removeAt(0) - } - }, - linkQueueOverflowEvent = incomingLinkQueueOverflowEvent, - onLinkQueueOverflowHandled = { event -> - if (incomingLinkQueueOverflowEvent == event) incomingLinkQueueOverflowEvent = 0L - }, - ) + CompositionLocalProvider(LocalAppWindowVisibility provides windowVisibility) { + NextcloudNativeApp( + services = services, + appUpdateReviewRequest = appUpdateReviewRequest, + platformCapabilityRefreshRequest = platformCapabilityRefreshRequest, + linkRequest = incomingLinkRequests.firstOrNull(), + onLinkRequestHandled = { sequence -> + if (incomingLinkRequests.firstOrNull()?.sequence == sequence) { + incomingLinkRequests.removeAt(0) + } + }, + linkQueueOverflowEvent = incomingLinkQueueOverflowEvent, + onLinkQueueOverflowHandled = { event -> + if (incomingLinkQueueOverflowEvent == event) incomingLinkQueueOverflowEvent = 0L + }, + ) + } } } + override fun onStart() { + super.onStart() + windowVisibility.value = true + } + + override fun onStop() { + windowVisibility.value = false + super.onStop() + } + override fun onResume() { super.onResume() platformCapabilityRefreshRequest += 1 diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt index 6d21d3bc7..216128d21 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt @@ -36,9 +36,8 @@ internal fun SettingsScreen( ) { val scope = rememberCoroutineScope() val isDesktop = LocalNextcloudWorkspaceCapabilities.current.isDesktop - var selectedSectionName by rememberSaveable(session.serverUrl, session.loginName) { - mutableStateOf(null) - } + val selection = rememberSettingsSectionSelection(session.serverUrl, session.loginName) + var selectedSectionName by selection val supportDrafts = rememberAccountSupportSettingsDraftState(session) val detailStateHolder = rememberSaveableStateHolder() var loggingOut by remember { mutableStateOf(false) } @@ -265,11 +264,7 @@ internal fun SettingsScreen( BoxWithConstraints { val expanded = useExpandedSettingsWorkspace(maxWidth.value.toInt()) val displayedSection = if (expanded) expandedSettingsSection(selectedSection, visibleSections) else selectedSection - LaunchedEffect(expanded, displayedSection) { - if (expanded && displayedSection != null && selectedSectionName != displayedSection.name) { - selectedSectionName = displayedSection.name - } - } + InitializeSettingsSectionSelection(selection, expanded, displayedSection) if (expanded) { DesktopSettingsWorkspace( summary = SettingsWorkspaceSummary( @@ -317,3 +312,21 @@ internal fun expandedSettingsSection( selectedSection: SettingsWorkspaceSection?, visibleSections: List, ): SettingsWorkspaceSection? = selectedSection ?: visibleSections.firstOrNull() + +@Composable +internal fun rememberSettingsSectionSelection(serverUrl: String, loginName: String) = + rememberSaveable(serverUrl, loginName) { mutableStateOf(null) } + +@Composable +internal fun InitializeSettingsSectionSelection( + selection: androidx.compose.runtime.MutableState, + expanded: Boolean, + displayedSection: SettingsWorkspaceSection?, +) { + LaunchedEffect(expanded, displayedSection, selection.value) { + // A hidden section is a display fallback, not a new user selection. + if (expanded && displayedSection != null && selection.value == null) { + selection.value = displayedSection.name + } + } +} diff --git a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt index 288da29c7..bb3abf4f3 100644 --- a/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt +++ b/ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt @@ -8,12 +8,19 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.rememberUpdatedState import dev.obiente.nextcloudnative.app.design.NextcloudDestination +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +/** The platform host reports whether its application window is visible. */ +val LocalAppWindowVisibility = staticCompositionLocalOf> { MutableStateFlow(false) } + internal fun administrationAccessPollingActive(screen: Screen, destination: NextcloudDestination): Boolean = screen == Screen.AdminApps || (screen == Screen.Root && destination == NextcloudDestination.Settings) @@ -37,11 +44,14 @@ internal fun rememberAdministrationAccess( val state by repository.state.collectAsState() val scope = rememberCoroutineScope() DisposableEffect(repository) { onDispose { repository.retire() } } - LaunchedEffect(repository, refreshRequest, active) { - while (active && isActive) { - repository.refresh { request -> currentExecute(request) } - val age = repository.state.value.checkedAt?.elapsedNow() ?: AdministrationAccessTtl - delay((AdministrationAccessTtl - age).coerceAtLeast(kotlin.time.Duration.ZERO)) + val visibility = LocalAppWindowVisibility.current + LaunchedEffect(repository, refreshRequest, active, visibility) { + if (active) visibility.collectLatest { visible -> + while (visible && isActive) { + repository.refresh { request -> currentExecute(request) } + val age = repository.state.value.checkedAt?.elapsedNow() ?: AdministrationAccessTtl + delay((AdministrationAccessTtl - age).coerceAtLeast(kotlin.time.Duration.ZERO)) + } } } AdministrationAccessController(state, permissionCheck = { repository.state.value.canAdminister }) { diff --git a/ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/Main.kt b/ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/Main.kt index 692661658..fc5359acf 100644 --- a/ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/Main.kt +++ b/ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/Main.kt @@ -1,5 +1,9 @@ package dev.obiente.nextcloudnative.nativeui.preview +import androidx.compose.runtime.CompositionLocalProvider +import kotlinx.coroutines.flow.MutableStateFlow +import dev.obiente.nextcloudnative.app.LocalAppWindowVisibility + import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box @@ -370,11 +374,14 @@ private fun launchDesktopProcess(arguments: Array) { if (mainWindow.value === window) mainWindow.value = null } } + val administrationWindowVisibility = remember { MutableStateFlow(false) } SideEffect { + administrationWindowVisibility.value = windowVisible.value && !mainWindowState.isMinimized applyDesktopNativeWindowFrame(window, darkTheme) window.background = java.awt.Color(background.toArgb(), true) window.minimumSize = java.awt.Dimension(960, 640) } + CompositionLocalProvider(LocalAppWindowVisibility provides administrationWindowVisibility) { Box(Modifier.fillMaxSize().background(background)) { NextcloudNativeApp( services = services, @@ -387,6 +394,7 @@ private fun launchDesktopProcess(arguments: Array) { }, ) } + } } } } diff --git a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt index e69df5a10..abaf8bb96 100644 --- a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt +++ b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessCompositionTest.kt @@ -3,11 +3,13 @@ package dev.obiente.nextcloudnative.app import androidx.compose.runtime.AbstractApplier import androidx.compose.runtime.BroadcastFrameClock import androidx.compose.runtime.Composition +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.Recomposer import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.Snapshot +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.delay @@ -50,9 +52,11 @@ class AdministrationAccessCompositionTest { var denyAdmin = false var calls = 0 var rendered: AdministrationAccessController? = null + val visibility = MutableStateFlow(true) val regularRenders = mutableListOf() try { composition.setContent { + CompositionLocalProvider(LocalAppWindowVisibility provides visibility) { val account = session.loginName val access = rememberAdministrationAccess(session, refreshRequest = 0, active = active) { calls++ @@ -64,6 +68,7 @@ class AdministrationAccessCompositionTest { } rendered = access if (account == "regular") regularRenders += access.state.canAdminister + } } withTimeout(5_000) { while (rendered?.state?.canAdminister != true) advance() diff --git a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationSettingsSelectionTest.kt b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationSettingsSelectionTest.kt new file mode 100644 index 000000000..c2d499e94 --- /dev/null +++ b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationSettingsSelectionTest.kt @@ -0,0 +1,74 @@ +package dev.obiente.nextcloudnative.app + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.saveable.LocalSaveableStateRegistry +import androidx.compose.runtime.saveable.SaveableStateRegistry +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import kotlin.test.Test +import kotlin.test.assertEquals + +class AdministrationSettingsSelectionTest { + @Test + fun restoredAdministrationSelectionSurvivesInitialPermissionCheck() { + var registry = SaveableStateRegistry(null) { true } + val visible = mutableStateOf(listOf(SettingsWorkspaceSection.Account, SettingsWorkspaceSection.Administration)) + var requested: MutableState? = null + var displayed: SettingsWorkspaceSection? = null + val content: @Composable () -> Unit = { + CompositionLocalProvider(LocalSaveableStateRegistry provides registry) { + val selection = rememberSettingsSectionSelection("https://permissions.example.test", "sample") + requested = selection + displayed = resolveSettingsWorkspaceSection(selection.value, visible.value) + InitializeSettingsSectionSelection(selection, expanded = true, displayed) + } + } + nativeSceneTest(1280, 800, content = content) { + requested!!.value = SettingsWorkspaceSection.Administration.name + settle() + registry = SaveableStateRegistry(registry.performSave()) { true } + } + visible.value = listOf(SettingsWorkspaceSection.Account) + nativeSceneTest(1280, 800, content = content) { + assertEquals(SettingsWorkspaceSection.Account, displayed) + assertEquals(SettingsWorkspaceSection.Administration.name, requested!!.value) + visible.value = listOf(SettingsWorkspaceSection.Account, SettingsWorkspaceSection.Administration) + settle() + assertEquals(SettingsWorkspaceSection.Administration, displayed) + } + } + + @Test + fun temporarilyHiddenAdministrationDoesNotReplaceRequestedSelection() { + val allowed = listOf(SettingsWorkspaceSection.Account, SettingsWorkspaceSection.Administration) + val visible = mutableStateOf(allowed) + var requested: MutableState? = null + var displayed: SettingsWorkspaceSection? = null + nativeSceneTest(1280, 800, content = { + val selection = rememberSettingsSectionSelection("https://permissions.example.test", "sample") + requested = selection + displayed = resolveSettingsWorkspaceSection(selection.value, visible.value) + InitializeSettingsSectionSelection(selection, expanded = true, displayed) + }) { + assertEquals(SettingsWorkspaceSection.Account.name, requested!!.value) + requested!!.value = SettingsWorkspaceSection.Administration.name + settle() + assertEquals(SettingsWorkspaceSection.Administration, displayed) + visible.value = listOf(SettingsWorkspaceSection.Account) + settle() + assertEquals(SettingsWorkspaceSection.Account, displayed) + assertEquals(SettingsWorkspaceSection.Administration.name, requested!!.value) + visible.value = allowed + settle() + assertEquals(SettingsWorkspaceSection.Administration, displayed) + visible.value = listOf(SettingsWorkspaceSection.Account) + settle() + requested!!.value = SettingsWorkspaceSection.Account.name + settle() + visible.value = allowed + settle() + assertEquals(SettingsWorkspaceSection.Account, displayed) + } + } +} diff --git a/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationVisibilityTest.kt b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationVisibilityTest.kt new file mode 100644 index 000000000..514c111f5 --- /dev/null +++ b/ui/src/desktopTest/kotlin/dev/obiente/nextcloudnative/app/AdministrationVisibilityTest.kt @@ -0,0 +1,40 @@ +package dev.obiente.nextcloudnative.app + +import androidx.compose.runtime.CompositionLocalProvider +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.awaitCancellation +import kotlin.test.Test +import kotlin.test.assertEquals + +class AdministrationVisibilityTest { + @Test + fun hiddenWindowStopsAndCancelsPollingAndResumeRestartsIt() { + val visible = MutableStateFlow(false) + val session = NextcloudSession("https://permissions.example.test", "sample", "synthetic") + var calls = 0 + var cancelled = 0 + nativeSceneTest(390, 844, content = { + CompositionLocalProvider(LocalAppWindowVisibility provides visible) { + rememberAdministrationAccess(session, 0, active = true) { + calls++ + try { awaitCancellation() } finally { cancelled++ } + } + } + }) { + assertEquals(0, calls) + visible.value = true + settle() + assertEquals(1, calls) + visible.value = false + settle() + assertEquals(1, cancelled) + assertEquals(1, calls) + visible.value = true + settle() + assertEquals(2, calls) + visible.value = false + settle() + assertEquals(2, cancelled) + } + } +} From a168863403d9cd3c20b67c86a9bdfff336c33160 Mon Sep 17 00:00:00 2001 From: "obiente-automations[bot]" <311907242+obiente-automations[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:53:35 +0000 Subject: [PATCH 6/6] chore(website): refresh marketing captures --- website/public/screenshots/capture-manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/public/screenshots/capture-manifest.json b/website/public/screenshots/capture-manifest.json index 97aa2e4bc..19cc6411b 100644 --- a/website/public/screenshots/capture-manifest.json +++ b/website/public/screenshots/capture-manifest.json @@ -451,7 +451,7 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountHomeWorkspaceStorage.kt": "5e0fa144df65840d15882c7da1dac19041083a302ced40578d07747f8ec7d828", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountPrivateMemoryCleanup.kt": "35c13216a14662f9bc2b47cee36b29f9d7d8602373b937536fcc5cc01da67e4f", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountPrivateMemoryLifecycle.kt": "09053be8a8739289395cd079d9eff473df53f5eb87305bb6609f4dabefe86bb2", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt": "da3a3320f79c5b9cd0926ce9a9a5017bfea40e1de04515d3101c280449bad521", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountSettingsScreen.kt": "dbd8a8e84812769affd73c83d10a7ac5cab125408dba75020c5ed81836c554ac", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AccountWorkspaceMemoryCaches.kt": "b987eb0ae9d1c30ecbda65a753aaf469b836394aca42c68c63e406a067a8a653", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityFilters.kt": "569265895b9442292c043f5ecbe2cdd55a9da6761a77b19b5f81fff34e999a10", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityHistoryPresentation.kt": "88f25cd079f7d7fc1553f8969818740816e2788542b70377ea11f64201c44474", @@ -459,7 +459,7 @@ "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/ActivityWorkspace.kt": "79a2ba91cee7ed17441f4b0bcc781eb7bfa8c5eb90a1717233df96794c56a61c", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppManagement.kt": "a82f5b173075a98e0c3bd544b90de08c1d3dc291a0e7329ce00822aa0584abd3", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdminAppsScreen.kt": "22c6a8d16faca6d0c3c94273dd05ffad27f9592805c9daf2e79dbab9a141d229", - "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt": "20ec6dc0998a90a8e3d7b8357e80bebd57498487afbba61226609659c6be9e78", + "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessComposition.kt": "ce7427c7e00de99cf5bee3782601ce1a53e09ff39ab215ee76a17d6599806680", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AdministrationAccessRepository.kt": "c9343041d0ce159bd97494fa7036c98d8140b089decd0d84b63dd5bf2a35a1a3", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppCoroutineResult.kt": "a0d6f140ffa50d1def77e0734b4ceae63855eed9766e2f3f82e82f2307ddc8f7", "ui/src/commonMain/kotlin/dev/obiente/nextcloudnative/app/AppNavigationState.kt": "115b9a0b5d360fae4f0738d9e16e1077d969ca4bb5d3c136401d7156adde431c", @@ -855,7 +855,7 @@ "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/DynamicBoardInteractionPreviewMain.kt": "7402f5b4bf3bbf3cf20761eaa10eca9131fb6e63da2988d0aa6038942d706c53", "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/FileSyncTrayVisualQaMain.kt": "4ce39ce3a53b72a32ca7489ef65cf301e9d8279f4be9ef9afc3ace701075c301", "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/FileSyncWorkspaceVisualQaMain.kt": "af79af05554e41806121b49f7fe8e31a67127636f0faec78f44ac812726c86e0", - "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/Main.kt": "b6f26394074b06186397d381dc7b20dc4690c36fd37865df5134377188520936", + "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/Main.kt": "ab84dc18e58bb410e9bbf48371ee74319601caa1356366f3ab5e35ccae01bb3b", "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/MarketingCaptureMain.kt": "bd7f6b8870c0030f061c5e466849b597f3388df6e9b4c5a6987000bb0dc0fbdf", "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/MarketingCaptureOwnership.kt": "c5bd9b63793a8884cf6b74cadf3061dc0ac295a982c97ae7f0a906ac3ae6f3c9", "ui/src/desktopMain/kotlin/dev/obiente/nextcloudnative/nativeui/preview/NativeTiffMarketingCapture.kt": "6970352c6e42d09b793c55ea296991d756d232f216d8d152aa00319b2ddb8d20",