Add lint rule for calling onBackPressed in BackHandler

You should not call onBackPressed on the Activity or
OnBackPressedDispatcher inside of the onBack lambda of a BackHandler or
PredictiveBackHandler. It is an anti-pattern and should be prevented.

This change adds a lint rule to ensure to call this case out at compile
time.

RelNote: "There is now a lint rule to detect calls to `onBackPressed()`
inside of `BackHandler` and `PredictiveBackHandler` callbacks."
Test: added tests
Bug: 287505200

Change-Id: I94d12850523b5b56aa34a5355fdb2228a8ee1236
diff --git a/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/BackHandlerOnBackPressedDetector.kt b/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/BackHandlerOnBackPressedDetector.kt
new file mode 100644
index 0000000..9822005
--- /dev/null
+++ b/activity/activity-compose-lint/src/main/java/androidx/activity/compose/lint/BackHandlerOnBackPressedDetector.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.activity.compose.lint
+
+import androidx.compose.lint.Name
+import androidx.compose.lint.Package
+import androidx.compose.lint.findUnreferencedParameters
+import androidx.compose.lint.isInPackageName
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.computeKotlinArgumentMapping
+import com.intellij.psi.PsiMethod
+import java.util.EnumSet
+import org.jetbrains.kotlin.psi.KtLambdaExpression
+import org.jetbrains.kotlin.psi.KtSimpleNameExpression
+import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.ULambdaExpression
+
+class BackHandlerOnBackPressedDetector : Detector(), Detector.UastScanner, SourceCodeScanner {
+    override fun getApplicableMethodNames(): List<String> = listOf(
+        PredictiveBackHandler.shortName,
+        BackHandler.shortName
+    )
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if (method.isInPackageName(ComposePackageName)) {
+            // Find the back lambda
+            val backLambda = computeKotlinArgumentMapping(node, method)
+                .orEmpty()
+                .filter { (_, parameter) ->
+                    parameter.name == OnBack
+                }
+                .keys
+                .filterIsInstance<ULambdaExpression>()
+                .firstOrNull() ?: return
+
+            // If the parameter is not referenced, immediately trigger the warning
+            val unreferencedParameter = backLambda.findUnreferencedParameters().firstOrNull()
+            if (unreferencedParameter == null) {
+                // If the parameter is referenced, we need to make sure it doesn't call
+                // onBackPressed
+                val lambdaExpression = backLambda.sourcePsi as? KtLambdaExpression
+                // Find all of the reference inside of the lambda
+                val references =
+                    lambdaExpression?.functionLiteral
+                        ?.collectDescendantsOfType<KtSimpleNameExpression>()
+                // Check for references to OnBackPressed
+                val matchingReferences = references?.filter {
+                    it.getReferencedName() == OnBackPressed.shortName
+                }.orEmpty()
+                // If references call onBackPressed(), trigger the warning
+                if (matchingReferences.isNotEmpty()) {
+                    matchingReferences.forEach { reference ->
+                        val location = reference.let { context.getLocation(it) }
+                        context.report(
+                            InvalidOnBackPressed,
+                            node,
+                            location,
+                            "Should not call onBackPressed inside of BackHandler"
+                        )
+                    }
+                }
+            }
+        }
+    }
+
+    companion object {
+        val InvalidOnBackPressed = Issue.create(
+            id = "OnBackPressedInsideOfBackHandler",
+            briefDescription = "Do not call onBackPressed() within" +
+                "BackHandler/PredictiveBackHandler",
+            explanation = """You should not used OnBackPressedCallback for non-UI cases. If you
+                |add a callback, you have to handle back completely in the callback.
+            """,
+            category = Category.CORRECTNESS,
+            severity = Severity.WARNING,
+            implementation = Implementation(
+                BackHandlerOnBackPressedDetector::class.java,
+                EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
+            )
+        ).addMoreInfo(
+            "https://developer.android.com/guide/navigation/custom-back/" +
+                "predictive-back-gesture#ui-logic"
+        )
+    }
+}
+
+private val ComposePackageName = Package("androidx.activity.compose")
+private val PredictiveBackHandler = Name(ComposePackageName, "PredictiveBackHandler")
+private val BackHandler = Name(ComposePackageName, "BackHandler")
+private val ActivityPackageName = Package("androidx.activity")
+private val OnBackPressed = Name(ActivityPackageName, "onBackPressed")
+private val OnBack = "onBack"
diff --git a/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/BackHandlerOnBackPressedDetectorTest.kt b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/BackHandlerOnBackPressedDetectorTest.kt
new file mode 100644
index 0000000..d27ab06
--- /dev/null
+++ b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/BackHandlerOnBackPressedDetectorTest.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.activity.compose.lint
+
+import androidx.compose.lint.test.Stubs
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class BackHandlerOnBackPressedDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = BackHandlerOnBackPressedDetector()
+
+    override fun getIssues(): MutableList<Issue> =
+        mutableListOf(BackHandlerOnBackPressedDetector.InvalidOnBackPressed)
+
+    @Test
+    fun expectPassOnBackPressed() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.compose.runtime.Composable
+                import androidx.activity.ComponentActivity
+                import androidx.activity.OnBackPressedDispatcher
+
+                @Composable
+                fun Test() {
+                    val activity = ComponentActivity()
+                    activity.onBackPressed()
+                    val dispatcher = OnBackPressedDispatcher()
+                    dispatcher.onBackPressed()
+                }
+            """
+            ),
+            Stubs.Composable,
+            COMPONENT_ACTIVITY,
+            ON_BACK_PRESSED_DISPATCHER,
+        )
+            .run().expectClean()
+    }
+    @Test
+    fun errors() {
+        lint().files(
+            kotlin(
+                """
+                package com.example
+
+                import androidx.compose.runtime.Composable
+                import androidx.activity.compose.BackHandler
+                import androidx.activity.compose.PredictiveBackHandler
+                import androidx.activity.ComponentActivity
+                import androidx.activity.OnBackPressedDispatcher
+
+                @Composable
+                fun Test() {
+                    PredictiveBackHandler { progress ->
+                        progress.collect()
+                        val activity = ComponentActivity()
+                        activity.onBackPressed()
+                        val dispatcher = OnBackPressedDispatcher()
+                        dispatcher.onBackPressed()
+                    }
+
+                    BackHandler {
+                        val activity = ComponentActivity()
+                        activity.onBackPressed()
+                        val dispatcher = OnBackPressedDispatcher()
+                        dispatcher.onBackPressed()
+                    }
+                }
+            """
+            ),
+            Stubs.Composable,
+            BACK_HANDLER,
+            COMPONENT_ACTIVITY,
+            ON_BACK_PRESSED_DISPATCHER,
+            PREDICTIVE_BACK_HANDLER
+        )
+            .run()
+            .expect(
+                """
+src/com/example/test.kt:15: Warning: Should not call onBackPressed inside of BackHandler [OnBackPressedInsideOfBackHandler]
+                        activity.onBackPressed()
+                                 ~~~~~~~~~~~~~
+src/com/example/test.kt:17: Warning: Should not call onBackPressed inside of BackHandler [OnBackPressedInsideOfBackHandler]
+                        dispatcher.onBackPressed()
+                                   ~~~~~~~~~~~~~
+src/com/example/test.kt:22: Warning: Should not call onBackPressed inside of BackHandler [OnBackPressedInsideOfBackHandler]
+                        activity.onBackPressed()
+                                 ~~~~~~~~~~~~~
+src/com/example/test.kt:24: Warning: Should not call onBackPressed inside of BackHandler [OnBackPressedInsideOfBackHandler]
+                        dispatcher.onBackPressed()
+                                   ~~~~~~~~~~~~~
+0 errors, 4 warnings
+            """
+            )
+    }
+}
diff --git a/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/CollectProgressDetectorTest.kt b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/CollectProgressDetectorTest.kt
index ce96fc6..e7e0f0f 100644
--- a/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/CollectProgressDetectorTest.kt
+++ b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/CollectProgressDetectorTest.kt
@@ -31,46 +31,6 @@
     override fun getIssues(): MutableList<Issue> =
         mutableListOf(CollectProgressDetector.NoCollectCallFound)
 
-    private val PREDICTIVE_BACK_HANDLER = bytecode(
-        "libs/predictivebackhandler.jar",
-        kotlin(
-            """
-    package androidx.activity.compose
-
-    public fun PredictiveBackHandler(
-        enabled: Boolean = true,
-        onBack: (progress: String) -> Unit) { }
-    
-    """
-    ).indented(),
-        0xd7427505,
-    """
-    META-INF/main.kotlin_module:
-    H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AZcIlmZiXUpSfmVKhl5hcklmWWVKp
-    l5yfW5BfnCokHlCUmpIJEk11SkzO9gCqzEkt8i7hEuXiBqrRS61IzC3ISRVi
-    C0ktLvEuUWLQYgAAnvRwIWUAAAA=
-    """,
-    """
-    androidx/activity/compose/PredictiveBackHandlerKt.class:
-    H4sIAAAAAAAA/4VSXU8TQRQ9s9222/JVFkGogCAoIMIWNOGhxkRNiI2lElEe
-    4GnYDnXodpbsTht8MfwNX/0HvhEfDPHRH2W8sy0fURLa5N479557zt078/vP
-    j58AnmGNYY2rehTK+onHfS07Un/2/LB1HMbC245EXZqkeMX95hsCBiJ6q7Ng
-    DIUj3uFewFXDe3dwJHzKphhGb2xhmF/cqzZDHUjlHXVa3mFbESZUsbfZi9bK
-    S7sMm7fCnq9Ur4R3dCRVo3zR8lFJXX6REM1Vw6jhHQl9EHFJ/VypUPMuVy3U
-    tXYQlBkyoTJTOsgxTF/TlUqLSPHAqyijEEs/zqKPvs7/JPxmr3+bR7wltPm6
-    hcXqv9so/z/m0m4/BjCYRz+GGLJC8YNA1BnYHsPMbdthmLpxtfN1ccjbgWbY
-    uH3Flf/HNEOlkcnDwhjD8AXDltC8zjUnXavVSdFbYcakadqmCSzKn0gTlSiq
-    0zPaPz+dzp+f5q2C1XV9iRu3KBzsescqPi2cnxatElt3HAJSlFqfLdjFKXfE
-    HS5lfn3L9DtZ13Ec13acxZxru4QtpY3EOqMZ4F4MeH0zYxfJyyupkaOCrcgz
-    OMdR2IhEHDOM37jE1Sbtz34d1gk8VJVK1NqtAxF9MBdkNEOfB7s8kubcS+Z2
-    ZENx3Y4onn/fVlq2REV1ZCypfDnHy6tnxzCwo0lyix/3KPI7YTvyxaY0h4ke
-    x26X4Voj1uhubJifhQlzWUhhiU5lOlvks8tu/gyF7wngMdkMLSpD/2WKx7oQ
-    DMNNKLLIYYTqTxJ0FivkcwZCawIKOdzBKMWGf6OnOzhpf/mKtF0uLp/hbldm
-    lWwKzEn0BmEegk2KaSKxqewloEWUyFeIbpwqE/tIVVCs4B5ZTFYwhekK7mNm
-    HyzGLB7sIx8jHWMuxnBiczHmk+BhjEcxFv4C1+LeOLYEAAA=
-    """
-    )
-
     @Test
     fun errors() {
         lint().files(
diff --git a/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/Stubs.kt b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/Stubs.kt
new file mode 100644
index 0000000..b4a9de0
--- /dev/null
+++ b/activity/activity-compose-lint/src/test/java/androidx/activity/compose/lint/Stubs.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.activity.compose.lint
+
+import androidx.compose.lint.test.bytecodeStub
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+
+val BACK_HANDLER = bytecodeStub(
+    filename = "BackHandler.kt",
+    filepath = "androidx/activity/compose",
+    checksum = 0x40a94587,
+        """
+    package androidx.activity.compose
+
+    import androidx.compose.runtime.Composable
+
+    @Composable
+    fun BackHandler(
+        enabled: Boolean = true,
+        onBack: () -> Unit) { } 
+    """,
+    """
+    META-INF/main.kotlin_module:
+    H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AZcQlmZiXUpSfmVKhl5hcklmWWVKp
+    l5yfW5BfnCrE65SYnO0BlM9JLfIuEWILSS0u8S7hEuXiBqrQS61IzC3ISYUJ
+    KzFoMQAA3mTzZGMAAAA=
+    """,
+    """
+    androidx/activity/compose/BackHandlerKt.class:
+    H4sIAAAAAAAA/4VSXU8TQRQ9s/1eoJQiCgURBQRE2YImPFRNlITQWNBY5QGe
+    ptuhTrudJbvTBl8Mf8Of4RvxwfDsjzLe2bZY4YEmnft17r3n3r2///z8BeAF
+    igwrXNUDX9bPHO5q2ZX6q+P67VM/FM5b7rb2KOyJ4J1OgTHkmrzLHY+rhvO+
+    1hQueWMMI0NAhqXVo0rL155UTrPbdk46iur6KnR2+1qxtHbI8PxW2MtB/LOS
+    uvQ6ylquXNEdsAw6Ssu2cHYim9c8UWJYrPhBw2kKXQu4pKJcKV/zXoMDXx90
+    PI9QSV8Z6mnYDPNDZKTSIlDcc8pKB5Qu3TCFUYYp94twW/38DzzgbaHNyCur
+    leuLKQ15qqZIg/iPIotxG2PIMaSEMlzrDOyIYeG2lTFMDm15qS5OeMfTDNu3
+    b7t8k5yhkkDShoV7DBODCvtC8zrXnLpZ7W6MToSZJ0EcW0axyH8mjUaHY9U3
+    GUqX53n78ty2clZPjERi2ios5C7PC1aRbaXTFCQttjWaixfS+XievMXEXsqU
+    2GLUA/kBgeF5s0PzbrRo1PiOXxcM4xWpxEGnXRPBJ7NBk+673DvkgTR235mp
+    yobiuhOQPvuxdyNl1ZWhpPCbf+dAB3s9evVl/4ONVTUR2uen/QZ21e8ErtiV
+    xpjp1zi8UR+btOQ4zM/CjNk6WStklci2SKbW8yMXmPgRAVbpTdJGkshgjfS7
+    PQjymIxKpGDjDsWfROgU1vv4NMmn9M8YOA0P5DKYonQW9druc8jOxb99RyJe
+    KqxfYLrX8hm9MbB01DuLWNQlSRXTJC1sRKDHcEi+onJmhMIxYmXMljFHL+6X
+    MY8HZSzg4TFYiEdYPEYyRCLEUoh89Nohlv8C003RZnYEAAA=
+    """
+)
+
+val COMPONENT_ACTIVITY = bytecodeStub(
+    "ComponentActivity.kt",
+    "androidx/activity",
+    0xd291c9ac,
+    """
+    package androidx.activity
+
+    class ComponentActivity {
+        fun onBackPressed() { }
+    }
+    """,
+    """
+    META-INF/main.kotlin_module:
+    H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AZcQlmZiXUpSfmVKhl5hcklmWWVKp
+    l5yfW5BfnCrE65SYnO0BlM9JLfIuEWILSS0u8S7hEuXiBqrQS61IzC3ISYUJ
+    KzFoMQAA3mTzZGMAAAA=
+    """,
+    """
+    androidx/activity/ComponentActivity.class:
+    H4sIAAAAAAAA/41RTW8TMRB9481uyralm7ZAWuCEkGgrsWnFCVClthJSqrQg
+    QLnk5Oxa4Cax0dqJ2lt+C/+AExIHFHHsj0KMQ4QQXGrJb+a98fPH+Prnt+8A
+    nuEh4ZE0ZWV1eZnLwuuJ9lf5iR19skYZf7RQ6iBCdiEnMh9K8yF/3b9Qha8j
+    IiQvtdH+kBA92emuIEaSooY6oeY/akd43LnB/i8Iq9Ycy2LwplLOqZLQ6Ays
+    H2qTnykvS+klrxGjScTXpgAxgQYsXerAWpyV+4S92TRLRVOkIptNU7EUEtGc
+    TQ9Ei47jH58TpqdJFm2LVi1YDoi3w+Z/F3o68PyCE1sqwlpHG3U+HvVV9V72
+    h6ysd2whh11Z6cAXYvrOjqtCvdKBbL0dG69Hqqud5uqRMdZLr61x2IfgBoUh
+    +GjuF2OTWc6RwsN2v2Lpy7y8xZjMxRq2GVd+L8AtpBwbWP5j3gttCfNfY/yX
+    kRZGgftzvIcHHJ+zHv5ttYeojdttrDEiC9BoYx0bPZDDJu70EDukDncdEodl
+    Tn4B9lImlUcCAAA=
+    """
+)
+
+val ON_BACK_PRESSED_DISPATCHER = bytecodeStub(
+    "OnBackPressedDispatcher.kt",
+    "androidx/activity",
+    0x38be529,
+    """
+    package androidx.activity
+
+    class OnBackPressedDispatcher {
+        fun onBackPressed() { }
+    }
+    """,
+    """
+    META-INF/main.kotlin_module:
+    H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AZcQlmZiXUpSfmVKhl5hcklmWWVKp
+    l5yfW5BfnCrE65SYnO0BlM9JLfIuEWILSS0u8S7hEuXiBqrQS61IzC3ISYUJ
+    KzFoMQAA3mTzZGMAAAA=
+    """,
+    """
+    androidx/activity/OnBackPressedDispatcher.class:
+    H4sIAAAAAAAA/41R0UobQRQ9dza7savWjbY1xva9VnCj+GSLoC2FSFqLLXnJ
+    02R3qGOSWdmZBH3Lt/QP+lTogwQf+1Gld6KICEIH5tx7zp2zM/fun7+/rwDs
+    4hVhQ5q8LHR+kcrM6bF2l+mxOZRZ/0uprFX5B23PpctOVVkFEZIzOZbpQJrv
+    6XHvTGWuioAQvdNGu31C8Hqjs4AQUYwKqoSKO9WWsNn+71veEhaL+yVCrd0v
+    3ECb9JNyMpdO8hkxHAfcAnkICdRn6UJ71uQs3+Y7p5MkFnURi2Q6icWcT0R9
+    OtkRTToMr39ETI+iJGiIZsVbdog/h8Yjz9rqO+7mfZErwlJbG/V5NOyp8pvs
+    DVhZbheZHHRkqT2/FeOvxajM1EftydrJyDg9VB1tNVcPjCmcdLowFtsQPCy/
+    BD+AZ8dYZ5ZyJN/em1+Y+zkrrzFGM7GCBuPCzQE8Qcyxhvk786Yfjt8PjeE9
+    I90aBdZnuIqXHPdY9/9wsYughactLDEi8VBrYRkrXZDFMzzvIrSILV5YRBbz
+    nPwDYUKQQFkCAAA=
+    """
+)
+
+val PREDICTIVE_BACK_HANDLER = LintDetectorTest.bytecode(
+    "libs/predictivebackhandler.jar",
+    LintDetectorTest.kotlin(
+        """
+    package androidx.activity.compose
+
+    import androidx.compose.runtime.Composable
+
+    @Composable
+    fun PredictiveBackHandler(
+        enabled: Boolean = true,
+        onBack: (progress: String) -> Unit) { }
+    """
+    ).indented(),
+    0x7806fd68,
+    """
+    META-INF/main.kotlin_module:
+    H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3ApcwlmZiXUpSfmVKhl5hcklmWWVKp
+    l5yfW5BfnCrEFpJaXOJdwiXKxQ0U0kutSMwtyIELKzFoMQAAfOuo51QAAAA=
+    """,
+    """
+    androidx/activity/compose/TestKt.class:
+    H4sIAAAAAAAA/4VTW08TQRT+ZnvblltZRaFcFEEtImxBDQ81JkpCbKyVCPIg
+    8WHYDnXodpbsTht9MfwNX/0HvhEfDPHRH2U8s20BwYQmPZc535zznXNmf//5
+    8RPAYzxiuM1VPQxk/ZPLPS07Un92vaB1GETC3RaRfqUzYAz5A97hrs9Vw32z
+    dyA8Ok0wjG2Goi7NNfGCe82XlMoXIcN88X21GWhfKveg03L324owgYrcjZ61
+    Ul7YYdi4EvZ0qXpWeEuHUjXK/SvvlNTlZ3Giu9XTJvrcw7bSsiXc9djne74o
+    M8xVg7DhHgi9F3JJdbhSgebdmrVA19q+T6h0oEw3NnIMM+f4SaVFqLjvVpRh
+    EkkvymCQpuB9FF6zd3+Th7wltJnC/WL14tTKl9tZ2BnEMEZyGEKeISOU4Vpn
+    YO9pN1dNkWH6vyuYr4t93vY1w9rVq6hcpmlIpZDOwcJNhtF+htdC8zrXnOpa
+    rU6CnhAzIkVsm8aw6PyTNFaJrPoKw4eTo5ncyVHOyltdNRCrcYvM4a62rcKT
+    /MlRwSqxVdsmIFmJ1dl8sjDtXHNGS+lf39KDdsaxbdtJ2nYx6yQdwpZSLzOm
+    yCojFnD6FM/P5kb/8HQpNVIUSCrSDPZhGDRCEUU0d01vfblJA0uuB3WKjVSl
+    ErV2a0+E22YjpkTgcX+Hh9L4vcPslmwortsh2ZNvu2+uojoykhR+fva86Ju4
+    GD0l9Q9saEvTGl/zw16B3FbQDj2xIY0z0cuxcyk/VmhVSZifhQmzO/IekFcm
+    3yKdWXQGjjH6PQYskkzT1NKw8ZDsG10IHFyLU2SQw3WKL8XoDJZ7eJu0S/+s
+    gVPzQD6LMbrO4lprPQ7DU8kvX5FKlguLxxjvliyRTIDZce1hJOKMacptk7SI
+    vgEtYJV0hdKZFgq7SFQwWcEUSUxXMINbFdzG7C5YhDuY20UuQirCfAQnluTe
+    jY17Ee5HKP4FMROs2egEAAA=
+    """
+)