First Commit

This commit is contained in:
2025-12-18 16:28:50 +07:00
commit 8c3e4f491f
9974 changed files with 396488 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/build
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2022-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
import extension.allFeaturesImpl
import extension.allLibrariesImpl
import extension.allServicesImpl
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.paparazzi)
}
android {
// Keep it as short as possible
namespace = "ui"
}
tasks.withType(Test::class.java) {
// Don't fail the test run if there are no tests, this can happen if we run them with screenshot test disabled
failOnNoDiscoveredTests = false
}
dependencies {
// Paparazzi 1.3.2 workaround (see https://github.com/cashapp/paparazzi/blob/master/CHANGELOG.md#132---2024-01-13)
constraints.add("testImplementation", "com.google.guava:guava") {
attributes {
attribute(
TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
objects.named(TargetJvmEnvironment::class.java, TargetJvmEnvironment.STANDARD_JVM)
)
}
because(
"LayoutLib and sdk-common depend on Guava's -jre published variant." +
"See https://github.com/cashapp/paparazzi/issues/906."
)
}
implementation(libs.showkase)
// TODO There is a Resources.NotFoundException maybe due to the mipmap, even if we have
// `testOptions { unitTests.isIncludeAndroidResources = true }` in the app build.gradle.kts file
// implementation(projects.app)
implementation(projects.appnav)
allLibrariesImpl()
allServicesImpl()
allFeaturesImpl(project)
implementation(projects.appicon.element)
implementation(projects.appicon.enterprise)
testImplementation(libs.test.junit)
testImplementation(libs.test.parameter.injector)
testImplementation(projects.libraries.designsystem)
testImplementation(libs.test.composable.preview.scanner)
}
View File
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2022-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package base
import app.cash.paparazzi.DeviceConfig
enum class BaseDeviceConfig(
val deviceConfig: DeviceConfig,
) {
NEXUS_5(DeviceConfig.NEXUS_5),
// PIXEL_C(DeviceConfig.PIXEL_C),
}
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
@file:Suppress("DEPRECATION")
package base
import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider
import sergio.sastre.composable.preview.scanner.android.AndroidComposablePreviewScanner
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
// Make sure we don't import Compound previews by mistake
private val PACKAGE_TREES = arrayOf(
"io.element.android.features",
"io.element.android.libraries",
"io.element.android.services",
"io.element.android.appicon",
"io.element.android.appnav",
"io.element.android.x",
)
object ComposablePreviewProvider : TestParameterValuesProvider() {
val values: List<IndexedValue<ComposablePreview<AndroidPreviewInfo>>> by lazy {
AndroidComposablePreviewScanner()
.scanPackageTrees(*PACKAGE_TREES)
.getPreviews()
.filter { composablePreview -> composablePreview.methodName.endsWith("A11yPreview").not() }
.withIndex()
.toList()
}
override fun provideValues(context: Context): List<IndexedValue<ComposablePreview<AndroidPreviewInfo>>> = values
}
object ComposableA11yPreviewProvider : TestParameterValuesProvider() {
private val values: List<ComposablePreview<AndroidPreviewInfo>> by lazy {
AndroidComposablePreviewScanner()
.scanPackageTrees(*PACKAGE_TREES)
.getPreviews()
.filter { composablePreview -> composablePreview.methodName.endsWith("A11yPreview") }
.toList()
}
override fun provideValues(context: Context): List<ComposablePreview<AndroidPreviewInfo>> = values
}
object Shard1ComposablePreviewProvider : TestParameterValuesProvider() {
override fun provideValues(context: Context): List<ComposablePreview<AndroidPreviewInfo>> =
ComposablePreviewProvider.values.filter { it.index % 4 == 0 }.map { it.value }
}
object Shard2ComposablePreviewProvider : TestParameterValuesProvider() {
override fun provideValues(context: Context): List<ComposablePreview<AndroidPreviewInfo>> =
ComposablePreviewProvider.values.filter { it.index % 4 == 1 }.map { it.value }
}
object Shard3ComposablePreviewProvider : TestParameterValuesProvider() {
override fun provideValues(context: Context): List<ComposablePreview<AndroidPreviewInfo>> =
ComposablePreviewProvider.values.filter { it.index % 4 == 2 }.map { it.value }
}
object Shard4ComposablePreviewProvider : TestParameterValuesProvider() {
override fun provideValues(context: Context): List<ComposablePreview<AndroidPreviewInfo>> =
ComposablePreviewProvider.values.filter { it.index % 4 == 3 }.map { it.value }
}
@@ -0,0 +1,139 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package base
import android.content.res.Configuration
import android.os.LocaleList
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.unit.Density
import app.cash.paparazzi.DeviceConfig
import app.cash.paparazzi.Paparazzi
import app.cash.paparazzi.RenderExtension
import app.cash.paparazzi.TestName
import com.android.resources.NightMode
import io.element.android.compound.theme.ElementTheme
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
import java.util.Locale
object ScreenshotTest {
val defaultDeviceConfig = BaseDeviceConfig.NEXUS_5.deviceConfig
fun runTest(
paparazzi: Paparazzi,
preview: ComposablePreview<AndroidPreviewInfo>,
localeStr: String,
) {
val locale = localeStr.toLocale()
// Needed for regional settings, as first day of week
Locale.setDefault(locale)
paparazzi.fixScreenshotName(preview, localeStr)
paparazzi.snapshot {
CompositionLocalProvider(
LocalInspectionMode provides true,
LocalDensity provides Density(
density = LocalDensity.current.density,
fontScale = 1.0f,
),
LocalConfiguration provides Configuration().apply {
setLocales(LocaleList(locale))
uiMode = preview.previewInfo.uiMode
},
) {
ElementTheme {
Box(
modifier = Modifier
.background(ElementTheme.colors.bgCanvasDefault)
) {
preview()
}
}
}
}
}
}
private val testNameField = Paparazzi::class.java.getDeclaredField("testName").apply {
isAccessible = true
}
private fun Paparazzi.fixScreenshotName(preview: ComposablePreview<AndroidPreviewInfo>, locale: String) {
val id = listOf(createScreenshotIdFor(preview), locale)
.filter { it.isNotEmpty() }
.joinToString("_")
val packageName = preview.declaringClass
// Remove common prefix
.replace("io.element.android.", "")
.split(".")
// Remove class name
.dropLast(1)
.joinToString(".")
val testName = TestName(
packageName = packageName,
className = preview.methodName.replace("Preview", ""),
methodName = id
)
testNameField.set(this, testName)
}
private fun String.toLocale(): Locale {
return when (this) {
"en" -> Locale.US
"fr" -> Locale.FRANCE
"de" -> Locale.GERMAN
else -> Locale.Builder().setLanguage(this).build()
}
}
fun createScreenshotIdFor(preview: ComposablePreview<AndroidPreviewInfo>) = buildList {
// `name` here can be `Day`, `Night`, or nothing at all
if (preview.previewInfo.name.isNotEmpty()) {
add(preview.previewInfo.name)
}
if (preview.previewInfo.group.isNotEmpty()) {
add(preview.previewInfo.group)
}
// If it's a day/night preview, we should add an index to be consistent even if there is only version of this composable
val needsIndex = preview.previewInfo.name == "Day" || preview.previewInfo.name == "Night"
if (preview.previewIndex != null || needsIndex) {
add((preview.previewIndex ?: 0).toString())
}
}.joinToString("_")
object PaparazziPreviewRule {
fun createFor(
preview: ComposablePreview<AndroidPreviewInfo>,
locale: String,
deviceConfig: DeviceConfig = ScreenshotTest.defaultDeviceConfig,
renderExtensions: Set<RenderExtension> = setOf(),
): Paparazzi {
val densityScale = deviceConfig.density.dpiValue / 160f
val customScreenHeight = preview.previewInfo.heightDp.takeIf { it >= 0 }?.let { it * densityScale }?.toInt()
return Paparazzi(
deviceConfig = deviceConfig.copy(
nightMode = when (preview.previewInfo.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) {
true -> NightMode.NIGHT
false -> NightMode.NOTNIGHT
},
locale = locale,
softButtons = false,
screenHeight = customScreenHeight ?: deviceConfig.screenHeight,
),
maxPercentDifference = 0.01,
renderExtensions = renderExtensions,
)
}
}
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package translations
import android.content.res.Configuration
import base.ComposablePreviewProvider
import base.PaparazziPreviewRule
import base.ScreenshotTest
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
/**
* Test that takes a preview and a locale and runs a screenshot test on it.
*/
@RunWith(TestParameterInjector::class)
class TranslationsScreenshotTest(
@TestParameter(valuesProvider = ComposablePreviewProvider::class)
val indexedPreview: IndexedValue<ComposablePreview<AndroidPreviewInfo>>,
@TestParameter(value = ["de"])
val localeStr: String,
) {
@get:Rule
val paparazziRule = PaparazziPreviewRule.createFor(indexedPreview.value, locale = localeStr)
@Test
fun snapshot() {
val (_, preview) = indexedPreview
// Skip for dark mode screenshots
if (preview.previewInfo.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) {
return
}
// Skip for design system screenshots
if (preview.previewInfo.name.startsWith("io.element.android.libraries.designsystem")) {
return
}
ScreenshotTest.runTest(paparazzi = paparazziRule, preview = preview, localeStr = localeStr)
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package ui
import app.cash.paparazzi.accessibility.AccessibilityRenderExtension
import base.ComposableA11yPreviewProvider
import base.PaparazziPreviewRule
import base.ScreenshotTest
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
/**
* Test that takes a preview and runs a screenshot test on it.
* It uses [ComposableA11yPreviewProvider] to test only previews that ends with "A11yPreview".
*/
@RunWith(TestParameterInjector::class)
class PreviewA11yTest(
@TestParameter(valuesProvider = ComposableA11yPreviewProvider::class)
val preview: ComposablePreview<AndroidPreviewInfo>,
) {
@get:Rule
val paparazziRule = PaparazziPreviewRule.createFor(
preview = preview,
locale = "en",
renderExtensions = setOf(AccessibilityRenderExtension()),
)
@Test
fun snapshot() {
ScreenshotTest.runTest(paparazzi = paparazziRule, preview = preview, localeStr = "en")
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package ui
import base.PaparazziPreviewRule
import base.ScreenshotTest
import base.Shard1ComposablePreviewProvider
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
/**
* Test that takes a preview and runs a screenshot test on it.
* It uses a sharded preview provider so multiple 'shards' can run in parallel, optimizing CPU and time usage.
*/
@RunWith(TestParameterInjector::class)
class PreviewShard1Test(
@TestParameter(valuesProvider = Shard1ComposablePreviewProvider::class)
val preview: ComposablePreview<AndroidPreviewInfo>,
) {
@get:Rule
val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en")
@Test
fun snapshot() {
ScreenshotTest.runTest(paparazzi = paparazziRule, preview = preview, localeStr = "en")
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package ui
import base.PaparazziPreviewRule
import base.ScreenshotTest
import base.Shard2ComposablePreviewProvider
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
/**
* Test that takes a preview and runs a screenshot test on it.
* It uses a sharded preview provider so multiple 'shards' can run in parallel, optimizing CPU and time usage.
*/
@RunWith(TestParameterInjector::class)
class PreviewShard2Test(
@TestParameter(valuesProvider = Shard2ComposablePreviewProvider::class)
val preview: ComposablePreview<AndroidPreviewInfo>,
) {
@get:Rule
val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en")
@Test
fun snapshot() {
ScreenshotTest.runTest(paparazzi = paparazziRule, preview = preview, localeStr = "en")
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package ui
import base.PaparazziPreviewRule
import base.ScreenshotTest
import base.Shard3ComposablePreviewProvider
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
/**
* Test that takes a preview and runs a screenshot test on it.
* It uses a sharded preview provider so multiple 'shards' can run in parallel, optimizing CPU and time usage.
*/
@RunWith(TestParameterInjector::class)
class PreviewShard3Test(
@TestParameter(valuesProvider = Shard3ComposablePreviewProvider::class)
val preview: ComposablePreview<AndroidPreviewInfo>,
) {
@get:Rule
val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en")
@Test
fun snapshot() {
ScreenshotTest.runTest(paparazzi = paparazziRule, preview = preview, localeStr = "en")
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package ui
import base.PaparazziPreviewRule
import base.ScreenshotTest
import base.Shard4ComposablePreviewProvider
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
/**
* Test that takes a preview and runs a screenshot test on it.
* It uses a sharded preview provider so multiple 'shards' can run in parallel, optimizing CPU and time usage.
*/
@RunWith(TestParameterInjector::class)
class PreviewShard4Test(
@TestParameter(valuesProvider = Shard4ComposablePreviewProvider::class)
val preview: ComposablePreview<AndroidPreviewInfo>,
) {
@get:Rule
val paparazziRule = PaparazziPreviewRule.createFor(preview, locale = "en")
@Test
fun snapshot() {
ScreenshotTest.runTest(paparazzi = paparazziRule, preview = preview, localeStr = "en")
}
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0db3553ee5ed730fda10fa78bb19f3714c7ecdf2b2b82b0946335aaede2c3c61
size 13557
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:901b31047da757e8f0cd391dd7bbbf9d7c20e66bb4c21497acbe1616648926ba
size 7084
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d588b54e770dd21a63208bdd596f3e7f3c4074b8cbfa33affcc8750c4bf89c2d
size 16187
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:56c6325a42172a4e9b8675e9777292b329f2262435cc90cb2c918171656d6156
size 17021
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:398dd5c12a4561286d3d9471e7bfd4e2797d2832ae51dec830d6c97b76413fc2
size 16190
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:96a867cb12498cbdc97957bee07855dfaa13602baddaf933aff2b666ef4c7650
size 3642
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dfcbb11744ad6ab80a011067542140a926e86862380d3be25069649b665b5b3d
size 8279
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d42f53b0b77ce6f20c61c0ee491df157e878611a7eeeb44c9cb6411b348638da
size 37102
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:249cb85b4d269ca7829a00587f6840cbf1f10e51e28568186e419b38e1126610
size 24285
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5bb36ccd718f3fec5b04f1bc812dc7718b5ea7fa4619c8b031466297a8d016fd
size 3659
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:11fb4712defab1a03444cb18403d3555e6d6f6069915252a36bea0c2c80a2187
size 7024
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f0569db10eadf71f6443a0693c67f92189eb7ca52eb73c038a9c1733c856b9a7
size 35103
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:75bc869a9591043ab8bf5ab9944c2152b7f72dccac2ab8a541d65fc2c97199ae
size 22311
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e0df5eff771a20895cb1f79b00b1991a84ea505b0b60741db8d72bc46173ad6c
size 8775
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1a89875acd53deed14d47775c283323036960476d0bb52b016f5eaf5bd800a8a
size 7408
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:071914fc3e7bbc2fc6ef8a1b4544b9126c05dd08b2123666d320223582423226
size 5632
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5e9df6017bd0771e1337f82b75d13a0a8a572156e6900ae72f208e9bb2aaddb7
size 7717
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:811bd4534f4f16530cea1489b62d393e2fe7bf1b18b859a924333cd9d309f8dd
size 5566
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:030971f2c5f8c19f47fed2fa207c6d84d536c603fa7705ea6c288736684b7868
size 7553
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b33e598d33b6f514510adceb319573e0fded75719b2ab01265dce08ef180d9ec
size 25833
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:153ec618066e0dc9738a337bac5bbcae459e8143e5acac2846f144a4ad62d48e
size 27953
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9d27f8fbaed8cdbb6ad03414cf6f8c2d38b3269731ee72f5fe9eab1ad6afe9df
size 21819
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a82a01623f008b3a374cfb4c08b1a592bf7eedfca57b64fd2e819b53056be626
size 24309
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:97fc1dfcde1dcaf67c6cfacc0fb172b053668d418165cb1d8f67eb18a220a563
size 26313
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4227570b201034be916a714dcf27c9ab4d17d6cc3d47a8eab9ffae3b9b61bb4a
size 19967
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f78f491a8643f02587d8cd8845e82071483e76977b2e7735d2791869c6f5fe8e
size 22370
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0a7b8718daff4a22061e556001827e4cf58330e0de36cfa331874d9d2f6638c6
size 18493
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:46dc3f8fec381c5102af2a08ebaa6bb5d5f2a05ecd5254bb8cae14766bb74072
size 21167
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0aa4f30dac0e0eadadf40f2b699c446fe4d236dbc9b373aeb1d115d08ce76e8b
size 17440
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0297e771c4370ede91623c024d63cf750826578381d2f08885e8246fc4c8c82f
size 83236
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:407a886dee6739c1075f8865603250ab0a2a7c79d4b8cdf8ed2f7617c8cdd9aa
size 82078
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b5cfe3523c7a0fe50dbac6fe6ce842999c60b205d7347697c72b89074bf29c56
size 76369
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4bdb9e6d6d8423e9d7a847095b2a96fb47b2ed6fee977c6e163682b5f20e43db
size 74563
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:48f54197f74cf0675e04a83efbb278728568024bcec38a8553b623cdba384e50
size 60460
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b2e2356a3f8521649d6ad2c10f654142f87141e3f747db5a6f6ba25483c8171a
size 59516
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:56f3fe80ef0161c25a8bc52a1649dde2c113fd2e91f0e7462bf2329d45d83508
size 9451
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1284c9d7c90881d5affcabbc5a14dad86234ff9da2c32d2575f55876e89642e6
size 11705
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d864ba8c82ae89eca602a4e373b9d3b3d5fcea7c91cf14fb1c57b39d08038ba9
size 10869
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9a90be013d15c9f074543386a6640a933b3826f1341a1c90884ef8364dde5e92
size 16277
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:82b710142d98db7234535b7d076ed0204674e73b2ef78a91cd37fabc8a9214f3
size 9327
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f5cae3875c9629e1ffbf0b741b9322fa94f6d43cf8532e13998c3e9c5dc8dfec
size 10528
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bb794e6065420c231ad755054a4da6fd51d002a9d909166c53f57db2a606b2dc
size 9499
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ae1f12e570de4e758018b44638340dee26ac38fdd09ad8de4d0abb5bbf8e4f69
size 14602
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a17c98fc02077a91853cefa1ad7865ba8dd8fb399e58b9bea81617b797cf373f
size 66410
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:baf0dbd830742e896f33c47254d0cc48598916758f6ea332710dc0d761002f36
size 58503
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21b8921e692e1877c4cd82ee5f661c03f43853a53c410f8b30ea83a3389b2e55
size 24822
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7439757ca2ea3b85f102ce751d2b361313f0d67eb0fe7b3d6aa747258ce5f83e
size 23590
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c
size 10038
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:efe665c1419f9674e74b04dd066adf042cd421fd3e18a8cbc1f2ed80a0977e07
size 10340
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c
size 10038
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c
size 10038
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81
size 9639
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d8b6fae4f9fa5be0bbad9855ce80b53206748970d1ea1f9473eaa476afa39bcc
size 9936
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81
size 9639
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81
size 9639
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:61d96e2f91d217a1112421633426692fc5a2c35e9756d4980bd75fb3088a4b8f
size 29568
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4cf57997e6ca0c7244811154564f27c2af135f0a85dc4598e16df51251096b65
size 35844
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6f8f4593373a4229d852a8b4e2e3b937796e45135a032afbbd0563a4fa5e651c
size 56375
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5c80c8f9ee81b35b6054a10872e14d4fc4d8654b7747a620ea4b9a79d3595265
size 56756
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:27c31889281d6ba95448b033a07f1e41bc1c55bed26840cc796283a0f9368bf0
size 58454
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6f8f4593373a4229d852a8b4e2e3b937796e45135a032afbbd0563a4fa5e651c
size 56375
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f3e9fb42af90f7db14c02d572366ce59808ebd551cac7cc8552ee308d65f7c83
size 30607
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3b9bb30aec0b92dd5d352dd9dec4d26177ecb38a10c2984bab5c4bd4584b9b2d
size 36992
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0c7b44d045dbea3f47c774465be245046e972ade8ad6b9240df956c685dcbd59
size 58228
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3ee8385caada3a2739834bbabe1411d2f6da4d645d5b99cf07a6da96fe5eabb9
size 58584
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fb1bff539ab70b3d8bb8ae5f5490374e855c9b7807d1868b0aa1cffacc10e1f5
size 60382
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0c7b44d045dbea3f47c774465be245046e972ade8ad6b9240df956c685dcbd59
size 58228
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81
size 3657
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c145d9a6d7465d75344ad4a30bdab4ef9c88bddc515b8ee80ae8e254cfa60f92
size 6643
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81
size 3657
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9bd3fe043d7fffab7b19b5af9de7ef58ce8d2d97018a058b5b3c94cb55b277b9
size 11273
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81
size 3657
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9051fa04b8658bae6d2f2e7f6006a1cd205c7a6b07c92735720c8233ac015cd6
size 6497
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81
size 3657
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:97bc2d4c9621a21533da2d35abe90a5e1c1ef1bc356a6342736b61f7be8d8e3b
size 10357
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:17869867557671ffd51eb97d007e4ce5a8e4f748d36de9a6239dd8d98b42b8c8
size 68998
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:aa92893b8828f832cda6b5b06252630c79d401385bec853aaadd9e64d0ea3f2e
size 60072
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bd21306e6755dc6ef85503d6452bc0b00e4a171f9c4980ae78149eadc4804ec6
size 29584
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:956bba0f418cf63f820765aebd07c1ade321694ad0a94fdf80d49afe7fc203b6
size 24673
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:82e281fb8a4393950447717fe6ddfde12b484c27897cae9c9b0381072fb0e5e6
size 34386
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:223b1fbad4d64dbf60d875244a8e27d11aa0cded90b765bd4c894cd5c3aac541
size 29622
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cd6ddafdb4bf56b2d79958fbff2cc6afb384d612bc3850a0fd4c0f4e9368abea
size 23346
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4a6f8a6dd408633bc26c447b8c7c2ed8456091ba575c3622d2f5c4fc3c006ebf
size 28770
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1493a5469e99dfac63d6b550d53b7f63292d4812780f69a4593ba7da772493dd
size 24149
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d4e8418722ddef821df6b4413547c2bd833f9d3736b9b51f9113b464a8296935
size 33392
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4255ae26dae22d495b6a4e027bda4fefb1eeb6182d2f945eaebf8258982cb404
size 28853
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5cf3c48bc7e54774134d819053e2e63d7e0a0b053c2364d54a39452d3c77b794
size 22896
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b8a79530bbf328c00921ab51a5b8cdee70e2e40b55cdadf1a68a32265c2b5e0c
size 26052

Some files were not shown because too many files have changed in this diff Show More