Merge pull request #5960 from element-hq/feature/fga/fix_space_ff_disabled

Ensure space feature is enabled
This commit is contained in:
ganfra 2026-01-05 11:30:37 +01:00 committed by GitHub
commit 7282b59467
28 changed files with 57 additions and 109 deletions

View file

@ -28,8 +28,6 @@ import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.indicator.api.IndicatorService import io.element.android.libraries.indicator.api.IndicatorService
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.sync.SyncService
@ -48,7 +46,6 @@ class HomePresenter(
private val homeSpacesPresenter: Presenter<HomeSpacesState>, private val homeSpacesPresenter: Presenter<HomeSpacesState>,
private val logoutPresenter: Presenter<DirectLogoutState>, private val logoutPresenter: Presenter<DirectLogoutState>,
private val rageshakeFeatureAvailability: RageshakeFeatureAvailability, private val rageshakeFeatureAvailability: RageshakeFeatureAvailability,
private val featureFlagService: FeatureFlagService,
private val sessionStore: SessionStore, private val sessionStore: SessionStore,
private val announcementService: AnnouncementService, private val announcementService: AnnouncementService,
) : Presenter<HomeState> { ) : Presenter<HomeState> {
@ -69,9 +66,6 @@ class HomePresenter(
val canReportBug by remember { rageshakeFeatureAvailability.isAvailable() }.collectAsState(false) val canReportBug by remember { rageshakeFeatureAvailability.isAvailable() }.collectAsState(false)
val roomListState = roomListPresenter.present() val roomListState = roomListPresenter.present()
val homeSpacesState = homeSpacesPresenter.present() val homeSpacesState = homeSpacesPresenter.present()
val isSpaceFeatureEnabled by remember {
featureFlagService.isFeatureEnabledFlow(FeatureFlags.Space)
}.collectAsState(initial = false)
var currentHomeNavigationBarItemOrdinal by rememberSaveable { mutableIntStateOf(HomeNavigationBarItem.Chats.ordinal) } var currentHomeNavigationBarItemOrdinal by rememberSaveable { mutableIntStateOf(HomeNavigationBarItem.Chats.ordinal) }
val currentHomeNavigationBarItem by remember { val currentHomeNavigationBarItem by remember {
derivedStateOf { derivedStateOf {
@ -117,7 +111,6 @@ class HomePresenter(
snackbarMessage = snackbarMessage, snackbarMessage = snackbarMessage,
canReportBug = canReportBug, canReportBug = canReportBug,
directLogoutState = directLogoutState, directLogoutState = directLogoutState,
isSpaceFeatureEnabled = isSpaceFeatureEnabled,
eventSink = ::handleEvent, eventSink = ::handleEvent,
) )
} }

View file

@ -29,10 +29,9 @@ data class HomeState(
val snackbarMessage: SnackbarMessage?, val snackbarMessage: SnackbarMessage?,
val canReportBug: Boolean, val canReportBug: Boolean,
val directLogoutState: DirectLogoutState, val directLogoutState: DirectLogoutState,
val isSpaceFeatureEnabled: Boolean,
val eventSink: (HomeEvents) -> Unit, val eventSink: (HomeEvents) -> Unit,
) { ) {
val displayActions = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats val displayActions = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats
val displayRoomListFilters = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats && roomListState.displayFilters val displayRoomListFilters = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats && roomListState.displayFilters
val showNavigationBar = isSpaceFeatureEnabled && homeSpacesState.spaceRooms.isNotEmpty() val showNavigationBar = homeSpacesState.spaceRooms.isNotEmpty()
} }

View file

@ -31,7 +31,6 @@ open class HomeStateProvider : PreviewParameterProvider<HomeState> {
aHomeState(hasNetworkConnection = false), aHomeState(hasNetworkConnection = false),
aHomeState(snackbarMessage = SnackbarMessage(CommonStrings.common_verification_complete)), aHomeState(snackbarMessage = SnackbarMessage(CommonStrings.common_verification_complete)),
aHomeState( aHomeState(
isSpaceFeatureEnabled = true,
roomListState = aRoomListState( roomListState = aRoomListState(
// Add more rooms to see the blur effect under the NavigationBar // Add more rooms to see the blur effect under the NavigationBar
contentState = aRoomsContentState( contentState = aRoomsContentState(
@ -42,7 +41,6 @@ open class HomeStateProvider : PreviewParameterProvider<HomeState> {
homeSpacesState = aHomeSpacesState(), homeSpacesState = aHomeSpacesState(),
), ),
aHomeState( aHomeState(
isSpaceFeatureEnabled = true,
currentHomeNavigationBarItem = HomeNavigationBarItem.Spaces, currentHomeNavigationBarItem = HomeNavigationBarItem.Spaces,
), ),
) + RoomListStateProvider().values.map { ) + RoomListStateProvider().values.map {
@ -60,7 +58,6 @@ internal fun aHomeState(
roomListState: RoomListState = aRoomListState(), roomListState: RoomListState = aRoomListState(),
homeSpacesState: HomeSpacesState = aHomeSpacesState(), homeSpacesState: HomeSpacesState = aHomeSpacesState(),
canReportBug: Boolean = true, canReportBug: Boolean = true,
isSpaceFeatureEnabled: Boolean = false,
directLogoutState: DirectLogoutState = aDirectLogoutState(), directLogoutState: DirectLogoutState = aDirectLogoutState(),
eventSink: (HomeEvents) -> Unit = {} eventSink: (HomeEvents) -> Unit = {}
) = HomeState( ) = HomeState(
@ -73,6 +70,5 @@ internal fun aHomeState(
currentHomeNavigationBarItem = currentHomeNavigationBarItem, currentHomeNavigationBarItem = currentHomeNavigationBarItem,
roomListState = roomListState, roomListState = roomListState,
homeSpacesState = homeSpacesState, homeSpacesState = homeSpacesState,
isSpaceFeatureEnabled = isSpaceFeatureEnabled,
eventSink = eventSink, eventSink = eventSink,
) )

View file

@ -179,14 +179,10 @@ private fun HomeScaffold(
displayFilters = state.displayRoomListFilters, displayFilters = state.displayRoomListFilters,
filtersState = roomListState.filtersState, filtersState = roomListState.filtersState,
canReportBug = state.canReportBug, canReportBug = state.canReportBug,
modifier = if (state.isSpaceFeatureEnabled) { modifier = Modifier.hazeEffect(
Modifier.hazeEffect( state = hazeState,
state = hazeState, style = HazeMaterials.thick(),
style = HazeMaterials.thick(), )
)
} else {
Modifier.background(ElementTheme.colors.bgCanvasDefault)
}
) )
}, },
bottomBar = { bottomBar = {

View file

@ -22,9 +22,6 @@ import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
import io.element.android.features.rageshake.test.logs.FakeAnnouncementService import io.element.android.features.rageshake.test.logs.FakeAnnouncementService
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.indicator.api.IndicatorService import io.element.android.libraries.indicator.api.IndicatorService
import io.element.android.libraries.indicator.test.FakeIndicatorService import io.element.android.libraries.indicator.test.FakeIndicatorService
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
@ -35,7 +32,6 @@ import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.A_USER_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.sync.FakeSyncService
import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.api.SessionStore
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
@ -54,8 +50,6 @@ class HomePresenterTest {
@get:Rule @get:Rule
val warmUpRule = WarmUpRule() val warmUpRule = WarmUpRule()
private val isSpaceEnabled = FeatureFlags.Space.defaultValue(aBuildMeta())
@Test @Test
fun `present - should start with no user and then load user with success`() = runTest { fun `present - should start with no user and then load user with success`() = runTest {
val matrixClient = FakeMatrixClient( val matrixClient = FakeMatrixClient(
@ -79,7 +73,6 @@ class HomePresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
if (isSpaceEnabled) skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.currentUserAndNeighbors.first()).isEqualTo( assertThat(initialState.currentUserAndNeighbors.first()).isEqualTo(
MatrixUser(A_USER_ID, null, null) MatrixUser(A_USER_ID, null, null)
@ -91,8 +84,7 @@ class HomePresenterTest {
MatrixUser(A_USER_ID, A_USER_NAME, AN_AVATAR_URL) MatrixUser(A_USER_ID, A_USER_NAME, AN_AVATAR_URL)
) )
assertThat(withUserState.showAvatarIndicator).isFalse() assertThat(withUserState.showAvatarIndicator).isFalse()
assertThat(withUserState.isSpaceFeatureEnabled).isEqualTo(isSpaceEnabled) assertThat(withUserState.showNavigationBar).isTrue()
assertThat(withUserState.showNavigationBar).isEqualTo(isSpaceEnabled)
} }
} }
@ -114,23 +106,6 @@ class HomePresenterTest {
} }
} }
@Test
fun `present - space feature enabled`() = runTest {
val presenter = createHomePresenter(
featureFlagService = FakeFeatureFlagService(
initialState = mapOf(FeatureFlags.Space.key to true),
),
sessionStore = InMemorySessionStore(
updateUserProfileResult = { _, _, _ -> },
),
)
presenter.test {
skipItems(1)
val initialState = awaitItem()
assertThat(initialState.isSpaceFeatureEnabled).isTrue()
}
}
@Test @Test
fun `present - show avatar indicator`() = runTest { fun `present - show avatar indicator`() = runTest {
val indicatorService = FakeIndicatorService() val indicatorService = FakeIndicatorService()
@ -143,7 +118,6 @@ class HomePresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
if (isSpaceEnabled) skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.showAvatarIndicator).isFalse() assertThat(initialState.showAvatarIndicator).isFalse()
indicatorService.setShowRoomListTopBarIndicator(true) indicatorService.setShowRoomListTopBarIndicator(true)
@ -168,7 +142,6 @@ class HomePresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
if (isSpaceEnabled) skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.currentUserAndNeighbors.first()).isEqualTo(MatrixUser(matrixClient.sessionId)) assertThat(initialState.currentUserAndNeighbors.first()).isEqualTo(MatrixUser(matrixClient.sessionId))
// No new state is coming // No new state is coming
@ -189,7 +162,6 @@ class HomePresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
if (isSpaceEnabled) skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Chats) assertThat(initialState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Chats)
initialState.eventSink(HomeEvents.SelectHomeNavigationBarItem(HomeNavigationBarItem.Spaces)) initialState.eventSink(HomeEvents.SelectHomeNavigationBarItem(HomeNavigationBarItem.Spaces))
@ -207,16 +179,12 @@ class HomePresenterTest {
sessionStore = InMemorySessionStore( sessionStore = InMemorySessionStore(
updateUserProfileResult = { _, _, _ -> }, updateUserProfileResult = { _, _, _ -> },
), ),
featureFlagService = FakeFeatureFlagService(
initialState = mapOf(FeatureFlags.Space.key to true),
),
homeSpacesPresenter = homeSpacesPresenter, homeSpacesPresenter = homeSpacesPresenter,
announcementService = FakeAnnouncementService( announcementService = FakeAnnouncementService(
showAnnouncementResult = {}, showAnnouncementResult = {},
) )
) )
presenter.test { presenter.test {
skipItems(1)
val initialState = awaitItem() val initialState = awaitItem()
assertThat(initialState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Chats) assertThat(initialState.currentHomeNavigationBarItem).isEqualTo(HomeNavigationBarItem.Chats)
assertThat(initialState.showNavigationBar).isTrue() assertThat(initialState.showNavigationBar).isTrue()
@ -241,7 +209,6 @@ internal fun createHomePresenter(
snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(), snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
rageshakeFeatureAvailability: RageshakeFeatureAvailability = RageshakeFeatureAvailability { flowOf(false) }, rageshakeFeatureAvailability: RageshakeFeatureAvailability = RageshakeFeatureAvailability { flowOf(false) },
indicatorService: IndicatorService = FakeIndicatorService(), indicatorService: IndicatorService = FakeIndicatorService(),
featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
homeSpacesPresenter: Presenter<HomeSpacesState> = Presenter { aHomeSpacesState() }, homeSpacesPresenter: Presenter<HomeSpacesState> = Presenter { aHomeSpacesState() },
sessionStore: SessionStore = InMemorySessionStore(), sessionStore: SessionStore = InMemorySessionStore(),
announcementService: AnnouncementService = FakeAnnouncementService(), announcementService: AnnouncementService = FakeAnnouncementService(),
@ -250,11 +217,10 @@ internal fun createHomePresenter(
syncService = syncService, syncService = syncService,
snackbarDispatcher = snackbarDispatcher, snackbarDispatcher = snackbarDispatcher,
indicatorService = indicatorService, indicatorService = indicatorService,
logoutPresenter = { aDirectLogoutState() },
roomListPresenter = { aRoomListState() }, roomListPresenter = { aRoomListState() },
homeSpacesPresenter = homeSpacesPresenter, homeSpacesPresenter = homeSpacesPresenter,
logoutPresenter = { aDirectLogoutState() },
rageshakeFeatureAvailability = rageshakeFeatureAvailability, rageshakeFeatureAvailability = rageshakeFeatureAvailability,
featureFlagService = featureFlagService,
sessionStore = sessionStore, sessionStore = sessionStore,
announcementService = announcementService, announcementService = announcementService,
) )

View file

@ -70,12 +70,6 @@ enum class FeatureFlags(
defaultValue = { false }, defaultValue = { false },
isFinished = false, isFinished = false,
), ),
Space(
key = "feature.space",
title = "Spaces",
defaultValue = { true },
isFinished = true,
),
SpaceSettings( SpaceSettings(
key = "feature.spaceSettings", key = "feature.spaceSettings",
title = "Space settings", title = "Space settings",

View file

@ -25,10 +25,14 @@ class DefaultFeatureFlagService(
private val featuresProvider: FeaturesProvider, private val featuresProvider: FeaturesProvider,
) : FeatureFlagService { ) : FeatureFlagService {
override fun isFeatureEnabledFlow(feature: Feature): Flow<Boolean> { override fun isFeatureEnabledFlow(feature: Feature): Flow<Boolean> {
return providers.filter { it.hasFeature(feature) } return if (feature.isFinished) {
.maxByOrNull(FeatureFlagProvider::priority) flowOf(feature.defaultValue(buildMeta))
?.isFeatureEnabledFlow(feature) } else {
?: flowOf(feature.defaultValue(buildMeta)) providers.filter { it.hasFeature(feature) }
.maxByOrNull(FeatureFlagProvider::priority)
?.isFeatureEnabledFlow(feature)
?: flowOf(feature.defaultValue(buildMeta))
}
} }
override suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean): Boolean { override suspend fun setFeatureEnabled(feature: Feature, enabled: Boolean): Boolean {

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:29076d1c09d92943b1ba143d0ed3798fe92f7d37f87f45c0ae5f7326afe66f74 oid sha256:cc3fcb72de86766e3b97ffe0802551d7597b688f2a52ef73938d91c9cfdf0633
size 136708 size 141868

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:580c70e645e954e9e3d29a68aa46b1eae3a82651eb5e419eb92cba48bf7baaf1 oid sha256:02f12178991ed984da4b2d0a9883250750b6e37e7c9ce8494ca12bb987f29ad4
size 61515 size 65455

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:dd257b64d9e91bedebcf4552e8b93d357304954ad844b7f7d52bc76fc1543747 oid sha256:4eb7b8997069e2a4b37cd27c33e2862cba1871e1b58e85feb0b1bc4da6a3fce8
size 29901 size 33631

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4e3e455fbe6e3a10ec1578e01dc3f10c3b2b0688f99a1855319143c8fc7044a8 oid sha256:ff84f90db0deea1d8edc52a2067855cf277cc747f5c357dc0758ce72bbc6d0c8
size 25355 size 28014

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:821cb6a2068561375d0988d4ba5404e52411a6d9b73cefbe1a6bd7bc6d467673 oid sha256:e8cd2089f07a93e3dc62e41d80a3253d800b4463947276ccd461428280aff6b8
size 88367 size 84644

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:f9f5fef39d80aacb9666deeea43e4df48f7c70231bd8ec41edf2f3eed5f0aa42 oid sha256:71f336f93dd3fe736187a38aba6c1f14420bb0da9d574603f6df2042bce8f8d1
size 81149 size 83116

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c9e019924f41de0c16f1f403944b8fe390afa65d1ad604db3dd0baadbc30db5b oid sha256:d7840847edf48b171393418d6fc26d846d772fa8be919f55dfee086d85cab814
size 50953 size 51404

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:580c70e645e954e9e3d29a68aa46b1eae3a82651eb5e419eb92cba48bf7baaf1 oid sha256:02f12178991ed984da4b2d0a9883250750b6e37e7c9ce8494ca12bb987f29ad4
size 61515 size 65455

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:580c70e645e954e9e3d29a68aa46b1eae3a82651eb5e419eb92cba48bf7baaf1 oid sha256:02f12178991ed984da4b2d0a9883250750b6e37e7c9ce8494ca12bb987f29ad4
size 61515 size 65455

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:580c70e645e954e9e3d29a68aa46b1eae3a82651eb5e419eb92cba48bf7baaf1 oid sha256:02f12178991ed984da4b2d0a9883250750b6e37e7c9ce8494ca12bb987f29ad4
size 61515 size 65455

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a5a68b4d8951b7c516561d538c5d328a84948c66af7eb7c80ac77cd005620cf2 oid sha256:9fb19cc1e169e81f301a12ff3e30b8118682248ec3c13ea29b54f87398a54c3e
size 80977 size 82977

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:37660e7c0626ae3e5a8404fdc7e57e41d43750abb4004572ffd9c25a501c668e oid sha256:62f84bd6941a00ee6b006318b8ac9e659694c2749a3bfa1d8ca72ca2ce413c90
size 58325 size 62152

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:496855b1b3186adcad8b35895ee51776dce00a8d3229b8dccac4d6e4482bdaff oid sha256:ab4a977d119ae80ddb92198b9c26b4b42d842eba0fd0543896f55914018d34f2
size 26577 size 30548

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8b98678dc90bce52ab2293e5102794b4fc3b51fc667a6c061d771ea90212a0f2 oid sha256:66824bcff1cf8fdd0fd88c3e0272bd11eaf6fdd16d24120c9346c99378226eee
size 22034 size 24633

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:541740cdd54ef7b9a868c1409330a6ca7417bce9f022b22c3d395ac9b215d470 oid sha256:7d1745b2665a9329808f69e2750b50d59eac2d92216a25bae03a52907b6c7681
size 83939 size 80341

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a44897f23fc0e6a90779fe96638c560973caf7dbb9a7c92ec4d2f5b56de3ddcc oid sha256:9017e66bb482de6a517065efe2e9d66ce4eb561fb848ca29d3245a2abc02d4c0
size 77280 size 79209

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8f0e5430bcd399d5a39c3d92e7551243f0e15bc315f9ec6ded43829d4672308c oid sha256:6fd8d9d809b65df1690bf132351eec86736224d50fdd1bc9f9d2e731a4669ad6
size 47186 size 47687

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:37660e7c0626ae3e5a8404fdc7e57e41d43750abb4004572ffd9c25a501c668e oid sha256:62f84bd6941a00ee6b006318b8ac9e659694c2749a3bfa1d8ca72ca2ce413c90
size 58325 size 62152

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:37660e7c0626ae3e5a8404fdc7e57e41d43750abb4004572ffd9c25a501c668e oid sha256:62f84bd6941a00ee6b006318b8ac9e659694c2749a3bfa1d8ca72ca2ce413c90
size 58325 size 62152

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:37660e7c0626ae3e5a8404fdc7e57e41d43750abb4004572ffd9c25a501c668e oid sha256:62f84bd6941a00ee6b006318b8ac9e659694c2749a3bfa1d8ca72ca2ce413c90
size 58325 size 62152

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:49ea33ae74532c350b4176355203561cfc5eb79c93c4993d6ffb0cf933f8ad2f oid sha256:6c7790afd67222ce61ea0b72f1af3c1877b7e88580a644524c33f18d6fe76137
size 77167 size 79096