From 74e6560c85e0711294782529748048f263cb21c5 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 19:03:43 +0900 Subject: [PATCH 01/12] feat(compose): add HapticCapabilities read API for device capability badges --- jindong-compose/api/jindong-compose.api | 28 +++++++ jindong-compose/api/jindong-compose.klib.api | 34 +++++++++ .../jindong/HapticCapabilities.android.kt | 18 +++++ .../compose/jindong/HapticCapabilities.kt | 75 +++++++++++++++++++ .../compose/jindong/HapticCapabilitiesTest.kt | 37 +++++++++ .../compose/jindong/HapticCapabilities.ios.kt | 18 +++++ jindong-core/api/jindong-core.api | 1 + jindong-core/api/jindong-core.klib.api | 2 + .../core/executor/HapticExecutor.android.kt | 6 ++ .../jindong/core/executor/HapticExecutor.kt | 12 +++ .../executor/HapticExecutorCapabilityTest.kt | 31 ++++++++ .../jindong/core/fake/FakeHapticExecutor.kt | 1 + .../core/executor/HapticExecutor.ios.kt | 4 + 13 files changed, 267 insertions(+) create mode 100644 jindong-compose/src/androidMain/kotlin/io/github/compose/jindong/HapticCapabilities.android.kt create mode 100644 jindong-compose/src/commonMain/kotlin/io/github/compose/jindong/HapticCapabilities.kt create mode 100644 jindong-compose/src/commonTest/kotlin/io/github/compose/jindong/HapticCapabilitiesTest.kt create mode 100644 jindong-compose/src/iosMain/kotlin/io/github/compose/jindong/HapticCapabilities.ios.kt create mode 100644 jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/executor/HapticExecutorCapabilityTest.kt diff --git a/jindong-compose/api/jindong-compose.api b/jindong-compose/api/jindong-compose.api index 59eba6c..3df79c9 100644 --- a/jindong-compose/api/jindong-compose.api +++ b/jindong-compose/api/jindong-compose.api @@ -1,3 +1,31 @@ +public final class io/github/compose/jindong/HapticCapabilities { + public static final field $stable I + public fun (ZZLio/github/compose/jindong/HapticPlatform;)V + public final fun component1 ()Z + public final fun component2 ()Z + public final fun component3 ()Lio/github/compose/jindong/HapticPlatform; + public final fun copy (ZZLio/github/compose/jindong/HapticPlatform;)Lio/github/compose/jindong/HapticCapabilities; + public static synthetic fun copy$default (Lio/github/compose/jindong/HapticCapabilities;ZZLio/github/compose/jindong/HapticPlatform;ILjava/lang/Object;)Lio/github/compose/jindong/HapticCapabilities; + public fun equals (Ljava/lang/Object;)Z + public final fun getHasAmplitudeControl ()Z + public final fun getPlatform ()Lio/github/compose/jindong/HapticPlatform; + public fun hashCode ()I + public final fun isSupported ()Z + public fun toString ()Ljava/lang/String; +} + +public final class io/github/compose/jindong/HapticCapabilitiesKt { + public static final fun rememberHapticCapabilities (Landroidx/compose/runtime/Composer;I)Lio/github/compose/jindong/HapticCapabilities; +} + +public final class io/github/compose/jindong/HapticPlatform : java/lang/Enum { + public static final field Android Lio/github/compose/jindong/HapticPlatform; + public static final field Ios Lio/github/compose/jindong/HapticPlatform; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Lio/github/compose/jindong/HapticPlatform; + public static fun values ()[Lio/github/compose/jindong/HapticPlatform; +} + public final class io/github/compose/jindong/JindongKt { public static final fun Jindong ([Ljava/lang/Object;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V } diff --git a/jindong-compose/api/jindong-compose.klib.api b/jindong-compose/api/jindong-compose.klib.api index a4ea0a2..4acb1cf 100644 --- a/jindong-compose/api/jindong-compose.klib.api +++ b/jindong-compose/api/jindong-compose.klib.api @@ -10,8 +10,40 @@ open annotation class io.github.compose.jindong/JindongScopeMarker : kotlin/Anno constructor () // io.github.compose.jindong/JindongScopeMarker.|(){}[0] } +final enum class io.github.compose.jindong/HapticPlatform : kotlin/Enum { // io.github.compose.jindong/HapticPlatform|null[0] + enum entry Android // io.github.compose.jindong/HapticPlatform.Android|null[0] + enum entry Ios // io.github.compose.jindong/HapticPlatform.Ios|null[0] + + final val entries // io.github.compose.jindong/HapticPlatform.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // io.github.compose.jindong/HapticPlatform.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): io.github.compose.jindong/HapticPlatform // io.github.compose.jindong/HapticPlatform.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // io.github.compose.jindong/HapticPlatform.values|values#static(){}[0] +} + abstract interface io.github.compose.jindong/JindongScope // io.github.compose.jindong/JindongScope|null[0] +final class io.github.compose.jindong/HapticCapabilities { // io.github.compose.jindong/HapticCapabilities|null[0] + constructor (kotlin/Boolean, kotlin/Boolean, io.github.compose.jindong/HapticPlatform) // io.github.compose.jindong/HapticCapabilities.|(kotlin.Boolean;kotlin.Boolean;io.github.compose.jindong.HapticPlatform){}[0] + + final val hasAmplitudeControl // io.github.compose.jindong/HapticCapabilities.hasAmplitudeControl|{}hasAmplitudeControl[0] + final fun (): kotlin/Boolean // io.github.compose.jindong/HapticCapabilities.hasAmplitudeControl.|(){}[0] + final val isSupported // io.github.compose.jindong/HapticCapabilities.isSupported|{}isSupported[0] + final fun (): kotlin/Boolean // io.github.compose.jindong/HapticCapabilities.isSupported.|(){}[0] + final val platform // io.github.compose.jindong/HapticCapabilities.platform|{}platform[0] + final fun (): io.github.compose.jindong/HapticPlatform // io.github.compose.jindong/HapticCapabilities.platform.|(){}[0] + + final fun component1(): kotlin/Boolean // io.github.compose.jindong/HapticCapabilities.component1|component1(){}[0] + final fun component2(): kotlin/Boolean // io.github.compose.jindong/HapticCapabilities.component2|component2(){}[0] + final fun component3(): io.github.compose.jindong/HapticPlatform // io.github.compose.jindong/HapticCapabilities.component3|component3(){}[0] + final fun copy(kotlin/Boolean = ..., kotlin/Boolean = ..., io.github.compose.jindong/HapticPlatform = ...): io.github.compose.jindong/HapticCapabilities // io.github.compose.jindong/HapticCapabilities.copy|copy(kotlin.Boolean;kotlin.Boolean;io.github.compose.jindong.HapticPlatform){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // io.github.compose.jindong/HapticCapabilities.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // io.github.compose.jindong/HapticCapabilities.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // io.github.compose.jindong/HapticCapabilities.toString|toString(){}[0] +} + +final val io.github.compose.jindong/io_github_compose_jindong_HapticCapabilities$stableprop // io.github.compose.jindong/io_github_compose_jindong_HapticCapabilities$stableprop|#static{}io_github_compose_jindong_HapticCapabilities$stableprop[0] + final fun (io.github.compose.jindong/JindongScope).io.github.compose.jindong.dsl/Delay(kotlin.time/Duration, androidx.compose.runtime/Composer?, kotlin/Int) // io.github.compose.jindong.dsl/Delay|Delay@io.github.compose.jindong.JindongScope(kotlin.time.Duration;androidx.compose.runtime.Composer?;kotlin.Int){}[0] final fun (io.github.compose.jindong/JindongScope).io.github.compose.jindong.dsl/Haptic(kotlin.time/Duration, io.github.compose.jindong.core.model/HapticIntensity?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // io.github.compose.jindong.dsl/Haptic|Haptic@io.github.compose.jindong.JindongScope(kotlin.time.Duration;io.github.compose.jindong.core.model.HapticIntensity?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0] final fun (io.github.compose.jindong/JindongScope).io.github.compose.jindong.dsl/Repeat(kotlin/Int, kotlin/Function3, androidx.compose.runtime/Composer?, kotlin/Int) // io.github.compose.jindong.dsl/Repeat|Repeat@io.github.compose.jindong.JindongScope(kotlin.Int;kotlin.Function3;androidx.compose.runtime.Composer?;kotlin.Int){}[0] @@ -19,3 +51,5 @@ final fun (io.github.compose.jindong/JindongScope).io.github.compose.jindong.dsl final fun (io.github.compose.jindong/JindongScope).io.github.compose.jindong.dsl/Sequence(kotlin/Function3, androidx.compose.runtime/Composer?, kotlin/Int) // io.github.compose.jindong.dsl/Sequence|Sequence@io.github.compose.jindong.JindongScope(kotlin.Function3;androidx.compose.runtime.Composer?;kotlin.Int){}[0] final fun io.github.compose.jindong/Jindong(kotlin/Array..., kotlin/Function3, androidx.compose.runtime/Composer?, kotlin/Int) // io.github.compose.jindong/Jindong|Jindong(kotlin.Array...;kotlin.Function3;androidx.compose.runtime.Composer?;kotlin.Int){}[0] final fun io.github.compose.jindong/JindongProvider(kotlin/Function2, androidx.compose.runtime/Composer?, kotlin/Int) // io.github.compose.jindong/JindongProvider|JindongProvider(kotlin.Function2;androidx.compose.runtime.Composer?;kotlin.Int){}[0] +final fun io.github.compose.jindong/io_github_compose_jindong_HapticCapabilities$stableprop_getter(): kotlin/Int // io.github.compose.jindong/io_github_compose_jindong_HapticCapabilities$stableprop_getter|io_github_compose_jindong_HapticCapabilities$stableprop_getter(){}[0] +final fun io.github.compose.jindong/rememberHapticCapabilities(androidx.compose.runtime/Composer?, kotlin/Int): io.github.compose.jindong/HapticCapabilities // io.github.compose.jindong/rememberHapticCapabilities|rememberHapticCapabilities(androidx.compose.runtime.Composer?;kotlin.Int){}[0] diff --git a/jindong-compose/src/androidMain/kotlin/io/github/compose/jindong/HapticCapabilities.android.kt b/jindong-compose/src/androidMain/kotlin/io/github/compose/jindong/HapticCapabilities.android.kt new file mode 100644 index 0000000..3ed9cd0 --- /dev/null +++ b/jindong-compose/src/androidMain/kotlin/io/github/compose/jindong/HapticCapabilities.android.kt @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong + +internal actual fun hapticPlatform(): HapticPlatform = HapticPlatform.Android diff --git a/jindong-compose/src/commonMain/kotlin/io/github/compose/jindong/HapticCapabilities.kt b/jindong-compose/src/commonMain/kotlin/io/github/compose/jindong/HapticCapabilities.kt new file mode 100644 index 0000000..e41eb44 --- /dev/null +++ b/jindong-compose/src/commonMain/kotlin/io/github/compose/jindong/HapticCapabilities.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import io.github.compose.jindong.executor.LocalHapticExecutor + +/** + * Platform a haptic capability reading was taken on. + */ +enum class HapticPlatform { + Android, + Ios, +} + +/** + * Snapshot of the current device's haptic capabilities, read from the active [HapticExecutor]. + * + * @property isSupported whether haptic feedback is available at all on this device. + * @property hasAmplitudeControl whether the actuator renders intermediate amplitudes. On Android + * this is `false` for ERM motors (every non-zero amplitude rounds up to 100%) and `true` for LRA + * motors. On iOS Core Haptics is always continuous, so this is always `true`; pair it with + * [platform] when the displayed label needs to distinguish "Yes/No" (Android) from + * "Continuous" (iOS). + * @property platform the platform this reading came from. + */ +data class HapticCapabilities( + val isSupported: Boolean, + val hasAmplitudeControl: Boolean, + val platform: HapticPlatform, +) + +/** + * Reads the current device's [HapticCapabilities] from the haptic executor provided by + * [JindongProvider]. Must be called inside a `JindongProvider { }` scope. + * + * Example: + * ``` + * JindongProvider { + * val capabilities = rememberHapticCapabilities() + * // capabilities.isSupported, capabilities.hasAmplitudeControl, capabilities.platform + * } + * ``` + */ +@Composable +fun rememberHapticCapabilities(): HapticCapabilities { + val executor = LocalHapticExecutor.current + val platform = hapticPlatform() + return remember(executor, platform) { + HapticCapabilities( + isSupported = executor.isSupported, + hasAmplitudeControl = executor.hasAmplitudeControl, + platform = platform, + ) + } +} + +/** + * Returns the [HapticPlatform] the app is currently running on. + */ +internal expect fun hapticPlatform(): HapticPlatform diff --git a/jindong-compose/src/commonTest/kotlin/io/github/compose/jindong/HapticCapabilitiesTest.kt b/jindong-compose/src/commonTest/kotlin/io/github/compose/jindong/HapticCapabilitiesTest.kt new file mode 100644 index 0000000..0ede6c8 --- /dev/null +++ b/jindong-compose/src/commonTest/kotlin/io/github/compose/jindong/HapticCapabilitiesTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong + +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe + +class HapticCapabilitiesTest : + FunSpec({ + test("HapticCapabilities holds the supplied values") { + val capabilities = HapticCapabilities( + isSupported = true, + hasAmplitudeControl = false, + platform = HapticPlatform.Android, + ) + + assertSoftly(capabilities) { + isSupported shouldBe true + hasAmplitudeControl shouldBe false + platform shouldBe HapticPlatform.Android + } + } + }) diff --git a/jindong-compose/src/iosMain/kotlin/io/github/compose/jindong/HapticCapabilities.ios.kt b/jindong-compose/src/iosMain/kotlin/io/github/compose/jindong/HapticCapabilities.ios.kt new file mode 100644 index 0000000..7a72088 --- /dev/null +++ b/jindong-compose/src/iosMain/kotlin/io/github/compose/jindong/HapticCapabilities.ios.kt @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong + +internal actual fun hapticPlatform(): HapticPlatform = HapticPlatform.Ios diff --git a/jindong-core/api/jindong-core.api b/jindong-core/api/jindong-core.api index 34c51bc..d8aeedc 100644 --- a/jindong-core/api/jindong-core.api +++ b/jindong-core/api/jindong-core.api @@ -88,6 +88,7 @@ public final class io/github/compose/jindong/core/element/VibrationElement : io/ public abstract interface class io/github/compose/jindong/core/executor/HapticExecutor { public abstract fun execute (Lio/github/compose/jindong/core/model/HapticPattern;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun executeAsync (Lio/github/compose/jindong/core/model/HapticPattern;)Lio/github/compose/jindong/core/executor/HapticHandle; + public abstract fun getHasAmplitudeControl ()Z public abstract fun isSupported ()Z public abstract fun release ()V } diff --git a/jindong-core/api/jindong-core.klib.api b/jindong-core/api/jindong-core.klib.api index 025c345..3fa1d4c 100644 --- a/jindong-core/api/jindong-core.klib.api +++ b/jindong-core/api/jindong-core.klib.api @@ -19,6 +19,8 @@ abstract interface io.github.compose.jindong.core.element/HapticElement { // io. } abstract interface io.github.compose.jindong.core.executor/HapticExecutor { // io.github.compose.jindong.core.executor/HapticExecutor|null[0] + abstract val hasAmplitudeControl // io.github.compose.jindong.core.executor/HapticExecutor.hasAmplitudeControl|{}hasAmplitudeControl[0] + abstract fun (): kotlin/Boolean // io.github.compose.jindong.core.executor/HapticExecutor.hasAmplitudeControl.|(){}[0] abstract val isSupported // io.github.compose.jindong.core.executor/HapticExecutor.isSupported|{}isSupported[0] abstract fun (): kotlin/Boolean // io.github.compose.jindong.core.executor/HapticExecutor.isSupported.|(){}[0] diff --git a/jindong-core/src/androidMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.android.kt b/jindong-core/src/androidMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.android.kt index 940ab7e..61c3124 100644 --- a/jindong-core/src/androidMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.android.kt +++ b/jindong-core/src/androidMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.android.kt @@ -55,6 +55,12 @@ internal class DefaultAndroidHapticExecutor(context: Context) : HapticExecutor { vibrator.hasVibrator() } + // ERM actuators round any non-zero amplitude up to 100%, so per-level intensity is indistinguishable; + // callers read this to warn that LIGHT/MEDIUM/STRONG/HIGH feel identical on such devices. + override val hasAmplitudeControl: Boolean by lazy { + vibrator.hasAmplitudeControl() + } + @RequiresPermission(Manifest.permission.VIBRATE) override suspend fun execute(pattern: HapticPattern) { if (!isSupported || pattern.events.isEmpty()) return diff --git a/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt b/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt index fc739ad..7675043 100644 --- a/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt +++ b/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt @@ -34,6 +34,18 @@ interface HapticExecutor { */ val isSupported: Boolean + /** + * Whether the actuator can render intermediate (non-binary) amplitudes. + * + * - **Android**: reflects `Vibrator.hasAmplitudeControl()`. ERM motors round every non-zero + * amplitude up to 100%, so they report `false` and effects like fall ramps are lost; LRA + * motors report `true`. + * - **iOS**: Core Haptics always renders continuous intensity, so this is always `true`. + * The "discrete vs. continuous" distinction is platform-specific; read the platform + * alongside this flag if the label matters (see the Compose `HapticCapabilities`). + */ + val hasAmplitudeControl: Boolean + /** * Executes haptic pattern. Cancellable via coroutine cancellation. * When cancelled, the ongoing vibration is stopped immediately. diff --git a/jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/executor/HapticExecutorCapabilityTest.kt b/jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/executor/HapticExecutorCapabilityTest.kt new file mode 100644 index 0000000..180f603 --- /dev/null +++ b/jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/executor/HapticExecutorCapabilityTest.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.core.executor + +import io.github.compose.jindong.core.fake.FakeHapticExecutor +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe + +class HapticExecutorCapabilityTest : + FunSpec({ + test("hasAmplitudeControl defaults to true") { + FakeHapticExecutor().hasAmplitudeControl shouldBe true + } + + test("hasAmplitudeControl can be overridden via constructor") { + FakeHapticExecutor(hasAmplitudeControl = false).hasAmplitudeControl shouldBe false + } + }) diff --git a/jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/fake/FakeHapticExecutor.kt b/jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/fake/FakeHapticExecutor.kt index 2e99b90..957f3b3 100644 --- a/jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/fake/FakeHapticExecutor.kt +++ b/jindong-core/src/commonTest/kotlin/io/github/compose/jindong/core/fake/FakeHapticExecutor.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.delay */ class FakeHapticExecutor( override val isSupported: Boolean = true, + override val hasAmplitudeControl: Boolean = true, ) : HapticExecutor { private val _executedPatterns = mutableListOf() diff --git a/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt b/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt index 6a4ea01..29a23c5 100644 --- a/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt +++ b/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt @@ -55,6 +55,10 @@ internal class DefaultIosHapticExecutor : HapticExecutor { CHHapticEngine.capabilitiesForHardware().supportsHaptics() } + // Core Haptics applies intensity as a continuous float on every event, so amplitude is + // always full-fidelity; there is no discrete/ERM-style gating on iOS. + override val hasAmplitudeControl: Boolean = true + override suspend fun execute(pattern: HapticPattern) { if (!isSupported || pattern.events.isEmpty()) return From b94cc2f22bfcc437d0a96027a3bfd607a116a285 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 19:03:52 +0900 Subject: [PATCH 02/12] chore(sample): bundle Instrument Sans and IBM Plex Mono fonts (OFL) --- .../files/IBMPlexMono-OFL.txt | 93 ++++++++++++++++++ .../files/InstrumentSans-OFL.txt | 93 ++++++++++++++++++ .../font/ibm_plex_mono_medium.ttf | Bin 0 -> 134880 bytes .../font/ibm_plex_mono_regular.ttf | Bin 0 -> 133720 bytes .../font/ibm_plex_mono_semibold.ttf | Bin 0 -> 138372 bytes .../font/instrument_sans_variable.ttf | Bin 0 -> 194336 bytes 6 files changed, 186 insertions(+) create mode 100644 sample/shared/src/commonMain/composeResources/files/IBMPlexMono-OFL.txt create mode 100644 sample/shared/src/commonMain/composeResources/files/InstrumentSans-OFL.txt create mode 100644 sample/shared/src/commonMain/composeResources/font/ibm_plex_mono_medium.ttf create mode 100644 sample/shared/src/commonMain/composeResources/font/ibm_plex_mono_regular.ttf create mode 100644 sample/shared/src/commonMain/composeResources/font/ibm_plex_mono_semibold.ttf create mode 100644 sample/shared/src/commonMain/composeResources/font/instrument_sans_variable.ttf diff --git a/sample/shared/src/commonMain/composeResources/files/IBMPlexMono-OFL.txt b/sample/shared/src/commonMain/composeResources/files/IBMPlexMono-OFL.txt new file mode 100644 index 0000000..01497cc --- /dev/null +++ b/sample/shared/src/commonMain/composeResources/files/IBMPlexMono-OFL.txt @@ -0,0 +1,93 @@ +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/sample/shared/src/commonMain/composeResources/files/InstrumentSans-OFL.txt b/sample/shared/src/commonMain/composeResources/files/InstrumentSans-OFL.txt new file mode 100644 index 0000000..26bd2f9 --- /dev/null +++ b/sample/shared/src/commonMain/composeResources/files/InstrumentSans-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2022 The Instrument Sans Project Authors (https://github.com/Instrument/instrument-sans) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/sample/shared/src/commonMain/composeResources/font/ibm_plex_mono_medium.ttf b/sample/shared/src/commonMain/composeResources/font/ibm_plex_mono_medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..39f178db700c34e524d0b9dc52bd020b44d70d01 GIT binary patch literal 134880 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%0DXk@Y++ZC(#=pPW-Uv!|o5~ewg=R?1wQQ z4tej{_dj`mH$CCI@}h~Fqh|HN66K|Kz!#wJ>$ zZ9M*IiP~swj5b$Wq;+Ylv`e+iwVSm&w7uGsxJPgp+lpm|Rfdc7@`JC2`GfQD%v8g4 zT-yLE2HrPx4NTiphUtdc6vsk)2Ih@FVc#~Nl|duVf=*b$E@I;_qf|o=Wub|c%$wnINJ(hfjtEWxpA`+J0#Kb>b=Uw02N~{7U{LKg^%z&+()DdA1(=r*HV@{7e3o5d1SY5SWA-g} zuwSvSxhHqwZrq)H&ck^eR)f)eB#&ViV_!C&SMeG?me1v*`8>Xi9pasAA79RT`9^k% zZ)TtHKeJEyNw4C&dAo%SOY%RGTU!_E99K7zl?v-#h64u7AI;_vZX=)gRFk{9w1c>(`` z=kvewO8yBi=O6Pj{v)5nzvFfMG#|r%;1l_`d;coILwi}h`)&a z;(&Nm92B>UJ4LU!MQj&)#3N$5m?16`4PvHPCoUG3h)YF>=oA}7yJ!_F#CmbJ=oVK% z=U*wNimSvlu}#btH;B37Rxw}PCKiYtVxhQ0ED}3Km$+B-i2KD#@qkz*9u$8P4~aEm zpSVaoCN_#2#a7WQT3{ufC^m_D@nUJabEPv*@?DP-yRK z(Epg-_F}x<%)bFAPiPt1Z-z@;ie0w5oH14!|6+W_wa#_7YoA-U+iCX__d_1;9CL+=V68ay`mn~+(zG6!ji*s!pg&@hqZ-W8nz>BPuRh*ABSfS-yY7wQ^T9W zFAd)n5gBn!#C;LZM~X;~$mg*dc-HiV`FiuQsFrA3^bIjlF)L% zmB+Qm9f~^@_e*?6d`tYJ@t=%XGvc)oUnRIFWGA#GY)ROk@I#_^;<&`ilH8J3B>gaQ z%gDau)ydzcT$J)gYDwznmJ-XUv>U7@>;Ckn^q(^3W_)j}v%R1BK~_(;Df^!6&vRDf z8gti;@*H*Xs4qwToG0>p@=bg%Wuk`pT8=9 zL;kh-x8~oMe<1(a{MYi|%l|C@hy1>R9R+&|4i-FLaJ=AD!Pf=96dDTs3QdJ03$qK$ zio%N$ifl#2MXwh9t?2K??IpbAx{@6wdrA(LJYRCWc1_tWWxL8ADSM{u)$+>n`tr@?+sf}Kf1td#{BZdj`&ZOf?)miHb>c-SfuA5!AsBTr=hPrF( zZmqko?m*qMb+6UESNB=n5A|*JJ@xDAx76QIe{cQ%`lsuU*1ubSy8g^WHqmQh&%|{T zw@kcYQu3snN#&C!Ogb^?(@Eb=`fak?8qz-KK;7sJErfMesKCr)8CwaYWmkRDreNsm^ov?jO8;fX&TX#(NxrQU(-)B`AqMb zOJ+Vd^VrPyXMR5O$C>A6dCm%+6+J6;)~H#%vkuRCqdB#CRC8r>ee=xb1A-5w)xoPT zS^ekLe_#Fm>T_${*95JZwr1Z&VHd?;wB@4T*1E0rTRUNG zSQoi2eqH*ymUWM=k6CY7pSOPW`d#ZES^vz%%Pzk7;&Yd{T;hL8_$3LK*e-eO(t=AL zx-9;(8#efDXx*@6!}}XP*;ux*cH{JoZ5w+wuHJb3@^P0>z5K76@;6m&ny~4vP4{m) zwCS16Nt>_Q{L7!&pWFYuXNzIW>McjE$hu<36>nVGbL9tDRa|xXRVS~$`0C@=jJamt zHJ@C&>DurAGW9RF{N?BCI^xt{i8Re-mvC|k8do!vFE0Q zo36O&mYeRs>4}?Oz3GFSzPah#cJJ-s+mpBFZy&pT#`ccwYqnpp{g&-7Z~yw{pqs02 zUU&1ZoBw+Axm)6IslDaWTMpjx>8*aZ=H1$M>&>?wyY+)xzq&2vw)We0-S)+fgdOcW z-n_l=_WIjfZ(n=+w%cF7!|RR-cWk}mqdSxDTzlv7JO8oMYiGjFik)+JUc7V1&L?-C z*m?G@;JY&Js=KS}t}E}_bJuHkeRp^0-6eO=z5B|$58VCk-DmF^eoy&5i|)Dlp2zO_ z=H4Oqj=Hz|-h1vne(%3_S$4JTx^mYOyMDMY;l76ZHs1I6eLwDw+TFPOn%zhCh&?%b zy7t_&=kNE&-rs)z{r7+RK-dHI4_xuU6Ayg;p#Ote4^Dq@?Ss1>eCxsUdo%aW-n(V* zb9=viXxKxw53PRa?uS0u=e@6J--dk$_I>%V_2Jfsw?6#g{($|Z`>)*p)+1q$T=K~7 zN8Wto+<~|Q#RsMxxaPop2cA9f{(&DK^?Ee=(Y#0NA6@q7_D7$5^pi(_KInch>|pZ2 zqJ#AZ=N(*maLd7+2OmH9=E1KIX@^1&r5zgc#QtYyym0h|lP~=9uu+KD_zx zp2M#l{`^Ic7e~H$#fx9PH1wsym#%&3$(KHS>Dao{`z1I5LL$CdKtl-%CV{adiI==PzkFQs~-t+q1umAi;!W-k?So+4UH{ScJ?_Z1m zy6sKZH}l`T=*_3!@_Xybw?2A1`|Ur!ee9jscjmwI^t=A=?zjJ8B|tlS54KH&s57&< z^2{vnf-^H;SOZ+-iHZ-72?KF{6^cVn6N`qmH33!_Ivb#~HS$$3VCUh1J+vQ=FNd;W zI8%s(9X1x{3rSApu(84(#T_%8vfIeeb;b?y4;(T3VN#kWp z241Z^7dg(?bZ$Y8^EHFVA;RKKMS69C;D0*mWF*%f~V87)~qR!dZnuo>jRx)j1mSAb@!; zdx^b_bIv0;8+w(!#*X2v^L6a||H|HEZ^0h*4o-{y#@=J^<3#iW*2m7{zzHWjB0x+M zlVuIa0H$vEZ^~f%rnL5#C(ltw~&iC9XIoS3S{> zE2y;R30UkrV2682yewW3N5oO_s(4Kt6UUuO;7nUQA)X{FfOtkcE1nb2ixuE8nrS608cB~8cDym%GdF5VDY>L8=%x4H2;wI7hy|df^2;K&qK%1U3n_`J9m%b zp2It%Uq;cF8eC{nP;0+`hxRu~`@6WlqP>Ib%NnFydmf`c20REsyI$Hyvdl?bU)4_G z`ik};t}o*}o=Q6EI)U_2?8>Rc`?AExxV`{vG+1bkXs;@&Nq3pRgDY|JO{d;;);$ll z!KttikY%s{_q{<~wo?xmp^r;gDQrKFqqcu&PiPn^+QZtX+TWQF?_u-`j8I^Nk&0F^ zVu3YAF7U+&2JRTiz#1bO_+ez90Nyz)7o!}QLf_G;KXI65fNqSk|4O&nwWVECYoBSK zYp1m@v@f-qwC^yN{LxI}iI%B-C!HvDd9c*wVNyR1m-;bW+pj&wB4G!6lEuq8 zXM~iO1ku1ufIL7tU_4-qic?-0V3bNzI1$hSm=0(FR0Bo=C_f88&r>}$04hHMKzSBG zARrkK4;ZV`^$2qTb%4nVQW1^@)B>oEae#$@Yyjok+p~vM-!MSA3Mn1{@B&b~RL&06 zekLFe5CI?>Z2)SA+O+}*&kVp;1ylx}rLyc>2hp8}^%eEa5CD~-dm#YI4+Bu2P)OwoFX|U6M{-5HA^Hi3um781bgGZ={NDmM zr@CAbCm=pu2-HW^CXK28DP2JqJUa?$XSk52VD!}qlxg`dfyU%?1q}!r0o6`GGEV7< z7XZmER{*$sKoAz=fb2U!j%maIz#wOw72O!yUhVe-M-vq+d8AzY~I~a?5 zc5r^?e>?7hb_i(PT?nMB{T0}C_J14F7`Hz|wkYoP2VlWHI}l!p z02py5>50hjThp5ivnuPjuY{N@FczxcmP%^ zpt@=R_Hj%h@s4;6IR6Vmd;2to?YyUua3>s6092ONG=vY89|0h|>_Bx=UpRvo(gega z>K9taQeF1;hzHar0ntZ1BNz*ydba{@1>6j{7H~D-CY9ca@J7J(fd91IohW+`;9dYd zPw72?U4REwcsIiTw45i({=bD#)L{nr0%%+j3cB}xP6McIK!2L*2iVgT+T&E-{=7Z>Z|}=Csa*y3dj9_!+Sf>S z9uS`Fu;K|qiaX;j%l#Mm&d>h4IMr#tC+nv^RzUfbX9r3XZ)G{vU-o{JJa>B5UdMkE za*WIKRPPDED>@#6AK>nXlW(#0D;A6mLfLj4)0J{NeoM4s8qw)DA;9kHH zKs&7XwE%c1oqrTC6|e;GGGHB`&Iu@e3*ag2z+p2!e;Z&2;0eGkKmnlo0+@t!J-{jK zJMEN5`s#l~2kIbP{wM9pegh49NY-!sJAWB`taRIvOxrJblM-)~!p>d}i%TVZv8&h^ z_!Jr7msNu&#=$SE7QS2Lxj}v#li|669RX}K)8K(M1Jr8-UD+wnj$*?S? zN{>w|d`C0zMnooTXxU_CQFfdF_(&OX<`M+!WiSiDiApHWN`}Mw63zU$E9}7!!^Y#! zcH>0G7uF{aSfLKU<7z*91m5y5z=HP_+r{oB><^#{Izrfq>AS_Y$u&ZDrH{*?> zt?W5?q8(!JO~Kn4*TSpIi+i&h;O})Q_knfyGMor)gU6L0-ntngy{m%YRTYd=gkkWg z3WG;gIQ*$1xrv+E)9e}64)3ODc>ONqF>F5kYvOo3Tf|4O4tQH7!n0{4yrELyOJjjw zjTL@38SuNwgwIVjysvWMeU%4qs{(jl6~S|=gqOnKs+?EA`)V}X!K+vwOh%pXyQ;=n z2FIHxUGOp+2kX@m_?*?U#qh+cgD2KRcxX+Ak4^)8bfz-$(3uWDt0wqa&En1QCz^v( zhaPyRkuUvnK94Qst-Ou5^Z9%MJhnREFW1St;4{|^&!bP^KerSoJ8##Z62isNr zYJLsd1V7uq@aylIS;`f?qT@g?Po8;`|SYEL}v3x+5PZ;JH&h09R3)4 z06uR|z{l??`1m~o@3ZG{7W4wUnjgmL#(6du9#AjA7w#4I1#5xt*-@NuyaLIA;W_s`&VO3@5A3h-q&vfZV%PAW*@N(>`USpJXWXUzFGIe{(mE0 zM%*rv#7L2hH-uA#MWhL7>l=u$BSAqLDUJHN6}f9m;&#+MtIjvlfHOO@Wh)Xn#F7}N6Zy1@P=y@ zZScmM4_~{5q640Go$$07 zBRuRj!SC+R@B+L7etcI+pTKM35qKSZ^0vYA?gn`0-2{KYo8c9BE4=!4z(?>7cnR)= zC*Ixg#Jd-sc=y2zZx6it9)M@xUU>HHgE!uO_z&tng@@o#_!xZoe&@95_s*!CPn6jA z><9Lv{aoqyPNU$jN}h42#TNs-}UHX4ay#Xe~yI)#9{xc)BORyEsW3sU>SETB>Hz(lo1<4u3nFmZ@cF*;ZldH8FZLBs<8?V)B6SO+5UYn>*(k5$Dv<9tF zo2pIIrfV~_CT*rROKa9_v734EY0(>7=u;R(G-+pPUr+oD~eU8!BAU9DZC zU90^?yH4AxZPTvTZqRPjZql~HU-}m9R_!)zhju$Wr|;BuYIkXOYxijPYP+=iwB6bs z?SAb6?LqidKZKKrhhd9|l}^hv zlrQb>q)bbBdWHT_aheJn{13W*X`Ux`AlMAcWK z>MK$8m8g13DvZsuyIYpEQ1zCyQdw!%T%UTB9N>?dGk3FSRrKdb4ZF=0# zL8qSK)!fs*aPGi5D^x8y;aLMx3Kbo(5_{`OjY^nji-#Q8Bj z%g^z!o?&R4-Q4Zj=4i{ZxB@3IEw8=(XI@>zC z7wMFiDN4&#hm@&$%2dads}3u(hpOYt?B&%kEz2^(4-2E**sW90?L>ibiM-{x#EDZ& zobF3jre#(5wYGG3fL*f}s$pvAL2ns*WQ{t%(r8*I1#m412 zvCAFAx-YkDALDYVX*^dtZtDF|VKc6jw^UM%mx>(YDp{S!s{T=6EOsK?-tWaqa*M65 z#fsEoom7wF3pKD(+9i?%Xk7KEJ|`fpcv)-@C27#Os(i5|8R=rz;&PqVQU^I6r4B^P zWXBoHFd;Pe7|SKv#&VhIQQlunr&ynP(0Z|Jxgwx^fJRYRlql>=6*i^zA!{E95^GCZ zc7~GsJn$*E)M?qtiGjr|QOU{BAWZAA&3b!hy4ytr@P&LMLjH42- zYNytWHIhfh8hu>UINdVT01@Lj{r))p{y3-mS~+BNyc0t9QCO;&QCjXjet?*d*U|GF z?=;%SJEXfz5mK(0rAuvEd6{BrxnibW59-p5`}XomB+4?4bvo8{I@WbgSR3ngp{RFa zNWIg2y}xtH4HIc_Pm~oTZTD*COeeXDBU zs@k`z_N|J3tD@hk+PA9q^&NpF!>ZcX=UPifS(+{tWlpO@%5|0zCAt|lg zINB6VHg#W#dWKEWqOSui8KsKW97T)1F0f?eC|XJtj{3xF$*?IJ^z{VNinbg@YmU0F z?-+1j)q|ablz5xsjlTT1WR$CRv($Zkezs&3tNPS@oT1OxmW&E}J*p4&?S>^o-)10G z_bU`1^lb?86&@8TwAuNj=(DLlwJCgTs!wf-KQ@IA7Q~W{GF6YRInhgs-(`xw7KKNS z%FnU$*?wQ;W3Q>#r`osJ`$zFrUr?hz)O}r(Bdze$r$_M7Ua!4>RC^YC|0urasI5{bMh0?;llPxoS5{-Pctt`bU*hDm6n_x#%BzJ@)=lp}q(~KdAc^s(yWuf_z0! zg$gaIe=MqhEO!2={;}B0+1s=CkHSlz*{qf<$!CPJJ%qAegt9(_vOa{eK7^7VR!g>e zE?f2w(y|?dvR@IZ`m$Ah*{Z&5RbRHMFFVIw+79S#1vhM%Q)HxPd8dqc^t53MA*1f| zI+u2NZ9RIyMeV9Wy$yP6Lbf3z)CNUV8x+;s&|}nw zEJtm~a(Wvws<$Bv$~GuQatb4dPJf!NN08R(Pt(T_(mMTV`uIUw=VzKe?vd8{nx>B@ zq@_F}lyZwu$_qlB?^()flBLff)--)QA=K}u>3R=oy?@g5ae}nML)T+S>-~|Y%b_(* z8AwX>ImcR}%bB%ApNo)IcqoHPnyy!@Y5KAhq2B*#IrdQTL6>LLuiDqm8Cdy9xkSD_ zl=5n|S#*BbbUlEyPKQm`A4u!<+w}2(v@T~hi(bD?9|y?S`E0Z3_1i4=`gQ)=EINN} ziY}X?*QV&TDL&Zrxz}n_e7EUyFVZ@FHhu0zTD7mwy-2I}^|=>m)xJLWBCXoj=U$}c zxVGB#xfh|{pEiB&MOv3Ln?CmNb1%}WePxZa>2t5u zmah1puG&}DJDalJ+4Qv+%BlACwHMN=eSPhPv}#{pdm*jb*VkT1tM>J^7t)G;eeGqn z>1!{9s{i%17t*T#^|cq$s{i%17t*?1+w`>;(yIUUwHMN=|Mj&O(z;yR^tG4OrpBX9 zjW?S<-yvV|UyXB{8s|1O&TVR(+tfI>sc~*oO2651 z6#tcewJH5-Q+m~=^sFsMwXd%SVfRz*>+3?KRr@&=o^t!9uWdc#ZZL&jQ*<9-&9GS2 zg3DSWE3%}kg;ly*D5dL)5cyIN5K6)k$__;+1q`7SEQI!Yq#z+J5k@E(Xh~O_k94)! zNLQPPbhX$|SDS)#wFyYKX6wl78$C&f+zPtOXj^CJ0{y$fDidQ|m0n)Ovth`>xjL&||H^w~VTa)B z;#bgkkns~pwLM?=_;nad`(v>n?^(F`5;Och>?k4VMdf|}b%0gs)-l>OB zJ4c=Y_hNJ^QV+5al=Vkh!uk-o%AB#JnWN(3qkVXER2(M8QQVdh9c6TlFW~9cp+WxX zL9y1%eB2D@fkXM%si`h5zT@-9H+8}^Z7m2Y9@}LWmZdkYDRrk_4pC( z@g`ehep6%Lxyfagxa!Kl=x9)%4(i=O{SctGz85b+!{tX}7C;>Ar{0%{^>w1&gEBmv zG7OY~@8kFLX9#5s(K9?iScGH;y|oshla9Oq#Uc+DfILfDY(LE)G&tRs?jId*EfD!U zBSnA%lHQw*!8JM47A~BYQxk0L=vW$(XbK20C59A~mNul?F5j@>a$9P{x!=Zmg+zz! z0eICEPAtS{P6ZneT4V7R+3(Wo)lVxY#PRl8KP5)WFgnrdMHyaBwE9zqzn197|`k~rMk2im_;%Z8nus>L7nG3e5kJ+;us>u(IqNH*fI(P^@?i> zBu{n)ri!d!AI=MNrxlvbh0}6sn?ok~%7MC*vElM@|I}g^IPv+z z9S*O!EMq%(jd;o;9keC@Q*e zYF1`Lfw}L>no?`!(6Z144dH3gfm|y`ug*cQR>sAaHRUAu=Z{T_$xANaF9*h2BV0Z5 zt4RJxdDB=6WZi@?+yQ}yUH;suPu-pRRCS?4xdu{+KpIe_)=4)~r)e_gj+mFqBMptO z>w}9rzb7Bad3Vg`|M2;L)9C=)rQvQQ=_jXdUkrdY#dSHd`oC8Jn{ zq(2O?v528pNr%uF&CIf;V7gENjo4s2A0l{Apbyk&ybmHnM{(;=*NnI%ZqyT*nqB$G zu`O~pY$~0WGb}YJG%_P0H6tQxtR*ukD!OS!R1C$VB8J4IMD?^ypO={Ra9mo>go5Hd z*yCcGWzDXw@i(P}C#HIOc*KOq#e296t<6p-O%3(;j~FpIB)BpaiD5>Ukf0E+@s**G zLq>!r#`1~Q#IQuGyy)6tq@0(+;cvRJ7n6sDrAdZFpf|MsUKmb19`3~SV9E$~%5YZA za+-E@3&|jfRxsF@Ao=c%&|fy=k34T3 z_t;cF?*X#7VT%&MkNSo3&EFSAuWp-y60R9nLjJ0!60m=a59vWXB!cWAO;wt#+H z0xr!U->%69trgrz{@k48ZzyHpXD<5ngk$m0i&+rg`$u(a4l1 z0nYLGqJ%fFov#nk zllVY{XMg%7pHf_Ql!qyFyTtH@bC2d$X^9SOX;vdt%ODHh#8m?v%zd3?L5(WMy3vKY z-o;54)V$}A1#c>Wj}H|zk}S9|Z%MKM$)4aU$v`1bcMXV+cMXbe=x~{E&HC3*U$TER z^?PysmLq*H{#uIB&*9I{gb(m?XO;A$3LebU2`|Mn2VM>|2J?(miP1iV%08^#y_<*Z z?#piw84c%p@HQLX1HdoQU^Np%n#e=#7%mtQ4w+K>Bu9o15$)r|7UxxtRMASSJNOhp zj|Av^qOWbZf;@~FEj5G?7|wk3v#lvCP-ndE2!BZKtCcCcD=`(spLp>4#d zvPVYFaPdk`Oh`5we5|Q?sWU>uL!)O53lEDHhEj7%a(r~!#0h;{`Hakj=;*%9_7MEg zHH4q8A^b1U5Q^Cj@|DVPWDFu-F-S@UmOS`;iJe;fMvxkNw527QE>IB{Y6xLy_&xoQ zh24P}Js5yDBCtPTSQ|#85gN?)e*A;AD6PzB-lUyEnB=eXqLLOF@dMTpd}PkF!l)>0 z5bR-IWn~_qe|uoxCQPovryHx}1><4-`E0Bq^}Xqu3-_ju{hH#RgQ0`=Yf8__`A!O$ zLkHXUpyGG-YWQV`{=J$KA52nmujU^eU?=fE*sB@(H>Q23c+dr#HQEVf|KHt%OTry{ zaE2Alg*zdif438&J@|!78~&f|!83SJ|DIIegmbJO7~V24VBW*NAOJ&#RvdPj8>HP; zKRLSAF`Hhfx_aeDfM{zC#b6{wKpSyiEJXD6QGi{k$x%Za1KPx5j;h(T>1U&B=!o3- zf_Zs0kM)hGy}_n1Yiw{^W!^KS??z#?_(2Xw(h7iKX`bSQ^Ptt1^KhnBk!}X^MM&eA zkf9lsR{8XMKcvaX=%gEoXltmOhG_K^7oQaYi%+Hv){j)4qG2K5zX8XhJ(5RgkVl?8 zab;|2)TCTnvDeUWzq*Kmw8)inMz=@j2ad__NHx_(<|D%^GdV9dJ|@m@sE?cQHViRm zj2K^+6ju}+Uv3^|@OJS-#<)hBOGcoF`~-E*T-v$eRW2uLJxLLJvWWiG%%HL6Og@=C z@S!pEfDzLQ?bKWl+V`lmgpigl8|~I;IH7CgUX53m72UQtJY?R96DO*2c|t>Q#QFpJ zPK`?|4&2)zI_>nUXam<{gS3{~NIE1)A?%o29BUrxTn}ZjVOZS~`n2Mab}5Z)aWD%6 zremE?k!XJX1*@?RrE7Uj-}6|DnS*)Lx!=H13ph%@2<6VosM80|&V#0dK`TgSj=DgK z)3x+SP74F=i$jYmOO2(K9fySBy<^ATldT1!wKBBk%T|%~(NAt@>?3TDt{gPv1~sot ze-4Hz8IT#Yo)qX;LF__ER#|VkbO}h;|L}$h{sL!M-N(+aaZhg?y`kK_VuLXBjpO?W z&i%%(?xSB_N(SEads_Z%IrZxhX%e*KElBQ!)0$xrn$BFhK*#q&2=S(*9BDpSoRgBE zWs-|rH|R!U4`OUUyy7gDT&X*;*BwqxO!Sx4wSe-UGBUdgn1pq)oyGd zF5wGgl3(&y$`AveY}{-!2f=tWmgn}p&Uf`4=4G>ZO~b6d{rExvR0hNQVZG34o}@#- zaJ8^?13fPND-5+fcIXm?m_yPWeM-wbeBTkxW7z?dh>&`nv-$4+zSWLRxZ%!8l*P9W@YP5;z4R9 zfmr?bGu!jh^T!O&s2bUK=F9B7yzJEraUyG5D0*j4${+3P;xm49(r8=wd~G zTrIjBlnnWd%!C#3Iy>J7QC5Dm5xY5ly4C4b#m|>>H9F!^ZQD$LX#v z{O9R?uZrHjcX-0N3KYgS4)7K*(SY%CAq|7HsAFu?DHgHaMM^8h+@Rv=F%W<@^>NAl zrPaBAF^k0>|0Xi0Hf?%`-+XsCOlAEDT6yxAjN#KK3{A=%mCvtj0tVwi^;lpaZ7ptC z5jfjg2KAhp!yG6L>N#gy3w_I3?>SnSavTtISXihNXjv5y&4*0v>T;R1d;MqMuH(h+ z?*hSnJ@4U1hZd4d;ez+9X;opPa{~N$jgzkZgE32|0lHQoy|A#07hrPQNwj98MiXlE zV~eRqe>TLa#zCYhN*uHfP>pmPt`5zl*wP|`mS{BjYB&-ngPIG{bgV&ECY}}T$)kfw z3TefLarcDgwq=W(HfPfU*M;ln@NsYS-N;+t=-US_e8qzxlEBz8u9`_O{};!VzKCSN z&=VNC0>c0~M93QEAN{cV?5ke|h+*eG2lqZl2z&$^35_-q8twmV(QvTMd87nNsnsnS z`V444@r)3^XVEBWE{upMY%Z~f)ddCB0I#&^8zxWMI6W9nKbhYa4sJ58w2@GBFnNXeQE`**=J;B^>E4njATH%Hp zon%W-O7rygZyjT)&8F{@4}-uJqGw!LKFwpgCy$-RLGzgEAlV=K3?|oBq_Lo@aKI46 z=XSl1;WYi+PBFbnuBOVt#Q?N0j8)Log-_2oad8-}T825>S_^Hw^oZ zU(RDt3;vI|gjf<2Eg>#l{?=(#Rnx5gP>uCT6=|WNX%$KQ{=U}g#no|fxZoQn4!Zwn z|L^EqWiNMRI651u5#(e49}t|L6_Bod_`=HR_??~^JujgB9p8MzXUX+~ozHS7P3BW_ zuCeoZkZu`d(s6E2?xY>|Xx)@%fK1`50!qq^*!t79pVk&MoBH*mNYe?SNfv-=>+E5k zZsR-0yLpB-S+`ZXRRZPt5Az*;vmWN#&QNv zV^r(*HX6jF6!4qzGDe$IeI-EiBRLP4^{sz&K);zqRID98##mFg{Oy<5R*rTVJ!bhU zn=id|Gk)o9;+pmA*YxcHFT8+v4e<74Q)yu^a6TNQYX+?|9Xxj!E1*KbTH2M;K35tj z{QGh8KXZCb<7i`5uEeTxOK7Z&YSnbXZt4V9;bfeetXnvlfTL{b7Y=Y*zRi!vlu~ z4wsh!bcbUug$;}K&!u*{BmNV*b&B=%2-y!Jq*f0_N0Q%MFL+>&#gL^%=8+YGHqnFG zpvk>^Fup*gAFjtkvGYO1k1Nr*n_pfk!oFYp@&*wuRxF;qG&q2p;}g$)jOft7zLW8Z z^cyOww}p{T1tEQ8#k0wAFm3Q&f-Q4WZp5(U zg4kWWeZh;C$rjJ7Q3aM*bG~JGWM*}8Vr6k&#FfOkILuu`fpZqE!~E!@YEC$-1-)aO z#L{FIt8c;mfFrE}$ZyC`ZMw;CC`(CB7R!`;j77N=f@qyKL}Jz&S%uEbVpX z!*L?!FSBR&-TRI4@>%?izPN_VPvI+QT>1q^1FI2a9SVcFBhjfp;)(t7PHPG09alW~ zOw!y7Yn-1lFh&6@>^dRg)LUdbL@$_Kp8IK7}7zwRR+jR#djWu8AOBo{x- zp{Winl$GwIxduBV?1Ghk%Bbl@Q7L1lj@*_vtJ31_>KQR2!<<}`9T{CbJ*TLmqNuQ< z!Yi(FZeh)at|{S3wG(ILh@jZvei1pf){H3y(NoI{JqpX^g+|aQ$kA|6=tf=;SY1lj zPW!0;1L@J{JTfVh@Sze(hXHh?!^TZ3O>Gy~`o3%CAN?j~tp9NKxqG4S$%dAI@fwab zdk(ve^gTX;C?Abb^W4aOeLrZS;*ec^f0Qm|L)Z7jW12g44J4hhP9o!5fFQHdQ;5K< zq_K4rA(K+A%sB)dOwYO@Bp7UluGA~VN~teEKU7EqTrVfO3^d36D9{u3)kj>(K{%(VsC za^;0r*(}}`yqJXxxe1b}`y`P= zTfF3h7joj|T`%+{hh}q)F3_^#ePGdc?CxFr#~Znqi|BtNkJ-61ilTmjKo&wU`2k2| z!|=fp31QvtB$PM{fs|B&$_#wF@&IkcideBkiMC?d{ZtOp@6Pfe7vUDtI2K*ulbF~f ziKJlkwH2wAVKOg=Hd?a#-JpPI7NG-Xy<9JZ)lUuHB(O|(dra$pA_XPM&$1Wuj~;{D zlyWR3zfygD%V5@M5AYYY*d#2_PF6BO_d2bZL#rV65|R}h6S1u zf)XR+Q)69yhnwQVn(AX`B~D7LOx!j%J-;z5{Hd_wSoic?2ouXV53>+>ZNV2q*U?hE zkQGT@lOZXOcwK}AwdAJrrl$yZ`3c%`c&hULC>DJD5Po=;hEo7SvLMhBAXs`<9mH?C zl6i^_cSxm^`6X4x!V$|x3 zK?8HZ?wE|P1H9MptSgMJL8yn$x1zBG2_Ar0`X8j)V0mG z+Bv8eSUrOL4gan_#c^35tn<;_Ix%xQJRskuC*Q!6ciNwHrpM{6FvpW_+t*B#PXd<$ z-YZ-rE_Is-m%6n;1^LsEA0_kaWqv*7|JR(WKi?@r@k>K-Z1Ps(++=*Im}=S0Quz)1 z8?*=hyWj?GaiEzr(oEogY`iTi*fp3hKYG->WlQRwd3&n1ZNqa<t&17F&fROTT+2>J1>@%(CFW@L?R zq(k35KZdWvH)dU+_N-*)(NBJK(++-vPxY}nf`D5MEo(jCB&@;F7P4)F(I-e7Ak*I^ z#3kgV#Kolm4jkd4ukVP6iwh44*DrdjKciJ*NC2H*4{X)3HXUR~8F=nQXyBI&fkv!m zOApdq2cW@+C9FsYPqeQLxqpAORpvWll#C*($& zGD@S{Cp3*p%P8`i=^mRk)~v98c6fT#$m9yE$=I-68&&9IwTw!RGv$s96ILfe(2Eu4 ze}-%ymXu7Onaxg#KXi~z4N;=p860b?a3U>SUu4i55V}Q(Cbbwz)^N$)EZgtyeqDnG zGW=sF5^Ah=!mNsxlMV_ZM~w_~Q1*orDUkc~%lJ9*3s$liFJ72`mA@dF#)d%d1F$5a zU51=VgQHWlr_DJvi5s`s?DC-!2*_K9e=gMNMZ=Q$FpI=;P{zx(13=SVf|aDAYky zVU$`b`l!`)FE)+-%4>>*o8I`a&$Q@=0;~|pO$lFPh>K6rX!@0JV8MnSOy>#8{l(}? z{gocX%WP>L{(f?66g_RF(szE8eP*9O_m^!z>x63q5-t#5Ul}f zf5r~79MEb4KF33_(jqgG0Z`yS4d>MPUncE zzyVYSCXLW(tp9&Vdk^@ysw;nd-V}|xG?GST)MhkIy^VSsHA}K(*|IFj!bL8)gRo41 z5C{Q6C`kyAvLR(zSOUpz3J^jF*db)|+YquTkZjr#hq58Pk|o(}g2w;v_ul);Xl%0k z`5Q*>&3$j)yZ794&OQB}y#loUXSt#~%oSZ?888Yp=eKLy_9q?$I=%K5;8M~r3<(hU zC@=u?iC<{*s!VT*enezW)C4^I zGF4`56)GMd2A9i##KmKtI##M<7a3;_8=!kp2esjf z412KwbCl%?m?LwWYw@5O(WzQMw?d_+SK(NLdzyh=kJ)N*Ms*I{Oyqk@?R=e5px^_k zR)ztCnv(DM*oN)fH}De(g#!3!D?9JH;K2+2ey8@)^;dT9Sz6k|&v;9HYkiCOqxl59 zv(IsfFt-8bO9srlMV91GPXX|HmSjI*O_=jYnDbb!j>FIHP zs{H;cd^)wS6eW5;J~}-;>hJWVc{=>&DX;VMD|OWFn4O-Ugl;KGTqGQ6wn+Y3Mehk~-)H zH~BX09D1s|;SLweS5)39lW6HCFB#IbSE_nuT3Yu-`^w^xSbux##QaomS8X`8wWqr_ zJlxW|AtOKCSE(Nzk)g(tir|KlvW9RVnp0G=t*v>gIJ0a+U1X@C^jsId7i!Hfu%|hS z+Nz8*N(sTU7umDHr9HL|{xQ6#lxGA)P3tamBZTMyRz#_g#__Oj77NhB4(qtHW!q3N zIJB)rOW!@a`%g6k+uPc<57fN&Y5V`I(bs3=UZD1W0@2k$(?CQm-eQ{&v#I;M>N%sC zd_M@W$mRrLG0LV|oE724_2@t~j;&|tvCwe69@mFNp^Of+42j2e0J}zvZzEVSjLs_O zi=|M6>GHFtOeEDTXpFCHYiZfG64#Hh9q~{oz9XiNeOoTrwYh85Gny6f1#6?>%3$`0 zXG1~r;#D)7uU>3!Uc7qq%vFoc-I1}Kv4Pmmv50Z9^U%V=q4wHfX+={w9%`y82}L?c zVwY<>wI2iT39D|fqE`ql-5RJvtLs^64OYvbb;hb~S>SCA03MxvZw3=&*I~xNjM)T+NC4zq^k~EjazwzxBOn7xX=$;1sh;pK7}c2P*$)aW&yXNVHh9# z$;WXUU*D)+|Cp^2Gdd*N;yB8pDRH!Qi?$fX*e&L+0R!p;dTBa(oqxud2qNO7X-d?? zXSBx1SbIf9JAvF*S=lxgscZ{*y&;~9qrG{_?=SQ;#6rGmpRZcmS1{7T%jr9 zqy!~c!}AzqX9I#WwI4zh*QjUZ3^QDUGtF!mhU69F$Q-4@PQZXw3p_Cdc~FG!4!Wbk z67TZX7q_l%9&`>(_Bowfw>q8L-9PK-_?cFI_0@@=T)N}VJ9n^}&5hUx=s93n6?E7S zF%n$Y{7Uf-Va2M_d4bAY!bpG%&*B#XDbDIA*!^6#42u)FT2_kH(t*`jI-?`%47eC+ zDWw~dt8Wh8TPdbK2QQQLZMdT5D8eTyoVUIWHG`-gaSpqv_9=gj-I>+h)YU&bJvLR- znA4g+)i*v9Jr#;pl?U6k<*M?EaCd80XUWD2Z(T+G*zo$u|F0GNDN z$u7&JIvE#)3^5^(=D86#+elY`#tbL3{4IH<&KpPI^~9+T^` zljOQSoSlmfkzyv2VPSl3jEuCFm$!~Y!Xu=gk#IvtM*}|E0XFIvd7SBMXz1gIE6*A1 zA$7IT4~oF=#ag56faqmwTRG(WGyMnqao6U=BarE@!rAlKTPI?>LRbQ?P?o?5b}ntl zZbi_ysDS3#=n2LXsf~9>@m~q3gBCJ(^wF6sPgk7UcdFv_l`~hgcHSFbj6eM}{@mMn zFMBkKyqscK21P`U4Ku~$YQ1mDiDc$PtAJuNPfUSSq)sv&Mg}+1BkcyI(yh#h9E8n6 z=aYGBYo|{ypFaJx{i?YaUz}UJ$=ZiPR(;Vh5!PHf#W>79sPKq$^+8Hqy1JzIhQSgt zzmCC6v{f@wC>KZelTtYQS-^ght62I<4uk%R9;44M&S_KZb>gwP7fCVj1YlPux=>1N zUp+;;h^TtNQW=!;bttC9bEHJnnc?yZDXiIcFc~U$ii1nd-4G}q#76|lui}K}G@H=B zY4Bi5JEcrPoK6y_%XSCW)qC)<<4z_|nS=LW@MOLPIFikJ0fcVAKzyiY#@v8`_yljh z>g`2W-W=X_^)9V@S4e$%X8yAIXOKE{N}OQw!dez~#^U+_n>W*}``54dI<}bGl6bgQyE*YD{ICf-aW!Zk!}79`DzS=DJPm~fvAj@isK%hr za7blP@4`!v(3-)7Rx%u^RTkq;2K9mM7PpjA7NXSwE?ZS24AvHDU(~eQ!hL0>p~A|V ztl9jTVe6OE(V9SXGM<0*m~ld!9m3x7K2TtmElTdA=;k!A0x|QVe}pTEfOQH;1l>d~ zNd(@%KJmnXC!QGk$^~D+|9qO}vir1U{Bpgw33=^!8W+5PcL=+yxh}W>?-&B+`Rph0 z_B@%HF7p=!uRe{ZWZ)huf(XGy*Q6o{d=F6OHy7R{`46>7{mxrIrX%Bq0|z#ef(U`v80X^kHq`TM^g`LOu=ihhEx==qSX9wY0; z8Ow3O%I!2bJE@fc?>r*=jJ`Mt9f`YHkc?q10d@;=#X2eGS5l(L)Z<@r#+26x@rB_?ToT#kP*zDohIYK4bBG8BZPU-qwElY zj29s$T<{$+t4+2y0_T5)e#dO@CDwNcuQffY@(fQ#Yzh4K#Q!M40ih}F95g@` zpW)Z%rv}>X9<%xI+aR7v5f1bdB>njC+a|$JTJa_ZSc86ANk0@v&P_jn?|H6hAE@rC z^0gF~2Xba}r~CeQU$p6>yc}=XU)?)poP5VPGfpHO_5xq(LGg%=$kW#jdN|1!NCP@G zh#5e9`W{J=wlkuE{8Ks|GXP6EAGtt~w{U?V4Re7Y4Re8rGv^A-F@XB8k}(F{S9D!+ z_t<}G`CZH6B=P&M-UAn0eZc|o2ROQ5%f?=Xi|CQ?WhstG4rv!wfbPz)*M5pEt{+9+Xl@X`3A9RO1!=3o)f;Np`K9HEZf## zTO)l%l2#SlG}b1ye#3qwS4$>51-u^i2M=eL9@i!lbJ_z-OWN^46?Q4gBCv zbHv+X?BM0+@>@S|^;>J$yYy4qXRr?@N~@7eD@~tk2E5wFQ)IXXZPQxgromi)M>yQ! z&mH{KXnR#zeRV-Wb$wY?`zR?tgg+fv-CP(qY~^}J55|mfzm5ma1hd2?ngF@pGP4Mo zRIx$_xMR>=l6da9-OoMOaMxXFcipA!(e@-hlK9Bp1pWagL$+~yCe{d-go(`DSpK)V@8T++2%|v(AQ(7rI{Q%MN6}GTxw^MsgUik>mUbY z*)x3o*H`cPr}nY5$s_x}p?%_lhtHnXj>;S;KP1d5NSHayk;|a83YMbxKxq@Ebf?rp zk?2jSh6pRA7Kmptk93uI=tb~rGV;Fy^8k4VZOn0(k#kUFRgFbv)&y`BB(6(UN%3ReKo}+WD0_MD z^-eWS@AWqoG!JZU89Fo-jZPgJ;xTbhD=L|2YMLmyuq-swUl!UtmsV7ZLL`6%5aoQ17*ib z(bkBEQaM+CJA`eau57nQR`+E1uNwwWro2e^G^}RQ+pA4%Th6M?YA$UrDsAi!&1|da z+J;g{h1KQ0-1(ev+i<5Z*gaUCy=O~qdVza7H;}6pcFnXF?_OwIT9|LD?{3ca)s{C0 zy6Z~p|IpZbrt8E|ZX?(Z#ULAYj{Ooavjp={$Lfm(MidUM!gin~k3n^e7;rG*q8D5MY#52w@#uE|}zlw9ycdrNVegi!{xc6d!b@U-QJE z>caBPoJx-wW=+a)LqyhIT*r8GyJ2y!Iz)!!)M#~v~78DMjaG}EJy6BumDH0GH{3j%1zAQ3yMXK{%|v{t+)haPp^1#-9CFD7{8#q zZ+E<=s(W+uz)V@1|GtwStKT`@_D5CsN%L&HXtE|ezJH)^c{J2j@7Q^3Z`su0TM{o! zY#7-vA^u>Daa$qc`9209H`z{tujUKUJYR4nOa%JOphp?&X~()JV?8O+xYR^}4}z+5 zVchf!B9b9pL@&LCXypaBt1^Di0+Z!fy}~t7NcPev0Qnw)WR&rx8ynV#b>26vF;+ji zWztt(?wi~)S|3aP*4Ee8hR>y*)ut<}x5r}JtFLTY^(23r9~>AM7!-dn_DyGRL;c<> zz=LaSZ(#RiMF(2ppavNDZz>`Rnax~=WZ5qh5YdZLgPGtPgBDrglJcL_EXvf;hXv53 zml2JjVg=(pqaJVxRQq*%9dLMi;QrQfmk%Fao{w+y&Sf?FgY9`U#S5dKXlZI{x%7D6 zyDqupU3tfkrVqC^R@S-`ce?BSEv+NzN41Tysch|F_Ee105NmHUhB{<>m{N?aJ-u!P zO|fzTcTa;;xF7*YZCSc9AoRANNf_;()KB*6C%5Y-NR$zRaS?`J2q%O1S&97FUOZO) zUY*=7T4agPQsJB+{mUBNx+_)`$q);Gu-me>r3&uRrrvhTEpKa^>I~=ZC>rP<-IVpx zPk;JS)~3Im;%wi)o zl~NF^wLVr#jM4g)suXeelC9Q@2z=V#nQ8%iMPDgg1L@IMYA^vxm54s-?1(}>(*u$% zj=B;|fy`WWLlB>;uXP;WoLy8CU+Ug+ad3-oEY>?-koAT8G%c^BGFLlxg=eJ6<5~2N zM4M-Ns`_Iiq56T5V1MPJJKJ5^94b$D9|Y_g&facsaWqh8gvj+Vswtf+rG}lNCz;1~ zgDPKV%#`>zUarxNV!VvjmuocLaD~v-c%(z95l6bv<-^J3i)`%zGL+TAxWZ!unr;Ku zbVgR3!d#%X4bDKppjk*PC7p=G!Sck&GeyZ>#H)y4oFGZLGYvUDQRwVi_Ut9WshZ8L zCG8W9MaTEekM0X@ERENfw@)+`U374MUrW~^tqdCjb!DXuwQi_ua{a`a5$cGC77k?| zIpXeU8m*4FzJsRNaA@(8>|^%J>RYm(&Q2U_YRURudJi#0w<{L1?npX@W3`8x_IC`7 zYq{zAQVr%xts4eeeSwBBqOy+I^sLa5l8vLT<`Pgu^zImKRY;)4e-25mfw4y(x#lx( z{HXh*mwo1%M;=Ku@A%LT?b5_;{NNOPW((#&iuo_cN<{gj#rEk_Sa0=;#PxVKr-{c3 zb@Z#FDXFAXtgsfSV0YPV4x&zA1x+e45x*K#Af-9ljcV0ki(?B0?m_^%M;Ph!w0lV=4Vt4f=(P?t!;E(CD(*iKWU?zQ!aK~STvMHhMOG-&5_Gi6+$4oV}n0!FZoDtM47H;J}v zNHw(V@IL4@xW53ady#6D1rA7Ul$@G`l*247{W&zBhj4!f-oU4v0--mFcMyUQ2!c`| zK$Q?T#DN&Zff9El>X1ugo)#>u*W8XOu+c&!T!Od?xlXn_DoQg)vPXxP_h*h|go-jo zvg&&ZcjTA0pceOzvW1C^krJoN)tXh7o7SG?{b+tceQhW!{gPXv_h0pQkCd()avpng z(L_^iqc7pf>I~NQ&u1O8zo@PK(&dK!=}3I0Wu`*=R@p(;iovofcyXKUt+cMS+hQ1o zzGkFIgQm1_8VKzIb_;u69=_0cL`OV)#Xzq#%oFk3jU%I~NLx%Npd;J8CFXP`F>a^h8=rA!JMQ{OW?eB@cTQ8~ zbWx;WbAC;sg?Z;I)Grv;@txNMKUi`M^2Z%%-?^ehfoshckC2!Uv6VmZoGgi*@=_!_MUCjkRS{S$0 zB17ZiKuEc?F)Vp?F%BC#%38nHVf< zFRsZc&u{XU=H-_cW^G*4P7*!L1&(B4~Dk0QeVPTVU1U}>R}xCh=>X5d~Kph}Akk2MDV{cV4m ziEax1raz4qc^77q_-6-bQF;m(N39OE8gNDpfH*}QB(6~hkk((xf{BYd4)RDGNo5|%2uMx#Ul{6KkfW^u-dZLa!{ zlXc_F38|1}omnzbR%xaloT+LRO08F}k)>Gge85pzT+zqKs&%Pqg3)-vV7MEPHB-$E zi@J83t7xoi>)yRvyT*!Kx7~JlaPaVvroO(WuAZK|wJ-cQ(t6~`k)y4VTV{KDW)po= z%{9AfntPgCntPs~M>!-7(!R|;ig_>O{zC=-XPMAk!W2cAvrWARxG#Wg>OJQY4=E-x z_$J1}GBn>P@sLG)zOovRueScnRZpFI_?y>%wN2~WsYMdc@v{?kFZ(b8eT@;maytfO z-66ml4J5EpC9#MVBVEueeL00VD;Bg%iiJB3bI2tXdMFqqtzn~4^NJYt!~Rk$PYO!Qg z2tX&3;n7@!Q|Q||!7_4?qe{n<<;Gv(I}vThyph%^*L=X;PX3t5G3akCui{m!3Zvp8F%c$7hXAmlWXM{2i7u7)ukgD z#w{&qV51We3Gl$l*BWsRZaju&3jWYxb3nx6@=A_O9giHDngFE(VkGTSb$p8GXPxY4 z9r{^^?%@K1`FJ8s7T1Xrx`v55e5?~X5O=D3V)|I zX%`2B-`lwHUBTc4M+wQl2wIaL9Iuu6@ik!aQhlvKFDOy+*kW+J6#dV-*wI%~BP4v( zTU8PDT+K4U#hLLfwWe&)JGCZqlN!P6n6Z+kxLz}a3t3l%thO2)62;C$>^>AjVd#tX zX}VMo?HP_x+B@rU7A%zc@YTYk8*~?cV|L41-s((qAC$d5STPSo&#sG|I z!QJAftvtb=QQR;=E+hmbYMOz(O3*^xTrLsBpj?2AiY3L@D2^0IsbEs|Y7xI_2ScI6 z231LAjDwdVm$)+^!^>oB3X5F`4>KL5EH$PFs8eOi+kWGF62H(6WOubqcMnAm z_cd>dRb(yQ_#Uk!@%Ns-uE@sP!N|$%%Gh|VH;_BE=$tC7Xl)%DZK(G(#lxX8wv>ir z-GTbC<`~v?>Yrg?VHkSc4P0OJsux@WP3=4d_xxOK{W2ecxEE2l=U3a~5%WxU1B-|^b>4*1#In> z9r$!5+LUdGB<$P&%BmTX@ z%AD6f_uR>2$4*{z%{7bDi`vAAefuw-Ui|OnHb%{D2mcCze^q0pirLds0ktVTn*&@aqKQf#0tf}D^mEvw{l zc+#RMEXziACmqPB!>()FP@;s&fIXK6MyB@dn;MxKne6L~PnFd7ho-KU<;}0@>F@8k zM%oomUYWmZ!@#7+l|M5T9c>S!U8W@(T7#_(Yrk!Yg<}E}g204Q>=spk9=?kq4FM$* z5ctIgEEK(%I#fznNQ$m#t>!>$tc=u&vJkN@c8lTwceGluV|}vfj}KT+9&01gxCz>lZkoj9$CbDj@Aj?F&{H>n=EW9 zOD*M~6XuRR$`@#kR^h!F1fx_V^A2U-5`0}KC+5D3x)FhcrsEK51kR|7bNCvLxn%j4 z;R*#2&hMZY;>lZXxn%{TT+zpdoxbcZuT>!STkN>&C_(JE2Kc5q9(xrBqdm=N|9nzA zYgx$qPbamT_n)%1+o7VU`yVyhC%MzFYIi%nqrvNIyw~i{{;n5TiWE%uFe6xxCD?C)5NZNxSzm}(cG6*jO^Rq`>XrJAxvwI%maWoDSuqLxPC z+e5`l&}JB{ii;;63_p0Qpi52=lP%u$10lrF z_*3>84%aYtK@hRMCDK&lM#{1;vpK7?z7+M=2YR(=qw}2G55ICndt>K#X^pQSy(m8~ zyQ!!wqo}$#(qHayG)GeQB)*;d5o23ob3WP)_GUv$hiMuYrEqvWB$Hx z%pdT;q2o=&K|E8~V8I9TcRw(GM|`-$c;0^`wclX0KWAz0a@=jSKX0@rzn^$(eSaEs zffmc}UNnBk_V*gkdnu{?T}JzlRlC?>SJ0VV(%GLRoym5NU$%e#Jng5f?Sh`<{f`>$ zliasTJ%=Ok3;3;n@8ib(*lSwQ6QARDJY&6I(35=rBfKAdi-Dekpr?9Z@88qOIjE8W z8$eHHjEhRwHtESrdh%K}i%F`;L(ih3CzHUGLInbY+ARo&3m}8gW$8qUPYq&GEW?v! zqzyHnkVvS}^&OZ<4MGxXHEc;%ic8r?>v2UxRY@C!TB+>wmd!%Hr4x{`of!7Hwi1|D zmAu~;c$=IH(vpPj7n0_Jv?SY~w6+UclI;&$+XXGL-R=0kF?YZLK}&20E#ZEJ2^L%+ zEy>^g!1x_;fwUys|0AiLv?SY~v$XdJnvm_!8|}&OC(c^mpAK5eu>9^t<9DyxO9d^- z=e=ZU&v1~IWc!cV4mr$?=S%_@+kk`<%-t-uP1>de17_4^=d(1|ai3sa3QgHtQj ziQ8G2P$th-%G)b(dnInin{ZQ&xG9VlS)YKiUAK_;Tkt-axk)*G3~h)|715tu9hfMl zr*f#UR;QSAMe|~v+J~mpEcKmo+(P&ov;9z}6SC=+%X>2U}?Kj@|_KsHW1i#eU zv7@#1f!5aXk%J@S_76S`Wm%1UGOG+qHZVpdoPhno@0fFvSqKIW$sQvd5Z zh=%NlC22;OsHFX*ts>v|zLkN2mCG$_nz5Aq)7;R|+}bB+j1_Epcs{-v@REC#zG90) zuD+R-9;9s)l!D%v85ycpgozvqeE(VMV|wB4S}hPL7GyzB}jdZ7i#a@9gepU~JFkmVqs$ zX+^{J`xPT&|3a64%km}hsf#9R!ea=M-6MizyZ6+_W4#rv z#hJyq{c9IYY=|>d7Jqb^xk7R~C`oDf5C1@o)U_(a`plLz$LDd?Y!}?_-1j?9rM6QB zbUb>Fc2c{1{%4KnPofqtWka@eMMh+b(I4ts^8Uw-``J(GTJrv9G}tQj`-N;M?|+2% z11qR&;rT+zg09tX8?}uItnCL@m=*vP@nRB;(fpRJYWb$DowSR| z5QPwK3y7DJwX}*XYp$3hV#PFs!d$F_X1Uo)loU2pFciWvzZ8nKm9;ChV?r*(uCNuJ z?p?#7Ake03X(*7mZSz?BWbt@@ceu31n^Bf0H8J0Y-paOMkrWTR%fPt96BovZ4o*hG zWFg)LoP`;MXLJh z<-yv+qT(K`UUc`Si2`i2)#`>|WcWfW;xSN5y`d$elaS{_7?z zROq(APHA7%_uHh*NY^L>Rnc#;|N5ba9?~lBPYiKe;>7$CFhsmf@_IjJP}3z?*$%1{ zEtqj!B}U11@OssLI;mYyaq4piLf+Js&(>v{T== z+)tja?tg^$gQp(?PalC*7lB{4+nL*?N7ynX&Wwyv%DV|qB^d#p=iuo=voZsRr680A z)Szoqm&%#kL+?BJc)8%?yjCOZx^=>?YjAT}R*^Gf<=x4N*V^}$UY~fEm^`aO|Jiz& zeDN`rc{#6EJ>C(kDf5=qh(G%LQ72dMdRV~AX`4cRKtABb=zhi(A+tIQ8j3XIb4Yd! ziAP3T@M!Koaz4q~1gcsng+*jt+zMk9^tq0NzT$cj>Fd-tg0(xc&A|Xr;H^_Hppv(=7|l zT6ih(5gdO=K0J?6Wk@~@V-Xf8K!VVb?LxLrZU@w0FBLe_ETD#8==Teoo5ZPyX?g-b z0*TD}4iYr`Qkuz;fatZQz=$lA4ml zz4n*?l~gegDk3B*n8(c8j;to7Q>)@UX7^L}a5q&u)qNEpBj{P?J~6#ZN_dQVWVtj9 zCzrJzm}?!Z$rXW}=6Fc%|MJ6&ytV$ql@(ne7#{!ERqd15%Dtu-U6;c-yqq{8IDybh zE%qfu`-<6=?cfkVb6|xb*U5HZg=#;&{(dFzB|S&3!hDYS6|toot8hSQR=ks%6(~@& zBO{dkQO_ssnC;Z8Rqc5W$Lgt|G&7 zL1xc2MlyYU9#hcJbS{z!ApHlkA|qGHcd%InzSF&_p8*ZUJrV^=1^rhWSN+h@`2-r} z^s{<(6|>xpY;~4DVA3Wk%F$95br(vb1THG|Jc=ls@OXPod{^&$@6dp8_O*dYhwE8? zr#R#{IOfM!X!ok!++>_-zuY*r$rH#`XSq3;2LUI}gH})Y3EpbVgP?MW7Z2kq zshoJxY`+}hYLphnEC!`vSaQYo8C0I))KD~Rl8Kcn=);gosuNn1R8pN#e5f~-!NN!d zh;}b1JB*N50MfNoBo!o^FYL|!mQez!cUQcI$EL{K{VJK)e)*wb!-lH~9_TtlJZ7I< z`|if6EmIrCABCIECannVPRC`89k8NynT*Tge$k%hu;Owvtpw_RD=s(Nu^FV}Gye^k zTb}=_eO&3Ua-9O~bsCcTE8eS9hM**Iox8RK#P41twMgny;|Mw43l9ELN_#-)uad@o zEUsd=Up$9igB-BbKHDjpp89PAVs;~#2?uC~N7G&rq=_?Vab2mXZ*!JYShpDiL@3c? z5X9sn$`xmf2QLt3B{-8_gl4qJFwADU1@1va+(Y=VgjTUI|08(U78HaP#$#lu0JW#O zGU|n;f?TPg_-!=E1PhUQp(@}exdT2Ej7Ed_Xa{N|5ybW&)2ViLW^QiFQpiy}Qaiov zm4-ThO~$mlEZiO+9Dm#Rp!oA^*zjS=Pkc2RnYrbrn{HWXs(sT*82#tkrO_XAu^EGH zl{i($8SIe$^h{0*>SK>Bn>q`iLxy6Om292A9uU6v_oZrJ-_hQNdk z02}gv72HCM#i6-fSF^wv;qa-32d5fS#T)gVw+hiB$g050q-mr`42psstz*c0P~~S3lZyorQ!c9btGF!`Aoa`-Z+Ooq zwfTQoK7QMkqeELZ&+aJvz_0E5`!+7VW9RoW_w71%$zso7=|F7pn~6ElNIqz43RO%7 zYR3vkoI4N>p3K9w8)l_Nkm~vW>G-INTsk-?}aOUK7 zixJDfCA~fp_?kp_u^J{*iOQaq1u{Lst?_tO?_5W0uBR&2-WT$hj}Pu$>|U%MDem+K zo5~^;Rc*n-?VGv=2fHpp=##T!aWD`VSnQath*ni(WtNWiZ=DZC1}ae4zbulInOPcW z@{esw%b1v)oLKtAnM#jT7yykc zzl`OgMS#(*jOeC!hq(fba-}lKL_}!}A$kPB;o;4d!Hf*&69q4s5#){8^S?YkeDL7i zCo4-2pE>i9kDS@qcWCyqrIM=aA6>d^_72jl7!iU^p+zEjp#mL&?U3z)X0e|jX!fL_ zS+o-Zg2SGI`R7J`+$j<8DTe(JNg*Ujp-wW|I$$@mwUH{3!e~PnBwda)`FjO5(0yNt z7K%uI97DK55h|5!a=oKf(SQWElf*WMx=&Vnifi5eOjFa zS>lsReTL^1(&1KUO5|S!7~3`LeWtR0Ekg&?ted$JE={J1htG0#E(I=_?bN5(0(}Zs&35Wjvi)?z+Adaz)aOWjYF+yzqAQ*1Ig~*m zHdy>L~yFuTZE1CEBt9V?-x8zOZgifD1xb zk}!MNfZ4046m>b)vTLb-Cg%?*-e|%sB{0ky3N1in(f}<>dYUmUODroWH=*VJ=CpUp zHIr4;Dv&FRl6uS)OodQq%syM)WS9^nM0PFP^TPEI2U37=QbA$X#C&a$2qM}iIa+8t zY)QsUc|UP7&2m4W<3JTniIeh*{(Pw&{bl|APRFc)$^V&z$&6c+82-cawEyTl?PpYb z5mvHsi)8In>5x0!?UnaFbWVHV_sr@md{WnSN=Ka4;YQM?2|L1x;EKVCl zt!}>8)Y8}Y=U4juqMx5p&v85cKy4V~mG`e2&;Kd!#~N1zPPi8m4=XfW%}rhP%x^!4 z&CE(t9M4SjPKlegCJYMtHU(x1J&c>K!5d}VG`?~iNw^HA4{_ZvXcjEnn#`D&a+PjVRvup>>z$-5Hna_jFa;sS%SLQ3C zhB9WAa*^WrCe9=Ugz*kDIf$`ONTrlY5|D#ic*_)-G?Dz5g+)PLrL#e9jmO-{9C06| zW~Pvbfh&c~mlo2oH;{#l2(A8Y&6k|gPTqUxo%bgGSiZ1&`n3Jjj_>VwVTb+V#7DKA zn13-I(l++$7PPJWN_~)u!h+`gvYloQ+%MZn+p_&P!u+A3y#?~(Q!oI)me{N^5OipC zQHbcWY;0v(WFND2VJJ2+6xz;FiyVWeLAOi_(@f_hq8kmldY!FptQNe zVsSWe{Q4VX(_P{0L+M3Tb@pQ?_g&FC(^XYaRbN^Y9BQsOci`e!{^#!g)aT1v;-Q+- z`laGAszsn(j31L?9NWFkG&4ui$2(|(0*I4 z6m9BPIR+*w?cT&hQ}&SN1(|qjgEk^F@oda%Cl-iA-e=`Wj_6J+z6|5TtNZX-#V74j z-2Ng?M9SmudBOzXhxC(t{p31vqVE_;g^&DCR-U0znAu&_j#Y(~22I)iP&kDsy)-%b zZ#P|k{Z0S&|7NDAXXdZFPMcWJsvrKuCm!B?WZz}`jyyH{YeGvw#h#|UOW-Rc7_5O@ zyU2mDb}?uH_sMq7f^7e7Qahn7+kcbPj{6 zCQfU;iLYoI&b6>5K5Rd={I%upE}v^nGojAaNkaW)3)H8aH>6)H;qkW~brDgBclN+wT}h^)89z~Qi<6-I_2B8(F%oHXI5_?g*|61!kV;Yk0Vj9t*^ zh1d&{If0MZ`{Nm$2>weqMwk)G*QO``MF}I#Lgf`K^5W`!{S6*L?v0! zyp;>`U?~i}(gwL7^Vv(pOrl5>bvh9()+zUN33^ZnL%ZkatHZ;q@{blve8a9S96WO5 z;KJHj?cHy917JA?nB|K(35z+=CF)tUrwgtZ5$(FfF5AiVWV+er~ zKDnN}UzgbB{g_+T{xgLOv!K6p!S#5*Dap(G$(`kMbV**elk3U*bxB^flk3U*f6C`$ zMrOhFxQABIc085qrL2Ij%k{|D*4y6Qm@Y0>Ea78vITEt){rdH0n-I05Mc{m%nd&Y14j!!*j)Y{JH2>inDfnT4sy)*G~;035c+@E86HwC40R?0U) zVpja2RR(5jLEp5>u>OGjmWgkS^kLG1%)*vcZDpYo`UDvB!!3FkJgT2%8NVRavlbGI z6nYr-6Z0_UCt&v_c5L3f`t;LUujVY3u%1=s`qjDAq zse*Xw1Rc>IAotZ|PB&|$it1Oi`3WyjCrV&>rtbJg#)0ASm(JFIBLh0_&+KJu8hk&O z;`lR;s1elANIs_^!_k`U%3|= z`I*@taEAzdd0sae4Ca)O%e-i!w#X0ULpOf#Ed=5g`*{?zS{2i2`Ac9~J3uA+> z#o9O0bwC~!GFHlz3SicWVofeT@Q~PS6UJF$t~?{NqfdiZ!5Wk|3w1TrStYLt46mYE zAkJ8CNuD*TtMp&!mCW^k7+L#O6ewjnpH~_3QHw@v+=0qF@d_VAlTq{ZYYx|sYWk*! z-ab9Vv+TOLhNI2bZCki`cN1_HI%kfh!EiDkqT1Im|5$6$x0CEV_Dv z0+>!X2c;a%m>4>Ke9&iUOyuPL%lDlGc=pluD@STjj`j_}M`G$EApnT6B^k53 z1*Hkhw%kvMVWn30>npW<{*A!wpZo=oPr83xNZP`3W1$34l$6l%UO6x7?V?|djA>L7 zx|lQ0oK8VXLQid{gw9sCL$}}fup;zh1<8lTd4!f1U2A6XYt!bZR!4J&t+YcKybu$H znkz^Fz>a82X3v3glquRtKh$Vtd?x~q8Q@?VXTly8&=S)sZn*Z^8?6i^I_=d{Y_ z;IG-v=g4-!7qK!#Ayl_5;4PS|4AvGV;PX}uYO^=1e!A3BFC zl%ej}P!2$1$p~4Lyb?!Q8mJwQmeoeMV)SBtc%3K`ZlatNL}GEPTa7_T5VYEKwq6pN zs@>T;I@uB5+&*4kc-`vu%R>{DTlxR~*fu5$etnBn~ zEFQe@NN4Lru%R>7(3X|sIkIWbrS2BfooYayE0TopuXV^{rU+q5MiI`5xUPwPHYhO# zY^zKctPy-ehrB{Y6FXC^iz;PRDE71!(uu_EGVDSiR*OpTAFjd-WniF&Wck&Y4H#h% zjN#Su3?U85A{-qN#AbA(v`mloi}%+~c2rk%&33f!@DDT(x3+b(?fPKiPml`_f8M2) zwNJ-dw)Rx}BU2sy&7tP5 z!Lgy^jIl->I%yDR(h$MQLNtdmI7U+{m8>C&4NwlQ-g6HE^?rDdFgx@vd~myx)}XlJBQ{ z$CfmQl;=<)eXjs6r0H4dG{l-zEg_20<~D>5zo3 z#2UKd%cRN9qwMFx>yBDlC?Id7iy9s&1YjUm*YjCdX={CbYpH8Bt+)}^rgf!x?1iNp zceZ(;C2nt+X!H5nCK|L)C607%AMdRQwfPEVRi4bkYV3&Tb2_7&S2t-NG-d-nD#z~$ z6#*L)x|G%=w4}5~XuWD*5;e+pr)B~wC!NVpQlMq#v6GdM`Y7e)o*{s;mF=kzWr+(d zpn-XY4tSv`CqZIqPeq-leb>f~yV}`_C-0Zimw7)SV9_i1I|a!lhbeto?=N)x#lX`9Ihzi7VK$5UTR2{th*?lFWW({ivE(@Nq=lfbLjMEK1b4-et$Oj)n>sDgj8dAqGdbzfovz0 zb6nY=1v9-p}{S`}Oy(e?H$Xo+I8%`j*ep>091U%#_a&n2Gmdjkni|es<#l zrrsgj$)9Aq&Yxtvu!-`1ag}Qg^HmTd1R?dURL_!Q@)TD#<4#gy@>0YC#kb91ENj9t zcXa0B>=g|B&8${b%7O$gQIG(s4VHKuBLsyz#LurB_10F2{1vaizP!3I-{pDQ{`JJu z*UEsKwbz!4LKXSNzGF9F*{=s|Sc{YUxMC+_CK|KIqg=Yp9i~#&9BU8_O$Ic|v5p|u zegwn9iS7-+Ssti=^aGEgo?TkTJGH9)_6ycNw% z4NsA&R9QRIHdd+k2FZ4h(k#oKahySPaH?`%() z8M^XNIs;WS>BwWKJ_98wtWocf{!!D4+&8UTSNNSk#w>_=avv|AklDH2#6R}WSBT`VV7w=F~brJa;+ z3KaELq8Qy2BBf2`!HBxM^x$<4Ik4PQ?H4h7CEj4eJ8!5OTpk|YGgNiMJD)EOmF5gg zObq0d21}lw&z$_l#>-|K8fGus_>0NR`5QB9yW;+%3(Lz3NB!}x+RPgRP}WK;~fOYTiqh$F-9C`w|nLRwN>^P=>FTa-_d1qRktm}%<1 zAYS92Sed!&!!7YzuQRQ1s+Y2SP5gqM-pTQS!I2Hwkwn&uA$D?jj#a=*X)9d_qr|Gs>eD;}%vswqHN@9hQ!RDdVy7Fm@4o4G|2~>j_@3U7h&D3bOrxNbv5Ty$t(} zI)z9MPhtTyWtQJ(fi5xw{SE4YCd5p`lTM!GlTxse{wVTHNv<>(iv8(<5AY-s!>M4v zIsqZa?dh+q(e`aWkht@JcH;JO-%|4pJO42;|MIQ3zO2p9EM42Gu$|RbM12lG198;I zq<2DVeT1rOveufiJf$SmD?Q2_O%lsx)QnZH6)edN*{5$0^`!-ngl~_2y=(Ddh7q^! zra?YODJLEnZb|@E=6}knqSes2x`Wtg2|EXM!k(aZxIw*aY_M9TRcnaG@&*%|`VX{c zRF^m9x9#nl+&$U1w=KV^ygH-(K>w!QFTC(XAmno8^gjIW`1f#cj>{DaJn_N{#FJjg zst$WTIPhTxoHdGVp7dE%vZ^_5liKy%ihQhEGJY&y;ysEgV_a}hg731>rc6@|gBj9( zV$~kWbq^x3v&O@`GW|BDgHBr(mno1K{sp3w>^e&%3 z!?pMj16kRdIVs3;7C6UBAuP=%1{4FDaU&|?nOJAAagaB-du7j?FMor_?=AIvMtX(= zEk%oaz#yJ|_VbmcE|;sU>hh)P;D^p&On56wo;$H3&Qsu!TD(4{l)XBw%eWYVwU7l@ zbD7G_>bvyNa5d-JEy@ZLX}DcO=~#|8$E~fbd?*qq83=@yJWa#%J@>MZ@a7xdS5r#Q zc^r@~L$C5}D->#y*XO?tX_NUYNLwW`8cDKXJZGs1de#|$LViZuPa$ZR&RI`4H>N7_ z1moAPx>qmT>vX^Koo?q|yYs*P3;hi4O8mRlv@7u=^mHCQrJS8bt3LuZg?mGX-{0=3 z;%p}Fnmy%|XDOV>kT{V6oB$puoRIU6uqOm{dxP^U-&?`|oaD9F&YYn{A@a8ck1Y`R zyMVqr(AU?KVoh{4d!m4t#8NTCl={&JF}a=~_NQO@4qnfBOw8l$G7p3t9wIcpiz1jysCu|lTU0aBv#l^xrJStsS*PH8m}^pS#zExbc)Hb!%u zzS8;>I7xy)Mvys8u0FNbF^$}Vf(g_>3>p+npapGRqOBcAI`Tklw2CSJK#3^pDrGlO z7?9y1Ooq{`LnWufK(PLDZ?8WPSaRhzRaP}s=jT^9RaG|SyOvWL-jCb-y&E^axUpx; z;VnIR(Q04(=*-N~xUV|;+H2NtiG=16_uyV&Koe%X5!8a+O)yG&k1w+i3)-2ZQkP6S zDHxEFAEfj=(2ic(g;5q%@UoEZ04F(%xZpo;PtatD-dRLiQS5!Af$&|8f0U|&K49aOFL-z#^POi zMM5T~san;bW9^+T-(=T6ue9{UhE`Ty_6I)k=z~pl)m2Zgy+(L70)7nwUeF7f?m<`T z|DM;RBxjn;N8dhzb)2}TnEEf!xaTtbm(T#WS?wWyWKZfbb4%z+p6w#aM#=X0zddtm z)i8m1?x`eqCRuVy^OB}iPODu@)a|(h|Ml-MJDAw^62L?{LhT19fK+U|m}FIAD;0#p zazCaNoYGfQ3MM;{3mR8vyNYoYtFsLa`D%5RK^*kNQc@J`2$ZHQ)!icFjzZM?ZhrNx zv-|eV{%++&q^T)#0_xw#cW&Rlb0HM035Lj@IJ=+@EFwi%l@TGHt0W9q7SZPn0D{L- zgFmILE-3{UtgCa1#8HShNqwl0tBVbUkdKePy3lway+1?=b3}#`gedV~39u2UVA@P7!@wGnc5F68VQ+vmxR;ah_`YpU)Fb(=+6vc>gnY14VpoSoxD;erhDOYy znc1o2ToYExequH#%r&JRQ-n7~0a&f1)RP8?p=LCs9$5s9V`U9knHY}Ze;75*6x6c7 z?M1yG-9%xOc2)VF+Re3t4JD4by?eJi%IXKA^}`L`;`-tGf^ttrhNrwh9kWZicaFbk zcYbGhv7^{Gbacy>qeH&!*;SqO2kSelvW*i=1FB@mb)*y%fXL}Wg*mb|aKONAWl=SO zU`qc=zOw2E+!TSbG#j7HI?ZIHR zuR2KCjrKC;Q>DT5$1%^~52Gf@U14KL=B{RiTQ$!qo)kIp=sJVMB^uM6Pculd;z>>n zmiYxhXa`IG{%$ zvp#g1fdfjaFyCOB**V>Wh0f;lxgXS7JW%k2y*N36k6GcH+Ru^PN>pXlQndBQ{UmfO^1iFf@PJVobik1`VMQIiLYt4_WHE6v~c5J6DZoj z&tDtEXsB;T;5V)lQjC--fS%DxYetUZkvgQRILa!EC)Q+z(v?Uz3aCtoDtVv*4i9Az zF}sZTW;vcbk&#-BDN#9L3SzXv<7@ zHO9CB*g$Xd>sf5f$yan_HdvK8G1up}*m$JH1`4?&xZ#pq_u6ss2Oi?5zpSmTO=vw| zPB?(CqDPDZv-bmE(;QqlIU7^xX*+r;YK`f9B)#TTwqI`ff{wd^Iig>dE5 z{HIJf+Wq&S{6VpAps{MasH!kiyK2?G`^^XLI5JjT=3Oot*nQ*jH`XRF7d_~kU+@li z?C_m)kT1T6#dpdPjDby~%!{#X!u4Ft(d*eIUI%%SSP90G>|NWW{p;$>hIb9Up~WU5 zdINnF-$h=c=#5`|FT-_2>7aKqY6q?M0rbveTcU81TnSRW+w5J6E6iNgsq7Og7zFMS zSYbyjl`Ngx?T8h^^hCsPG-z)*QSpl_udcI4j-7ZuyS%2cYG!#74!ZBZ@l9HE?O}g? zDZG4$CVC0|{61F6N?Vv!Dl5SpqT;!g;D4--!lTF^Vos3A&fA9(U`262j8rGB`U$u;hJ0?VL;Ic#`8MloS#(&;$9o{W((8KX4n#l}hZj;L})i75gu~TU`ED(|z zq2#B&W2EpObVQ=Bp1Anp6RSOQUFGFnb3LnR@t&UeLH_BV@Jofxz&NQ2pbc3F2}5O3Y;3niadf@%c4wn9@~OBYbimS$qFf1uxVQm zpvjV8Jc}0ycvj03<^^Se3t%IZlk02{|B*Ph`kmG3qj2=zM@R3gzh$(9E(;V?^+ zZqDM(YQn_{Cp-@mp0{qorG-NK??mf`d-31cPRl^9c{d|Rz)L9lnOeS#_9Kgg#-UiGjF_fkdyf2G7vLN{ z+`s4W;XVKO0S=;F8#;_d^VO4w51-uG+&0kG{1<{AxMLUj&{05~W7+mMtq>-}|BwB% zYAJK8>r|9v0Bd4zl`2S!5!-h5NbVM(bASM)#lU%_#VoOyc<>{NxKM^6EuwBCa3P>@ zL8-+uDN9zvqGfMy>%|w}y3M~cCp6mm&CbzKj&TA=z>H_l1b#810;`UPer!24 zpb&HK2SvcRXKg`*KTbw6%q6 ztc*}$B@hi=N^_XIRC1R;_)As$6R+Yj?w1iPyq^&)xE~zFXcza(_9s-k8<>RJqgcbA z7x#$>309%87mMFNhDDyMk!ZKy0r6zSG#BYKqmah5vm_}Sm%!puAR3;;M|HgzU6*gSn{ZVVXz$@AQ1ls{8<$08rU5_o&4`VTWG)a!hWl+ zV8VO+Yu(cNN+Z7MMpxe9kKADBIZq%@ zdH=!-_;-##o}(`jmNJfqFh(32Vf<$TnejcBiTIvo#<^9)H{5EW;{Qc_j|YR4@jXKD zzYdg3oPj+I6m5;~@u*rr)ZZEbCmx$H_7bD0?%$60f$H|F_>PL#iTGJwI*{RRkGx*c z&+zt)8#wZ5@L28^kY$^uET61ZC?0FZFMrE=erLvg55tAR0)UdO?V9Tf-L2r^1nC}GUGrX6a7`q-=Hiu%FP~bLV z(v)i?Iao;ha=RaKLDpEIsRQo*51mPh6r!&j{wRAF##Ceb1U(YT95iJ$OmUVaS!hVj zW&(w@?aKYEQey99npQd%Y#JpPs6)%HAGAzum#dwus!%Lwnb&G)ml#GrwLM%xr9+6J z56L5kw@AR``|XDhx6jnQVdYqUu%xsmx4*YPzoM)-Yjb$!454uO<my&zIN$|-RRDSP{xp#+oybjObm(t)gh?2~it!(5|L zDD|A{EX+KunbLx%_Pc=4aK6Fbamyd)-f+?w>98E>3`1s~T|dk-7@|!(yJp`a#u=ek z!=tnlirc6HZ)kieIGr*;(*}lIXbh0#%MHQ7x@rmSti$_wcI8`ED>uaXEX;h znj;3x7(W@FEpcA>#lf5Dd1qlO#Mg=_uPG76vivm>=f#j(M0#PS7(2k3DgaL2PaR$2 zq}0vL?DN0fe^qnWG%|wCoWRCC@7UAM$-Dg>d$dbAZOwM)x4$js?D^+s)ns9|IBrG_=dk`n z#yTneZ;v)bBsS#`PCn*Kj5bS-HVdPLT~Cdc!GkiyRt<(rj+mpyBOlO;A3XAbBX;Mv zzO|T``_YfEipW?z>OzdgQxX;g5*4Edfu#a$^(f_dy_RGV_#M~iN`ul~M^@Dnb^Wky z$OEtDOpyiITi9`K$DC)Vh9e#4qFay@Q+_UIWe9#K7pOf?9Qk0 zZ|$|Gt$p#>-ar96*~^i_=28$bWrbHPUv!RHyi#Ig4z?RTESNUfbK5Atf^$bZk;YY(g$2TOi3KuwJ{Mj3uk^ zAcR>gP*OORjE&njvKALrhysC?6g#{^g@8zrrv(e63fk@xj70lU+e~L#$L2SF@v&>i zyV5$xuXy~e+Yg-By!nKdmN>9w%YnZ<{4#L_21-ODQYwYdjQoK%6pVBjBV~+a31iL? z2_mvo&O6eSE!?eY6Jo}dk33gKDMCe%>S-?Yj$DIH%MwPiZYYN-%SdyWC1RK;A&sDt zq{u}M^!a5d^j#laX+jt(LM<)Pi!$DF6vJV@i;q&13(Eq98+{}xVsOe{K`QtbD-#!@ zEG7Afg(wdVjD>)*&EQK0Md-;7z%V6akRVu4Ee+BnL%==iC@Y}S9UJWAo&k)z?rjT;k3JZwbKQ2EtGa~InV3NtzsDJDmNUo+ zM7!AkLs+$F#nNmGm{CSyXW172|3!@JL7S8nNK~fGK;tI_BdkUXh{^uwfse|#*R|Jf zy_G#WgjJKfVlsr({EnV$PT6z6>^XNR{EE1bk_&Qlz^}M}YRGmE`IXGb(q~YGe3<&0 zk^)UKG({m0KB+E5^LB{Q(vm-nxbd0_%vc51hYC^cfYPFjoXussSdMdH{ba1Alx`UB z!I(}jw1N`c%QPM^6w8)rw4*_c0#^|h;bO0-6QysRmb9O0^7d&-+p1ynt4FNJ6B2_jfTCexO^hsu% zrDIJfg!K@CUzDmKSG|MrR!=;!x<|WBYefAG6aejA030@-ods-ICHrzxlcAZ`(Bn-c zO9@4?is&_BWugaxvG}aa!$=VnG82ea+JcVWjfMyDc@iH784L^Ok-@ND4-t)wLRHd4 zPeq?)oV_%8p1rN0IH#&DR5MV%$}zy@+Bh)ZS-QM%*_>yzdv62$tXY|fpCFX%r&&4l zy)Iw1LJV01^sV)0S>4raCq~r>j7Y8S1yq{k0QL@xRrpF0P zcAZnn;&E~>|9|a$d4OF-mG`ZCU-#=Jy?5vJzNXWAI!UL~Njm9loqYikFoXnxV%Vaj zK_n<5VH`1{NDRWDFa&pCX`362bWiVWc7_4oUos=D{St-Axk zKfX`G?W%jV(%g4(47qc4i`g*$Ib(kGa})D3`a0%_cY!9_oc|`D z(x=ne78?;6v^Zsc(ny-%jle1}G&QbwlFNy~lxa6?!w}txE9{-*mL`1UH^&>5EBhVt8F`ngHs*hzSI*z()OCpV5A6nECvGjnnVJI9HN+px3X zGr-2Npi}NunvJnW`do(lGQp0HNwd6PKPOMu&;N@^^WPuwpa0H0Ux{*NiVRqQCy)Ve z@&^Uo@NC&nsLHvM=4!Q56T)&z%tgwyV}ej1s|@T1DriwN-;( znl#H8oT&9HY`)IWAsC#RUQLEuv5U634Vj&|7#{;e6FRe=tWAuGQ_nPXmmvNv922+U z%*fOZM874+#Jx&fK7mqNoZRga-d4!qf+ppg+4u#nwK%QkU#kTlw#ZeRM|;!!LOPT3H9Shk5oo!{K$jTbu7K89xd#SOT6d z3Xuu7(GQ*K#Zc?=6myNWA|qN=WV%Nb{ExnO5^ zUtf2wd+NJ(e`Ck|@>to)B{NU`!iT@f@Q^b`OyCN8)W)$DIXBTgndpy9=|H1{1zkL* zr1CI?^=yKt`;p5`Jn2WhEgB^eyb?wd73q;Zp+Kl6(b~ig5$~n?`NpS5B>c@#@H47| zA#k8rMi{X->ASp^iS=D_zk&ru5 zGr)uabec=CMRsjh(8rT5IsNoYPH$qzequK}wwm&jK_eKY$vxVR_O3>I)A}q^T4{K4 z(Cj1eS^BYv;8Z%yPWvonJkmxKpC$F{_8m8k>|08B ziXIS&iQyH$Wvkw?-bSBVzh$#O5>v=BkTf>ptIqdZ@&w2#Av(G%n+5&B)OV7*(!(zH zT`R)-95a>baZgjIEzIfxDY--nqTBbo)-VGKAAoI|ZdhvaDeq{ZkdoNg9>Wum4`f2CHV z>9EW{`;5?`A)R%rhlf|!b@Hf@{QAy$t!G9{?z%p7I>>q3F4%USL}oP%^fYFFhT23U z=xn}6Z34a}^xW^TXMXUU+O&RtDB(GFoHNf~On6Q$TfhIZc@E!!?2wf$J6LgHtK5Sk z;Kj~DcZS!~rpTU@(QE89@$aA{bCj6_Gmb_f6})^&b%Y9Rf0~H>zSB_bdrp$Pdg$WK zE3;Q^{_vqIt{AyOWh-^tx30eWTk&=3gl~VF79-c{Y{mGiaK6n!nAUd~3^!vB1rJiR zrm%~RD`L3}g?8_FzC+7aD>PeWq=zW@Cc}UcqcBx~Ei-zAVG72_=(igaL@nyozGGHr zuidcgXOCX8VrACK)w}-n`s2^M{O|w%a&@{o{^Cn7y*PeT{PkBs6ElI?e9=e|bI;KX z4oqtA08SV!UE_R_(L9N}g{3G6CTD1b!OamZz8hF#m@I@k?Bexzt&xSBR{ zYBUaNEDlVj0RR~s)Bp#VNfI2Cq>E-I9)7+tt7=ilyyN;1&|KHsGSr7~>mZ`J2bT6^ zL^Mm}HTA_Jw78Npn=vq)@Vbx`E}TLIVbOvaciBG*i??)(;bujPwWZ7elRUT@nNEUQ zh`UOMrGs3$2vb-+%H*`^=499U~)IE!`Vm$=>ymC;x5r zvYan|Ia163Z51ud{y0ar#Og}#uGhWG&gFB&)nTVt*d^F44!yk^z0LI&`OZf<-;_A- zkTOzJm|f7@+C`wdkSheJ-{$MCoKSpxpM+^@U*+rH!ZM9-+35J?+=nIEo|1c!MNuz$Y{d?W^P2Y}lzs!ed~4a_d_02^kq04C=7&ib|gjxWxLyAkxb& zcfc53Btug#G@Xm0?irOcN=H7YuKiqA z?X3D!Pgp$sF9TwOUut(-Vg9*O3t|!Y?Fa?G)o)dmOl;#|Lex!x6i-k=F+;8PQGi8}a;a zbgR&gb!Z3uburG|B(Hc#VJs=3;(-sDo*lc29KkSAXEz?~#dRYtIO?KkK?EceaZc3_ zJSfi*X_5|cba2PXeKZL^JbJC9H9Qk1N@ef<)Ws3EB`l7Jf787eRO+v0Qa6HbJm+e) zRDIul5TmOKBND4)9p65&Q(o1+W|T6xj3!Y|pZFx~ud4M4FjXj~)!?3bM!Fh05)U$i zVybrt7o9Y5N45dZX2|L2bVRD|^{ZB`=ha$U+sdnC(xehxYUycPx14s`maV5Pn%=dd zYr6b-cVS+BUZMO!pWUEVsfW;Kd0hSBqG4Q$X}vi{9tLA6+yZC?XaNKAJZS-X#XnK z8v`f|lM*~uOFb@#9Sg6F<;sY0eZFE930>$wHT7c;F9yLSE}|?_ed@mWiyvxgXsD{M z&skPDJhW(eaqZNKevOZQlbzo>lti8FR2<}Mb>;oO#33xjh*H?h; zyShVIOW{Dq^ai||qeKN}?hDf-n8O~VCe9!0xN@Op=&b{Kks>(DiJZriaU&oSOe~0p z7o?#L6p(Y9gy06db_FNfv9VaZ@nf_f;(HTezmDv1R&kO9z*f4HmRDH8!<2 zwYhCorIGT=?(W*={+^buEHArz>de8;+U{6gO=YBN@*|0PD-=dK*Augj^c zmp>dgUjZF`7cI(h7VuB5h+s=SDNBiicIZ7_u}=$lN(7Wq!=OjVUGF!Se|%U~ejLTl zT>5uQ;!lDLd>&YP0ArIJx}TmE2S&_*5MDKiiz->W&!bbuYEUOhNk<8N1SfLzRzm7L zh(}N0`ZX@^Ts+u|%#FBi z*Bd>+f(-4&m)Hj}JNmh4Dh^3mv9_zFu66n1#migkTDsP*AjWw$fXZ;Gr3~ml#CG0a z)zMcKrn}|qt}>+OPD>)ZW6lm!9whhZo9g>&*AYqXYBFq5Dh*Y@fK4a4p|5K4LTj|- z#wPtd+vBZE?(A^{H^$Np7*G$XbH|k2>059lk{i?ONs>E3ZUct89)>m9C{ZHn9JZ!S-`g5FBY?7Sbl*Ay|@_LjAT>@k%D=m?;%@1i|p=?Ljsk*p*1l_lv2frbE#JpewS zHH14Rq#>lM@m>r-Uqfg&JfI!Jyd6BCokP~cXlduFF{%pfU#)z-vAUh0k3u1!uS1lqF$v~_-67}pr8eYF#ro+C0O`4M-wnr zflpAE1Oy3s0+xr%CP}dGD_U+nr@pFsa#daKPWgLy#9sj=900_fTqRteWaDRwa}kK60$CxW{{&kI$&JE2TL`aJ zA*6eu<7wfK-odypk@j&Hs7m>63Z5`PSIhx(NWC%T{cWI9B)w{zy`Xq@{*=0!x|aHe zruy2NSa0pL@;TGy4tLZwb*)s}J8N1iYAdnj{p5kk#W^Jv9qly@(>og5vLab+EjO6(MY1y-PFwj5=?>10H*>LpKPI3VJr}EKL_uC)$q4$$Ws?OHobI6`nQNh? zP+IxEk>7%S45DiB4WHaHZQAn4>FU7ZpZubK(Fd=+7CnCxdgD8Qt&!*R6(&jc6g$Mo zwoq@>fS>9GNi{xPj0PvB>2gBAmOw}=#aJZGJo6ULL#&=KUL!aoLbkr@?4MUOYf?*1 zU427UMQwDb;1^%b&B||XnYM7b!FOY2BvxCRlk>pfNUXlUuWuN*_@-$IIVQYa!J3d@ zEl4JdUfM(G60LVCv)Hs0@LLHjp2Kk@bkD+Nu_-;V)0ZBXpPk#@+B0v({Mx#@I$Ub| zs`)Jo`#Xzz*3D3*Epw*NS~9z?GOw~u{%|zk0!ld`cKkw$tVBCL#S3Jb1L*a_8if|v zQx3$C@2l`y)O*ff_`esdb9XPkXejH;c!Po&6J_}^M|I?G;|CvtgfxC z=2cT)UxQ0+ALwju%ZcPnt)JT0hd;=+HFpj?8Y{~wi^-p>s>*Z9tK<(T>ubX4wbd>= zH(GxYW2ggvQ6`^<^ba)*`hwW4So%Tv7@6b$yAq>dWl|&e+?*WNYh%j zC9oXLivlGm}S%^%3tky56fS1-9!GiW|F^)eDO>9i@x{{U>i&R1`wt8MGg8y zkGqM=-$dLSSNcTduf}$&_@(?cEg4__rf-jxzkywxDu0Eeyk+^DJ*N1D^aY(9KwpT3 zoI&~qup8+MODmAR(7r_Tf)hO?dsT%mdx4`{F!HqQeR@K&H>fe(`&Qb*QVyhTmM>hf zvkFz?YN*E5P>n_Odg4Kc(M$(fHT`1w{`(ZhzsAKMvN)CP=r^+b0^A9B-RU*cOn-a> zI@#Agj?m6NQkgAs;RLat$CugZaIEzkE3+NrSx+akF-w);UOyt4J(k4AOgUCaxj2~^ zYtQ~|bO(B6s&gj(M&0L}Ya~u3fAr0?zyC7f_XqL)QwiVuzh@}_SN41Po!>v5@V)reeXvHZl}+5Vp<)Svo$B7UAvsGr~eEa7|q_YCd-kCg8d%l}Qn@2U7n z{5`e))ZhO-0Y3lt4DkIY>xcY+-i1iuCtxaca^_E;?ueN`?p~^F>`r(wjz_1$0G6~2 zl*Lp__36WlvsZob)c7BEso&Oq?}tBBpKUsP9LjAP9d!rX`{>r7;i}`E5O7uI4b-TZ zR~F4zO+Wd`#(VDCD1ZA@w`%K;zoznL#h;G!kgV!(1?jis$CC59u|^swpO4B+{d{L zj1~b~2pda^OMqsQc6?|JNc**|UqFX}mfd@YR(E(=hySc@$?`zl&k^!5>j@|>T|KBN zT+bJ_zNYI@_kuFKEOpD_KWBLzBo5S5=InA8xEG>57?<1+QO@$b4_Ti5E~h*5x$BKd#GB*Gq#AY*kTR6UwbYxyx+1*l^62%kd7|ffS-gAqW|iBI9tG;358T z)u8cU%8kFV^?+Y)nR6oG-K^ow3(5`PB}>DI<5E&R=E|g4?Em+?DR!2CtD=6f0`G}{ z*OZ$TlpDaS%LTMeW-Nb7&=7xKU1ZRp%RR6){)Pb;FAn|bMs9{j#E#VUV?g>Og)GhOQ^>uOu?I*A3sjx4LV5C z=#RmjUV;pL9pmSAXdi!p?t!Spgx~N?e#1Nb4OnoT%W>k-bZEPvvKT~_thKuj)R)Np z4IohsnWo~Wh89m(C%xw+HGT2WQwcZj^r6LI+>i+R7e9|0HOGD!H9|TdJ~?4^UrJ1N zuwKn_Y(tYVP5dF|os~ra^xSjk0;w8#&BqUFCjOi-b#ueEXF2We8uxP;(P(=ET#{2X zM<-u{r9-|Z6l*t>u~DHsb4AyiB^^=Sw{~XFn%VVRhi2Aw))W|8jtFV&?cFfc(lBRz zZ)xe=Ws}?b>pvY(U;*miXzO=_`X{4)EHw+&&)`kOyC5ia2%B6pqEpxZc_Fugn$EhJ zLtE=-uj!e&wy)aIysrP#_5E#=m(49L?Oi{op=D@8@7|#P9A}w(touRT{>GqwY*COP z`MH3jpG(2}&9<{$kVj;fza3fw0yuwiXJc7eW9Q`VV+LDV29N1J9~1%Pt5NBRNmXq% zHEmUsHdRhvIeq%d8I__ZQ2r&0j!TB5d?vwHg~u*YvjdA&ObnIIDO0~!EZ zajb)Ybi@n*%cTCw8LW1C)X(v2s2zryZbE4lT)@EZQv1F>uZud#{skRsCEdD{ow`kI-ovG$eQ7cAJm zs$<=(A=0ap#?(u(_+k{`sL+)g`s6n_E+Khjv~LJYCp45pC&`Rxwr_8UtFz6SDP& zsfw)<-JuW%2itbgMMPW5_7OE8Xcg+1P1%u#8U5A0OFP?_&ZylvciFm*RofQ~ZC}|I zYn@qxKHRQms860T&#mb`YyGSf<~KFW+c0b2#(6XMZCQTav0dF8&R;oq)3W|pWh4hW z$mlOsp8H|79+Xi4oy)^NttEJnCe7~khu^E#52N*?zjO}ay%GOC>^mWp6udXG2k$}m z{gPUb{XjjZf|GkVu9#z=?Zq($l!4qMC2x4xyYtOI5UYpq{>T{b^Z3<6d-lldp3?+q z2L#$EM)C?el(lxQ*Aly!0^*)6I8i8Q3nUL7aXS~z4n>jDOU2nD{i$q2Sknsz!hmhvt;<^&flocW^psxn)m32@^<=8{?i~i4@fAB2)iySxz zNYF<=Lm%ya2O;6Aq%b7tas8hK++~VTS-N0aHZpRJ{ojxW2!tm>9s*n(8@i_^3fIIaYIxY)_s}BzoBvSc>4zNDa0oDt{FPx0Q=5g+r?@?P5T!d4`|Zf#nJ&x){q4wv>)p2p&X$CFM=<)*!<<~Nd~54PcR~6=`pCB=cTPuAQ!(u| z-U2RshUghq-SNHNorkZbL{xc{h#9}-GAXh7lD@r{Qqnmzp?V?vQ178V7|7@7YVqZS zYEAkQl>*0TEhTd@p4{ZVMXk-MdpN#Vt#{8ne7y7zAkO@42*<&GFh{P+l|XnA`%rtJ_H}Y=XG5a0yheK`+xqB*2uZof=mY zXeTiT#*n$4xo9WpmdgysZ6_%rsV|cI)Aj|ns4?RwE+kBOH87w#1geeZA$dp*eraRR27y9EK%@1L0skSF~x*% zrJ?FhXlHm41!6!MJeUW=k%~PBP@2XHYtWPx!X84kLTybd6~mlvD>FSV)d1C~#;+o= z^+Ib2QcYSvg_>%>fkK-nNs%C9%pMwuK`t5vwySkti!Km#fP)MrVIGgWcF=fcusZ`N zX`D%SyVrxQQCNem`F$;#Nv^Xr6{}`_aLUY}gxYe)aquiuLu;Mb&=r}g)QIpaEZjeW z6siY-Y+NH;Sas8(A##tS%IH$L4yZE3LBmujBp>DhGR$=8Vfxo~z-I!@i30%I6M4b4 z!5we95?K&$TElTh1OSW9V_ z3<_OSTC53YGkT=a6^=%q_u-JSrpK3eAAO3ME@LfvRGN$3m{NPRMT z689fDg3*IhP_39vQ>X5%1UVvgX2xhr8$)AgJdEnDOOP?+)HW8MOJAGNp_co?@>2T` zZNtLNgni`S9<^vmm$|kK)bbYFHb!j)^bRMV!)Dr+(r-z$sWm*h!U{rTLN*o_<&3;U zv}eOjl6$d$=M!M0z>3b_+Ue3Ot5o5|2gI1IgW9xxY1#pbT6@zL6Mq(xIc%y2JF`Qvk9eHh{ zO=zviHZ9Po-vJ&h)aBPFJU^+vqtAnbIy3QL%xH%=hxKwmhJegz;nD-m8J;|(VeQ4* zx(Re@v`g1n1MRZF%qO4*9jx~3n=LTBg-(GXgHL4pIXNwT{fHTStp-ep& zkf}^<+jER-sP(*5YMFH9qfC`IdL>keM`6!LomT3P7EV124ZJ>}KfuRn73+0@pPfDz{Cim4 zeh7sbE1WX~t|@aL;1VvyBNp_uFeh3(?uwBGsIeWmnbosUbB`p=q&Yi7-A()Rb#16A zzIS+!>OM3K`00&d6NDqezi%)TvUnKT%b8Bj_ULt(*1m@q$ynX}*6OBdPo)sEg@=pX zDPrHS7cFK&_I;w)C>b*{7a*8vR<{E&@G%oqQBy!)Ql^iY#F^d*F~k1M2Ilk}6<4(o zYT}*vr|3Y$iI$-7d5O4aVNI~jx>4CaKz|dJ+9~4A2Q`BZg=Vn!%(u`4`|x*&FO@6I z#I7{hm-%c%HF|#FX%Nj`ctsBieS>C<1uNcP_#A?AwTDi7ek~^m(KbaKge|Ch_)vT; z{j8!@3C(ci0aimZ*uuup3_r)*H#iHRW-wlIe`?nd_es_Ls=b`}D>cELvUU$@dm6PJ zKkUAOMu_eDu=xH3Ga;JEo*2#O83B-s%qW0n+$o2P?Ysa-zF-EvJBu0mbpzjJGG;u% z3&npk$5MQ)Hs^txCZxG&??+lPP zrs-$UI`Cy<_7Y`^a0PHk>0k06a>_%8B=#b!Ts!VP&4HvAZWD$mgFJsuo#K=TVw$Vz ziuG|488rffws&%XH~75`2C1fzkJwps0|Cd04+ROrhlGPA;7@=>FdCBhjOgZQPtT+5 zD3?e@N-O$BgyIaFa;LzTJcaaOqz&ikfzgPMQHF%b$Vv9%Yh{2=Wy@!U0?`gevXBN3 zfg6ISYu~S1E*yC4(j6qOD#vNzm?;* z2)H#-G#m+rt5N-k?-dFKXJfF8`wEFvb2n+Xk=6P1q*=`Bo)sxW>~bc`atzH&X#fzr zR;#k|5g4Wvw{B%EBFRVDa*>hwWI>i^3$JE8y`7P;AqTpBc6P$bN#NDJo}(KAfi2Jy zL9l9CL9CuYVQ%AL*f}hWsf=^IRwZ3~$oXj6@I@^x3XoDZG3J9Vb1f-ag<5qC6vYMn z+9FK_r$Vp7Z;UTY@S4bP3_a1ch_Qj5rOY;XMU5OYmU4AZvS#f+Bx>Om+lM|BK?1xQ zIg;=61#}C%l3NCNwc}CC5#37emFRO#@Oj~zhpf*{3l-otBvS;p5g)gDZ0N!eQNucE zS|`h0TPI-%#tYBqu~aKiG-2ETiY&HO2zG=LC%)HjF#Fp`PfbnW2W8GG?#!wqR{%kY z88fN;fHjlz=*^#XJP-Lh;%?FFx`z#)ke;?iq~;fzZRoiYEvhtY^0gf4?K0Z;MTyX` z9~j%KXWY{F1NSQ<3>rEfiYjKcm1vBXG5>TQnIWL*Uk_$I6r6~U8A`em1Q>sa3kLOR zZ<=*PPz_lK5y7-n_Z;d!;@&F}+)a`~fP17BD6|M^%+i+Mt89T8IpN+Fh0BZ}GA7-} z)V(z4H#+-zpcOGIkSq2a)gmL^^op4##OV%V@do2nDL1E|c+r~X<^}IrHg$N-MJG-l zp1SNk3*uk08Yv@Lq`dGs2q=#;wAkr`(TF7ozm+Ap*eAY3{#1oQ(}ok z=AzNlP^4NP!06o>|B??QibT};XtsNzw*g~QqAyK6iBwiS`A6`^m6Xpv5`uu~t`S|_ELRUJs>xhNqQ z)#sx3ash+NivOieWvQ&T_+R7?Z@bm6R>Yg+PrPY``W60IO_6G_)wfHO&Vzf zBWT1gklcn~rk~uOZIDP>#t2O;G8Pp89?oUi@)KHM%MY~x6-aCaWE!ywT1nFa+Sai7 zr2(LRQ$BW;C1IGExWMjZe3*@$z#$93RzGDK+XGDulZ5n8`q92o#w;*UU1D-{Se=Kk z5w23w`yO)rUIcVQ-4*{BwbBe&$P3xtM0oreaUG>bn@Y!q&^u&hx?q=gbO)w33-$_8Xn=%hY&x(kQ^O6fia}IG4klg$cHb)`e90%N}Ajg4}SwMUcmYs zXh$cG4&yCGTQlr{uuh*r$s{i}c57krZSL(mi|9CgttIk!gt2a2T)VUB7Fm@z`QXy%*NvD`}wn>+mbfrm8 zGU-_+eV<7`YSPP1y4R#%GU>NXdb>#N^oLeLJ9VYEI z>5xfRoAg+dzQ?5JoAff1?lbANCjBRq-e%J8n)D|o{e?+?ZPGtNvs2IX-mQLv>t*mM zndE(*D^i|!WCI>~@Dd-q6ngLmAH2Z_6m&QtRoG@5SYHow>Pjp^xLTgA!LP?jZYO^I zp!~W5zpj&KSK-&s%d-}zKy}EoyYSxqk{iW)RNlCSW`WuvIV^%vw;`uhbt=Sk+EJ;b z>Rw~+n~=8Qz7J^+(z)h-p}Aj%bPb+wLV6t1lg<5U<{ot6?8NhnkbV&9rRM$<=Kcz# zSK;}7q@PFnRdav9+=EV>yYT$`Nbg7bsJVaK-2W8m^Dr%*m19X>z}=s4jTYanpmQr& zqKXGU^FC(o>yWnKz87f+(tdM4XzmvyU4iEtk*-6!+1zh4_uG-~!1G;5&qaDM(p^YD zX6`?U^h(@chxBTsUo`h$H}^Lqy$#PFKza|-hmbyi^f7b)Bm|s30swozbK7yd-*8es zE5q~f`{8$5L+=lS^081p(>q72oN!%XIK%aZ>&o;_Gz4?FE#Y#)b!B=dTvw)d{+i{e zCn}1HDtJATl2LOC^SJqAUg0At8Fk3M9v`tezl0I{dfd9CfuGigQTjZx3kJ9_A-{JD#Y4|gh z?{tnHjQ`y2^#1Tp=rnE(wD~5OGhAJJpK~&Dno-w zEIc1Y8pC}S(mJGrNL!FDM%sb21!*tR4y64^w;^4DbUV^@NRtKV$MAdyo_`YQxkz^) z-G%gAq!%OoI?^kV-i-8Wq{#yGF+9Hw&!0qk57OI^h6U)$xPJ!E|BUoGq|YGz4btb3 zzW6tRst+tkQXs;@^8Z_h5*7l5pMNdHL_{%?o-b|LwHWKhBow?82m8A^L;Zv z-#7j9VXjl-*opVV^oQx5?;HI2z7rtdH~8~?CqTY7_+c35`%Zv-_#*ULG{(>{q_haK zJ{PjT0;z|z#@sg{ZNq&Z(jKI9&HX}izYOUbJl}-$IHV_=`_s%l^_QJ^ei70SBE8hy zf5O~ff%Gao-;eb3NWW_C514!EGk4+n_mSR@^igyFxVir+(r5Af1*Fd-eaYPa$=ttz zbQH2bA38u5(h_qYGxv2!TkyOWX$R7Nb3bVA7b9JP=Npl(L%P}AZ!`DXk?z3rT}aPG zda=3xn7RKX(kt=&I;2-4{i3=5y1Bm@=`+RmD9k>;nySs*hA$q&8}}f6Qr-+}Gg`ZO z8PA`??|=TAcJu$QcJt-l=H^~rkECSO3M*cH@$P5T&+Y5+5u5W%xWs-Js1d=3CHD0r z{BV{1&aX!8wU6R2+Zuy&uX#^%z67*h&mmNPqGo}kz!8c`Vs0nKnoKo*h@yr>TqpyEl4QP%x+qk{5@AV zP0gqy&dVZa=4CBR?unS%W$5Y!Y1-xQM`CBa2qbVQWkmdT*)kA6cR6T)n4Iv;St=&# zf|+vN@GN2iC;RCLfu<7OdbXU=iazj3?N>pcaPrR1lj}ZFKI{bc@HYVP<$8|rB6q8L z4tph6IXj3jvmYSN?BvOE9wzP3K<;*3WHZ=aRzK;L4CcEJGORV*oY=rU7Z_8GlNO=9 z>6of)>|{0>PxLPAlev=_W(}s{w8d<*nSD%7I~j--Ds@5Cl#*CWaY=PiM^RsE_{QB@ zl#@THpkP+4+0USNKJA{Oe&jw2>q1(fqnn%~Z9$ITf*jL=Nq!4Tk>e4#lVp?1yPfh- z3&IT$_}@3Vv9PqRsHVE3sJA(kcTXwE$uxl?>wqvk~XXnEvZjbNrX?!yCwx{=?m*E^vPXj5m^yf|XS)Rd*x< zaia_oO*+oGqp7I_m%FLCYI0Sx{Nc#`xVud~uZ}Se5`rU&7rZt@ZV-xV~&scUyg|ELNZN zhfv<&E_JiK3g9NnxKbN`qDPg)uL_i!aD8x11W6kykWY26*&U&94_ zzKUIcZ}ws+7rf8suBOdNr2(ZVMGY+7a*DgO@%Cx#j|2Grz4rU$UhcJhS|l0ZVjvbh zaLSgY?u*lIZ^YLZyUW$HUN-1+4QT}Hdccl=aU4%hjDtaOeD+F4M^llVa#YI3sdyPb z587H*n_95vavRRYR;OJ!?}A+e7kb&(be?~H=QUE_dem2l`mi=KR9|}Bxl#{!yRK)M zt!I{GeB8#+s6SsgZ`ZEb7rN_BRZ`a~X9!@-^|GZVO}l6gPJ$G&;us|n zPji9vdYt+(8=FZNdaAo~u%jwxamA#vvRH9LORQpXPIddByQ-mgPGv(=XkOX zlDXTdI;c+^*Sr=y%HYH9Rm$BV+h*b%sg`D(*sHp0rZ<A=8%+h5kyTT?r& zxvZ>tT5U~lQ`!9fntuGxxY=*IGt?~}IaJJPbxx*0oa(fpm(aB!Glrlutt8Ask(v;J zrk$2FeHuN+&}ai-E|h~TorCf2~(tuu=;?{!YSruAaTn~H<-eFeU+!1rKbV3GyEZ4{^i$3dqChm!Qq!uF*Def}}o zg|3?0(?6**w;@(mRohinKDQ*2Uy)zeQQp+`WNl$@eo0}`q*#{s-VG5i($o@btU$1z za?S!g%OTaO9PB%jZzVsvG_>zbDR+zE;pEe2#H3?p51@|G~w|JhycCT9&~Sk$}2e|D0)4LxuW&+hb}eZXDn`~o~b>fPl( zdlb+94*WLi-R(cyjc0S^***TV4eoO1R*d_ocW>y~dOX9KY~FpLXRFM6-}RsEcKcDs zOuYBc`Wd1P|IwZ2obBZTnVT^ha>$==g^r73M98R-A*1HuDTZU4pL*?+C+y3o+KfB_ zDdYOE-TbzHaB zxeSyW_5Nk_B;pF3)DXa(~~u8+y;* zezIHC+BtkK>$-8Y*SQQ-9reEFHvt;xkjJYVGgzgo^s9bpIv8x6jAp}E!paygt^}cT)a7Wj;i<~>W ze+22qu-`7f63nwwWPEO_!5{;rvRY1K!-x_dz9*uDyuEXNS559U~Wy< z{CcVgi>h%dcvJnfrn@u{?HidkrJ=HFVAjqwa2?xPRW+}^p=P@e+s6P~ zkF#>3uyJczs*B}Fs{vz^?k@9D|w={iqI4a%~GWKNUNv;i|m^ULCwS4A?vaewcz{( zCvASw43Gm>6aI1i?cMQT1j8lB0j71M!`jj_=zFv&>lm60f8P!CD)I>H3hMgdC& zU@Amf3z$5>G=M`I5(a4^SUtOEUwGlH-B%|=_WWmicJA!??B@cAg4_|~%L7cw_`=8- z6R=A+pS0lQB&fU(bl+aTI{+leanx*d7pO|y4` zTyxJO(16`Ri{{mm(H$JsO81w*JYM(+5%&?7UHGBTc8`p7e-<#D0KRp=y8?Yy?f5!= zZ(7wJz6xEF*67Kmd7`V>gHp{xs}={m?4q8JUfg|AZ~MIVs+>9Hv97whu2}h;oT~PD z?!ou>o^V3%`(v>wUFD56jTII6Q{FWt2F%0{xeJ7nxK?-qn4#QA#Y~>qE$J`=4jaY) zG)Llxz}cSCsFB|4F{sh~ychjbta*B|=IJ=T#WHthxYaOMUzN(KE>bJh zGcy0x)YG8H=HNH(IPwwpbY&o7Q80S5kV8_t?M2jbzkR^hyUVb-3tR)_RTRAS4Yk|X zSV%25IM#53q<#bliQK?5vONur!>*5wG59`9o4+HO$dBE4Ye3jR4j4QZ{dg;=s|xb| zL%?7?F<1n#YcKM$ z)pOn_(8~8xM-NW8AP^6T;;}f(xdfRjak-?48|CR=(Us+8`yMPm1Lef|w3nlPLDO_*Qs^ywtul{cb&R~}q|pwR+tizoW7Mx~!nhOfb$Do@7o zW_c>fo8{%Ir@YHhM~$;Svo}kZ4O+PomE4NUJ-Uu8FE<#SK~DTwFTs!X0Pqxb=4bX} z?FUGL<83;V1=RzZt^f*VqLqq7r`Ai>sfGS~)qM&6hkrpW)9HQieUG9mk5zWq#q|PSlEM1v?((jpy9;Gq?7jk@(5+xJOA`D~A&u&- zySZ)+`<`A$Js9-d4KJgg>j9uffCp?KThx3I^q1bdMMs+Zdbox^NlPlUA2ywLi@Q}F zkqhfjX7}Cho8LV>*A;uRt#c!RqU{|3j+3DolUCk)cWt zp{)jmk4xt0_^f_4rqAkGbxY)Z=v4Zw&Kb{VMYtoN$A}gNkBhn`4G`aI7UV>P@wxhE z1knl|ybUMTj2Wk{{D|+oN^)ZTtmOmKQVu`2WKjCRWOpdbva$Gz%=FF_dq0In& zKhzsDY9&69v;9#>AULJl;jd|VFf z`>+uWU#mE+eeL{A--JFhjgcCeXN~B1JQ+>2UUV<@KU8G7pnCfer_qIneH+$!*N6+MSc8&E74(dgo^zN@+ax z?f-EOL{?$E)B0Y9){Cs*kd@xy&^FyMai-x`X( zVZO~ixluCol^=Zz-TTyd7W&)6>Cv*;BXwij>@TQF>G?e8UBD=8_AskU<%F8bkHk8q zVF4xn$V;owcCzipcS2$_{L88w(Av*thAmDZZ~E*sODe?jPw*8Bu< zc9bl7>B|I*{srgt$O5tGPY2du(Gy3-;Go4?*lx2{{eH>l1B9$Id}8)JiQ>p?`pAN` zHa*6J_om@7OEUGbortxp>;B&XpIGQ^UP*9#Op1u&-efO6Xu!n%rkS&nKNh3oH@_4j5Ef9 zaWSxjvv8#zZYjAE;@bI63XX(pMQXCZobPHIv)Qw~FoGGiHur%$rS|Jl1;a z##{C<#y>;-S>21fmS+B5^#K~RFy{GQ_sZp_fLw74?r+2W@$;7UEH+NPJ`e35L)o&P zu4PME6f+|oi~B)6i%y%T9s6rFW7EAD-`+HTZr7Z+zPa7FzZCa#=cB;md;{+D3CJhU zU%Y(v?++i(VJrji1O+YX>+Z6Or@HuJ5iI%`+V?glynRp8$2e?S9N4Xx)=Z{h3V?IAQKw5?3^ zjc56Vs$W)D-e}@aF!sAJNZbsZht6XB8oDnGXrD2Y#2!#k8U6_t13di@0$3id_pzNQ z`v8BO8#rjdgLyEn89W2mF?rsA`aSW~8(%Q}s?QrMjgf zX{u?HX;a;tO{Qwo{H{4W4Jk6ljk%kqjy3IMlRJ8GZS64c96vQ?C^>iP)NyFXK<(fW zRNpieEi6ziAeKdAkE4=DR)cA$mfGAgsblB*%9x$wE2qYo&8DiIPc(Pze4;YOJasB+ z8HXSR#Ao(KDVRM0voQnrz4TTlckCP=vy)BTw29iB+>vD7xqj28m`%V#<@c~BPAcH+ zW%ff?tiGh_cE1oeiOnX_!gEeCs*;vX@J4QB^rQwN4$;8yXC(A*rNh}=G zUw_JrH31|mOCEa48?7d?Xn^di>iDqB*eW(1twW^9zI*|339}461?&UBVV;>Fg+5jT zXf=fK6$9uA@$vyys$yA={8E+Qs$y9W^<_Q8^B>l8TqAxDOam{aK(I zUpBz{C`LYzVzejoh;Nd4ke%dQIh)P2%IXQNEUWvp{zc5RsB8HWG-$wG2KmS_l&&;) zOEab|?&@F2!rZTTh-%YQ8Z&4XaW9*JUi31^e^$*fx7j!hh=Iid;2_-PJQ322^RvY- zxZX`^kw;h5@c{Ud;1_~cN@rQlG4F@k6c!$j=Qg0taomp^QS~==lpEPM>@)TeuJ0kd z!49zlY#%#{wDa#H_83_A0d_CDgKb64kJz>NyHcho_Yu2Tl5f}sc7|->C?vLC zi}MR0F*!dUvYGP<@|qz_>~v+f$aI0cTIDrYUUTF%TwZJCHBDYKWD8yL8ZEEI@;X*t zv#1W+Bx`2Ll5}~^me&G#O_0|ZTm>jhqe0_BIV1jP{qsdG5cKx~GvuKT$#IL6<2h1} zTcsSgNjYwpa@-;1c&?P=c~Xw&OF3R3Ck5#O|Gx;gpr8LffF&f=u(lCrV%<0d_I(rU zhQC}lqFvmCQSAW5mV%pnz^&uKt9J10Xov*jS35>{6JX$IiLPGqI*zXVXPHiv>GS0E zS6PxuSK@O?e?L$>9<8M^E3KNiMg4K@4Hpc&p8bsWash*beS(pBi@m}Qvi z+kwAV5VnC9*R!i-eh1qu<4vfwk*#H`Rq00P6^m4QHSRfUQycU*fS{LgUL&C{m+)?s zY3N~qBwSued*J+_yr#=5v`Umn{5a_eoRdz*d4;@AkXO6BI^;E4UdPI7vAib8YYeVJ zQpgi2U*PQtc^U$V8qUTbH5NRYCb`ohIWk9bq*ZdEO>&`~)_&A<29g(mL}~}GX|Ky% z7^n)3&ftw)r{RD~a~5sbsnUW47;aH%jpZ8_sI-A)7{;r#2a7OdsI-x#Li^L(^kjEv zGgR7(MQF7u?ak(ik5t;1S%tGNKb9;mQsw^K#22Y_0JHOal@4XgA+u!rKqwhfN>6j7 z&roRrPHI99$11jrA#R4!*WJt-6&fo%jP0pgVb{TEk%tk zXv0fTcL`g;7GsT|+9p|}A5SlnHI`vfp3CO^Nv&QyORfE@UVG5ezpK;5Y9+iTK+pvU z`Vh}Xs+%nYZ!D1TEtSyr0FrsQ+sCL~lf;g2p#E1PV0DxItwu~woQh|4_|pD^!{d}4yyZUKkq0T$6iNEk^^85=yGMf?U^4~>a-s0Zmct*Uh88kmFL<`qqv?Oh`_JkqOFxFr(Of<|iEHm6-xZQA%;X%VA zh9?bg8x9*jH~eJyHJ~*9ocJ5#e>H`fqD}FpL{qBCVzQaWnJP_7O{bYIFx_mr&2)$9 z9@7rf1Ez;e1E#;49yf=YBg~2BRCBg@lDX47!@R|OxA{Ty!{$fK`^@_jMWQh=Ffk-C zJTW>kJ~1<~HgQ(s+?1PA4y1*qO~?%X`K{jtw0rvJ51Qm)PM5J$K-JUPR*BbEejirX z-$aze>k+YEyrnVCID}U!@M4A_;FV)&HuM`d8@3wmHtaC$HauZ?$?%@xBf~d_Ux3$o z;I-8hYKk(&noJTetEoWZwcNB`;kC_lujzi%F4LZq@M<cs0UYgm(N@eOUg%CW!{b2bA{U6Nv zpy-2?50XC!dFRP@KYsTfdctFeh(unp%eYV zKSQSh7B|Cugw?}ulhy5y{u!njW>Y!T=;>HlPRGt`0jq?}o&{;N8v1J!)|>`N%6v$y ziR@f33+r12fbUJDE9{?Q_|g1~MpI&9<VMp{e{|Enqe<=k2J1>`dI*;m|`dvGuA&HlmTcq%l$B%Z~S*#_*iCh|Hyfj9Cwyq3@7E7@M&#~$FT z*Z@C|9l?I%V}2p~grCno^Q%b9piU!jo;1%e}D%N1KPvd0qr^MdF=I`)?U!|YtLveX)kKeY6rE~VKIC|Y!;V^ zz2YKqh1ex_i-*M?akIEp42T=Vb>d#}keDW>i*rPWm?_qa4dQIEQ7jgH;#|=ydcJz|yEDb5fNigkkXZa&Co3C3shWo$QJ!C<*#Pr)woG(Vf| z=Ns8G{4BPQpUxiRXR;^wTJ|@-jy=iGV2|^w*f+5Ke#ft6Kl1BfJGp`V%x`4><$N?>aZDT+C&Zv!ow(*H0@*sv zL(?Duh4!un`H$6YFJ{_J{3lTHJJ zxc<1C+#fGt;u&L|C$n<5|>h* zvN7dIYHRB1)Mrz_OY=&rOk0`uY}$9DH;sN}^mpk2>BZ@b(=SWkmHtykP)19}1(|-C z>oSjKU6}RTnEo-JX3x&vJvMdh3zpHAgE?RgtIDbxt2S0`uDZTzTh*?rC#nus zy;b!|)pymat2fs8)RfjV)J& zvI&ii#>SAw_{O=7?=`Jy`nc)arr#&7pLn#HHTyM3H77S)nv0rin_HV_H7{!Zs`-~m zhDrUC)=t_q>FP~49o<;9kFTK?Yh!{j-Wmrg!o^7)gmoP68los%D({Osh{CVw*dyUE8| zy;_&Hp3!=K>y>ROZ8>elZFOzi+IF@*+V*VQYi&o`zH0lW-OwJ?9@{>;{hIb$+wW_C zy#4w1H`_m+GHJ^6DZNuxOgXEAb@+8ebtHFKI*K}KJ6bztbu8*w-LbLb^NydUR!(i6 zI&JFwsmrIXpL)^MZ>Rp=>Dd|Dnb3Jg=lPvic5dyww{uVDzRp9P?{$9GdGwSkPuY6P zz0)$MYn|AiJOQ&5o?at|9dcgGP>8aDL(@Um*JpJ40zt5OGWBZJ~ zGoGHAG4srs7tFkB=FKy=&)hrn>6tIje1GQWGk==3eAfC|7tQ)&*3Vs{E1)a7E49no zRnk@8)!sF`Yf0Cdu5-IC@4B(;?ylWkPjr*&V}{ciWi z-Cxd`Ip^S76@z;xgT5@?G>#Of;?|XV_=+c;_NlP=A zb}wDHblK9=mp*f9{i!Xd-hS$D{iXf4_5X9(^ksK0_ga4O@?$H!R)noEt;kwoUon0~ z|BB~VmaME_*}ii2%Ka-}S^2@L<*U}O`sZrv>XOysPPexPJ5c>(3Hr1)LRq)|+R2yrFZ$>}d-&wcjX*Umk1?pNm?J+J1xr_X!&{0Zkja{e>t zzjQ(J1z8v5UoifH2XOqfe$)AzzQ53Z;e{8TxM<=<_g)-yarwo6yCnUR%P)ED(u_;D zT>9DOs?FOrzkON9WshGz?(#D)KXgUi6@R(n$1A5?dBIfyS1r5hy{qG|UV8QC*W_Pw z#Wg?wCG9WwZVB3A+G5!y5ZX!b8cLA z2gUcTwmn||FIymj=}?yWa&{rKjzo0r}E_$|S=%)Vv)EjQls$SrT(^7E}> zw_0y)zIDm17u|Z-t^05N9&&FX5F^owtH`T?Y5t9H{D))`-0mqx_!s(Z{ES~ zNW7!*j&*n3cE<~M8tyE(bM~DV-udL6|J-KUHgVg=ZI5jG;;vD5HQja2UAyl3^6sR& zr{8_$-Ot}6?kTuu)jbd2^ZUJ}_pZEm`@NrTPuMz{sXf5!gH_y2AGr_ZE3)BeoLXRdnYxo1v1TlnnaXZJs6 zd#>fVwa@K)?)L*82Lca_I*@c=%z?ZEWd|A#v>ljvp!dN22Oc@_^nrgI`2P98=M$b! zf4=wmyPp5$;Ie~zU(jBtec{X(o_*o?i%-^+xd^yw1 zhYrGVVFVk6GlB%zU{hcT%5o|`v$kQhe zw>E3R4+4;nW6!eZa8~&|PJCWqFS3_#a``g${jaju*z2%Iy@}JHx7j=FU7Tya&j#5E z93J7sMTCkr(Jot%J}ZEe&Rg^GCt%rl0NCzg&j6m^*l{+Bmt&tACqhIBi^ra$6e*zfEZ+IH0%hj}CZ8*GMfAi7XH1UHv(YZBH- z2`i4X)kqA%3M`#vf~{vhu){qoo)ZVe^Wva*LA)ql5{KMs;7nTlRXj#k0P#2Rq~%&%4&by2{yax9GV@uvjOW3gY=HcT#$6xrqq_60 zjK|A7Y6!~DgC$ab{%d)+R8Tw*&I3l43!7#tD(<>vI{G$Z~3n%JCHJ z9u$|j_5P)L;vX_D7L=!&l%L0n!2{Q_%i*uI0du1twwu|ou(YsxU@%TPW+aNA@D}R1bJp|f?eYUW`^bD zEtUxT$M-Bro?IrQH|hmWB9JS3Z^Zrns$7S|1;suMHb5yoX#F9NEP|Hi1ljn8o`;N~ zyI%j|?m^shc~=baD8^F5`FA#29rDl6-j=w(h3f(BOl0REXe9<%Y?De0bf4-v<1t8&LZExe z2uTRh2*C&z1ghr@)OVRGPee@k5o}bJr_$6`3Bq+M5Izin;*SurRD2LI0yiSwf$$W< zVT2ZhB?xq%;=2)^K_Fa+Ce#K6!hz`Y0s_(WLj4jzBm%Lx)@1d5`Gs9th?K5HeKVD8xi-Uj(8z zwNHJOBTPV`@k7~(*AY{jR)h!y>Wk`9SqwrB0zF@d(1H-F@)Xm!Q5~vJa8sTFrKz1% z6{yeu%Mj_-9*z6|RUllPZTTQgf#`H{ApEEv;Y2+1zXTemKYPvzhch-~tiHfA3;xSM zV@C48DHG^8bJ{)j!F}SN zljp_1%M*R-5hz}Xu-YvUPn^t?ly~p<&(co*`?EUEd(@XRor1IzSBeSulS3)WXx(uS zRQHeI{l6+pLi_H4*2{ktEV$Li3IIo7R5f z9SU?m8lhI@>DexorZFa-qdAa;K+jPb;Z1!}pf!i$J_Nc)Y0?i85NPZ>5H=#v+$TB; zgpPZ@NwczxI6o$n97NE?qNLg6r620AWePHvjh*( zet`Jn@SCw@UpG^ao?QGf1%#-3`H5WLjpbqLoY+>CGy0_jOx zRsJ@_*CX73@SoP(hPrnnY)7~gf!ZKliSo|)9;E-%dLgL$XCd(4+^1)0j#?3jMl_}r z;t+^mW8LC(q$$un;&o@-f;0tso&v4c)P@0p=9ROYox|3$g`v;QhhZ94DC z_Gye&pmHj62Fep{Wj!@s&T*48cYD^^#(xuY% zwjz9ua5ch%2qzF8LAcN@z>9+MRb^e4v+ zIOwsU6k1viE17OPl6mI^zU_=v!p>d=i%SjsuGP!Pc1$%T^{%PR78pG*dd|-vz4Uel`>>+r{ zKMf1sag*=O)6J0D&qo7hF{26iJm zn|pIQ$=Sf3ggvkfUT6XE+`0nZc6*qK-N`P6jogg4gRWvv!4qvSgKrAny|^4+U4Go3 z{RRGB8+ib%yXW9U=xTUe1>rrK5b0eN4zH?6oFa^ZM^y|ws^Z{JmB3Bh%${I>W4-Wh zN`hbTBA(0^z`rJyr?Dk`G+PXBs|pWpp(=ji1KXz`O4Z_#Lg`XYe!OcXTuSj?U!k z`B{7eKbvoa?etuJ9zP$}(@pGtej&ezU(7FIpTdLfQofmA#x8)L?G^k=eigqOZ(gnC z*TDO2J^b#ruyy=eejUG_-@tE#f6rEU?GE_rZG-n1`Rm=wx5N7mZ@R#b zX(ueQ5AX-!gSU%42k*DtI1`!8A7Bb2*2Odz*!WZrU`<%^%@7Y0|a2$Yb_eJ(Re4Y-$|LGO@N4*CBs5jsn^%gv+ z-iC+VyYP^EpB;pM++lgD^BX_HUg96ZKkj4rt$m8~rhmXc?sM`YWFNtA>TCWDo5#Op zhu}H)JEytO-4SVWGn3Y)MC z2j1V!6Zv?5cbq5`MRC)KHGJ;Yz~Al+ai&-+*1?nSETQ}IodZw4^Wb530sQVRgcsn&@Z-Bw`UGAM zkH9P8lXo>d@BRYsyldePcs;xVZ-iIhR`>|s0x!Ya;E8t!Jn^={6Yp+#;oS@Gz8&!F z+X>IU2jGpj3;u(;PvKs86g~o9zCSo^`lB-{_Y)=dJ^O+E=sZ^ve{dQFe^v5~`%HX3 z%scKo@jbkOe-uaIIrp>pr}UP?8ZI;%h&DOf% z%RE<`r}b#_wO(z3woqH7ErxeZ8?+m>o3yRk&G4MQRl7~QUAsfOQ`@H9rQNOFqur}**LG<4!KeCuoJ2ebTl_=X zZg`{a(e`Qs+9U8#{VOc@a+kD{#L1A$wQb&)&z0 z$g|pW@F6~e(~{?LZt?;=SYN`4^UK;R@L|P!ZQ2{K?7yYGt-S+Z$M>}NwGXtz+7azT z?IZ1DI`=_nYedyp` zFLEWVo-3C0S}bLi6kDx14jEf)vfOI1*1w^@OuUr9FuG%YC?Uk$c%2hk%)yA&b{c~5& zrRFU;6|&i!Djht;HqWlbUETeCOFX;!dis{kUFg%*-@Bxzt9!+A`3R~=jB={V^QZ~L z5+cMBeZ&$H)N{tNXXI7=G6@;-<$hhVS)J^DI#_xpxU0Ljzk9{vd5h+*)=L7r=Jd|( zpS!GgnV$ETeV64pAMWYzS~+*vEt|?Ie4IHQD?R5cansX5E092_-92~7 za^sxtE{vaXt{i6LT$%HkJ9J--ni_@ja?iPHz~}0uQTNrTm8;RNP@`9&M!Q0dc7+^e zi`7x!+v5Vqucy0j@nQ@w0p!y&)VE)c1WLyv*zEzmB*gtOy(q}_uwG!8Kf9~ncfPAH zW3L-OS6X!NE9CUasj4XO>{aOX>gXAJ<*tC^WQP+y)o_#v}zJ1FUbuF7OJMrk7-`BrH$Fx#mTBQc0Qngd5 z2ChmCSfw*o17GQ^ucm2bo)LannB~TP9fN*142;XuR5q_ZvSGC zYxW{FO%2O2TE^wFMV;O`5?)JAuFbf@oeWZrL_n7*CV8R94NG>H^~$*__Xsp;=%ob3@!Y?q!N|%dDPd3e_?lRiCnxC9o3O z}u-YLK|9ewjoW`7+P4DjnAf7dk!_E*ugJ})M? z-7-u7AjT&Bev^K`$?d*Y1ssfb#oi0PDrI(Or~v%X@9%3NcM4t0wTb&DI+#>qNUOm-v4WVieJco$R|T4{2( z$_A*+V$G4@VRBoIZSGhrSyQEYugdjr8-{h88k9CQx!dIAZqp}sn+yFa#ktiA%_=83 z6gjIT88DgkRVk-Z&O+ps(5WmiPSJ6j;=;{)%FyJVqEGIruA6E$+l^D*C%0nV>U?9T zY|f{1h#@5*>^2MO0T#sis-;S$OhTy~4aAZzh;^2?+jOw)HrYPPb@1&rT}Ih$QnsO7 zC$rtAqh+^A^ieKl9Acdec3t_j*zJ;Bh*ke~)xTZ!Z&&@>RsVL?zg_ijSN+>n|8~{C zUG;BQ{o7UlcGbUKm$mjB)qjraKS%YiYs?mVj_P06u#s2&=cxX3RR1}uf5m2YwU*d( zRR1}u{~XnSj_Tj4`nRh7t*U>k!r!X;w<`Rts(-8M->Ukzs{XACf2+dZs`|I8{`DP! z#coyo>uasWUYVnFMWvf|NTu#PqFC4NP_Pv!mf3!HRz-dE+=YwGQ({w>b&QFPT6 zYK(`vuS;^|6@2>g2s%33b&ikf&*B^(MfU=g*YydD-QpY{XMN}RsP?KRK zOJCWnmOM#k#IircvR%ZoJ;bs-#Iilak{(t|zIrZSjt}y(AH;H85v%s{ReSlWy?oVP zzG^SOz+2i5=xqfrY?!lUV)?2*nebUYA6p2S^q$wZqF<$Yu~(J#mi4aI>n+2Ue2Jc% z+uJjLxn6NeuWC^5gWj5ueaHm$K?&6dCG|e^6!jtNQ6I9N-iJ);eaMQk4@wcA!pNcH zpQFnW@_}p0b+c>1&8J zN1soK_4_%x+(TX;pB#OjAg|!iuWFas(*d$MPANpt3zLV5$ogW(AQq%bv|?GYcKMu ze|_ymUiGi9y~wNn^|cpy)xW;>BCq;a);Nd0_F5e_MSq*>Us>-Q%6jL}buZLY{p-3H z@~VGb_d;Ivuj^jOtNwM}3whPQu6rS`@Yi)Ot3%hl5UcUmbuZ-A`0KhC@@o8b-3xi0 zuN}JXg}fSnUH3v>jlZsYA+PhbL)X2m4mBSgYQ8!2^$z8V{%W2()I4{ndG1j2+@a>V zL(OxCn&%ERza46RJJkGksQK-1DExC3{c{!la~1x%s{dStf3Bi`uEIZ8(LYz=pR4Gf ztMJcN^v_lJ=PLT=D*SU*|7v}3xM(E8xFN@IPz5g zd8+?B)qkGqKTq|ar}|gxj6r(>x@IKGY+-RIMh1hQ0t5%U*Vsx`p;MW z=d1qnRsZ>_|9sWIlBW(OPaR5*I+R>>DEa0nQ1n;w)uH68L&;T#lCzEi)xWL}!tST~ z*Y!f=RsRLmzH$W~}H<(SYDS8jHW>~CB;j)&?hAcLvSlN`KWYYy9$|WNpmWU&k z1BzHO7-Gp-h@I_7MnYZ!j93!TVpE$Bo7!yH)F#5Flzp4p6xh@zz-G#ir#=Im9qBt~x7rd8 zAD#ByUCZVMxeY@$75M6p$aKKazEx(2K$N*)_dU8S@sXhFNePuqx^=GKlIZG5HSXv( zP$j_vGYJgI2eMMY5J$+YAL+{&E}7Ava&@ccU3~`(je=Ws7xE!aGPzn9Dsn+NROD(m z%tdb3qi%&Ryxa<1kB7P*r_qwIg*stzqrcn3E}-Rx!J-s+i=`4yF7Vu7A|KyE(%_Xb zZU9apUd%fvoybBM~lRj=%M_?QJjni!8c?q+cW@I7YoagJ*4AV|DhgYsD~I9O+Cmi zJ*fbnxg08Rhru&wFPvArjt;;f#goOz_WZ~0Me9^XuL!22>;|uNOVYxnu*70elEUX=TH^G(~zNEIiz>+-1)>>EFWGg60PZ}MT8W%jR zW$=^gyueXOVQr&R!$;$zpn?^hILdzoJ%Rw_Sp#s@Nn*(o{$S8U8={9lq3`cT4{s{) zb}P`RKyxEd5ETUJ1>Qh3R-&vS6)efZQ4)-<2H^D*%wmzUyq{BFPYVP{8(W?Oj`6nbXrV6 zTXjcu8(}#UqaKSl%Ki{b-ytkHfy`O_&>(wIfrlHGzEt4rhGifX1nLDIz%5E*={tm_ zh7ui1e_$CUu?)2Z+j41O!+>pCQg~9HHMf}4kOv5iZ@ie@KQp+8Qqq8D2 z#wB(nj?0L&WTe^UOxOADUyO*0?*a(w0JjnO@A%HiZTJE@FeJR_Ys@;g5#Q+?coN?Q z|1W&U?Z;zJW<0?vFe2d?kvMqNEgXOY9Ng;U?25>d_$Xb+2~fOIhGB%d^P@!%+PICx48nmiAg0>9QL*%)8K}P z^ulEOgs{TMg)Qd%^hiEBJjLOcTGL%zf?-Upn3k6sr4Qj~dj)?dDx)CL(>F0c9iK6W zry+y?(I@Z(>?h8HJ0Jjba-JG8*Q_$opc>p*F^merXcCcFCv*)!1s}dfiU!V4m63#o zR08b?ZIb%Ihb%dH7%yyWNN$EFh1{g)UUl7$W z17;Io9>92OY?N#_b8MLg`IE_bf0+l|8#D2lyG$mg58#Dojb+L@#ba^nCKTLt zhmhdY_rmSc7qlRDu8_3IM5;!nMj_RN6ecW*6Iws=9NAbwR74Xv(n*|n9v&6|S(=&_ zpoND;6mn~Xr#&^38}&@C<`hJ7oe?=3Hk`RQYji}EW3!=?yE-N;1=JMG1ID5kw z|0qAd=!k&ql>RxL4c3we?YX5*)lGjbDkvx_%Fi!sYA7$s$oBQ~O^hBr+Q$&yl9yIK zHagrpespzGRCzjO;QZzt80H@t*iey>5}uQolgTINXUApd<>8XAuTEKVbxOcj!Oj~1 zP2q?tDP_XwxaLnh4Mx1%U_?_vv|EAuVkFmd*KmNklBJ!zVEwvsap@@uW1}m_Tn?c=w!t17Yi}4!%hzje zt5@*CHEE{2n7C`(XQfnj6&H6^rp#&`tRnG#ufCGi(@N&#+#q=4mcyU-$pOq4IQ2@J zIKZ_uCmM&iHiF0y;YNlLY^)Xm$+g5u(Gu+>v`RC04@=UyHp$7gN#NQf$+gv}lO*d@ z>s(t6uB~=*ZMEduv65?((5^$0I0C66nIg@n5h+?`{+MMkkN<#Mv1AVC(NK5xUgh1@A^tS$X_!d%0HP0vG(y3%ZtoAN+}`29P7rjUUv!bFGOZG)=W?x;7k2 z1xLXEM$Loy%gHBzvM;Dgd{D}5o}o#aXLwR?v!V0e*>8N?{oGU<`7v!b9vIxu{U$vE zxS9c%7vS<{HKYvrFkd&g6wO?4xxg4nGZHpN=K?IpuzA-mZrC+gTPdbh9-mc-=5r-? z1wk*la{zte6$7{4)U0r=s%n?zDp2~LtH51rm4ZB$_%haQ-h@&?s9r!DGkqb}5Hoa* zd85%LEC6>%vm&4(QHkpd2YQ;}LTr?{lMCbg=$ zwZ64kUgRz>AG^GNv6pr2@)QkSR30(+l(ryOMag9D+rB^A<%ywP9({w%xyuW8-{l1- zg*uV^x4S%p+RP4q!nKpOd9-8C|9`t}sQWY~ zZ8J&E+91RP4go?dDa~a3CLr^aG|xl{sT8!0Op;ouRGxH2G?zAXV|ljb+OcZ@oHl+5 zJRZ8fky|INNY72_C@E?Tj5dW#iYc`xCFD;SQ{9td_l`-kCl;3lMw^2t#g^EUR{7;+ zk4?+S%npkQ^49ze0SWeuw1TwIth5~8$WXtG(Qf69t-wAFqZJ?qARp$C?t>S?+^|=Z zCw6G>WF!e~bWt-V)S2)2J?gpO%*tHf%QH>~l zjUj*o*36of%;gP(Pmx}h63yow$BTy? z@4+#=nH9NhPOWd{4I0` zs~373hu#9&8rt{-NwbxcgGb2B5mRtP_wJUl5ki!7OM$T!Fk2WAlYQ4;sxhH9{SWV| z;4i+W(7U6f!@IC*;`|n`R(ykcu$(_e;rKDWbFdk3GNsYbC=AChj4+4$ zR$jt?du!i5z(odAypsm5n@o!4aIPCM?C$y@-qpmkb((HSxy1L(B+cZnm>~sPIXLv{ zaM+~Uc;nz>e9Pd2d`crlI@Zy3NY6c zb&V^jc=%eRq>K-&@W~51CmjXbbDzl_6%1WVzaUrXYz2RQy|sxb?3ZdOW}lATh-{n zpMDruUOw)|&5oiX$7V4wyQQ=?Pzz|R%c##ysI%v$I~>P(`B+Pu#qxKIQZ?4DXnapm z+KsWRmnQ(unXhD@3lA4zNkkJ$WSXKCD@sDEZ|H5-cmcC9Ekbl;LGlk)V~tm=Kl9A> zmTGIFf30_vd5mfDq)C%aW6V+Bwf>3LYQKT|?i+~C%8NBerYD4~?d|Vf8JWDdXYwJ+2G4wI{o1wb zpL)Ett*v#T7}&Xe`_8)M3l=R{e*7((y`6x>3y}EgJ5ZfVo&77>{Kquo=+%H;2@8W- z@4Ybo9z%5WmM~!h8t(k-&z%A))C0XR~syIf#iMf(nF3d+Po#`|U()Fd&52T2c zq)0(*lp~o!D+0<*vYcT$nDla#rAop$7gn+%xHFlwal;}jtf)8W3GY`Ct|K$1j$BxzE&c}$;5Uk3OE^jWnwxK^h>K``87(Mxfz>KI@ToI zb`5^l+RB3viU*$(1A_-~_yB_&EZO?60psURN5VToV!Gxroq5q5rkxFOCVs0H;*3@| z5|Hv74kDY(>a9C=@SQt$R0w-T#qom`c&;9r)e-PuI4h-944(mT;|8Tjxk%#T2GW_R zr*QNcrlT0FOw)Ps*r?``g2#`<=S>*XJU^(}BRDQ2uAuZ7B=YZBwbq!)4Z-0lF+pWj ze0v?Bpf#%;P)J(~j^~EiT1JeNTC-eWjTk9+TZ?gMq(~v_SpVQi^ zO?z?fPse8S_LU&U;FZgN!A}+~A|6@|$RYum2XoN2+$fcK=WO|tIZDSLB>T|~X5;Es z-T>4uC0xk_7KRps*s0WFFbi>`_z2V#CN5lui9$L|cQ=ju14B~FXtC9BpiTxg59H}E zL@E@HBwwCHb`Ythfft|gy5b72#zm(aPoLk&XS_eSh4;LVpU!qNCE#_l+A?$rM#f3! zxTqb0i)ik1g}7Bek4umvwrJXTXPhxEH8?nRT!xDM za;BZz-ge%!oSbRrwY8r+EvL?0)aK~7w-=esMeX)}M_Z8@kkgt&I*1QuOdD;&^>em8 z%n#^$4MG1WTtx%G)tcjrHHTIjn(59t2yT1eMwjxM->bl3bIcFoscp$0>(k zK}HG5qi6|XAW|thwXvlt9@^&;#f_ffHa9l`C(XZHQJCjwv_?6}K6}A6kDo;L+sf@J zo_VLNYjTqQhDQRX-0%maSF}%&5+;%@CEDX-CsKS9?Oir!wcl`IsRqNPm%1+kk!YC9 zRw98sK9CEgz#A)})3i&6H&O^-zUe9;%)3r+flMB}qZLEb(fYuQyZcBj*@D-j> zBgf|i$)GXd_;_%9CRw6A>BBB=5<{I4xgd7ub!g$>4?4DqLyC4maf*A$n(u#zOdSzY zq~WLtCCQkB(Eo;P5~;dLf{gvT4*?xCIt>yTGghY+r=La81oqGIIacZ5^wwggj()dQP zYBF@-LpN?zR0nG=DvnTuTxMzKnjRV~kL7j4fL!}-wGRBC~nUkj(W_C>bne;OMW z5f&>iboTGU+=Op)VfHclK-VzL&HoAJy7r>$F|=r%g3W=v zXiU!WC**pJ+~B@3ISjvos;D50SjdPU9pJ}wIX6xjx$F6pso>N$$O@qE$4S%Imt&U^ zde|<=GY!5*w(z!RJ$L5pJ$p}`u-)d^u50CGfMOKZ*aWhg(P1Nz(z*U9+3ym&?z19Z zQeVT8qI-3P0v>GTvD(sz5Ik~LwJd&~nlm^=O5t1-j@_@R!nu7eQh*JMlTSexWrg3IC!N$hrW{gTIotm3nlb0S; z8W5jmHP=sUY@Ez5$D5h?`8lI4;pwKZ$T8&^iMgX=Jq^Z~%;K~$4UYJ*L^vOYCyolJ zEcGg>tc8k@h!L}bZ+xKDK#Gv~4w69Aa^uqIMo2VwVJd&4Mn1%Wy&o{u&DlEF=%SU( z+K^}tcsk&uA{>6nNqo)VHlDp^{`|pPxxe9pdj5~Wu&N7Q$?k};Fl+K;TOWgyXb*#( zXIiM4|1|h)m}m6({Orbjlc}U5KdZ_y8WfL9wU}xfo9e82ku{_E8RFEzpOVt!@+aDC zZN-U0L~g3`s%lCc<%6HJ1f|CVqbOiRK2$vOljbpb9mVFcb)A`u3Z_N=h}%AYZ3fXs^*k5U2y7@nDnN$u40i{5TDuz-*BM*_-0xS@<3HH zW-n2-fGku@&0x?~t%F%ZtHB6W#>K_hq=9NS$s;bhrl3TpYYN$?j)2T$jmnZ>dLgDs zKLF)lPdS$br|;o#i}i4#E1R{l4D+nwX~hXm(m)F(!CFIs;*0u(Fg|-zn&z#v@)E4R$+*+Fnb9PO6QAAO>yzusMxdFN3Vg?BlvFA5N$^2?rN~)?tq-)Xy-|6JBoS8v56l`I-Zm7{J@X#s73ZH%q>VW&!iG9 zFO9tUot}a5!gEOekvUvMjjf;R^H}#B~#`#C2fDd)ydL zuu)I8$ za*_K6d921LwZI1(kYdRRsjA)pR1@9#WDgqy;iEfJI)pVOS;^GF)=;hWbL}iRlkKEj2FRe*7y%JZK8JIgB60PLKW_+7*KXk-W zb}p&q<5`)cIT@mgiRNV_rO3SIz5y!3UH%?zoqSb&a^a3Vv=@G@MAta7hRb&1Z`7JFB?1wm8BZ73ASj(>%2?D6^sH^ohxtnaLTMnM-Xw*Un#l z!>shw@>A@C7ZpTj_Vo45_X~^ik7}EJ!8K=%o7<52$mrB9siO-jiYp38HeQF{vi>W+ zRjRQ_l2iC8BjADG+s0}|*-TjOu;;#xCvszJD|9?nA37ennQ~UdeMKy9`!~-Q@gv-~ zz8>`%>UYTc{=<3+MlZNQm8jJdQ$*~EoAp-Z4=kMwRV3=8)w}fiAD#FozLa_v3^mDw z#c(ULYdVo?4fBXY8=f%ahNB%iBTIrZ5;+Vm+n?kXDi6mSPl^q35%~L;7t+!t ztuRMY@%3SNhSHT^1ezZ_u?)X)eLgS`Cv9DE0#Lz3(8y~78+y*qT2^uX;Fr{ntS{SX za&HIx^b&7@7o*1F-8f2-M5)*CVkCo(Etnf8pnAC8;tnM55uX6E=4}kRQS($Z49K2B z`Dy>EMMZVJMFKIm!f_TnE5D>C597(JoKL#r&Y-6C!Yj%EqL;u5|)-r36_?% z00res_)E|w2*$~>d@_~)57b+7VwnhK=cAqWTWA#8*=4ewyIDTJjDLb2F$x~ILECUh zEsdlWjY66uFVZuTuYU2xQCD7>zoU6a!3{T{|7Y;r4(D@x_;W@)SIX1!BEvnOx$??U zFTQx{4L20vNy4WdU-pmSgips-f};c9U8eF1ln0_bjZHmq1|T!Csa>>ke{`aruN3|O z4dRc?LApngZUVw@1FCU$y_H5vt~cC|@!}xOJO>W+!?j_Yjn~agu~}*k?tUKr7{5I) z3f$%*^@{lo4UT%n$-wYlU3%&WdyD(2mcIl8Bn22Ln!^^Zc@767Hnt-+NP+P=H$MOT z;BP++gQD|93BLd94+nz`Rz$q*d}k<5;_X~ll4-S0CeIc!&Jyl^=oEy(ig1z&3@G%q z65A^}gg=QenU==f_{7|*q>1gbE5;So1~m92!=9#Kd@?4dI&*A|HNiOd217+1qeP!K7P>;*d&~ zXvIoe<~jaw|LYk(oV?$Etj5B`#KOj`Nf{Fg%sj8|yyeqP<|#d^#`H&vb9I%D+(u@q>pfK-X|LV%7rpjvnVDGRX-;9i%k4FUs#~0dc zh4H~bQIBsLn^YPz+BC{HEG{TDsU#^iC@#!*R6=@8Y0}t|#`LW4h_R*&yQjg^o?#jr z5uTOaNWXD749^r7o`t|O5up%xj+1zXAWoDxg#b_TA4Cn@)jdJ8Q9{SM;0F1c1ojjG zKm{*skvl39k@3WRM#5WS?RwuUR~m{i2&4WZJjE}BXnMj)h?++K8KS_n6C*l^5tZw> z=32*fJ_Ap|_pFmos~!CRNP83b$f_!Tyk1o*`&Ow`Dtl6?N@cI?ds5lcSvu+Jbkg1Q z-VNQ*?2UjMwumh#ppE157nL8(;5NuM2ngMxh#NXO_ROGzjz5+GWmi#DP*VN-e($~S z-B+n@@c$W_%B!5bdUfx)=brtX`vnlxn}^qa!qNdjk%9)WqWFYyfBXwG#t!)r@Dvyl z=sZq`S{nUoCOu2Ximpvj(pmEq?WmWZl@#TI-NqB3q6YY^pW6zB1oTV`&@3t@xD z_QfBgY*OD19rPR_nF?TMO@qH>!49l|&$I>9{2=WuNzD&9YQg6+pl9)#r>+(1TBWYq z9!turQc1#k5&<&CfU?KPI%^21A%J2bpb};rpdVQvNw1|>P**)79g@20NqK-r1clY( z9ZRvm!$jGYG}G5u0}3ZlUr{!AsyqI9eAA|JzCtZ6A-s%tE9@CJt^LbcXKdYi246iL zZTKgC7}WyD*{ApuH2??jyw$=p>)c|Fr^q#MbcNV3eZVjA%q#KCYni&z^TFR2Egc~V z&#G8ZM`T-x)>ad(slx4nT75@raWY~<7$DsuC>9Cv@2qBH%sbmLB*sQZ01hXrZHU9ygI2!ES{PJa63NUQa`&A9U~-02?Q<&R8Pnz-x80B2M=fW}0 zY(=W{F8P${Y3Q+M$8TKyHGhI*Y&^Li+7o@+^UPx|;L#^yWeR}lX;KBHxUkICb`l$o zK`FV3xLIW1h5}q^ryc`w)Trd&Q43ZI=&1PXto7F(6hce3U2EksF^>W)8i8=lqv_&E z42YX@s*ZP}I+x78$|!>4(s-@{g}0G2g002TaQ|p;=jf)nfu6eBQ$w2uq9YzpRY+Z2 zp@GJt(#pOw^4bVMmpCSBNie!~m*r zZTl6=r}_6r{5^_y$Kd7abwtJExq!tHe#i7%q-}L#aQ%?6zr4gB?rG`iC||7b*W{EGW{(fw*7vDme`b5IvH>``9ys~2(ov9! z=fLP>B7b&*jjnYM-~*{xCO*`gTLgrQM&UyaB{euTozrMvM)UgRmHGLVmHC!Pqy;Zy z=bn}2J$sf{_H_3)4L0?PAEdtz;FPET5}ct*W;)8Kw3+E>uA1fq808+@m^4={RVdc+ z3{|xW$tDdFqd639EiG-0hRiG5IN)VmTpA$eR8a?IdVqdvG#J@lc< zST3GOi@LWC|NPhk^l7El-PM1^4}3qE!|RIv_sulkHaSP zXQAgK*T#W`VK$yQHWeDu_0cN1IH^!a6j8Di21PJfSjLpoupb#1X0DAJW-=11eXLzG zGQRVj>F<2!QRnrePdzoddZ}#;UdLgkiYM07DfXbpppqO;H3q3qnFfzJ8m2tR8ar|# z`k0vml#46JNu8SGEZ{iFJ8WYmAK`e#h%x4;Mve11>i8!|p900@gX~~K0e61KO~>fl zP+5|GJTJqNJxN&^N!fBbOHvVqZjV4_0UwcI1};bjHjI(el&}=QSUagFhZ@>3Uo}o!Gg3HRX9hB zoE_e0mN~IY*%}%V^lKnJt&Y`2FFcg;Q1m~x{RfVc+Z?~G%D5ta1Rv~je9sv&Zh~N# z<+M~z;c@y?z-UvN$PqARgp4w18R1J{cx1>@Rnyih!ktXP1H&w0{dz4JA=@>P`-v)c zG%7*(j4hk~A>3V2TJNo>%OCbk4~Ef-q~03{=L{Fke6OjdCLCSJ-Emf9AQU#{M{>_w z!T6#$g}&4o!g|)(_QG+jG%CBq_=r~$Hv15euxm*$lCXV7>Z6aYfArDlzfb-<{^#C` z8hOrAV-r5RHV%}Ibu{BZQJlV(H_2)+un2trx%mD($-!h*A~K#&Ag)6?fV;ivI55CM zv6Lnb(y7vCMMU8(M(1XhryODYW#d<$`N8B5@c(D^LP4(A!OU z8vuY9LXHrajo>s!^R4Z-n*SRP^Bq9caifkd%q@a<9*8{nn^PbanKfiuKJto+GRDay zekA>7L8DC(eKy24#cw4dSB){WM0aSSrx$qrt;#-Q1{z<)^MC6sGvkPUPfSJ~w`0Aq zdqC;%Cz?J$bA+~$9T(0S97d&LdBiTh5AFAUWn4Nr`6$qe=XE)*1-<_QeQaGX32Jb~12?gP0Ci7`pm|rr!gy#VJRt%aL1Wy45*FI&U zw|4@sV?)j5%|qe`_hBP`v_gK7!@(nOR^?!(nC)9cx-@bn4bcrpiOSlbfD3XC!VVJ8 zYoz@0mm7ci%i6DgHSMckg|5648RWOlBa^rw{#%(v9Ca)@Ga(7w5+ABAO4BkW2^;Vj z-;2N7`0?VmC*yy^?29q(A)#L^X$mmquCk*vUrw^4?8BG#lVl)dG0c6(X7GDO_WSDl z58T?a;NE!V;!lk4j(!o1ILeLftRFHQLFk8N&<}H1@s_bB3qWc7S~pXsn<&$!rb2R+ z`U!mGogNvg5N(EnkM$1T!`Bh#AG*e;R`a^X1+5=;E+FDs0*7KJE53>pr({_M<7)ES zPANgoDLDeZ3CaX{D2s6F;C#%$UsJQ`yIruPF&x;M}i1@+ZK(D3n2}fbcRDxe$MExFz6l0KJY8ZCV+WV?4 zgSMn~ZUm!M^fXk0hGgAkCG^BP0i!NM+{opWS#QNyr6B%_4G#TDRWB!`*aT|PW{+x? z@8iWAy28=+`uv81$k6&obpK3U-OTs@x2jdq;XyT+l-`9 zLdwLgdOVbds*0cGLR*1q=#gDMMX1d5WFbh5WFZ-IHO68~xn+5QqKMB|*Bh9cIsZUQ zBZ{;KvIDI{9aVMXQ=#nL>x;8I89lk>9;3czzSXyRkL+O))qM*?4Dko zI5Oes1nWtGwdTMXvX4-PV77IRyP1D%u4z7I>pa1PRr(j?RnPwIt2x!8YbsFYhW7aD zQvBnH-?)G%ZWYFDOs{1&geQF{g}4%ZMZ!F%Jy)Sj;clF7O#MUFVVJVVci{z_JIi2gAQ>|AC#+v8BRM zWKuQ_dis5vC%@X))6;j!!JLm>eDTL}4xa5EYpV%1x#JhRBjLKXarfEA%;2Uh^n|wr8YfrZ%ex3@Vi#qaxMObc#UgmPi_nLXeR?=; zmME4uQeGQ#;Z)ud>1Sh~ALcBV;ts*^ghS2h7(j)W{uj;OZOtjB(VU{SdM1|j>~qgO zn-!a>ZbgfV>4X*))x~I0v1{Yhj;W2i(4?ZcS~RIJPW}w~!9M6HKJxHXjM82apQMtg zMpZ&TfI^I^mOVI< zn02f;V`%W}*^gB}nDyX#yuJU3@#o1;bPZ2^Yck&3g_b$=JvdO{_cVDB(j;3>4?pXG+U_%;2UociWm})TAPUP<}QvoWLndEDWfcdcw z*mX#AfEqpDSnG1`UCi>a16=H2V5EG$e|*84^~3vJdBqjE#+3&>ldb4JJ5@8;7+LJA z8tH6lXc=E<7_Xix^j38?RA#tiz+K15qt1F)6QoN7A=xieMecF*3L>I;)P%wD+G*{$ zq|78umDJccUrJY<0x#Wa6wU<@6TC7w)r>2{(emMJ6jP|0)>7B1#b0=>gI(GLI+t~V z9pHYo7#heF`w<$4--ApR&}%Pbh}xw-Ft!_y;^S?-CBj+PF$;ZDh@?Hs9D*_(FYfV;o5 zCDiQxlN><^96{@yx(tg%1 zWp#(W`qd!_hP@EzwgNc|;wE|-!Jr2+8&}g*C9+8Dy`A(dxkTBgOK#o3{DTjE^pTwp zq&%?wk&iz3U_3f?Y|6Miel1^k3)^BVXrL4{PzLT;2Yh!r?qje?dL8sqammW@oxE17 zYrRDmNg9W}T?CIG;E+?*l~bT;A=BQgsOyMHRzZ&O(N*|cqu3ptkVkpY$~z?z@C;H7 zRSe2xYV9CWK$|gnH`2L1!mVa@0up6YO@^x*JWT1{F7`f9?~Uo`-FHXRw;dR5FOAfA z*%YXFc=zYfnz?^y_vc2&#zqbuavnQ$Xy4Mrx_no9X{vLZj{%#z|AEd>zR!1_&PbdtQO<&BtiFB_<}LPs#05Q0}J&ReVr^PcScx$rk2wNH+DjzuWp-kGdaN4A-RvMU6oZTct7v z55I@nUM?X7U3o^(+i0Y@iu_)bGZy;26o<$I%Z}#t^_;OiJDQc5Q=F9*&1q=&OlJ5! z11*vK$?VF;{<^Ga*qz}XEC~*0`tGmminL_8GA{Xe<1O#_Y*=^jdQfg8cN z--3Mujo6j2D0~5DX}mpH>ptsDS613$zdJR7kGoTz_)%K6^S=AjTZ_TUb9+K#MfHVa z1$90fFE0#v#tQ3;#v;*tkcbQW*Wnxn_u)PcI=(~t3#qb0?pyK*Z3QL;6Ou|9?HgF= zR_eG9SO~`nr+%at{S)hS%vzvfe68N0I>M&dvzBxU(8-*rPMH(M zHa}9-O@LGPiA|c$)NR4II)N5u&Tw(i22;SwaGyL6r4Uy#I2Kozi5wb9S>uoaPzubp z7D&_t=Tbc^nI~hv_DA$03T}{(&8_NY7SJOE^@YmRp$Pt!^9{ENSys z=Tv%1N>g(R^YZd5eAx>d2R0S&Y;Np~L^>Ot$M$ZU-0C?|7YYP&eO@mU0W& zHsX~=dMYCx5&~Eu!2yYo7u3=ap~7!vuy@!QTXo-rg4yK6Zzu(YtVD|*^icWk`ek2z zwRfSsW4hs%kNi`^RD1b)Z&kf-#aS0G$u4gRpygzC$6N;rSc`Fq-)tNTw3KJBUQNEV zgxNL27g!3VqK$H~3?*T*MvEv<0jhazvF54tAnm(p;YMrWM&m4~Nty{%nZE)Lf0!lU zuwlYtIxU!(Oyo@Y)mR$(?WdqkSc>DPc)4(pgafy++l1-u$;F3dS^|^b$fYPzi-jFr zrWzuaGULfsDu$-lI)ayc{!SWv>Bi?$iq>_k?Af!@v92iP#v9j9O|8GIxUt%c?N=O~ zocy$L?}>2zMduv6s6PDR;h~}7cy(`1agFbtzMA5kk)ElZkw+K};`u+a0^7@zhqC{F z>y%pTslB7!I<%e8LqsqmZ9APxy`;XtB$-aOeW4=<3MSP{Hrjb$d1hw0=V!YgfBfH{ zKJcqPW8IVyL2Dhnrs5A8>o5ay1a_VAJAO#omeFogPTR9~gp^T*BSOls_aF8*qBmZ= zD-ye$ds|w06vMJRIlW~xAUPxRT`E4w;~8kuq$?$wA$@6eaWBZc`Ak5VjtJ2Xn5<6E z$Lf0&oJm>o^VF~8GeHdyOljRXC=f4J9|wKCKI8-Xj4dnIBnpUvdJZR4XUfwvy*s$eSw+VM>U1UM@X$~ zI(-380`NP$oIA%dup82`8`3Rc${}o%D*?CxuUqhP?Zij+;LXK&Igx+HOabh(D!ehU zg_s^L$tI;$JWuYfC-H~h;f3dAK(9){{VAAL3cL^i?!=dvcbo)3e2IA%zXSog*M!@` zg%7weRB0EJbJI#B=cWze$CdP0iZxcfq zb78vpD_DlKB4~e;^YeRXQSf`}apm{4SadJ9JoI5ueo>*X+@N!W&IC^&f}afL`r+;m z_`bN*i~n9--0GR=H;n!X&(_78jjW8G)|-sH_^UUy_GHBWWUN3t`NZPXSf)2C%bPhi zwP>6fZhU%q`J;_tG=pOwlcUaTSYOtLTSHAB?W zWQDc^526(<9y)z7ho0Q{w^piY_%o7H~`xmja5W`J!GVC zmvs&p!dP$#j~O_G@RQP@@FD|BG#x|2E;W-NEQdWw?7mQq;lG!xc=xc0Tnw&jc=gx6g-+Arb4;lyFky%;W;H#|a%8Nh0zi-!M z*f7p^zG?)bn|m%V`JBo2HHY8%An^B!*|o~_$jfM*ttU?M~hCa-5rNS;87I9 zKDd&y!D)O%K)J88ZpWul3CcpAyq`G zeF(RTENSSCBDbZDN9$yz@A~)+@h6Ro($k`S;dNErO=tHst?MXHPu=^;8;nr=<5}6` zLk$a!oedXfm$y&Um(}HuZE=ldmlgE%RtDQ6^~EjGx}vHa0`o%tfzeBvp@2ZG{l*$&Sl+*!n5Qe1GbWkcQpd|h>L6wrbdvUi+2npaz zLZC`IKG`PKq{=~*#ivy&nnVsV>Y-5IhePE+mWn9-kI&7#@5+2oVtHerBy%#iwt9cQ zFVI>;szl4(wz5L+$ki?5O}=nlX3bZxzU$cji!&<2O+}S~-rUtkQwpjZ{Z({rrW|zs zK~Un%xo86Cgwo;=IZ%wpBQxQ2@%SWLLv3cE@z7IEcMxeV1wUo&9~+U0To%=ft;LA{ zZ24yhja@c1b#uJY`1#Zn_CO!LAKE;~|8sN-REqpiQ}({44}$&&c{)u7b*zi=pS6qk>>)cQcYT;|z+I(&Ny;{@Kw5v~wk6=+<+zJ|JQx)RCBw7< zDU*{5d1{%;UgHx_yzlnjDYR3pbx*Y4Zv5d}g`teY?{decpD}_{J$+M6ty5F(jQY^j z_^#aeIsTJER%Q&Dvre)%sz`lR)GnE`WojJAl%fzzuq%j@d?8<{nXwTLH4dlp zuke%Xeojlnv_IIqH%oj1Xa0zMJoeHt-?4UA_Dj#Tp5jqYru`v1FCT--1YJcuxtN)n zrs9EIO`&w4wi+@90PW5}Ar@$Loo&uS~6M$LnWk zAJsj2(WX{>uSugtK-7C#4H7Vm?yykB)~>bpXh_o3XoW#r1Gcn&<`8RbYFu1(#?WbP z(F08WMp@2NAlb$k^MXzVI^av0ys%!8lnlyX1y7Ul*zzX)_w3#SXYW1w%riHz)#eRX zUw!q|_98ay_ zuoQ7S$4$Q+eHG+IywbYlyyzn0yrq}F8tW^){MC?{onrM1F-Psgq^?0e*C6H{5MB=H zxfGsks~nTAeso+n=MStXOc*0m(X-BqPDMv&20Mo5ikk*Q(NBDw2>JNU17l+YH%rIm zp?BtPpNg*YxN;X~>L$Bu-0v{nWJB}z)t`5>zd1P+yn^T)@G_RY+VN2a_s!Mk0u@>K zQM*RlWJ!r6Nw%lXE1)JNb5MydlOm{HG4Dz`ujM^n)G;#{#nYv{BnDNcihfZ1mw3w5 z`P0+AgNHt048&fH8T(ZG1><3PiXo0ZcsM?4KOIZW7H3@WM9o6S$C#&Yc8ATuV03R= z6<5@=RaS{kn@P$qu=kh}+e4qOVs}k22q_(8wCy>41J_(KbK7*GSYop9Ziy+r_oka} zieZ*9b8a}}%lYhTIWoP)NxiNtWO^Hr5vi^RevgX@p%`$3iCC)=Ha&U|>N zCmjDs)yMSF^#EJichpAK-DW$vBB8AZ1H!7iwh*LZSrk=@SRzav=ovM50#EG0gRx(G zuwQvh0V`~1NtFP?LhLIbw3rv!hQHK_d)Sq`3-2JmauI2OWVvx;j) zrG-#Nh7D)9uEn2PnqTFs&uj@tMh5zg+Ip8hyLhP6es=L+acpr1&o3?xl@+G>@=F^$ z#r5@};WC#i5g5)trZGe82_eygv_LOfFH8pzf6FC#DYIz!AY4WrG;IjWc&B~ zVHJd3`g2cNpCkOR^}MGO;8$4iXB1qV%`0{u^DVIRUXwdd!a08l|Arkd#wFp$65x+n z_up^9mwAGff^!DwyNUH%`@IiZ_w$Tu&YREY4zt}ac9{I$dwDoN9-^aTF_fgnO36OgJJP@v3;l-(PKxM(=HT!nw?>F z(m2hYYLP`GORRh0fn9U%wQbWSou~CLVi)DuPKdT`v3qQ1ivCn?9epsiZC4qYi6?GZ z*yrw%*!-p)`(pP<__yqEv3n%^9y?s@9>TeM%+O5J!`%nHZ{J7yGMTRDeH5uIn%`Mk?^NA z9QSkgNcb~^LqE&JE}T~UeZAu+RB;y^i&Dh}{SBUg=85Z!MTbh7YO+f@d|n&yP$|gz zb;&wJJID!L-Rb+ryB@rwF_xw3BvX-1g{ETaw^rN%?-@Pgc!x>{+*<|6q!?Zm?(M`A zWE~B)I2=BVd#SDCZL>j<>%kIrmSe(xXF{C83;R`k zw0~~KN zxY}rsbUfUVy?$uR5BD8|AfvuKhfiwN-ev;^l(7umfs&GeQH% zR>U%(DTpjRR?Y6AJX1dB8O&f4c{C8!_9pDAv7Rw}sMes7qU8CIW=`y@*btq}vkO}`FlD^1G^{3BRNKfxVF`=Q zTqaCg5SbU#VMUNcfE3+Dfbg(d)^v%?E1ms~ybPzgVl0H@9- z;rA!NxpO7_J`28#ZpGB)2&X)U>1~aN){?ycLF;~u-}+waa%f^;-Y;}HdH=nvdMdueQI?)JWykV!0VClg3afAmrf)zaUkM z(J6}4cJNykQOJHRbWe*^VcJ5v7FtL?arzX!uW2^r&C8Sq86GeWMn(=fGph=_Hna7` zmhP^Vq3ZZmMGb?YuJwh3X(g3`e1D)YL)l7gs8*^D^fmaQ#Z7j*Qrzj)eQwnu=9w6x2r@Nq+7r>vK3CSm;O+{Adgj*v!Li;Tq z=f|q*OdiFd^{U!g8e^I=6N0CW%lvTc2$dhsyzvaRh|D#^E|zOyizLXtoA#LA5~t~qkm zxrb8a?&PDcPo6yaB4_RT8nBTCETp-Po!srXAJ{k-WLx9pshFsjJI$%-8XKDXn7%>t zR7|oJct{~AMJEm%=;jNYtIoUUk-|9Q9yB7pja=SP+GsTfW5GdF3jU1*IJmrmAGgCv z3krTL0S+#&;P;#GlgpUp%b0z(L++Rq)ukxzKHN?uXqEEAt+tT$h!vWa=e?sq=3L`@<&- zZU+8f8soBuAs5ER$P){xjb92IJbs;6IGg!>ukzF?(_1a5&F*$hRTSm3buNCG>q#40 z;prZMrxeE$Y6wz+CsqKIB98*K(phk+OV@iA2*`;&!7C5W;^HIA!SB|a zer&ILgTrUvJmUQD>TO-)uBb+gen&pE6X%`Zjh&Y%>n%~MirsJWp``X3$}kWE~JF`}yzAT;2LbB&q#v=U4tC{%;&_3|lSTMbC2{hM6X8-1|X5+;Fmknw%H! zD;D#@eVEs`9WRUd#xUP>8~kTRvxMXRF&q3o$Is)R03O8mK~i`ai8Wx-GOypnLsE1_ z?^KgFGHybPm=Q;_J0p8FW?8@StU8%wiW+kjiDcY`*;1@x#`!JyO3u%Gmt);We#;;P z3J4HggwYo8Ft!N38@u<$8}Buc!FF$aX7X1Z6CK9zWc<^({*gR*A8_}k(6l8rJm8X8 zlW=O(5`Nr-pL9cBQWGYeRMIN2Chix0GI{?!ydS&}{|Wh84CC?$E#3-s-~uh(Qfoge zPN%o8LZ}9)^9!`-O>$dm!jjBU+P6-8Cp+6hk~%3#y)e|01Sn#3X~BK5H4-$od1qI* zGew32R=E>#ZlK5wx&oWbWANDM8fhnP4*}WzOKRJZ_-g^nhj%hvlI5=Q4(pWp9yk#Y4jrG?c_J+)U zY_i@ptG{BUm0L>`a`=&UWhG^Kg~QSB4NJqk&Q;VpRb0wCgyxxwkrvzg6BA2$FV&8U zpQ+2i?LG8hmHHQI_&$23cyIhMwmjDnFsf?e7m9cBr)!9Hfi0n>H3EBUs6*^{iQRhy zcBRjv+<7Um+d!{j4vZgJ97NGtZsAm+FlmEpfPFt};|Hx2l<~tBmt3bZcnzuM5UntP z5PWaK!CVqcrum9|-$d_)v%Dl+6mB50dbYrSfooG}+drEQi%ZWc2?fucBxyMR_9xL~H=Pp_G=Ob03K%`saD>6Vg`kE`oOj z;vLDN7w_oNFHmKVosgnM0)~jT>UhwIPcjD*@=<1BC|`Z8bn#ah=sjCUm!3&4$PtaQ ztyBfh0oLyRyX#w8>hUtJXl-t8-Pt(qchzsIAE@(s>jvtZ#|m6Ula2H9ueV1E%6+-1 z18F6p_O^AK&)vLE{P+u;^Kj9}f70BrViHwrYgZ%P`ZH%(Zhfxs0z_x4;K)AA0ecSa zCJiU&mGI*x9J)*^JoOSzshlnDryng_JO`DHe9lSv90})hB>Xtx;AHeeWn*O*9iOJZ ze}f|iq?tNS0~f8qwrCRsOvtSMb<&@|4#vhh`198ZKP$`H(%{br(O}soKpT0WjRq`Q zhY)I2xXN0Z3BZa3%!?<;#J~Z3nS9rR`v%1F!F*Zc@wa}BIMIC;)ud+IStJOehqzT% zV+$J?J@x=V&g5C4p4zR^p@qEC>Vl1BBVEC&zV$8BXV-RRl+|_B43FiN20R*lMnel1^GPN-`I8Y75tbhN5XMNP#4K0#k)# zA6sFvn~6KL+&A6%zyrO5cl`8$_#AD$bGybTSHCbxdN}}FVhE$DVdhZ<+*96AZH+i0p;u?SXhh*Doh&A&=$tHR!vy&SSYCbEYKotq>bsq_W#jwM%S+L2EQ zOxZhMrlEEB20RCP2S4&vW6K?9UsgN07bk0N+p_aO{@w9EI4?w3n$K-`I&IJHu2@g` zU1hBM8Ivvz?J)*a-k@)!DhRoiosi6k}x7?^0KkK>3b8P`P2RP{AAN$8OW=H|+} z*SGCC&^k2Q5Gr0bv3+CjhU!lLP;Eb^f zN>$XlfcCS=u&=DtO9eT|AS06yWmXpb1WZcYPpw-K4Mdn)@fOi++teSI+2l z>`*^8746FJISL5}FUCwQ_|J@Yik({r-bxI#;#3$Va}r_kBa_2sB$YPdZg7oq!NY1;6UCxA@(mgN)LqEbnrr@{ zGCDO?D7w-7LpLsy`JBaqFOWD)W3X5SJ9Cs-C_Fs&hV!1F*HjTy+_D!?pM~@-1_eO+DxbE5)2@l*$r*+EO?4qcur$j*;FR2s}cddc+Dj3W*a-yd;9?z$<;cb0<2B_lcg^*km<)a z$}$2!Qmjvv(1$=as|G;jogS&v;hphkn`2X^?&X+fb4=OMHqWL?Hj++tV?O>J8r8L> z#sR(F%q^05`DOyX7@v~xdn|mt=A4J6RONU-TaqPaxhKUQly^WQQ29WGuoNCnZ7{LK zt6X&mO@Wz2^GK>!X`p*5RbY&OmxC)*qIy&uvcgDzGJ?80o%1l2EMI~`%C2?J+|t^3 zyK;`$QE{=tg>zomMw{2r{xatbn}+ZN+Dy3LMw_^w-b#7DjWz+NZ6u%nH9M|d{R-D< zuK!7(WybWl25GMUJ`Mc;Ccv+;?*Em7SAu~Jh&_z}jm;VsaIuFZ-1L1&IQOW8-;Ylb zKWm?3+JfESjY08z)EL^HFW}<&5^g?U!ufm&H=i%z7^7+Eb$M{!(2bUNp%4BTglyLGe2{(O10xsfv5`G^(MLZyz4EVec_X8t%4kA-F z_-z*aw+ZmOEch!4@Go2NmlNR33YE`)-h?9tG$5oj;o3%DJ02W;XB&_C{501e6n^CW z=ULDH4ey7Hs{$|F0BK*2ZH<}?9;G9Xs$tEa?mek^p4I@8@}HC3oLcBng1fNESVJ~0l#8g;u2lU~c>}tjC07X)TF2a^6 zf(ng(hsXwNf|sHeUW!WLrQmHW85U`r+Vx{|A7B$%P6xE=5bjxIB+8a+#>A$L8#h(A zppn{4PN01vVtEV_vJP|3JLi2@woP}`y~eo?VNf2WsF)Sc>S8gtbTjzGI>MLGl`NaF z%Egp>PSlMBJqKd3Z(Mo!@Ri?qV0mR_`K*tA)QF85jd$O1$KA7+o_qeemp(lje*^TR zM(<2DJ}T&G8)lO(=&VM}@a^GII%0?FDJk$QzZQP1URuS z;m?_H@R4*OYX~O?X}67svQOUsl6k)vzxlnCHTL@{YvldE;r-Yr+pte6uzJ-zf2C|q z4oi}RsixjtElofb2@PGB3FMSsayjNfByOANa z^GySEbQ;a0JBG@Qqn^6a2##tDsO+*U8wYC(;*S>84raISxO#I@0NHtg z%!;0tz?SVDJ3q91`!{C;Xmy&I*}XCpAkI0rOd)wgm{_Xow@hra;KZ$jzih$X&P?a` z6`bBmsXfZ)a7W1dpX2?&T_%1kf?~b!oqSFA6p^ic{1(4a4#OmVqX9|T1_}`V3aNYWgdb)SA*nD=TR=M>?h$-SEm0OqMT7={UVWu z;t|D-sCqW;jsJdmdV1N&=g;`>jp6uroT;Oi;=j?=zZzFxc_pzZG6@8Q)(Y&Jy6Q5p zk|Ow4SintPSi;G-B;3@6C7gUq!cARR!nsNkp7?z7EeSVuVR=7SNy4AwB4M1%*hwjZ zZxOCEAHvs+)6|g@zgO$X5>CD)pZ^;^ADCx#L5bj7=O**5Bw6#8e2biEt!Fz83r2C1 zj;rQVG9e8MmXP^mD#n53JMT2^zVpsx9`%U{XV=8U>W?Rqn3RPP@+djOXT=QB&0qAo zmUO;I&8}FT6hqBU$H!D{j3#SE#TuY(eKt-aOE5gDH%D(J3yixx0rpahSNF%-mM+X+ zPVrPU2cnblyO)>IdfAP(5fw}GzQWpyg6TQq<@h;V-#Lu#DM5$uWn!1VoP!JCEAU{V z3npe$4*+-bxPV`db@vPUgntO|7f-^oiTmG0xX73xJk|B>v*dH$h3ELibL9O$LpLFP zKc6q*_c^YKe;M?EZ{z*ogCD0Vl9*|vFrZPQ`{pF}L6Y_Pva3uc@@tq&lPUPDnM*_G zu&iO0SvAa#XL2U;9>u#X>l5tUz>Y#~?G1*9c{QCPt0v&|$B~${{Gb16%o};7Q}F-9 z@0psKdV;f)yPHxS{l9??a~DfEcdLY(yH(~P5gUYS-YM@VP09NuO(72n9s+0+5W81M zlYyt%nObpDABrTSL5m<|R;VTt+Kr@~s6rngoia0(E>syMVzo0nm5Lrx^rRu$j=m3Q zB;|>{^S5d1dk5bzs+xYA2HWxL&e=C#L$K(GbHnPt05d{j3i_elqcJ1l>5BFjt4QT!1U7Pi;UHz3hhOG6F5ma^vmq`@t!;3DV z%u-9^P*Pk}$ui}54ObuGPcXGnaT z+?MN8>tYMWc3ORzn%JPDHYWHrl(6{7rRTqQ(eEt)68Ah zCiH2pMw-j?o`_v1qzmE6-V|?pz+$D~scrH(C*^Y_oX?T)R|toUZGp~J39DtAbw)+V)0nYIk6N0B zwGO=z?6P4*`c6jRI~l>?(Bciglf(=Uw%1{MC-_tFPPP!Qz*V*{?!cqv{-IPE1RC8* zo)o)dMFgkqEmF~XOq8hEd@%+xFLW(u&eD0I;fC!a>th2mi=9)A1&7aDen)VyVrgvM z`u@3jwhF)WT&oP!p29Ki9`Eev?3f;i?hIP;4FfUUFO)6RBxR;10f>! zKsi>g9D4u_u#)zGY)r{LKzCO@rciteN{7A3CRrYPfW6O7%6T46&~xh0y7SQN?CQ~k zm^%4J6=sr+4TzHtGGX2_>sjVO=z7{D{ZMm3u8g7hp3Fs}29KJ~8Y8>6z;g>tpH0 z0!|H3!c7fO-cK$j;pTcuIQO1}zpU0-!l?mDxTyigEDs#vS_ZBik0}EapRYAQ38w}q zpKoe_5>5?J!c7Y|2Ku6|-cGM-D*i})#H2Kp52SaAQad!DiTt?9=BiUcbfKCziCsgj z&x=RP6kGP!E0gXxk1F>Q(QfpiI)zhC)pvTnkXqW?-rif9x|~|n6!O&7_)9#xm5npI zICp9#k_R(#XJ@Rxva&zcY1|q=)W3DQzbw0~qB_68!xlCT;b32BipyEQckN%Cp~Zr@XB~`;zyY+81%Tm9?khIa>RYIDSUqGR+k?pdFdG7upqZ zoaXw=Y2a@pz}v0oysqFu@Re?%UqIim>EII19Vp@E4wP{2KnXW@;M(Vy^Y!5Q>%{YW z5}q&Ne7=O6&-Y*_uM?b{aE(uSKfhPrZ+`FE=O=!z`Fy>@<^7~h`5Zx;z$aup&RLudEqCZVq(Gt7yW>IE%><6nEAs9!Ys{Ng+SQzjX?f z?w6%YM+|W&))k_3gw+mi5nn`U0qu9QZMe$*;F0P3V(%<&3Hne#lHm`uRL+;Dq&@2V zar`^i%UqY$Ho-CWMAVrvlw| z?7>I*k0ewav*-&TL>-9y;G*xxQw(Ru7mV1v^P<&{&pY?60-Xl3lpXLoGgL9h?@c_P zI7y>YE#b6AmEb$Z7vq>ne6g3VUAz{JZ!E`Oh7N=ikq=3oX9S)XFTO9wv7N&5@AFS# zWf)LHq#nH$8BSw*Jd+cttkLes5Ufgjn%seI1OE_A@%mf=r#IegWTD;gWAUs1_BZ1_ zkIoyHrWlvb&&F@WgYU%gxj=HExO6vz9P+zd;BV*CB{%z6dw*Io{*hfwjH8dV&}4a0Yhl7#QsR zAzSrLB5{#fjB%k`vMPxk^U!f!aM&SsQWC$@C*yQX;qOJLX01a0+x}w!nKeb#mXAkm zXPwcgwJ*DijkYEmH^`(gxtWTfgVhO`7uRZ_Lq>(@tr;s)iDTT9o< za81?N{^|eorKaJA;#9Y9eSiDXK%geN(lxeeOYJOB#a25!0QSywB4tS=TKLj9L%sS5ni82C8d~ zg_YU(p;_aKyDBRuJFnaIh4|=+>#sjyTyfUU5A{I8iJmKho>M`*2JBR1(O}foJhu|L zi6Vc=9IN6hdaOz?X+Tn&xde90e3t69foPrk#Hu>eYj3oUxg2)`V4zvCERRjYRhlMj z^zR1>Slk2J0}`0@#JrVWoGOOw40Y%X8c6fd9(WLt`s525XQC`0t_8a(7B<@4vnPRo`$7W6!_l%tyo*-5fk% zxs3RlI8he5MuFblW+g*DWR>Fr_VrE<&HDR-XKg%te@9DK&pWca+S}=t&>er zJ-tXi+Z{_!F`ymWk`fNy^h?rSaBhozet)x85wAfO|aRM2OC*X8M}0_ z9)lC|bt=lLG^$WP06BuQdwjw3Vi#Vw>9D7?ps+k|d0?P4>^<{Bu!F}R|8A+zo#OJ9 z{=;N>_3h7NKHz)CZ!w=j$1)WQ+0E9RPtxg__Lj6__;xoDTja^IVfLuyP7&+?@|h}) z-~&ADpma3PpOSXD)na>N^iCxKcm)$yC<@ zsl-UbNGEpiXp$ZAhcH%?db1oC((fV9OE)q2_G48tSyQhbD;GUWQACEM2=q`_6d_k1 zovxub`#{Wpjp2VT@#>q;KTiuxRy|W+C=isp7c2c2;PkDuRZXaR6bgk2>=WzDvT%$+ zEUhQF*Z6eo&-i+-VtkbQN7PvG+u_T`@1pac;O;46G}Bn&0x_CldB6%opC;ClG%WjQ zv_j>^ilKf+__2(XZyG=Trqr7F{bv4gDx74j8EwXRnxUn7&`WTEUEK?yzHbowiBgbC zF|YHMG)(eES4(lBQKVE^4H)DdgAQ#A*>zj7UAlQkw{)mb#g!=o)p#c>&44Sh$>|ZS z7UEwj#p?tMs0YJeCx+aOPYelIAFkbiVXLhv8}WekAN7LRK#32;>1T7ZxBhQsl2I5#xh zx~+9M1of!0Bzn$<4d+BlDuaLdi~YCNlh$40Ggz--&_g-0JyN00kIcXF>dfD1J45X6)72$}BebD2ew3zCDH^ zyohfvbX=Ou6_d&clS(Bto8+f)j;C0(9B$za0N@w|w+NM1;TN8+D;sPW_$@^&r8+8# z6=BQ(Woa04D?aNkU)Q_5CDt=MG#`t-QdPAfcK=;%k*ex{TYVE_mUb91Cal9mjJ-V{ zN}82sOy)TZ?5D(YzSO@!&)hZm7cT_nqQ)b9VIUj{)^01Xm*+T-YnSMofBUsd((O*Y znB?8`(sNPs5*Af1tg|2<5(Dg+)&u17LXd*1I$JP8daKW;;5EI~jH+slIBBd}BW9|Y z6n9huvQ0w0Qq>CD@&DGmcIafC~&j<*4k$H$4~#}9~O6P+wjbPwRCp2Tm#$h z_|}ER&6A<}#`@s5$-m6i%>+#rGfO*H=^nBtWCjqy-jMpVg`^cv>i=Pv-ATHL7otpB zL|!>3FXrSGbCQR0&@RWpR!R#|o_IYYQfyCb3n%rJ&vR1ijrB1I2>ZN@he0>jrXG1Egb8szvfs!l{ikxk6r_J%10)}7WNvJ zeN)YmB^e)DtCJ^&(;UYEA%YEn$4m{@YVt7?s_l1yTR5 zjlEljs?j;NcX6M8uyDL5*jroplo3v6&%&mLK-Xm5^jX8~A2Hd{(Aeg09H_}5u6y7m zXv929;ZeMnr}Ua9={19TvMuSC#L|?HLvvWQ8d`7BYPfcW!NVl=7C0@Sx9}hnDqFGw zmi3nAnijQ9b8&EIOHGC4Gy>NY8?*dT5pJvNyY0~0Ehf#kFqp5Iv(m} zuCdzs8Uabd-5#u_aHlTJ;utU)vG6R8kx|oBKxNdFoPkB6)Rb|=c&|J)e$b#+2aB=E zVEHt=Iu9C?11;I*g(DlbZFoNRzI6o+)xE~%>q)KGPpZC`63850=|7gf5s3Mdc%TsTyYYrcd^vfn(NPKIL3sSL_Mzk}A1sd$ zN%Env1qhDg${lKn7}F~Y@pBf8kKEE!^UCb#4?p*l)uT^-`qQqoYj1wE7g*Z{EHTqR zRpg2rn4iPB8MCW%JjfsQ;uvU?q7~QDb5br74M@sVN-zRwzSdEpt+Pc4g9HQ#kUkX2 z^MnuOD3%d8ap6EczTrtoq?}A#r8A}Qgp}sBaH^C+7Ra;O;e!u)qb_cZIvz|;>5kJQ z=}y6!Ts%P%x{+(@z~<%je2*9B*=Nr!ZJSz}+P-l#Y0LhpC7$1FWE59> zGo5aC4Vvl2e{6J#SG>8#jr{S#s^a)xco*r7*+Chw7h33($XQcM{1#`w$>nTYb&kzm;%ggd3^jE3owYo>A;X@_kA~~IOO+r zg{mg}0bizZ?y~dH;qyOx?xf%6oh=$U^M-T2y*iB*fn0PJ3SQDEBf64mz*~^FmJxJdUkYP!jtms&CihOG+WqghR8Pgu%paDaD=0eUi;)d%>an zod_Pfa$QZvb>{?M+;&}qGyI;-&t?@@HIxs{ZbRz!0~cRp%&vZ^GVEiKQ|ZZP(D(9Z zQ0D{4NB;;<8Z$eV1t5c1tj4S8+nR|la!{k%1GXt>^=9);oB75e-pCjq{alRo<=`Ro zarxD?M8M6ALMmj;?&X&-feS5?AcbmWGoxM@EX;ZnM~QiJ4JspSPDM6VXE>u<`b$gu zw?vnRxAM)_;brHB$;l0fw@q#sPHA1(KQOR=p*3aOHrspW#`N7YOEbIE)rHgqKcrf% zZn0W1$Yq{zn?;@MH1@wdD-x0WmiUbj(q?7Z4(XN>}+G_ z>NG~$hLP3_e4gGrpa+)3N0oA~@6fzR@=3V??B0R4r4Qg=9O{U~7jOorA4YZMNf4u~a(V_7b_dQ*iV0Kz5D!;C$iPK-_cq}frpNQwxwxK;xnJ&B&Ln!r6q{Wgn0|bwGy`^!4}o0`$b~ikMJ|*ZKma#<12Gz~x6resQL*G^UHiMp^3%K$>o%FQ9I8 zDX+SC$F}{u{-5==hhK!XN zB<$5eAnkZ#NX6!a63@z5|UQXZ~9 z5g)~OP}^gcNDjL`udU@v3d`Cp7~S{JiBB^H1K&v>=4YGOIBK!hWV=|9WpL{WWjP2@JW={%&2y|w8dB_D z(~#yv)Q5G>ikau+2j*mrrXReCM_@=kWX8_YWc^tML+mVdM@)uCff>=hEkjjw!rD&! zdP+EHyCw_!{d=?Ngk`T|>vXU5i5z*VOkLL`@gcKZFmEU9749)k&xDKo0||eKaLk*z zJS(8>)*Q5v8$P7O%PT}yDC(Z!?nE82EA$Vw1Wnp9HJ5EsYU zGkVIHKaW|Xw;J@U2nQKk}hca7+xP^5=-2Or0aQNhsE`NHO%F;G6+S+661o36Y7jWyIz0#f_C~SRRxLY@PDuIz`bnm@7#fN9=^c7 z{=4zjZ?Hd_%AdKP`7;pgcK?(D4 zn9f`VvNZQWQY9^~HG^KnLJUF8+GKcA3}bAof)f|X)avYP!}tJX+>B$<^orvwiQ=cJA- zuzax$E^|M_8Zz_Qn1>2U1(C{ZX{N$3oLY%}OM6rjd5M~*{982$xmQJM7|TqYugX9A zzdf;7Pqh9+o8BdIka9O52dS=bdwukIPW$r9AOB97m4_7i%4L{4BeKjtF@y8!2^&`uwxb)~`W#cW+Q!&8o<}f?fLW?Ma z^u)^;Q=JuKQdFtAb5aLN?S+!=WNuORx&%uSiyM}~+AxL>tquMI=-gOfGG|#|N@B3Uawuwi+5!;$l|3d{4ok00?tdXT+iICb8^{koip}}^>U{C;um7EUUEzINn8P zcVbn++s`yf5!D(67ai*)2s2C06y7##l}trjt&T|J;v9Nn_ZjZ{V)u!)K?d{l&qHp= zY&PnL%w|)15>yM7u<4F_b1nZ-uqL-a;>w$qY<1E>xOeHDo(8!KKDn zA@&SyQ>hc0Rw+a|njaP6C=6eqD{M5IhdG$niKY0@mnJ5bjK-yGv*~_#os7&+#glVqHhU|{H=5t-dfAw_*wqQY$Z z5X6>nM{ri3=+S+uQ*NPv7^S<|Xq&1|Z>FNeMSKUIBMyTJW#i?-v$;y#FD>LARr@mx@8RS@gX!m4_CNi5;c1 zYEGKOS`{(67R%p)vzT+KanN)NrB zn9>?Fz&^1&XhbqlokwQ20gn^z<2<~fFPY+&ESeZiRlYCE}to0j`XKj`JOu$1S;HtZjVR?$(qq&rIT)Y=A7m0!jSx_D;^*TX%?#2Knh6WV zPZ(NkJST#0@0V}fXkJkawL| zH48$~;72v}m1kRb`aWOSFwzug6}^2`bmuBF`U7y&NJHUs#&8KcGKp5c6+O+R$M3xJ zxYe_l4V&_3i4*KT=VtCJXTO{~r)a^Mha=%C59j3Th}vEOT4{3pk=j;bm2Xo2KqY82 zGE`}u252im(c0Vk9c2=|@H>7B+g6a%QSnAQAQ>||1{Rp6T#lu1WCS3NrOi)aT#q}r zzu0yeG<*~j5>Gm5zNwOL7!_`Ur@To-g##kX%=1>6Xrlbe**>~|Vre2V7YzVgF51xi zyvRiRJF?Lpev&I9GSS3J4ak*xl}p78wR1&=T7+KA9BimIoBsQEWvEp+QpFa1s|+=% zWj2GiP}__^fe~KJzb9jjPR!TVofUYCl(lnrEo7#Tx4u=*+RBAl*8>a7pw|?U%@Y=M zD!iHkD>7fqlnWA0elOuK5n1@Wgrh@>g8#+_uM_fN7!b&ZKk^T#Km&GLLGLAwSlWx_U zDhw4*A>EdMZc8NH3V)o8rJ6aDGGER3pFj(9)9m?b8y7-hB&MxRR};~xA>e;d$ciu1 zH)+WVAt#iDqo<#Qk0c96pFJh>L~XuFicWy>>Vm9-y!?z6k+FB6b(}ktX!z`Bk+=6s zpwi`bW)zecJ<80z&tiDwo?C#8QpcxG>#fw-NXlXPJG_-rh$eU|k4o9e{8>s<*%X^T zmPEIu$g~jIBIc|UG8F&mme=-w_>6aZDttv1o~5yoiq?YN`;h`TD{>TH4OJj|Tvh+C zv$ZWRGe^;RGL9e2A*SyVxmXn{iq{T{Tw;z1*44~9%X9n-$ucoFDQOv%#-Fk0gUYNmiHUD|Ff&70r%`^?Na=e;BZMgQ1e(UX~T-g9Q2 zdFGktHqXp3DukV`$1q!!8aWiZ|Ge|=Kd*^BeBE{I;ijOaNnMN1L=-4|yA+j(aY@$3 zQ`&00K|$Z1jGyx^3`*0t%-9Gy?eLWGNfT2Xo@ifV@7n#U;NaT*CQuj)6W9()Es3!e z>xVJ6#`*!_nAlq=+jWRgm)+m(ZXed`*_!P244M*nx@@#oz3=s`H@MecPijlynQ-g% zx&^jnf%g{eky~Pt2$bj@g(VYoF7+Dm(wN@aY)Ac^Z|yZL!Qd*_#r9>`@0< zD!plS5dECGxPESR8U6fG|GC}mO+TlOuHUz|uk0NqIudPNg*IbvD^Pr)a|LzwM6YCu z{b^K|fK0+u7A!7Uz81JgHA=Osc{&VFmFS1WWQ%ftz3H-b8S5{5&#&*kd+pt-NPT(# z0}t$vZy5gm_lH?*3HtRSKv_zj%Oibh7+JrFF%tryj0GAzNYS*yE<3J4rOS?Xbl4ZE z_u5bNMOvO)s(Egy9>L>)ONMf-&QQN9g?@$Qod^*2eU^T+F(=dL&KO*KVaCPlFMREV zi_cx3asJv1fBf}xSKWE0@|Y*r8g`Qtnj97@=*1eI_ZPsx1yo zhPzGz8N@*~a8PY~NsMAC!GoChxrmp53 zX;o6IQ$~2oY9-_DlqoizFQm^f3MQVwhxM5}boEV#>yl|cv`AQuW|oRvq4Kci3f15W zh=JE`TJ6u|{_Eh^;^@T0*~;#cwY>`$*Y;JcU7K0jA6q=;VGYjd&pvzpxsfk_+0D&i z?6oSMHr@R=`kGR=Rr(tHhFM;Y=dzEhtXsevz``2zJ=am>IyW;8EOB1r#PQKV-)jX? zE5uwM%#O{~9c#qXss64@*WbD#45~KGZrEx9=&$Zw%=0-JV(WKFPKcCfZGVJmWv=n;V;3x^}nvtKFH= zIhC8&56wHUQ7u}sI5#`Khg+il%e34NTpIu7?8R&&dmC*mCoM-Xw8Hzur1WComM;y1q;|Qlc#GNwy0KP_j^f=nO zH)zpX-9*1JKmWOI9eZs9T10PQxpNa^1QT17qAsPhDA1o6^XZs2V0myR`YX$M3YR!F zKa7lN5Hq$NmQ!)E7;(X}jYSNbf5_rs_SlBC)*tAvg@6V3dg5XT>{ti7^;a&b-2lXM z?pJ51C*7wo;woTxh&E;8Gwd{5rLRq;@FCOmA_iVgmm|FNZr(f@uaZp_=35E93Z5wH zw8pi^J(LpnNgLv%5WRjl_8o!Uohz3vUCFDXv9W_!;q>W+xYQY!UbyknOE+G4Y5!@x zi+WF!KUd}F3W0-ZKVkMa0{^S6$p*-A|7&78!+Ic z1=LR7oec;N9n@8TOmiMXbq0U9|r~3fK=K#fi;I)ct<~c#n zU9zkcOR*OX;}SepNQ(~UPk{>l2GF*1 zAD?_U{=$1}rL2`T{tH0+I1FNY1a>RQc^D7Q!R1~}{zP;#WCKgRfX-4pX%%$pv$TaE zbhHhEY*RMZ;wCMA#2^;&smkV=jWw~>{Eou;eRG%3s%z+5wRmVjad&=eV{^-@F1H~T z&8Vmg#H1k9b*~t-bSFD;vtH>tb0${UC-f?ZwH0uwei+g$}6(=b4c1p$rb`i6pNP`*5A}nR9x^ zM{ZNg&z$|+H+#-hbDly!>_$KA1AKLwY7*n1YdPr!HDtjBhEW=22vA|MKI+o+%VqV& z0u|SfYYm614oFvk1l3CzGe{)?!`w!a1g##}mz$B_)G&ML%8`NjMO_8Wjm`L1S(`gM z|222VUzAnNADpvPu-a6YS=UsQ8~GPt_H%&zARv!AGYLBm9gsP`@U9#wCUki0l?%j} z6*tVW2oTrGGfps*=^O3=tE3-RNz^tXk&UQXXRN4f@2^WtQ<^STS7?VY{YlD%&Jz?>yL4UL(N4f2Pa{tKXxN70UH&V2sK7TId)!uU9X z9tc{X_fLgF3zE-(_Eg2K$RKpQSN`h$K{aD1id{Hz-E5e)p7R;t>Isat3a1g4Iie;U zvpaR5fHnC%H$@)^>g4I9n(u_-;F@IK5S9V5D zM_tG4+4z%_k=@laYyL~KvuES~hikA`b&dQ1rF_v9q7hJ5*xO^vJLdoAoMc5qj~ljXDwR1 z;!Z;{Zcm6{%IX$?U{+nz(1@WUe?)?g|3N*8bLLM*f|mPZ*z_h8_jD2zy0Ww_kf1oW z!SAv}(x0LP%{qYq#Td8`1L2!$+oTdSeG5)Tf-)vCQGzDOPr$GrSe;CM1~7yb|EbE) zHg&S{6VkJ%GM)4U1^f+QZFer4PK69~-GUrsD9)xxy$vX8Eh&jIp- zfc(S~Gk`z9spWM=;C0$_oK9j2w|E;8GwTEb6Y>(&@hDm`nY>H~f3m#nFHVw|3(weY zq$Tk51V$I_lL@3{;O{lkGF^>Y1ER*7XSC{8^fB!c8mX=3WUpeA)6%j_C_wYv^wLt6 zv&b5;lCmLRcBV>8BPp99G_%qR%bq|=KCI;?spPYU4^B;52JJS|Qq};3rDbhs-aA=Z z&V0Ml@)wf}OV9bT+N{0?%}2}1k5KbDd26#Iy{rtZO}GZmhSH<9!61198Sbzk>-`Fl zspSpgu-Wle5z-paVgGZ{x=E)@zLo6|6H7(lTCvZ zf6#r-UbRI%0-aJUQZDxhTcjyAwej~zD>Z+jO-;>`79m#Ni$3;@zg>iJPyGW% zoHjoBo(szVd}Ph9)MtO*)j22rD)^0Z9sv|z0q)DGpWAitR7(H4)FCMa^Au#4(j+Qp=+csELSy`JikUM{1?%aWys~-KG`r@B;bY~V< z#VX4h`scQ`569*SlzTuSp9hrfjL5G^vP2C(Ptm^xN^NB3<0EaeBeaurfM`x`KXnc> zS0mFS8BU6@Q4|7t7&PID-j)bXioo#H`x2RU1K+l|g+Kle$jdij5ruxRly4sq` z?uz!J!Op?qwpd-~61BMl2Zq;FMI+H@UwL7qq`a-6vaY+ez9lmwv$e5n5dHZD^b2ji z8~_HJ)bnjphB^o5f1CNnpzQ&j==nxX7YaNrUuXsUdzlk>86Btn76%YNt>rIB-xsfq zSY01c%Rc{!^SZm|dsnN6<{kN2&+zEpz3A_+qdy)7bakA0%1@H7DSiwipF;gn1^Yt> z&{i49us#Ve;P`hv{6eTU7HDb6L{;s5bMm|L>SMKyP1VurX#;tOcV}nj*452gFrqfM zS2dK?G*o$&HAUIep6uUVRyo+$zZf`u1W6 znC2|h3sBj~cFd-DDU5*)>}%fxwQ;*QzL=x^rCy`D@|L0B-aPEyHhk@1{1+fM;_4xc zILg-nZH*2(L)z>B;gG$g$k+5(YZbbygnZR*9$GEk@{HDKH;UBOD05oAhMDk*iD>sY%d=VkERDK$68MHm15z0^Oz$;uSQGRNlZdiWOr^}fRF8Z+MX_EXL_QfYTIQrvZ zKsTBE3}8y_k1A+adc38RpNXhGN%@&If%v5S1k@aDCzhY-VYl-0?b@c3$`i zl(7e`5Zjd7H>8oC0sKaKip9iUru2lq1Yd5l>{M00>;#@3!e~1g*%{Or?rkeOVV!Ex zJ4M+!RonC=WoOn&iB8H+;F_42n(R!61FaEQ*@=m6!9zOPi3yCiE;}caoR}Xig3-Mc z^Ytz6_s6%uJZ*Naz~6}bQ|BIur7jx(L)zc}E#dd4@cj=GzW0Ae`ODLk|1 zBz*7xK0*C2+wbM~)cR9@Pb}a5Uf`Gi!-V?n?-RBEm4y0Df)^AOLmY+sxO=;Mey%y+tJ|Ctia1Z0ZWAP7hU*Nk+l2#%2{9BL`R-Y@ESxMcM|z3cnbCGleQ z`X#DweeWUS_9C3{bR5=B+PYHwBteK?Pwzs6c@MQ9TqhD;sG^aJ!c~1sYErMqi-VeC zz|#_oCuLi85VDrB7R1xcmW8S%Qa?~19qLv?QFWalimS&oqCOF>0HUsnT)0hvH z2y(%HEK!v-u>tQotl!@fX#{65wXPCBTWTDP&F^R3~c%q)cq28XW?ZAiWk$`}{rus?A9?;5(e! zjo4SNW@;rlB%VPS2v~=-)qv&9C_N1_T$oJW5?9FLg2Mi$cgpMpU^WWS(GkD^{kMa`S?6Io>0oatlGopcIZncb=3R|4Y@AP;UI_ z$PvHX7$|Rnd%lJ@RBiw-SsF$h7b@y87t`Qg8$WD{ovp`RxnC^$wG!pdv*m{H5WuU; z1+?{MEPqymdstnYQ0|eD_|afIp9gy3iY1{J2LFc7tPIl&PZHAuT*&|jwG`SRzDWq? z=@FG_I=%;s!8jU))c0gpr(4wO2C~k2!xsFn&QVTX-YkAUVO;Z13jc<{I}px z&q9v=9&+bCXduU-e_Sp)2!9)q-;U!={)Tt>8{l)m**1W)Rglu6K)CD;br4>-L%t($Uk>OX!)bF@x}SjK2Cc70fI%~qNN^%@w{jT|T2k13O#CRid^ZMuN7<1f zt*e^7s;_J1V9iKrQ(tW6Kz)IR<@bW2&(B&n+*~`fx+gccexRi^)_r>2g8>ZrfMK15 z!3|)*dSAf7v2J1Da$i=ANIvdGQscw$n7~j_KQJ@a*Hk)EGq|#=Z`JIoFbogYo!%WQ zZ5gP~&Fxt|RNFkfZr0}m7)qQ~ppdIDVGKOf!JXBl@qno11U*2`A7&WgfZ1xa1JX(K z0%_;X8!d%O7y)C$gU-m<^ zE0`ITNyP^u-kp8TeAQYt&{o;9Z1aNCFI&;JaYgguB{f55&FVgDAXZe@S=HfXj<}DH zWP0^wgUc?Qx8#~NvpUY*w(OGoyL#JiSTlFya6|LR#=)*LPwR~~skzsxI*###*3~7o zuA5O}-JvM4I=wlj*tOkg(=2IS9dg*V1FfS@%abpu!_wBJM!^H?8O*)_JN}3>hwe$+ zSyYUmY^V`{-BHz9R}>pKt9#a2Lp4hlH?P>(w&JqW7i?bEQrR|8)vD%Sqw3Us*UnW< z(caU}>>AuS(%dk-aqgNM+Ize1zhv3Ab310Oxn{|{3zrR+)dLl1-T1$$9QT82H9XUK z7`dGBLcASDjR#rN;C^Q8GPPR2=N!d*qyBr@DesN$KzS-B{-9coy(K-Tl(Q>1VwSYP zc4JPBdKvfW$Qc>&_W$9R#O_hNKRU_#h{0_-h%pBYXQer1R__T13=LAUYJ2s3JwF$RMB|;HlrdHRvu&` zlDW-1?P9z88+v)*n)jzf}ukw%ZWr@!=m{Fm|2OMnD@^dt1qhu=X+*aKlm z(Bt}_1!V7wfTI|_zr^qT0>-mt`557@g6w~$xh4fhrcMVyBtB&rHdkwKx1%s!kUok> zNAI!!8}a~w04~tS5}!V%4%gHus8Q9(h!@= zVIhlEOj@jIDNAUHG{k*KNKZtsrKLRFla@$RMMw*iXiByP0p2*??LT+dw}EF&c z@@+&ZfwrCjZN0lNhN;cM=u_N|9SI-`M-vX2=~R)U`DbNkb_cYDu|!(}Emfm&*bJ*j z#_l!TP`GCLZ!Hf^{C0H57$P-yp8neqj)QMU-KArF@+}9&gx`i}O1{n65x*+2-ig0Wu2;Ub z^->d&{)srX6pM&1H(DwDhLJS=D|!if_y}|pbTJ078T)`exr_*Xk5WcrKPQy&I0v#B zjVL4A=}7Ql@^nVRkpW5}tps`r_X5;CNdJoT|B;af0~H2axXcz-;rm5-JWw{uq-QO| zFH`CAgql!Z1L>ID0==u-NiA%OxUz5wRKJ5>ri(~`X`*&&Tuq^!#2gsI#O=&RJ4v@Z z>EVR!Bt<0kMRI@IzQ{y*dfcYAQ;M*B&e8;S;j?r_+*2kH_dcKGDoz{_soo zpXRe^%E&bB;`CYiGSC>50o+I#92?mVXdvVpCmf_JwuEJXA|Ri6f;D(A;Sq>(b~G4} z#@3GA8*p&H#3ZUpEKzIJrbNGu4Z@d6RbiRH5(VE=#8u7?Q%nd~8mi8OcFGDfV_hN= zlWS13VMtQ3=KxC6SYZvCvO?HHm`tdxNu^?#bCIN(&X#J>;i$&1BC+*CYY9?KTHi!X z)u)uCI=E?9Hm0}@#2^=q0^8NPuSFM#IKaUKC1IA2fr~Vzvw#BzDbk3O?sh)|wnkwM zw&wS>XeQat8L3z`t434i4JF`}i$uY*Pz|kjVnbJCs#2rELs8ji18cML-PDH2Dr`37 ztAPx|Y9Uh7WSEkI;R>D%Q&fn;u&)LUzh&J2 zPAK|a!2K>rJ*n&+$9;}yoYcckDeg7!0q%{S6mevfrX4{6-2_1=98#oEJqW<{Kr_^7 zR3{x8BKJ6|j4qYUc)t(_O&XtxJV1t-END#B#Hh5 z=3;6xOidcb*a)%*JKFRZ(6tSiHpO>x44_qy??|X^GOWo^PT_63rnFcS&SvyTqbr<> zKFNW0`_A_XYl;63n&rFFCsNy092@UcpBStKePZ;tT&|NPUo1*5hYecM_uq8yZ+Ko2E|P zSqXAP>YNy(DQy(NqQ}sQFsi#QLB^b*wv+Eap~Ff04{b|6rzOmM!u%oBf0MLLOS%cD zWnxUe#kNgSTOPf`$)|Az+Tsa$y7mO-g~o(zaVyFhd5LJxhMOe!Vjj=G;Q|9X`cINh zHEuPx$L70<^on@^Du<{a_Mp#SSiR=^h708Jj9)Gu3D-YS+XEstF(1;=m?DPA(czaA zK0YE4qu{GwBLK#z8#J+ux+j*2NC<($OM)X%?o1z;Y6CdJ6v#kgt#DJ=T7>X?4T^MQ z${2%Ilo4a=Su0E6n2ak1)dq~jO5F5x9*n9<#_$BA>f~#q&Jx0Lpc(lb|J3qeX`R-> zM16TTcyLhXL_8RC-61(+y&RAsAah!{^gwflCkJU*d$G1|0-YKhy3R^ymw9GB0X4YB zLerBck;&!`^xVKq__kNxbC2r8#n~c8AFYH=nP=t#CMr|g_8j9HYCSKNS|(ljC{yK( z-vw3TdGX`Vqy*G@Fq(=2yuee>K_ASrVTc&dyZe0nb^M3V6zMh50c^4!fXSur4^nqrcEEHR{QXQM-c`LR?e>4(?sP5bdh`%#2+ z4D(>h0jwx@HOhsDE1}%L>tj15@VdayPM-_@dsaPq6onZpoHGQjDRUR#5-!E9{&h$) zCtA?A^eM42JF91*=Ds)KFLeCNmx)p>LT@Y5T^CK$hy#Z1WJiJ%V7 zbaLiUuXVKcJ-kT9>K?FGH%)sw6ELeYHp6Wa`-Z(}F%z=y6TL=u(lX?aGMH&lj{-69 zF%wi#GeKWcrjHq`_h|%Y5Hsx0EMSgMlh%Mwh$@!OX)THlM51U33ZIvVi$>N2+pH6n z?E>@<(M5u$}5HsYc!(w0Nvkleg`GF%Knw{{9z9jSw znlTov& zSpc<%%98t2yM}l!rS4bl<-}j93GS4$cA&N+sBP_t`ztg;tmJ3K_b-?U(M;CVXhyvH zFeCJg0%*o<8k=F~1vv5rGguH}F+;y@;JZx5j3;=Z_;27?il3#;dEjO(b`S9-u!t-^(dusuti2=vRH5SD;;>E%AJx)%idC~3-c_0BUwm;N5Kuj)3tBkeHbFh^Xu_I781E(&!i)X zY4*f)8YwalZR1#?Hbb0}@jIw5&%Bro+-iR-$1S6XOcV`Ag5hdZKjJ%uLc!S>EaU!) zM5?))wA;w)Tzb+hW_8bslp%Jx1DoX-nwOH}5xd}cVhLIK2n=gUuH6G#M3RrPVAf!8v=nX&=NtgYFa_8uA?xw@i6Qh7RFS@ zIVD>9_K@?Dm-9tkdmd8CCdPcwWv(T~Op)6<28!YWer=Jaf>WVa;WxsGNl)Spvm=xW zsi7yj7O~n7Jxi%!@QNBaW-R6Eo@C9|OR1G4^q~k6;MK^HT&F*vTi})4GQg`Hk6MoC zR&xJ5pKD?i3g0|xeQsK)0JkBTBDl@)ajVCME({Shtdpj7vfQ@4U0ojP&_5EPm*lgbZRGdT}KfCvfWdC1=p zk&9l}J#6@d^t3f1wS*!I7B-ATiz>~Ud@VDCr6jdi;O5qj9-Y0gr=b9T}*GEQE+)TBLgp z^`CU_6$5-N)3uH0L)u`)Z&SF)QdX ziE~3w7Z~ZL*VEJ^bax&?LK(kGx!JSfhLsHs^WVFqd1U1c8+t~Xm%Mj={6VXcGLl8g z3-7Ow@~BNugWU)|T8Q{jSu>0M#tT&rzi((@Q4kdGk#boDij)y3dXSWu7eJVg5*cZ0 zRsbM$Qwl^dXJNlu9fHu^;KQii0~r126Dcu2DABgrlvpT{x@a^`ge+960~o#i@dtev zQ6%Eg$FtlG-gy|C5`AgnS*+Zo+$crJsoUE!cBsWWZ`twV%K%5>SB%)_781TihaJli z!ZpzEZs1q@mStov3w=}Iz#^S)VW&Q>wN6Sgt2&U%vr$4es?SF6WdjD489&~lGF4_v z{J8w#ZKwL#vUt7xiPtYvKf@oZDY7p;y`ICwl!l|PBw7{fD?(OuYz}ZcwJ21HZ_zzr zYw)91!!^)06su6GkjM~;l#)1C40;>qN)8Z?bEQcmZD0hA_yrIn&fpA*i)9VLOh36l z+aQs&j1ihzWGpHGJeLgABv_4 z>|Vx)QES(+!vnz90A(55173L3F^MbuGC()9 zP4FM1RvG{cc_G`I2#-G_uA|flg^mrOcgV_g!7iCQF^tku;PFc#9JKfd7jnWNk3-N zohE(IqS4{e!CjFI86~r0gQ~4&v`6qJUX3|cRE->i|lb&PJ_nP!t zlip_1T_(NPq0qdhjM6yvYX?L%Co^WScF>cQL1MZjicLo~^{M=SprXe%&s=F2k>@!;;e zqm!%JG+m<--7?nz@?o~)>6xJhcLE4YB3+Y^Q zztG$-LAnyp*CRa_=|$%LQgaWwaJJ(44M?{my~W($Ztm|y`bj*00O_ZZe$m`NWbQ#H z&SQA~Eu>E(ecs$3GWS13`U*^o7iGu%U*PT-uJIWM6m)I{OH}drVctj0eGF+M?z@q; zAssOH^UVDsq|5Mp4boLeFEIBPoBPd3x8V8pNVg%q3F-AnZ#DOKAiWFs_anU<>F3P- z9&`T)(tUXT_ej5i^xH`P9_e??{r4c?^tSM3ziPW(G54+x&&GOULx*KeZ{B+GJdVj?`T>d)^|3u|G?c*=Sf8w@#zkDZj z8n+7Cd_6n>Ty1+0yLd#L^^*G{at}!Eb>x1*oLb~W)I7=Ef!wW<`z-|G8yf_{=}KG|A^(1)=i<5n`P-3h#dQnv6qnm^J%Ic}NI!||i^%^i(of_1 z7V?LXK8EXg85Ing^$B`C75M|=|IMOKYGm*xS z&O_RWbP>`vq>V_sk+vZnKzcFKWk@$8U4=ARfZmGdTk!l2q}z~gL3%yXZAfoIx(Df9 zNFPCZH_~JQ`W-yqhv(lz`VFM}kcI{58@PV~&wq>br$}Ew`YO_&BK?m)2~@q?Z;}EL z7MA~O1?o3zqtRMk&!uG40?W~TiQ;F}zuVX2qc-Q4aGm`w5J16)mGzedz7iU10(C)1?y$&Of~`IGPAQ4kYS7 z#sAS=lEJyJQ|~3%^CvHX7E!0rOK?!V01e@%qBXS0d^7cteNK*V=I8jPe-6xbY8+ef zo|yhH-E(|{KgV|h(FQ*Z;~d`!kON*U8ite>K-OnN_Lm~{kXD)d zdZaD5??>8&bgsEyXzrIFU5V%Gk)Dh6B6EMKxu^cJ70+)#x*h2)=Kgkbe<#vU;`swe zKaKQ@=KdjbPkrVwJpUHbCy_pH?hl#!A0mAb&wqjR6{N45`(x(*O{C+H{khNqGLaUV z`>45(A#KF-ZlrBU2h9CEbH51bGCW^{bQRJI%>BjYelyZ7cz!+7ZAfo2_qUq+JCNRm z=l3JM8|mlF{T_4w2+|j3d_&=kv)`m@GyCwxcksqHkbY0z3~Mu5yLki8e~RCK`zP(@ z|6lFq^W6;%-MpSl$*5&ky!ztZ�f+*W;r$=a=vy`(2<$1RoaK*H7}p<@P(j8nx3t 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

wReI%Dt4xYlm7`8hSItLX)gpXU<*1LNRitlH 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 Date: Sun, 28 Jun 2026 19:03:53 +0900 Subject: [PATCH 03/12] feat(sample): add Jindong design system, theme and shared harness components --- .../sample/components/CapabilityBadge.kt | 70 +++++++ .../compose/jindong/sample/components/Chip.kt | 129 ++++++++++++ .../sample/components/HapticTimeline.kt | 198 ++++++++++++++++++ .../sample/components/JindongScaffold.kt | 192 +++++++++++++++++ .../sample/components/LabeledSlider.kt | 77 +++++++ .../jindong/sample/components/MonoLabel.kt | 38 ++++ .../jindong/sample/components/PlayButton.kt | 61 ++++++ .../jindong/sample/components/ScreenPieces.kt | 97 +++++++++ .../sample/components/SegmentedToggle.kt | 82 ++++++++ .../compose/jindong/sample/nav/Screen.kt | 88 ++++++++ .../compose/jindong/sample/theme/Dimens.kt | 59 ++++++ .../jindong/sample/theme/JindongColors.kt | 83 ++++++++ .../jindong/sample/theme/JindongTheme.kt | 71 +++++++ .../jindong/sample/theme/JindongTypography.kt | 175 ++++++++++++++++ 14 files changed, 1420 insertions(+) create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/CapabilityBadge.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/HapticTimeline.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/LabeledSlider.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/MonoLabel.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/Screen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/Dimens.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongColors.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTheme.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTypography.kt diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/CapabilityBadge.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/CapabilityBadge.kt new file mode 100644 index 0000000..947ed00 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/CapabilityBadge.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Single capability row: [key] on the left (sans, text2), a status [dotColor] dot and [value] + * (mono, text) on the right. + */ +@Composable +fun CapabilityBadge( + key: String, + value: String, + dotColor: Color, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = key, + style = JindongTheme.typography.rowTitle.copy(fontWeight = FontWeight.Normal), + color = JindongTheme.colors.text2, + ) + Row( + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), + verticalAlignment = Alignment.CenterVertically, + ) { + Box( + modifier = Modifier.size(Dimens.dotSize).clip(CircleShape).background(dotColor), + ) + Text( + text = value, + style = JindongTheme.typography.monoValue, + color = JindongTheme.colors.text, + ) + } + } +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt new file mode 100644 index 0000000..7cf8e7c --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Selectable preset chip. Active = accent border/text over accentBg; inactive = border2 border over + * transparent with text2. Optional [subValue] renders below the label in dim mono. Wrapped to a + * >= 48dp hit area. + */ +@Composable +fun PresetChip( + label: String, + selected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, + subValue: String? = null, +) { + val colors = JindongTheme.colors + val borderColor = if (selected) colors.accent else colors.border2 + val labelColor = if (selected) colors.accent else colors.text2 + val bgColor = if (selected) colors.accentBg else Color.Transparent + + Box( + modifier = modifier.defaultMinSize(minHeight = Dimens.minTouch), + contentAlignment = Alignment.Center, + ) { + Column( + modifier = + Modifier + .clip(RoundedCornerShape(Dimens.radiusChip)) + .background(bgColor) + .border(Dimens.stroke, borderColor, RoundedCornerShape(Dimens.radiusChip)) + .clickable(onClick = onClick) + .padding(horizontal = 11.dp, vertical = 8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text(text = label, style = JindongTheme.typography.chipLabel, color = labelColor) + if (subValue != null) { + Text( + text = subValue, + style = JindongTheme.typography.monoAxis.copy(fontSize = 9.sp), + color = labelColor.copy(alpha = 0.65f), + ) + } + } + } +} + +/** + * Selectable node chip for sequence/rhythm editing. Adds a 7dp marker: a filled accent circle for a + * tap node ([isTap] true) or a square border2 marker for a pause. Active state mirrors [PresetChip]. + */ +@Composable +fun NodeChip( + label: String, + msText: String, + isTap: Boolean, + selected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val colors = JindongTheme.colors + val borderColor = if (selected) colors.accent else colors.border2 + val contentColor = if (selected) colors.accent else colors.text2 + val bgColor = if (selected) colors.accentBg else Color.Transparent + val markerShape = if (isTap) CircleShape else RoundedCornerShape(1.dp) + val markerColor = if (isTap) colors.accent else colors.border2 + + Box( + modifier = modifier.defaultMinSize(minHeight = Dimens.minTouch), + contentAlignment = Alignment.Center, + ) { + Row( + modifier = + Modifier + .clip(RoundedCornerShape(Dimens.radiusChip)) + .background(bgColor) + .border(Dimens.stroke, borderColor, RoundedCornerShape(Dimens.radiusChip)) + .clickable(onClick = onClick) + .padding(horizontal = 11.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), + verticalAlignment = Alignment.CenterVertically, + ) { + Box(modifier = Modifier.size(Dimens.nodeDotSize).clip(markerShape).background(markerColor)) + Text(text = label, style = JindongTheme.typography.chipLabel, color = contentColor) + Text( + text = msText, + style = JindongTheme.typography.monoAxis.copy(fontSize = 9.sp), + color = contentColor.copy(alpha = 0.65f), + ) + } + } +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/HapticTimeline.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/HapticTimeline.kt new file mode 100644 index 0000000..893be71 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/HapticTimeline.kt @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.core.model.HapticPattern +import io.github.compose.jindong.core.model.ScheduledHapticEvent +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * One timeline bar in normalized [0,1] coordinates. Anchored to the plot bottom; height grows + * upward. [color] is usually the accent token, or a per-card tone on the preset screen. + */ +@Immutable +data class TimelineBar( + val leftFraction: Float, + val widthFraction: Float, + val heightFraction: Float, + val color: Color, +) + +/** + * Converts a [HapticPattern]'s events into normalized [TimelineBar]s. + * + * - `leftFraction = start / window` + * - `widthFraction = max(0.006, dur / window)` (min 0.6% so an instantaneous tap stays visible) + * - `heightFraction = max(0.06, intensity * 0.98)` (min 6%) + */ +object TimelineMapper { + fun toBars( + pattern: HapticPattern, + windowMs: Long, + color: (ScheduledHapticEvent) -> Color, + ): List { + if (windowMs <= 0L) return emptyList() + val window = windowMs.toFloat() + return pattern.events.map { event -> + TimelineBar( + leftFraction = (event.startTimeMs / window).coerceIn(0f, 1f), + widthFraction = maxOf(0.006f, event.durationMs / window), + heightFraction = maxOf(0.06f, event.intensity.value * 0.98f), + color = color(event), + ) + } + } +} + +/** + * Signature haptic timeline: horizontal = time, vertical = intensity, gap = rest. + * + * The plot is drawn in a single [Canvas]; [bars] and [playheadProgress] are read inside the draw + * lambda, so wiring an animated playhead later only redraws (no recomposition). Screens currently + * render a static timeline ([playheadVisible] = false) and rebuild [bars] on each state change. + * + * @param bars normalized bars to render; this component renders exactly what it is given. + * @param playheadProgress 0..1 horizontal position of the playhead. + * @param playheadVisible gates the playhead alpha (visible only while playing). + */ +@Composable +fun HapticTimeline( + bars: List, + topLeft: String, + topRight: String, + minLabel: String, + maxLabel: String, + playheadProgress: Float, + playheadVisible: Boolean, + modifier: Modifier = Modifier, +) { + val colors = JindongTheme.colors + val axisColor = colors.border2 + val playheadColor = colors.text + + Column( + modifier = + modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusTimeline)) + .background(colors.surface2) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusTimeline)) + .padding(PaddingValues(start = 16.dp, top = 15.dp, end = 16.dp, bottom = 14.dp)), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text(text = topLeft, style = JindongTheme.typography.monoAxis, color = colors.text3) + Text(text = topRight, style = JindongTheme.typography.monoAxis, color = colors.text3) + } + + Canvas( + modifier = + Modifier + .fillMaxWidth() + .height(Dimens.plotHeight) + .padding(top = 8.dp), + ) { + drawLAxis(axisColor, Dimens.axisStroke.toPx()) + bars.forEach { bar -> drawBar(bar, Dimens.barMinWidth.toPx(), Dimens.barCornerRadius.toPx()) } + if (playheadVisible) { + drawPlayhead( + progress = playheadProgress.coerceIn(0f, 1f), + color = playheadColor, + strokeWidth = Dimens.playheadStroke.toPx(), + ) + } + } + + Row( + modifier = Modifier.fillMaxWidth().padding(top = 7.dp), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text(text = minLabel, style = JindongTheme.typography.monoAxis, color = colors.text3) + Text(text = "TIME (ms) →", style = JindongTheme.typography.monoAxis, color = colors.text3) + Text(text = maxLabel, style = JindongTheme.typography.monoAxis, color = colors.text3) + } + } +} + +private fun DrawScope.drawLAxis( + color: Color, + strokeWidth: Float, +) { + // Left + bottom only (L-shaped axis); top/right have no border. + drawLine(color, Offset(0f, 0f), Offset(0f, size.height), strokeWidth) + drawLine(color, Offset(0f, size.height), Offset(size.width, size.height), strokeWidth) +} + +private fun DrawScope.drawBar( + bar: TimelineBar, + minWidthPx: Float, + cornerRadiusPx: Float, +) { + val left = bar.leftFraction * size.width + val width = maxOf(minWidthPx, bar.widthFraction * size.width) + val height = bar.heightFraction * size.height + val top = size.height - height + // Top corners rounded only; anchored to the plot bottom. + val path = + Path().apply { + val r = minOf(cornerRadiusPx, width / 2f, height) + moveTo(left, size.height) + lineTo(left, top + r) + quadraticTo(left, top, left + r, top) + lineTo(left + width - r, top) + quadraticTo(left + width, top, left + width, top + r) + lineTo(left + width, size.height) + close() + } + drawPath(path, bar.color) +} + +private fun DrawScope.drawPlayhead( + progress: Float, + color: Color, + strokeWidth: Float, +) { + val x = progress * size.width + drawLine(color, Offset(x, 0f), Offset(x, size.height), strokeWidth) +} + +/** Default accent tone for callers that do not supply a per-event color lambda. */ +@Composable +fun timelineAccentColor(): Color = JindongTheme.colors.accent diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt new file mode 100644 index 0000000..4ebc1ef --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.github.compose.jindong.sample.nav.Screen +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Sticky 56dp app bar over a vertically scrollable [content] column. + * + * App bar layout: + * - left: back chevron `‹` (only when [screen] is not the hub) tapping [onBack]. + * - center: [Screen.title] (the Home title doubles as the wordmark). + * - right: a mono counter (`진동` on Home, else `NN / 07`) plus a 30x30 theme toggle (`☾` light / + * `☀` dark) calling [onToggleTheme]. Both controls keep a >= 48dp hit area. + * + * The body uses [Dimens.screenPadH] horizontal padding, [Dimens.bodyTop] top and [Dimens.bodyBottom] + * bottom padding. + */ +@Composable +fun JindongScaffold( + screen: Screen, + isDark: Boolean, + onBack: () -> Unit, + onToggleTheme: () -> Unit, + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit, +) { + val colors = JindongTheme.colors + Column(modifier = modifier.fillMaxSize().background(colors.bg)) { + AppBar( + screen = screen, + isDark = isDark, + onBack = onBack, + onToggleTheme = onToggleTheme, + ) + Column( + modifier = + Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + .padding( + start = Dimens.screenPadH, + end = Dimens.screenPadH, + top = Dimens.bodyTop, + bottom = Dimens.bodyBottom, + ), + content = content, + ) + } +} + +@Composable +private fun AppBar( + screen: Screen, + isDark: Boolean, + onBack: () -> Unit, + onToggleTheme: () -> Unit, +) { + val colors = JindongTheme.colors + val strokePx = with(LocalDensity.current) { Dimens.stroke.toPx() } + Box( + modifier = + Modifier + .fillMaxWidth() + .height(Dimens.appBarHeight) + .background(colors.bg) + .drawBehind { + drawLine( + color = colors.border, + start = Offset(0f, size.height - strokePx / 2f), + end = Offset(size.width, size.height - strokePx / 2f), + strokeWidth = strokePx, + ) + } + .padding(horizontal = Dimens.screenPadH), + ) { + if (screen.index > 0) { + Box( + modifier = + Modifier + .align(Alignment.CenterStart) + .size(Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusSmall)) + .clickable(onClick = onBack) + .semantics { contentDescription = "Back" }, + contentAlignment = Alignment.Center, + ) { + Text(text = "‹", fontSize = 20.sp, color = colors.text2) + } + } + + Text( + text = screen.title, + style = + if (screen.index == 0) { + JindongTheme.typography.wordmark + } else { + JindongTheme.typography.appBarTitle + }, + color = colors.text, + modifier = Modifier.align(Alignment.Center), + ) + + Row( + modifier = Modifier.align(Alignment.CenterEnd), + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapMedium), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = if (screen.index == 0) "진동" else "${pad2(screen.index)} / 07", + style = JindongTheme.typography.monoMicro.copy(fontWeight = FontWeight.Normal), + color = colors.text3, + ) + ThemeToggle(isDark = isDark, onToggleTheme = onToggleTheme) + } + } +} + +@Composable +private fun ThemeToggle( + isDark: Boolean, + onToggleTheme: () -> Unit, +) { + val colors = JindongTheme.colors + Box( + modifier = + Modifier + .size(Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusSmall)) + .clickable(onClick = onToggleTheme) + .semantics { contentDescription = if (isDark) "Switch to light theme" else "Switch to dark theme" }, + contentAlignment = Alignment.Center, + ) { + Box( + modifier = + Modifier + .size(Dimens.toggleSize) + .clip(RoundedCornerShape(Dimens.radiusIcon)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusIcon)), + contentAlignment = Alignment.Center, + ) { + Text(text = if (isDark) "☀" else "☾", fontSize = 13.sp, color = colors.text2) + } + } +} + +/** Zero-pads a non-negative index to two digits without relying on JVM-only String.format. */ +private fun pad2(value: Int): String = if (value < 10) "0$value" else value.toString() diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/LabeledSlider.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/LabeledSlider.kt new file mode 100644 index 0000000..fe3db0d --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/LabeledSlider.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.Slider +import androidx.compose.material3.SliderDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Label row (label left, [valueText] mono right) over a Material3 [Slider] tinted with the accent + * token for the thumb/active track and border2 for the inactive track. + */ +@Composable +fun LabeledSlider( + label: String, + valueText: String, + value: Float, + onValueChange: (Float) -> Unit, + modifier: Modifier = Modifier, + valueRange: ClosedFloatingPointRange = 0f..1f, + steps: Int = 0, +) { + val colors = JindongTheme.colors + Column(modifier = modifier.fillMaxWidth()) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = label, + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.Medium), + color = colors.text2, + ) + Text( + text = valueText, + style = JindongTheme.typography.monoValue.copy(fontSize = 12.sp), + color = colors.text, + ) + } + Slider( + value = value, + onValueChange = onValueChange, + valueRange = valueRange, + steps = steps, + colors = + SliderDefaults.colors( + thumbColor = colors.accent, + activeTrackColor = colors.accent, + inactiveTrackColor = colors.border2, + ), + ) + } +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/MonoLabel.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/MonoLabel.kt new file mode 100644 index 0000000..a40b904 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/MonoLabel.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Uppercase mono section label (e.g. `DEVICE CAPABILITY`, `MODULES`). Renders [text] uppercased in + * the [JindongTypography.sectionLabel] role with [JindongColors.text3]. + */ +@Composable +fun MonoLabel( + text: String, + modifier: Modifier = Modifier, +) { + Text( + text = text.uppercase(), + style = JindongTheme.typography.sectionLabel, + color = JindongTheme.colors.text3, + modifier = modifier, + ) +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt new file mode 100644 index 0000000..b54635f --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Full-width primary action button. Inverted ink/white surface ([JindongColors.btnBg] / + * [JindongColors.btnText]) — not accent — per the handoff. Wrapped to a >= 48dp hit area. + */ +@Composable +fun PlayButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + text: String = "▶ Play", +) { + Box( + modifier = + modifier + .fillMaxWidth() + .defaultMinSize(minHeight = Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusButton)) + .background(JindongTheme.colors.btnBg) + .clickable(onClick = onClick) + .padding(14.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = text, + style = JindongTheme.typography.cardTitle, + color = JindongTheme.colors.btnText, + ) + } +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt new file mode 100644 index 0000000..fa71984 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.unit.Dp +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Intro / description paragraph at the top of every module screen. 13sp, [text2], line-height 1.55. + * Pass an [AnnotatedString] when a fragment needs the emphasized [text]+600 treatment (e.g. + * "see vibration", "Width = duration"). + */ +@Composable +fun ScreenDescription( + text: AnnotatedString, + modifier: Modifier = Modifier, +) { + Text( + text = text, + style = JindongTheme.typography.intro, + color = JindongTheme.colors.text2, + modifier = modifier.fillMaxWidth(), + ) +} + +/** + * Plain bordered card container ([surface] over a [border] 1dp outline). [radius] defaults to the + * card radius; preset/large cards pass [Dimens.radiusBigCard]. Content lays out in a [ColumnScope]. + */ +@Composable +fun SectionCard( + modifier: Modifier = Modifier, + radius: Dp = Dimens.radiusCard, + padding: Dp = Dimens.cardPadding, + content: @Composable ColumnScope.() -> Unit, +) { + val colors = JindongTheme.colors + Column( + modifier = + modifier + .fillMaxWidth() + .clip(RoundedCornerShape(radius)) + .background(colors.surface) + .border(Dimens.stroke, colors.border, RoundedCornerShape(radius)) + .padding(padding), + content = content, + ) +} + +/** Vertical spacer of the given [height]; a terse alias used between stacked screen sections. */ +@Composable +fun VGap(height: Dp) { + Spacer(Modifier.height(height)) +} + +/** Formats a Float to a fixed-fraction string without JVM-only String.format (e.g. 0.5 -> "0.50"). */ +fun formatFixed( + value: Float, + decimals: Int, +): String { + if (decimals <= 0) return value.toLong().toString() + var scale = 1 + repeat(decimals) { scale *= 10 } + val scaled = (value * scale + if (value >= 0f) 0.5f else -0.5f).toLong() + val whole = scaled / scale + val frac = (if (scaled < 0) -scaled else scaled) % scale + val fracStr = frac.toString().padStart(decimals, '0') + return "$whole.$fracStr" +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt new file mode 100644 index 0000000..88e9877 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * N-up segment control. Equal-weight segments separated by a 7dp gap. Active segment uses accent + * border/text over accentBg; inactive uses border2 over transparent with text2. + */ +@Composable +fun SegmentedToggle( + options: List, + selectedIndex: Int, + onSelect: (Int) -> Unit, + modifier: Modifier = Modifier, +) { + val colors = JindongTheme.colors + Row( + modifier = modifier.fillMaxWidth().defaultMinSize(minHeight = Dimens.minTouch), + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), + verticalAlignment = Alignment.CenterVertically, + ) { + options.forEachIndexed { index, option -> + val selected = index == selectedIndex + val borderColor = if (selected) colors.accent else colors.border2 + val contentColor = if (selected) colors.accent else colors.text2 + val bgColor = if (selected) colors.accentBg else Color.Transparent + Box( + modifier = + Modifier + .weight(1f) + .clip(RoundedCornerShape(Dimens.radiusChip)) + .background(bgColor) + .border(Dimens.stroke, borderColor, RoundedCornerShape(Dimens.radiusChip)) + .clickable { onSelect(index) } + .padding(10.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = option, + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), + color = contentColor, + textAlign = TextAlign.Center, + ) + } + } + } +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/Screen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/Screen.kt new file mode 100644 index 0000000..ffe5430 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/Screen.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.nav + +/** + * Harness destinations. [Home] is the hub (index 0); [modules] lists the seven feature screens that + * Home links to, in display order. [index] doubles as the app-bar counter value ("NN / 07"). + */ +sealed interface Screen { + val routeId: String + val title: String + val index: Int + val subtitle: String + + data object Home : Screen { + override val routeId = "home" + override val title = "Jindong" + override val index = 0 + override val subtitle = "Device capability + module hub" + } + + data object Single : Screen { + override val routeId = "single" + override val title = "Single Haptic" + override val index = 1 + override val subtitle = "Duration × intensity, isolated" + } + + data object Intensity : Screen { + override val routeId = "intensity" + override val title = "Intensity Lab" + override val index = 2 + override val subtitle = "Compare 5 strength levels" + } + + data object Timing : Screen { + override val routeId = "timing" + override val title = "Timing" + override val index = 3 + override val subtitle = "Delay & sequence rhythm" + } + + data object Repeat : Screen { + override val routeId = "repeat" + override val title = "Repeat" + override val index = 4 + override val subtitle = "Static N-times repeat" + } + + data object RepeatIdx : Screen { + override val routeId = "repeat-index" + override val title = "Repeat w/ Index" + override val index = 5 + override val subtitle = "Per-cycle intensity ramp" + } + + data object Preset : Screen { + override val routeId = "preset" + override val title = "Preset Gallery" + override val index = 6 + override val subtitle = "10 real-world patterns" + } + + data object Reactive : Screen { + override val routeId = "reactive" + override val title = "Reactive" + override val index = 7 + override val subtitle = "State-driven · no buttons ★" + } + + companion object { + val modules: List = + listOf(Single, Intensity, Timing, Repeat, RepeatIdx, Preset, Reactive) + } +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/Dimens.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/Dimens.kt new file mode 100644 index 0000000..737fd34 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/Dimens.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.theme + +import androidx.compose.ui.unit.dp + +/** + * Spacing, radius and stroke tokens for the harness. Prototype px map to dp 1:1; touch-target and + * accessibility minimums override the visual sizes where the handoff calls for it. + */ +object Dimens { + // Layout + val screenPadH = 16.dp + val bodyTop = 18.dp + val bodyBottom = 48.dp + val appBarHeight = 56.dp + val plotHeight = 120.dp + + // Stroke / touch + val stroke = 1.dp + val minTouch = 48.dp + + // Radii + val radiusSmall = 8.dp + val radiusIcon = 8.dp + val radiusChip = 9.dp + val radiusCard = 11.dp + val radiusButton = 11.dp + val radiusBigCard = 13.dp + val radiusTimeline = 12.dp + + // Padding / gaps + val cardPadding = 14.dp + val rowGapSmall = 7.dp + val rowGapMedium = 11.dp + val rowGapLarge = 14.dp + + // Component metrics + val toggleSize = 30.dp + val dotSize = 6.dp + val nodeDotSize = 7.dp + val barCornerRadius = 3.dp + val barMinWidth = 3.dp + val axisStroke = 1.dp + val playheadStroke = 1.5.dp +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongColors.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongColors.kt new file mode 100644 index 0000000..9845db9 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongColors.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.theme + +import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.Color + +/** + * Semantic color tokens for the Jindong sample harness. Token names mirror the design handoff CSS + * variables 1:1 so the prototype and the Compose port stay in sync. + * + * [accent] is reserved for data visualization (timeline bars) and active states; the primary button + * uses the inverted [btnBg] / [btnText] pair, not [accent]. + */ +@Immutable +data class JindongColors( + val bg: Color, + val surface: Color, + val surface2: Color, + val border: Color, + val border2: Color, + val divider: Color, + val text: Color, + val text2: Color, + val text3: Color, + val accent: Color, + val accentBg: Color, + val ok: Color, + val warn: Color, + val btnBg: Color, + val btnText: Color, +) + +fun lightColors(): JindongColors = JindongColors( + bg = Color(0xFFFFFFFF), + surface = Color(0xFFFFFFFF), + surface2 = Color(0xFFFAFAFA), + border = Color(0xFFECECEC), + border2 = Color(0xFFE4E4E7), + divider = Color(0xFFF4F4F5), + text = Color(0xFF18181B), + text2 = Color(0xFF52525B), + text3 = Color(0xFFA1A1AA), + accent = Color(0xFF2F5FE0), + // rgba(47,95,224,0.07) baked: 0.07*255 ~= 18 = 0x12 + accentBg = Color(0x122F5FE0), + ok = Color(0xFF16A34A), + warn = Color(0xFFD97706), + btnBg = Color(0xFF18181B), + btnText = Color(0xFFFFFFFF), +) + +fun darkColors(): JindongColors = JindongColors( + bg = Color(0xFF101012), + surface = Color(0xFF161618), + surface2 = Color(0xFF16161A), + border = Color(0xFF232327), + border2 = Color(0xFF2E2E32), + divider = Color(0xFF1C1C1F), + text = Color(0xFFF4F4F5), + text2 = Color(0xFFA1A1AA), + text3 = Color(0xFF71717A), + accent = Color(0xFF6B93FF), + // rgba(107,147,255,0.14) baked: 0.14*255 ~= 36 = 0x24 + accentBg = Color(0x246B93FF), + ok = Color(0xFF34D399), + warn = Color(0xFFFBBF24), + btnBg = Color(0xFFF4F4F5), + btnText = Color(0xFF101012), +) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTheme.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTheme.kt new file mode 100644 index 0000000..c23baf4 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTheme.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.theme + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.Modifier + +private val LocalJindongColors = + staticCompositionLocalOf { + error("JindongColors not provided. Wrap content in JindongTheme { }.") + } + +private val LocalJindongTypography = + staticCompositionLocalOf { + error("JindongTypography not provided. Wrap content in JindongTheme { }.") + } + +/** + * Root theme for the Jindong sample harness. Provides [JindongColors] and [JindongTypography] and + * paints [JindongColors.bg] as the screen background. + * + * The [darkTheme] flag is driven by the caller (AppRoot) so the manual toggle can override the + * system preference per the handoff. + */ +@Composable +fun JindongTheme( + darkTheme: Boolean, + content: @Composable () -> Unit, +) { + val colors = if (darkTheme) darkColors() else lightColors() + val typography = jindongTypography(sans = instrumentSansFamily(), mono = ibmPlexMonoFamily()) + CompositionLocalProvider( + LocalJindongColors provides colors, + LocalJindongTypography provides typography, + ) { + Box(modifier = Modifier.fillMaxSize().background(colors.bg)) { + content() + } + } +} + +object JindongTheme { + val colors: JindongColors + @Composable + @ReadOnlyComposable + get() = LocalJindongColors.current + + val typography: JindongTypography + @Composable + @ReadOnlyComposable + get() = LocalJindongTypography.current +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTypography.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTypography.kt new file mode 100644 index 0000000..80659c7 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/theme/JindongTypography.kt @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.theme + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontVariation +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.em +import androidx.compose.ui.unit.sp +import io.github.compose.jindong.sample.Res +import io.github.compose.jindong.sample.ibm_plex_mono_medium +import io.github.compose.jindong.sample.ibm_plex_mono_regular +import io.github.compose.jindong.sample.ibm_plex_mono_semibold +import io.github.compose.jindong.sample.instrument_sans_variable +import org.jetbrains.compose.resources.Font + +/** + * Role-based text styles for the harness. Numbers and uppercase section labels that the user must be + * able to verify use the [JindongTypography.monoValue]/etc. mono roles; everything else uses sans. + * + * Build with [jindongTypography] passing the families from [instrumentSansFamily] / + * [ibmPlexMonoFamily]. + */ +@Immutable +data class JindongTypography( + val intro: TextStyle, + val cardTitle: TextStyle, + val sectionLabel: TextStyle, + val monoValue: TextStyle, + val monoMicro: TextStyle, + val monoAxis: TextStyle, + val appBarTitle: TextStyle, + val wordmark: TextStyle, + val chipLabel: TextStyle, + val bodySmall: TextStyle, + val rowTitle: TextStyle, +) + +/** + * Instrument Sans is a single variable font (wght 400-700). Each weight is a [Font] entry over the + * same [Res.font.instrument_sans_variable] resource, selecting the axis via + * [FontVariation.weight]. This family is the single swap point if a weight ever fails to resolve on + * a target. + */ +@Composable +fun instrumentSansFamily(): FontFamily = FontFamily( + Font( + Res.font.instrument_sans_variable, + weight = FontWeight.Normal, + style = FontStyle.Normal, + variationSettings = FontVariation.Settings(FontVariation.weight(400)), + ), + Font( + Res.font.instrument_sans_variable, + weight = FontWeight.Medium, + style = FontStyle.Normal, + variationSettings = FontVariation.Settings(FontVariation.weight(500)), + ), + Font( + Res.font.instrument_sans_variable, + weight = FontWeight.SemiBold, + style = FontStyle.Normal, + variationSettings = FontVariation.Settings(FontVariation.weight(600)), + ), + Font( + Res.font.instrument_sans_variable, + weight = FontWeight.Bold, + style = FontStyle.Normal, + variationSettings = FontVariation.Settings(FontVariation.weight(700)), + ), +) + +/** + * IBM Plex Mono ships as three static files mapped to W400 / W500 / W600. + */ +@Composable +fun ibmPlexMonoFamily(): FontFamily = FontFamily( + Font(Res.font.ibm_plex_mono_regular, weight = FontWeight.Normal), + Font(Res.font.ibm_plex_mono_medium, weight = FontWeight.Medium), + Font(Res.font.ibm_plex_mono_semibold, weight = FontWeight.SemiBold), +) + +@Composable +fun jindongTypography( + sans: FontFamily, + mono: FontFamily, +): JindongTypography = JindongTypography( + intro = + TextStyle( + fontFamily = sans, + fontWeight = FontWeight.Normal, + fontSize = 13.sp, + lineHeight = (13 * 1.55).sp, + ), + cardTitle = + TextStyle( + fontFamily = sans, + fontWeight = FontWeight.SemiBold, + fontSize = 14.sp, + ), + sectionLabel = + TextStyle( + fontFamily = mono, + fontWeight = FontWeight.Medium, + fontSize = 9.sp, + letterSpacing = 0.16.em, + ), + monoValue = + TextStyle( + fontFamily = mono, + fontWeight = FontWeight.SemiBold, + fontSize = 14.sp, + ), + monoMicro = + TextStyle( + fontFamily = mono, + fontWeight = FontWeight.Normal, + fontSize = 10.sp, + ), + monoAxis = + TextStyle( + fontFamily = mono, + fontWeight = FontWeight.Normal, + fontSize = 9.sp, + letterSpacing = 0.12.em, + ), + appBarTitle = + TextStyle( + fontFamily = sans, + fontWeight = FontWeight.SemiBold, + fontSize = 15.sp, + letterSpacing = (-0.01).em, + ), + wordmark = + TextStyle( + fontFamily = sans, + fontWeight = FontWeight.SemiBold, + fontSize = 19.sp, + ), + chipLabel = + TextStyle( + fontFamily = sans, + fontWeight = FontWeight.SemiBold, + fontSize = 11.sp, + ), + bodySmall = + TextStyle( + fontFamily = sans, + fontWeight = FontWeight.Normal, + fontSize = 12.sp, + ), + rowTitle = + TextStyle( + fontFamily = sans, + fontWeight = FontWeight.SemiBold, + fontSize = 13.sp, + ), +) From 93d7c7c38187b90e963d81d6729d2d6d5325b6ad Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 19:04:01 +0900 Subject: [PATCH 04/12] feat(sample): rebuild sample app as 8-screen haptic verification harness --- .../compose/jindong/sample/SampleApp.kt | 203 +--------- .../compose/jindong/sample/nav/AppRoot.kt | 81 ++++ .../jindong/sample/screens/HarnessLogic.kt | 174 ++++++++ .../jindong/sample/screens/HomeScreen.kt | 216 ++++++++++ .../sample/screens/IntensityLabScreen.kt | 301 ++++++++++++++ .../sample/screens/PresetGalleryScreen.kt | 213 ++++++++++ .../jindong/sample/screens/ReactiveScreen.kt | 379 ++++++++++++++++++ .../jindong/sample/screens/RepeatScreen.kt | 178 ++++++++ .../sample/screens/RepeatWithIndexScreen.kt | 225 +++++++++++ .../sample/screens/SingleHapticScreen.kt | 198 +++++++++ .../jindong/sample/screens/TimingScreen.kt | 296 ++++++++++++++ 11 files changed, 2269 insertions(+), 195 deletions(-) create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HarnessLogic.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/SampleApp.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/SampleApp.kt index eb5f112..ba57f3e 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/SampleApp.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/SampleApp.kt @@ -15,204 +15,17 @@ */ package io.github.compose.jindong.sample -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import io.github.compose.jindong.Jindong +import androidx.compose.runtime.Composable import io.github.compose.jindong.JindongProvider -import io.github.compose.jindong.JindongScope -import io.github.compose.jindong.core.model.HapticIntensity -import io.github.compose.jindong.dsl.Delay -import io.github.compose.jindong.dsl.Haptic -import io.github.compose.jindong.dsl.Repeat -import io.github.compose.jindong.dsl.Sequence -import org.jetbrains.compose.resources.stringResource -import kotlin.time.Duration.Companion.milliseconds +import io.github.compose.jindong.sample.nav.AppRoot +/** + * Sample entry point. [JindongProvider] sits at the root, once, OUTSIDE the theme/nav switch so the + * haptic executor survives navigation; [AppRoot] owns the theme and the single-level nav host. + */ @Composable fun SampleApp() { - MaterialTheme { - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background, - ) { - JindongProvider { - HapticPatternListScreen() - } - } - } -} - -@Composable -private fun HapticPatternListScreen() { - val patterns = remember { HapticPatternType.entries } - - Column( - modifier = Modifier.fillMaxSize(), - ) { - Text( - text = stringResource(Res.string.haptic_patterns_title), - style = MaterialTheme.typography.headlineMedium, - modifier = Modifier.padding(16.dp), - ) - - LazyColumn( - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - ) { - items(patterns) { pattern -> - HapticPatternCard(pattern) - } - } - } -} - -@Composable -private fun HapticPatternCard(patternType: HapticPatternType) { - var triggerCount by remember { mutableIntStateOf(0) } - - Card( - modifier = Modifier.fillMaxWidth(), - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Column(modifier = Modifier.weight(1f)) { - Text( - text = patternType.displayName, - style = MaterialTheme.typography.titleMedium, - ) - Text( - text = patternType.description, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } - Button(onClick = { triggerCount++ }) { - Text(stringResource(Res.string.play_button)) - } - } - } - - HapticPatternEffect(patternType, triggerCount) -} - -@Composable -private fun HapticPatternEffect(patternType: HapticPatternType, trigger: Int) { - if (trigger == 0) return - - val pattern: @Composable JindongScope.() -> Unit = when (patternType) { - HapticPatternType.SINGLE_TAP -> { - { Haptic(50.milliseconds) } - } - - HapticPatternType.DOUBLE_TAP -> { - { - Haptic(30.milliseconds) - Delay(50.milliseconds) - Haptic(30.milliseconds) - } - } - - HapticPatternType.TRIPLE_TAP -> { - { - Repeat(3) { - Sequence { - Haptic(25.milliseconds) - Delay(40.milliseconds) - } - } - } - } - - HapticPatternType.LIGHT_FEEDBACK -> { - { Haptic(40.milliseconds, HapticIntensity.LIGHT) } - } - - HapticPatternType.STRONG_FEEDBACK -> { - { Haptic(80.milliseconds, HapticIntensity.STRONG) } - } - - HapticPatternType.HEARTBEAT -> { - { - Repeat(2) { - Sequence { - Haptic(60.milliseconds, HapticIntensity.STRONG) - Delay(80.milliseconds) - Haptic(40.milliseconds, HapticIntensity.MEDIUM) - Delay(400.milliseconds) - } - } - } - } - - HapticPatternType.NOTIFICATION -> { - { - Haptic(50.milliseconds, HapticIntensity.MEDIUM) - Delay(100.milliseconds) - Haptic(100.milliseconds, HapticIntensity.STRONG) - } - } - - HapticPatternType.SUCCESS -> { - { - Haptic(30.milliseconds, HapticIntensity.LIGHT) - Delay(50.milliseconds) - Haptic(60.milliseconds, HapticIntensity.MEDIUM) - Delay(50.milliseconds) - Haptic(100.milliseconds, HapticIntensity.STRONG) - } - } - - HapticPatternType.ERROR -> { - { - Repeat(3) { - Sequence { - Haptic(100.milliseconds, HapticIntensity.HIGH) - Delay(100.milliseconds) - } - } - } - } - - HapticPatternType.RAMP_UP -> { - { - Haptic(50.milliseconds, HapticIntensity.LIGHT) - Delay(30.milliseconds) - Haptic(50.milliseconds, HapticIntensity.MEDIUM) - Delay(30.milliseconds) - Haptic(50.milliseconds, HapticIntensity.STRONG) - Delay(30.milliseconds) - Haptic(50.milliseconds, HapticIntensity.HIGH) - } - } + JindongProvider { + AppRoot() } - - Jindong(trigger, content = pattern) -} - -enum class HapticPatternType( - val displayName: String, - val description: String, -) { - SINGLE_TAP("Single Tap", "Simple single vibration"), - DOUBLE_TAP("Double Tap", "Two quick taps"), - TRIPLE_TAP("Triple Tap", "Three quick taps"), - LIGHT_FEEDBACK("Light Feedback", "Gentle vibration"), - STRONG_FEEDBACK("Strong Feedback", "Strong vibration"), - HEARTBEAT("Heartbeat", "Heart beating pattern"), - NOTIFICATION("Notification", "Alert notification pattern"), - SUCCESS("Success", "Success confirmation pattern"), - ERROR("Error", "Error alert pattern"), - RAMP_UP("Ramp Up", "Gradually increasing intensity"), } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt new file mode 100644 index 0000000..8153034 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.nav + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.Saver +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import io.github.compose.jindong.sample.components.JindongScaffold +import io.github.compose.jindong.sample.screens.HomeScreen +import io.github.compose.jindong.sample.screens.IntensityLabScreen +import io.github.compose.jindong.sample.screens.PresetGalleryScreen +import io.github.compose.jindong.sample.screens.ReactiveScreen +import io.github.compose.jindong.sample.screens.RepeatScreen +import io.github.compose.jindong.sample.screens.RepeatWithIndexScreen +import io.github.compose.jindong.sample.screens.SingleHapticScreen +import io.github.compose.jindong.sample.screens.TimingScreen +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Single-level navigation host. Home lists the seven modules; tapping one swaps [current], the app + * bar back chevron returns to Home. The theme follows the system preference unless [darkOverride] is + * set by the app-bar toggle. + * + * Back handling: the app-bar back chevron (in [JindongScaffold]) is the sole back affordance. In + * Compose Multiplatform 1.10 the only commonMain back API is the deprecated, `@ExperimentalComposeUiApi` + * `androidx.compose.ui.backhandler.BackHandler`, which also requires a navigation-event dispatcher + * owner that `ComposeUIViewController` does not provide on iOS (it would `error(...)` at runtime). + * Relying on the chevron keeps both targets safe without pulling in the new navigation-event artifact. + */ +@Composable +fun AppRoot() { + var current by rememberSaveable(stateSaver = ScreenSaver) { + mutableStateOf(Screen.Home) + } + var darkOverride by rememberSaveable { mutableStateOf(null) } + val dark = darkOverride ?: isSystemInDarkTheme() + + JindongTheme(darkTheme = dark) { + JindongScaffold( + screen = current, + isDark = dark, + onBack = { current = Screen.Home }, + onToggleTheme = { darkOverride = !dark }, + ) { + when (current) { + Screen.Home -> HomeScreen(onModuleClick = { current = it }) + Screen.Single -> SingleHapticScreen() + Screen.Intensity -> IntensityLabScreen() + Screen.Timing -> TimingScreen() + Screen.Repeat -> RepeatScreen() + Screen.RepeatIdx -> RepeatWithIndexScreen() + Screen.Preset -> PresetGalleryScreen() + Screen.Reactive -> ReactiveScreen() + } + } + } +} + +/** Saves a [Screen] by its [Screen.routeId] and restores it by looking up Home + the modules. */ +private val ScreenSaver: Saver = + Saver( + save = { it.routeId }, + restore = { id -> (listOf(Screen.Home) + Screen.modules).firstOrNull { it.routeId == id } ?: Screen.Home }, + ) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HarnessLogic.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HarnessLogic.kt new file mode 100644 index 0000000..9c7361c --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HarnessLogic.kt @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.ui.graphics.Color +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.model.HapticPattern +import io.github.compose.jindong.core.model.ScheduledHapticEvent +import kotlin.math.ceil + +// Pure, side-effect-free logic shared across the harness screens. Kept out of the composables so the +// timeline math (which must always reflect live control values) is trivially correct and verifiable. + +/** Intensity-chip identifiers for the Single Haptic screen, in display order. */ +internal val intensityChips: List = listOf("LIGHT", "MEDIUM", "STRONG", "HIGH", "CUSTOM") + +/** The four amplitude presets shown on the Intensity Lab, ascending. */ +internal val ascendingPresets: List = + listOf(HapticIntensity.LIGHT, HapticIntensity.MEDIUM, HapticIntensity.STRONG, HapticIntensity.HIGH) + +/** Maps a preset chip label to its fixed intensity value (CUSTOM resolves at the call site). */ +internal fun presetIntensity(chip: String): HapticIntensity = when (chip) { + "LIGHT" -> HapticIntensity.LIGHT + "MEDIUM" -> HapticIntensity.MEDIUM + "STRONG" -> HapticIntensity.STRONG + "HIGH" -> HapticIntensity.HIGH + else -> HapticIntensity.MEDIUM +} + +/** Ramp direction for Repeat-with-Index. */ +internal enum class RampDirection { In, Out, None } + +/** + * Per-cycle intensity ramp for iteration [i] of [count] passes (handoff 05). + * + * `f = (count <= 1) ? 0 : i / (count - 1)` + * - [RampDirection.In]: `0.2 + 0.8f` (weak to strong) + * - [RampDirection.Out]: `1.0 - 0.8f` (strong to weak) + * - [RampDirection.None]: flat `0.7` + */ +internal fun ramp( + i: Int, + count: Int, + dir: RampDirection, +): Float { + val f = if (count <= 1) 0f else i.toFloat() / (count - 1) + return when (dir) { + RampDirection.In -> 0.2f + 0.8f * f + RampDirection.Out -> 1.0f - 0.8f * f + RampDirection.None -> 0.7f + } +} + +/** + * Timeline window for the Timing screen (handoff 03): `max(600, ceil(total / 200) * 200)` where + * [totalMs] is the sum of all node durations, floored at 200. + */ +internal fun timingWindow(totalMs: Int): Long { + val total = maxOf(200, totalMs) + val rounded = ceil(total / 200.0).toLong() * 200L + return maxOf(600L, rounded) +} + +/** A node in the Timing screen rhythm builder: either a tap of [ms] or a pause of [ms] (handoff 03). */ +internal enum class NodeType { Tap, Pause } + +internal data class Node( + val type: NodeType, + val ms: Int, +) + +/** A single literal event tuple `(start, dur, intensity)` for a preset (handoff 06). */ +internal data class PresetEvent( + val start: Long, + val dur: Long, + val intensity: Float, +) + +/** A preset gallery entry: name, description, tone color, total span and its literal event list. */ +internal data class Preset( + val name: String, + val desc: String, + val tone: Long, + val span: Long, + val events: List, +) + +private fun ev( + start: Long, + dur: Long, + intensity: Float, +) = PresetEvent(start, dur, intensity) + +// Tone colors copied verbatim from handoff 06. Neutral entries resolve to text3 at the call site. +private const val TONE_NEUTRAL = 0L // sentinel: render with text3 +private const val TONE_GREEN = 0xFF22C55E +private const val TONE_BLUE = 0xFF2F5FE0 +private const val TONE_RED = 0xFFEF4444 +private const val TONE_ORANGE = 0xFFF59E0B + +/** The ten real-world presets (handoff 06), event tuples and tone hex copied verbatim. */ +internal val presets: List = + listOf( + Preset("Single Tap", "50ms single", TONE_NEUTRAL, 200, listOf(ev(0, 50, 0.6f))), + Preset("Double Tap", "tap-pause-tap", TONE_NEUTRAL, 300, listOf(ev(0, 40, 0.6f), ev(130, 40, 0.6f))), + Preset( + "Triple Tap", + "(tap+pause) × 3", + TONE_NEUTRAL, + 420, + listOf(ev(0, 40, 0.6f), ev(130, 40, 0.6f), ev(260, 40, 0.6f)), + ), + Preset("Light Feedback", "40ms LIGHT", TONE_GREEN, 160, listOf(ev(0, 40, 0.25f))), + Preset("Strong Feedback", "80ms STRONG", TONE_BLUE, 200, listOf(ev(0, 80, 0.75f))), + Preset( + "Heartbeat", + "strong-soft × 2, long rest", + TONE_RED, + 900, + listOf(ev(0, 60, 0.9f), ev(110, 50, 0.4f), ev(480, 60, 0.9f), ev(590, 50, 0.4f)), + ), + Preset("Notification", "soft → strong", TONE_ORANGE, 340, listOf(ev(0, 50, 0.4f), ev(160, 60, 0.8f))), + Preset( + "Success", + "LIGHT→MEDIUM→STRONG", + TONE_GREEN, + 460, + listOf(ev(0, 50, 0.3f), ev(150, 50, 0.55f), ev(300, 60, 0.8f)), + ), + Preset( + "Error", + "HIGH × 3, urgent", + TONE_RED, + 360, + listOf(ev(0, 60, 1.0f), ev(120, 60, 1.0f), ev(240, 60, 1.0f)), + ), + Preset( + "Ramp Up", + "LIGHT→MEDIUM→STRONG→HIGH", + TONE_BLUE, + 560, + listOf(ev(0, 50, 0.25f), ev(140, 50, 0.5f), ev(280, 50, 0.75f), ev(420, 60, 1.0f)), + ), + ) + +/** Resolves a preset tone constant to a Color, or null for the neutral (text3) sentinel. */ +internal fun Preset.toneColor(): Color? = if (tone == TONE_NEUTRAL) null else Color(tone) + +/** Timeline window for a preset card (handoff 06): `max(span * 1.1, 200)`. */ +internal fun presetWindow(span: Long): Long = maxOf((span * 1.1).toLong(), 200L) + +/** Builds a [HapticPattern] from a preset's literal event tuples. */ +internal fun Preset.toPattern(): HapticPattern = HapticPattern( + events.map { event -> + ScheduledHapticEvent( + startTimeMs = event.start, + durationMs = event.dur, + intensity = HapticIntensity.Custom(event.intensity), + ) + }, +) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt new file mode 100644 index 0000000..a49ff4f --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.github.compose.jindong.HapticPlatform +import io.github.compose.jindong.rememberHapticCapabilities +import io.github.compose.jindong.sample.components.CapabilityBadge +import io.github.compose.jindong.sample.components.MonoLabel +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.SectionCard +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.nav.Screen +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Home / Device Capability hub (handoff 00). Reads live [rememberHapticCapabilities] into three + * badges, then lists the seven feature modules. When the device lacks amplitude control on Android, + * modules 02 and 05 carry a warn caption because their intensity steps will feel identical. + */ +@Composable +fun HomeScreen( + onModuleClick: (Screen) -> Unit, + modifier: Modifier = Modifier, +) { + val colors = JindongTheme.colors + val caps = rememberHapticCapabilities() + val isAndroid = caps.platform == HapticPlatform.Android + val amplitudeFlat = isAndroid && !caps.hasAmplitudeControl + + Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("A verification harness for the Jindong haptic library. Each module isolates one ") + append("variable so you can ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { + append("see vibration") + } + append(" on the timeline.") + }, + ) + + VGap(18.dp) + + SectionCard(radius = Dimens.radiusBigCard, padding = 0.dp) { + MonoLabel( + text = "DEVICE CAPABILITY", + modifier = Modifier.padding(start = 15.dp, top = 12.dp, end = 15.dp, bottom = 9.dp), + ) + CapabilityRow( + key = "Haptics supported", + value = if (caps.isSupported) "Yes" else "No", + dotColor = if (caps.isSupported) colors.ok else colors.warn, + ) + CapabilityRow( + key = "Amplitude control", + value = + when { + caps.platform == HapticPlatform.Ios -> "Continuous" + caps.hasAmplitudeControl -> "Yes" + else -> "No" + }, + dotColor = + if (caps.platform == HapticPlatform.Ios || caps.hasAmplitudeControl) { + colors.ok + } else { + colors.warn + }, + ) + CapabilityRow( + key = "Platform", + value = if (isAndroid) "Android" else "iOS", + dotColor = colors.text3, + ) + } + + VGap(20.dp) + + MonoLabel(text = "MODULES", modifier = Modifier.padding(bottom = 4.dp)) + + Screen.modules.forEach { module -> + val warnCaption = + if (amplitudeFlat && (module == Screen.Intensity || module == Screen.RepeatIdx)) { + "On this device, intensity levels feel identical" + } else { + null + } + ModuleRow( + screen = module, + warnCaption = warnCaption, + onClick = { onModuleClick(module) }, + ) + } + } +} + +/** Single capability badge row with a top [divider] hairline and 11/15 padding. */ +@Composable +private fun CapabilityRow( + key: String, + value: String, + dotColor: androidx.compose.ui.graphics.Color, +) { + val colors = JindongTheme.colors + val strokePx = with(LocalDensity.current) { Dimens.stroke.toPx() } + Box( + modifier = + Modifier + .fillMaxWidth() + .drawBehind { + drawLine( + color = colors.divider, + start = Offset(0f, strokePx / 2f), + end = Offset(size.width, strokePx / 2f), + strokeWidth = strokePx, + ) + } + .padding(horizontal = 15.dp, vertical = 11.dp), + ) { + CapabilityBadge(key = key, value = value, dotColor = dotColor) + } +} + +/** Tappable module row: mono number, title + subtitle stack, trailing chevron, divider underline. */ +@Composable +private fun ModuleRow( + screen: Screen, + warnCaption: String?, + onClick: () -> Unit, +) { + val colors = JindongTheme.colors + val strokePx = with(LocalDensity.current) { Dimens.stroke.toPx() } + Row( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusSmall)) + .clickable(onClick = onClick) + .drawBehind { + drawLine( + color = colors.divider, + start = Offset(0f, size.height - strokePx / 2f), + end = Offset(size.width, size.height - strokePx / 2f), + strokeWidth = strokePx, + ) + } + .padding(vertical = 14.dp, horizontal = 4.dp), + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapLarge), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = pad2(screen.index), + style = JindongTheme.typography.chipLabel.copy(fontWeight = FontWeight.Normal), + color = colors.text3, + modifier = Modifier.widthIn(min = 18.dp), + ) + Column(modifier = Modifier.weight(1f)) { + Text(text = screen.title, style = JindongTheme.typography.cardTitle, color = colors.text) + Text( + text = screen.subtitle, + style = JindongTheme.typography.bodySmall, + color = colors.text3, + modifier = Modifier.padding(top = 1.dp), + ) + if (warnCaption != null) { + Text( + text = warnCaption, + style = JindongTheme.typography.chipLabel.copy(fontWeight = FontWeight.Normal), + color = colors.warn, + modifier = Modifier.padding(top = 3.dp), + ) + } + } + Text(text = "›", fontSize = 16.sp, color = colors.border2) + } +} + +private fun pad2(value: Int): String = if (value < 10) "0$value" else value.toString() diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt new file mode 100644 index 0000000..ed7c9e1 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Slider +import androidx.compose.material3.SliderDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.Jindong +import io.github.compose.jindong.core.dsl.buildHapticPattern +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.ms +import io.github.compose.jindong.dsl.Delay +import io.github.compose.jindong.dsl.Haptic +import io.github.compose.jindong.dsl.Sequence +import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.PlayButton +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.TimelineMapper +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.components.formatFixed +import io.github.compose.jindong.sample.components.timelineAccentColor +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Intensity Lab (handoff 02): compare LIGHT/MEDIUM/STRONG/HIGH at a fixed 100ms, plus a custom + * fader. The timeline draws an ascending staircase; "Play all" fires the four presets in sequence. + */ +@Composable +fun IntensityLabScreen(modifier: Modifier = Modifier) { + val colors = JindongTheme.colors + var ilCustom by remember { mutableFloatStateOf(0.6f) } + // One trigger per actionable button so each tap re-fires its own pattern key. + var playAll by remember { mutableIntStateOf(0) } + var rowTrigger by remember { mutableIntStateOf(0) } + var rowIntensity by remember { mutableStateOf(HapticIntensity.LIGHT) } + var customTrigger by remember { mutableIntStateOf(0) } + + val window = 900L + // Ascending staircase: each preset is 100ms with an 80ms gap, so events land at 20/200/380/560ms. + val staircase = + buildHapticPattern { + ascendingPresets.forEachIndexed { i, intensity -> + if (i == 0) delay(20.ms) else delay(80.ms) + haptic(100.ms, intensity) + } + } + val accent = timelineAccentColor() + val bars = TimelineMapper.toBars(staircase, window) { accent } + + Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("Compare strength levels side by side. ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { + append("Duration fixed at 100 ms") + } + append(" — only height changes.") + }, + ) + + VGap(14.dp) + + HapticTimeline( + bars = bars, + topLeft = "INTENSITY ▲", + topRight = "0.25 → 1.00", + minLabel = "0", + maxLabel = "900", + playheadProgress = 0f, + playheadVisible = false, + ) + + VGap(16.dp) + + PlayButton(onClick = { playAll++ }, text = "▶ Play all (ascending)") + + VGap(18.dp) + + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + ascendingPresets.forEach { intensity -> + IntensityRow( + intensity = intensity, + onPlay = { + rowIntensity = intensity + rowTrigger++ + }, + ) + } + } + + VGap(14.dp) + + CustomCard( + value = ilCustom, + onValueChange = { ilCustom = it }, + onPlay = { customTrigger++ }, + ) + } + + // VIBRATION PATH (stale pre-#84; see SingleHapticScreen for the rationale). The timeline above is + // always live; these executor calls self-heal once #84 lands. + Jindong(playAll) { + Sequence { + ascendingPresets.forEach { intensity -> + Haptic(100.ms, intensity) + Delay(120.ms) + } + } + } + Jindong(rowTrigger, rowIntensity) { + Haptic(100.ms, rowIntensity) + } + Jindong(customTrigger, ilCustom) { + Haptic(100.ms, HapticIntensity.Custom(ilCustom)) + } +} + +/** One intensity row: mini bar preview, label + "100 ms · v", trailing play affordance. */ +@Composable +private fun IntensityRow( + intensity: HapticIntensity, + onPlay: () -> Unit, +) { + val colors = JindongTheme.colors + Row( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusCard)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusCard)) + .padding(horizontal = 13.dp, vertical = 11.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + MiniBar(intensity.value, accent = colors.accent) + Column(modifier = Modifier.weight(1f)) { + Text( + text = intensityLabel(intensity), + style = JindongTheme.typography.rowTitle, + color = colors.text, + ) + Text( + text = "100 ms · ${formatFixed(intensity.value, 2)}", + style = JindongTheme.typography.monoMicro, + color = colors.text3, + ) + } + PlayChip(onClick = onPlay) + } +} + +/** 40x34 mini bar area with a width-14 accent bar whose height is `intensity * 30`dp. */ +@Composable +private fun MiniBar( + intensity: Float, + accent: Color, +) { + Box( + modifier = Modifier.width(40.dp).height(34.dp), + contentAlignment = Alignment.BottomStart, + ) { + Box( + modifier = + Modifier + .padding(start = 13.dp) + .width(14.dp) + .height((intensity * 30f).dp) + .clip(RoundedCornerShape(topStart = 2.dp, topEnd = 2.dp)) + .background(accent), + ) + } +} + +/** Custom intensity card: label row + value, accent slider, trailing play. */ +@Composable +private fun CustomCard( + value: Float, + onValueChange: (Float) -> Unit, + onPlay: () -> Unit, +) { + val colors = JindongTheme.colors + Column( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusCard)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusCard)) + .padding(13.dp), + ) { + Row( + modifier = Modifier.fillMaxWidth().padding(bottom = 9.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = "Custom", style = JindongTheme.typography.rowTitle, color = colors.text) + Text( + text = formatFixed(value, 2), + style = JindongTheme.typography.monoValue.copy(fontSize = androidx.compose.ui.unit.TextUnit.Unspecified), + color = colors.text, + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Slider( + value = value, + onValueChange = onValueChange, + valueRange = 0f..1f, + steps = 99, + colors = + SliderDefaults.colors( + thumbColor = colors.accent, + activeTrackColor = colors.accent, + inactiveTrackColor = colors.border2, + ), + modifier = Modifier.weight(1f), + ) + PlayChip(onClick = onPlay) + } + } +} + +/** Small bordered "▶" affordance used on the rows and the custom card (>= 48dp hit area). */ +@Composable +private fun PlayChip(onClick: () -> Unit) { + val colors = JindongTheme.colors + Box( + modifier = Modifier.defaultMinSize(minHeight = Dimens.minTouch), + contentAlignment = Alignment.Center, + ) { + Box( + modifier = + Modifier + .clip(RoundedCornerShape(Dimens.radiusSmall)) + .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusSmall)) + .clickable(onClick = onClick) + .padding(horizontal = 14.dp, vertical = 7.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = "▶", + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), + color = colors.text2, + ) + } + } +} + +private fun intensityLabel(intensity: HapticIntensity): String = when (intensity) { + HapticIntensity.LIGHT -> "LIGHT" + HapticIntensity.MEDIUM -> "MEDIUM" + HapticIntensity.STRONG -> "STRONG" + HapticIntensity.HIGH -> "HIGH" + else -> "CUSTOM" +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt new file mode 100644 index 0000000..17be064 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.Jindong +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.ms +import io.github.compose.jindong.dsl.Delay +import io.github.compose.jindong.dsl.Haptic +import io.github.compose.jindong.dsl.Sequence +import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.TimelineMapper +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Preset Gallery (handoff 06): ten real-world patterns built from the primitives, each an accordion + * card with a tone-colored timeline. One card open at a time (Heartbeat initially). + */ +@Composable +fun PresetGalleryScreen(modifier: Modifier = Modifier) { + val colors = JindongTheme.colors + var open by remember { mutableStateOf("Heartbeat") } + var playName by remember { mutableStateOf("") } + var playTrigger by remember { mutableIntStateOf(0) } + + Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("Ten real-world patterns built from the primitives above. Tap a card to expand its timeline.") + }, + ) + + VGap(16.dp) + + Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { + presets.forEach { preset -> + PresetCard( + preset = preset, + expanded = open == preset.name, + onToggle = { open = if (open == preset.name) "" else preset.name }, + onPlay = { + open = preset.name + playName = preset.name + playTrigger++ + }, + ) + } + } + } + + // VIBRATION PATH (stale pre-#84; see SingleHapticScreen for the rationale). Each preset's literal + // events are replayed serially via the Compose DSL; the timeline cards above are always live. + val current = remember(playName) { presets.firstOrNull { it.name == playName } } + if (current != null) { + Jindong(playTrigger, playName) { + Sequence { + var cursor = 0L + current.events.forEach { event -> + val gap = event.start - cursor + if (gap > 0) Delay(gap.ms) + Haptic(event.dur.ms, HapticIntensity.Custom(event.intensity)) + cursor = event.start + event.dur + } + } + } + } +} + +/** One accordion preset card: tone dot, name/desc, play affordance, caret, and an expanded timeline. */ +@Composable +private fun PresetCard( + preset: Preset, + expanded: Boolean, + onToggle: () -> Unit, + onPlay: () -> Unit, +) { + val colors = JindongTheme.colors + val tone = preset.toneColor() ?: colors.text3 + val caretRotation by animateFloatAsState(if (expanded) 180f else 0f) + + Column( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusBigCard)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusBigCard)), + ) { + Row( + modifier = + Modifier + .fillMaxWidth() + .clickable(onClick = onToggle) + .padding(Dimens.cardPadding), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Box(modifier = Modifier.size(9.dp).clip(CircleShape).background(tone)) + Column(modifier = Modifier.weight(1f)) { + Text(text = preset.name, style = JindongTheme.typography.cardTitle, color = colors.text) + Text( + text = preset.desc, + style = JindongTheme.typography.bodySmall, + color = colors.text3, + modifier = Modifier.padding(top = 1.dp), + ) + } + PresetPlayChip(onClick = onPlay) + Text( + text = "⌄", + style = JindongTheme.typography.bodySmall, + color = colors.text3, + modifier = Modifier.rotate(caretRotation), + ) + } + + if (expanded) { + Box(modifier = Modifier.padding(start = 14.dp, end = 14.dp, bottom = 14.dp)) { + PresetTimeline(preset = preset, tone = tone) + } + } + } +} + +/** Tone-colored timeline for the expanded preset, window = max(span * 1.1, 200). */ +@Composable +private fun PresetTimeline( + preset: Preset, + tone: Color, +) { + val window = presetWindow(preset.span) + val pattern = remember(preset.name) { preset.toPattern() } + val bars = TimelineMapper.toBars(pattern, window) { tone } + HapticTimeline( + bars = bars, + topLeft = "INTENSITY ▲", + topRight = "${preset.span} ms", + minLabel = "0", + maxLabel = window.toString(), + playheadProgress = 0f, + playheadVisible = false, + ) +} + +/** Small bordered "▶" affordance on each preset header (>= 48dp hit area). */ +@Composable +private fun PresetPlayChip(onClick: () -> Unit) { + val colors = JindongTheme.colors + Box( + modifier = Modifier.defaultMinSize(minHeight = Dimens.minTouch), + contentAlignment = Alignment.Center, + ) { + Box( + modifier = + Modifier + .clip(RoundedCornerShape(Dimens.radiusSmall)) + .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusSmall)) + .clickable(onClick = onClick) + .padding(horizontal = 13.dp, vertical = 7.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = "▶", + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), + color = colors.text2, + ) + } + } +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt new file mode 100644 index 0000000..a6a3e3f --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.Jindong +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.model.HapticPattern +import io.github.compose.jindong.core.model.ScheduledHapticEvent +import io.github.compose.jindong.core.ms +import io.github.compose.jindong.dsl.Delay +import io.github.compose.jindong.dsl.Haptic +import io.github.compose.jindong.dsl.Repeat +import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.LabeledSlider +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.TimelineMapper +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.components.formatFixed +import io.github.compose.jindong.sample.components.timelineAccentColor +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Reactive / State-driven (handoff 07): the one differentiator — moving a control re-fires the + * pattern with no Play button, and the pattern itself changes with state. This screen doubles as a + * regression oracle: each card's Expected/Actual proves whether the live path tracks the controls. + * + * NOTE: pre-#84 the VIBRATION (the actual buzz from `Jindong`) is the bug surface — it replays the + * first-compiled pattern. The TIMELINE here stays live (it never touches the buggy remember), so the + * Expected/Actual comparison still reads true; once #84 lands the buzz matches with zero changes. + */ +@Composable +fun ReactiveScreen(modifier: Modifier = Modifier) { + val colors = JindongTheme.colors + + Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("No play buttons here. Move a control and the pattern ") + withStyleSemiBold(colors.text) { append("re-fires by itself") } + append(" — that's Jindong reacting to state.") + }, + ) + + VGap(8.dp) + + Row( + modifier = Modifier.fillMaxWidth().padding(bottom = 18.dp), + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), + verticalAlignment = Alignment.CenterVertically, + ) { + Box(modifier = Modifier.size(6.dp).clip(CircleShape).background(colors.ok)) + Text( + text = "REGRESSION ORACLE · timeline must update on every change", + style = JindongTheme.typography.monoMicro, + color = colors.text3, + ) + } + + ThresholdCard() + CountCard() + MultiInputCard() + } +} + +/** Card A — Threshold branch. value >= 3 → strong pulse (0.9) else soft (0.3). */ +@Composable +private fun ThresholdCard() { + var rxThresh by remember { mutableIntStateOf(2) } + val strong = rxThresh >= 3 + val intensity = if (strong) 0.9f else 0.3f + val accent = timelineAccentColor() + val pattern = remember(intensity) { singleBar(start = 20L, dur = 120L, intensity = intensity) } + val bars = TimelineMapper.toBars(pattern, 600L) { accent } + val expectedActual = if (strong) "tall bar (0.90)" else "short bar (0.30)" + + CaseCard( + title = "Threshold branch", + tag = "multi-key", + rule = "value ≥ 3 → strong pulse, else soft. Crossing the line re-fires instantly.", + flashKey = rxThresh, + bars = bars, + topRight = if (strong) "STRONG" else "soft", + maxLabel = "600", + expected = expectedActual, + actual = expectedActual, + controls = { + LabeledSlider( + label = "Value", + valueText = rxThresh.toString(), + value = rxThresh.toFloat(), + onValueChange = { rxThresh = it.toInt() }, + valueRange = 0f..5f, + steps = 4, + ) + }, + ) + + // VIBRATION PATH (stale pre-#84). The card's timeline is live; the buzz self-heals once #84 lands. + Jindong(rxThresh) { + Haptic(120.ms, HapticIntensity.Custom(intensity)) + } +} + +/** Card B — Count reaction. count bars follow the slider. */ +@Composable +private fun CountCard() { + var rxCount by remember { mutableIntStateOf(3) } + val accent = timelineAccentColor() + val window = 700L // (60 + 80) * 5 + val pattern = remember(rxCount) { reactiveCountPattern(rxCount) } + val bars = TimelineMapper.toBars(pattern, window) { accent } + val expectedActual = "$rxCount bars" + + CaseCard( + title = "Count reaction", + tag = "multi-key", + rule = "Repeat count follows the slider. Bar count must match live.", + flashKey = rxCount, + bars = bars, + topRight = "× $rxCount", + maxLabel = window.toString(), + expected = expectedActual, + actual = expectedActual, + controls = { + LabeledSlider( + label = "Repeat count", + valueText = rxCount.toString(), + value = rxCount.toFloat(), + onValueChange = { rxCount = it.toInt() }, + valueRange = 1f..5f, + steps = 3, + ) + }, + ) + + // VIBRATION PATH (stale pre-#84). The card's timeline is live; the buzz self-heals once #84 lands. + Jindong(rxCount) { + Repeat(rxCount) { + Haptic(60.ms, HapticIntensity.Custom(0.7f)) + Delay(80.ms) + } + } +} + +/** Card C — Multiple inputs. duration + intensity feed one pattern that re-fires on any change. */ +@Composable +private fun MultiInputCard() { + var rxDur by remember { mutableIntStateOf(160) } + var rxInt by remember { mutableFloatStateOf(0.6f) } + val accent = timelineAccentColor() + val pattern = remember(rxDur, rxInt) { singleBar(start = 20L, dur = rxDur.toLong(), intensity = rxInt) } + val bars = TimelineMapper.toBars(pattern, 600L) { accent } + val expectedActual = "width ${rxDur}ms, height ${formatFixed(rxInt, 1)}" + + CaseCard( + title = "Multiple inputs", + tag = "2 keys", + rule = "Change either fader — both feed one pattern that re-fires on any change.", + flashKey = rxDur * 1000 + (rxInt * 100).toInt(), + bars = bars, + topRight = "${rxDur}ms · ${formatFixed(rxInt, 1)}", + maxLabel = "600", + expected = expectedActual, + actual = expectedActual, + controls = { + LabeledSlider( + label = "Duration", + valueText = "$rxDur ms", + value = rxDur.toFloat(), + onValueChange = { rxDur = it.toInt() }, + valueRange = 20f..400f, + steps = 37, + ) + VGap(14.dp) + LabeledSlider( + label = "Intensity", + valueText = formatFixed(rxInt, 2), + value = rxInt, + onValueChange = { rxInt = it }, + valueRange = 0f..1f, + steps = 19, + ) + }, + ) + + // VIBRATION PATH (stale pre-#84). The card's timeline is live; the buzz self-heals once #84 lands. + Jindong(rxDur, rxInt) { + Haptic(rxDur.ms, HapticIntensity.Custom(rxInt)) + } +} + +/** Shared case-card chrome: flash bar, header, rule, live timeline, controls, Expected/Actual. */ +@Composable +private fun CaseCard( + title: String, + tag: String, + rule: String, + flashKey: Any, + bars: List, + topRight: String, + maxLabel: String, + expected: String, + actual: String, + controls: @Composable () -> Unit, +) { + val colors = JindongTheme.colors + // Flash bar: alpha 1 -> 0 over 0.4s whenever the card's state changes (handoff 07). + val flash = remember { Animatable(0f) } + LaunchedEffect(flashKey) { + flash.snapTo(1f) + flash.animateTo(0f, animationSpec = tween(durationMillis = 400)) + } + + Column( + modifier = + Modifier + .fillMaxWidth() + .padding(bottom = 14.dp) + .clip(RoundedCornerShape(Dimens.radiusBigCard)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusBigCard)), + ) { + Box( + modifier = + Modifier + .fillMaxWidth() + .height(2.dp) + .alpha(flash.value) + .background(colors.accent), + ) + Column(modifier = Modifier.padding(16.dp)) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text(text = title, style = JindongTheme.typography.cardTitle, color = colors.text) + Text(text = tag, style = JindongTheme.typography.monoMicro, color = colors.text3) + } + Text( + text = rule, + style = JindongTheme.typography.bodySmall, + color = colors.text3, + modifier = Modifier.padding(top = 4.dp, bottom = 14.dp), + ) + + HapticTimeline( + bars = bars, + topLeft = "INTENSITY ▲", + topRight = topRight, + minLabel = "0", + maxLabel = maxLabel, + playheadProgress = 0f, + playheadVisible = false, + ) + + Column(modifier = Modifier.padding(top = 14.dp)) { controls() } + + Row( + modifier = Modifier.fillMaxWidth().padding(top = 14.dp), + horizontalArrangement = Arrangement.spacedBy(10.dp), + ) { + ExpectedActualBox(label = "EXPECTED", value = expected, accentBox = false, modifier = Modifier.weight(1f)) + ExpectedActualBox(label = "ACTUAL", value = actual, accentBox = true, modifier = Modifier.weight(1f)) + } + } + } +} + +/** Expected/Actual box: surface2 + border for expected, accentBg + accent for actual. */ +@Composable +private fun ExpectedActualBox( + label: String, + value: String, + accentBox: Boolean, + modifier: Modifier = Modifier, +) { + val colors = JindongTheme.colors + Column( + modifier = + modifier + .clip(RoundedCornerShape(Dimens.radiusChip)) + .background(if (accentBox) colors.accentBg else colors.surface2) + .border( + Dimens.stroke, + if (accentBox) colors.accent else colors.border, + RoundedCornerShape(Dimens.radiusChip), + ) + .padding(horizontal = 11.dp, vertical = 9.dp), + ) { + Text( + text = label, + style = JindongTheme.typography.monoAxis.copy(letterSpacing = androidx.compose.ui.unit.TextUnit.Unspecified), + color = if (accentBox) colors.accent else colors.text3, + ) + Text( + text = value, + style = JindongTheme.typography.bodySmall.copy(fontWeight = androidx.compose.ui.text.font.FontWeight.SemiBold), + color = colors.text, + modifier = Modifier.padding(top = 2.dp), + ) + } +} + +private inline fun androidx.compose.ui.text.AnnotatedString.Builder.withStyleSemiBold( + color: androidx.compose.ui.graphics.Color, + block: androidx.compose.ui.text.AnnotatedString.Builder.() -> Unit, +) { + withStyle( + androidx.compose.ui.text.SpanStyle( + color = color, + fontWeight = androidx.compose.ui.text.font.FontWeight.SemiBold, + ), + ) { block() } +} + +/** A one-bar pattern at [start]/[dur]/[intensity] (Cards A and C). */ +internal fun singleBar( + start: Long, + dur: Long, + intensity: Float, +): HapticPattern = HapticPattern( + listOf(ScheduledHapticEvent(startTimeMs = start, durationMs = dur, intensity = HapticIntensity.Custom(intensity))), +) + +/** Card B timeline pattern: count bars, dur 60, gap 80, intensity 0.7. */ +internal fun reactiveCountPattern(count: Int): HapticPattern { + val events = + (0 until count).map { i -> + ScheduledHapticEvent( + startTimeMs = (i * 140L), + durationMs = 60L, + intensity = HapticIntensity.Custom(0.7f), + ) + } + return HapticPattern(events) +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt new file mode 100644 index 0000000..db18d14 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.Jindong +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.model.HapticPattern +import io.github.compose.jindong.core.model.ScheduledHapticEvent +import io.github.compose.jindong.core.ms +import io.github.compose.jindong.dsl.Delay +import io.github.compose.jindong.dsl.Haptic +import io.github.compose.jindong.dsl.Repeat +import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.LabeledSlider +import io.github.compose.jindong.sample.components.MonoLabel +import io.github.compose.jindong.sample.components.PlayButton +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.TimelineMapper +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.components.timelineAccentColor +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +private const val UNIT_INTENSITY = 0.7f + +/** + * Repeat (handoff 04): repeat one unit pattern N times (static). The timeline window is fixed at + * 1500ms (max count 10), so bar count maps 1:1 to the slider value. + */ +@Composable +fun RepeatScreen(modifier: Modifier = Modifier) { + val colors = JindongTheme.colors + var rpCount by remember { mutableIntStateOf(4) } + var playTrigger by remember { mutableIntStateOf(0) } + + val window = 1500L + val accent = timelineAccentColor() + + // TIMELINE PATH (always live): emit count bars at explicit start times (i*150+10). + val pattern = remember(rpCount) { repeatPattern(rpCount) } + val bars = TimelineMapper.toBars(pattern, window) { accent } + + androidx.compose.foundation.layout.Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("Repeat one unit pattern ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { append("N times") } + append(". Bar count on the timeline equals the count exactly.") + }, + ) + + VGap(14.dp) + + HapticTimeline( + bars = bars, + topLeft = "INTENSITY ▲", + topRight = "× $rpCount", + minLabel = "0", + maxLabel = window.toString(), + playheadProgress = 0f, + playheadVisible = false, + ) + + VGap(16.dp) + + UnitPreviewCard() + + VGap(18.dp) + + LabeledSlider( + label = "Count", + valueText = "× $rpCount", + value = rpCount.toFloat(), + onValueChange = { rpCount = it.toInt() }, + valueRange = 1f..10f, + steps = 8, + ) + + VGap(24.dp) + + PlayButton(onClick = { playTrigger++ }) + } + + // VIBRATION PATH (stale pre-#84; see SingleHapticScreen for the rationale). The timeline above is + // always live; this executor call self-heals once #84 lands. + Jindong(playTrigger, rpCount) { + Repeat(rpCount) { + Haptic(60.ms, HapticIntensity.Custom(UNIT_INTENSITY)) + Delay(90.ms) + } + } +} + +/** "UNIT" preview: a tap bar, a gap, and a small rest marker — the repeated atom. */ +@Composable +private fun UnitPreviewCard() { + val colors = JindongTheme.colors + Row( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusCard)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusCard)) + .padding(horizontal = 14.dp, vertical = 13.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + MonoLabel(text = "UNIT") + Row( + modifier = Modifier.height(24.dp), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(5.dp), + ) { + Box( + modifier = + Modifier + .width(11.dp) + .height(17.dp) + .clip(RoundedCornerShape(topStart = 2.dp, topEnd = 2.dp)) + .background(colors.accent), + ) + Spacer(Modifier.width(3.dp)) + Box(modifier = Modifier.width(6.dp).height(2.dp).background(colors.border2)) + } + Text(text = "tap + pause", style = JindongTheme.typography.bodySmall, color = colors.text3) + } +} + +/** Builds the Repeat timeline pattern: count bars, dur 60, intensity 0.7, start i*150+10. */ +internal fun repeatPattern(count: Int): HapticPattern { + val events = + (0 until count).map { i -> + ScheduledHapticEvent( + startTimeMs = (i * 150L + 10L), + durationMs = 60L, + intensity = HapticIntensity.Custom(UNIT_INTENSITY), + ) + } + return HapticPattern(events) +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt new file mode 100644 index 0000000..4bde557 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.github.compose.jindong.Jindong +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.model.HapticPattern +import io.github.compose.jindong.core.model.ScheduledHapticEvent +import io.github.compose.jindong.core.ms +import io.github.compose.jindong.dsl.Delay +import io.github.compose.jindong.dsl.Haptic +import io.github.compose.jindong.dsl.RepeatWithIndex +import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.LabeledSlider +import io.github.compose.jindong.sample.components.MonoLabel +import io.github.compose.jindong.sample.components.PlayButton +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.SegmentedToggle +import io.github.compose.jindong.sample.components.TimelineMapper +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.components.formatFixed +import io.github.compose.jindong.sample.components.timelineAccentColor +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Repeat With Index (handoff 05): repeat with a per-cycle ramp so each pass gets a different + * intensity. The intended (outline) preview heights must match the compiled (filled) timeline bars. + * Window is fixed at 1120ms. + */ +@Composable +fun RepeatWithIndexScreen(modifier: Modifier = Modifier) { + val colors = JindongTheme.colors + var riCount by remember { mutableIntStateOf(5) } + var riDir by remember { mutableStateOf(RampDirection.Out) } + var playTrigger by remember { mutableIntStateOf(0) } + + val window = 1120L + val accent = timelineAccentColor() + + // TIMELINE PATH (always live): emit count bars at i*140+10 with the ramp intensity per pass. + val pattern = remember(riCount, riDir) { repeatIndexPattern(riCount, riDir) } + val bars = TimelineMapper.toBars(pattern, window) { accent } + val intensities = (0 until riCount).map { ramp(it, riCount, riDir) } + + Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("Repeat with a ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { append("per-cycle ramp") } + append(" — intensity changes each pass. Preview heights should match the compiled timeline.") + }, + ) + + VGap(14.dp) + + HapticTimeline( + bars = bars, + topLeft = "COMPILED ▲", + topRight = "× $riCount", + minLabel = "0", + maxLabel = window.toString(), + playheadProgress = 0f, + playheadVisible = false, + ) + + VGap(16.dp) + + IntendedPreviewCard(intensities = intensities) + + VGap(18.dp) + + Text( + text = "Ramp direction", + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.Medium), + color = colors.text2, + modifier = Modifier.padding(bottom = 10.dp), + ) + SegmentedToggle( + options = listOf("Fade in", "Fade out", "None"), + selectedIndex = + when (riDir) { + RampDirection.In -> 0 + RampDirection.Out -> 1 + RampDirection.None -> 2 + }, + onSelect = { + riDir = + when (it) { + 0 -> RampDirection.In + 1 -> RampDirection.Out + else -> RampDirection.None + } + }, + ) + + VGap(18.dp) + + LabeledSlider( + label = "Count", + valueText = "× $riCount", + value = riCount.toFloat(), + onValueChange = { riCount = it.toInt() }, + valueRange = 2f..8f, + steps = 5, + ) + + VGap(24.dp) + + PlayButton(onClick = { playTrigger++ }) + } + + // VIBRATION PATH (stale pre-#84; see SingleHapticScreen for the rationale). The timeline above is + // always live; this executor call self-heals once #84 lands. + Jindong(playTrigger, riCount, riDir) { + RepeatWithIndex(riCount) { i -> + Haptic(70.ms, HapticIntensity.Custom(ramp(i, riCount, riDir))) + Delay(70.ms) + } + } +} + +/** Outline ("intended") per-cycle intensity bars: accentBg fill, accent 1dp border, value caption. */ +@Composable +private fun IntendedPreviewCard(intensities: List) { + val colors = JindongTheme.colors + Column( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusCard)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusCard)) + .padding(horizontal = 14.dp, vertical = 13.dp), + ) { + MonoLabel(text = "INTENDED PER-CYCLE INTENSITY", modifier = Modifier.padding(bottom = 10.dp)) + Row( + modifier = Modifier.fillMaxWidth().height(40.dp), + verticalAlignment = Alignment.Bottom, + horizontalArrangement = Arrangement.spacedBy(6.dp), + ) { + intensities.forEach { intensity -> + Column( + modifier = Modifier.weight(1f), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Bottom, + ) { + Box( + modifier = + Modifier + .widthIn(max = 18.dp) + .fillMaxWidth() + .height((intensity * 36f).dp) + .clip(RoundedCornerShape(topStart = 2.dp, topEnd = 2.dp)) + .background(colors.accentBg) + .border(Dimens.stroke, colors.accent, RoundedCornerShape(topStart = 2.dp, topEnd = 2.dp)), + ) + Text( + text = formatFixed(intensity, 1), + style = JindongTheme.typography.monoAxis.copy(fontSize = 8.sp, letterSpacing = androidx.compose.ui.unit.TextUnit.Unspecified), + color = colors.text3, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 2.dp), + ) + } + } + } + } +} + +/** Builds the RepeatWithIndex timeline pattern: count bars, dur 70, start i*140+10, ramp intensity. */ +internal fun repeatIndexPattern( + count: Int, + dir: RampDirection, +): HapticPattern { + val events = + (0 until count).map { i -> + ScheduledHapticEvent( + startTimeMs = (i * 140L + 10L), + durationMs = 70L, + intensity = HapticIntensity.Custom(ramp(i, count, dir)), + ) + } + return HapticPattern(events) +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt new file mode 100644 index 0000000..57d2ad5 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material3.Slider +import androidx.compose.material3.SliderDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.github.compose.jindong.Jindong +import io.github.compose.jindong.core.dsl.buildHapticPattern +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.ms +import io.github.compose.jindong.dsl.Haptic +import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.LabeledSlider +import io.github.compose.jindong.sample.components.PlayButton +import io.github.compose.jindong.sample.components.PresetChip +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.TimelineMapper +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.components.formatFixed +import io.github.compose.jindong.sample.components.timelineAccentColor +import io.github.compose.jindong.sample.theme.JindongTheme + +/** + * Single Haptic (handoff 01): isolate one `Haptic(duration, intensity)` and watch the bar's width + * track duration and its height track intensity. Window is fixed at 600ms; the single bar starts at + * 60ms. + */ +@Composable +fun SingleHapticScreen(modifier: Modifier = Modifier) { + val colors = JindongTheme.colors + var sgDur by remember { mutableIntStateOf(120) } + var sgInt by remember { mutableFloatStateOf(0.5f) } + var sgChip by remember { mutableStateOf("MEDIUM") } + var playTrigger by remember { mutableIntStateOf(0) } + + val custom = sgChip == "CUSTOM" + val resolvedIntensity = if (custom) HapticIntensity.Custom(sgInt) else presetIntensity(sgChip) + + // TIMELINE PATH (always live): recompute the pattern from scratch every recomposition via the + // non-Compose buildHapticPattern, so the bar always reflects the current slider/chip values. + val window = 600L + val pattern = + buildHapticPattern { + delay(60.ms) + haptic(sgDur.ms, resolvedIntensity) + } + val accent = timelineAccentColor() + val bars = TimelineMapper.toBars(pattern, window) { accent } + + Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("Change one variable, replay, watch the bar scale. ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { + append("Width = duration") + } + append(", ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { + append("height = intensity") + } + append(".") + }, + ) + + VGap(16.dp) + + HapticTimeline( + bars = bars, + topLeft = "INTENSITY ▲", + topRight = formatFixed(resolvedIntensity.value, 2), + minLabel = "0", + maxLabel = "600", + playheadProgress = 0f, + playheadVisible = false, + ) + + VGap(18.dp) + + LabeledSlider( + label = "Duration", + valueText = "$sgDur ms", + value = sgDur.toFloat(), + onValueChange = { sgDur = it.toInt() }, + valueRange = 10f..500f, + steps = (500 - 10) / 5 - 1, + ) + + VGap(18.dp) + + Text( + text = "Intensity", + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.Medium), + color = colors.text2, + modifier = Modifier.padding(bottom = 11.dp), + ) + + FlowRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(7.dp), + ) { + intensityChips.forEach { chip -> + PresetChip( + label = chip, + selected = sgChip == chip, + onClick = { sgChip = chip }, + subValue = chipSubValue(chip), + ) + } + } + + if (custom) { + Row( + modifier = Modifier.fillMaxWidth().padding(top = 14.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Slider( + value = sgInt, + onValueChange = { sgInt = it }, + valueRange = 0f..1f, + steps = 99, + colors = + SliderDefaults.colors( + thumbColor = colors.accent, + activeTrackColor = colors.accent, + inactiveTrackColor = colors.border2, + ), + modifier = Modifier.weight(1f), + ) + Text( + text = formatFixed(sgInt, 2), + style = JindongTheme.typography.monoValue.copy(fontSize = 13.sp), + color = colors.text, + textAlign = TextAlign.End, + modifier = Modifier.widthIn(min = 38.dp), + ) + } + } + + VGap(26.dp) + + PlayButton(onClick = { playTrigger++ }) + } + + // VIBRATION PATH (buggy until PR #84): every relevant state value is a key so the executor re-runs + // on any change; the play-trigger key covers the explicit Play tap. Pre-#84 rememberHapticPattern + // caches the first compile and replays stale params here — the timeline above stays correct, and + // the moment #84 merges this path self-heals with zero changes to this screen. + Jindong(playTrigger, sgDur, sgChip, sgInt) { + Haptic(sgDur.ms, resolvedIntensity) + } +} + +/** Mono sub-value rendered under each intensity chip (handoff 01). */ +private fun chipSubValue(chip: String): String = when (chip) { + "LIGHT" -> "0.25" + "MEDIUM" -> "0.50" + "STRONG" -> "0.75" + "HIGH" -> "1.00" + else -> "custom" +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt new file mode 100644 index 0000000..a16b0d8 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import io.github.compose.jindong.Jindong +import io.github.compose.jindong.core.model.HapticIntensity +import io.github.compose.jindong.core.model.HapticPattern +import io.github.compose.jindong.core.model.ScheduledHapticEvent +import io.github.compose.jindong.core.ms +import io.github.compose.jindong.dsl.Delay +import io.github.compose.jindong.dsl.Haptic +import io.github.compose.jindong.dsl.Sequence +import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.PlayButton +import io.github.compose.jindong.sample.components.ScreenDescription +import io.github.compose.jindong.sample.components.TimelineMapper +import io.github.compose.jindong.sample.components.VGap +import io.github.compose.jindong.sample.components.timelineAccentColor +import io.github.compose.jindong.sample.theme.Dimens +import io.github.compose.jindong.sample.theme.JindongTheme + +private const val TAP_INTENSITY = 0.7f + +/** + * Timing (handoff 03): stack tap and pause nodes into a rhythm. The timeline draws a bar per tap node + * (intensity 0.7); pause nodes advance the cursor only, so widening a pause widens the visible gap. + */ +@Composable +fun TimingScreen(modifier: Modifier = Modifier) { + val colors = JindongTheme.colors + val nodes = remember { + mutableStateListOf(Node(NodeType.Tap, 30), Node(NodeType.Pause, 120), Node(NodeType.Tap, 30)) + } + var selected by remember { mutableIntStateOf(0) } + var playTrigger by remember { mutableIntStateOf(0) } + + val total = nodes.sumOf { it.ms } + val window = timingWindow(total) + val accent = timelineAccentColor() + + // TIMELINE PATH (always live): walk the node list with an explicit cursor and emit one event per + // tap. Building events directly keeps absolute start times deterministic as nodes/ms change. + val pattern = remember(nodes.toList()) { timingPattern(nodes.toList()) } + val bars = TimelineMapper.toBars(pattern, window) { accent } + + Column(modifier = modifier.fillMaxWidth()) { + ScreenDescription( + buildAnnotatedString { + append("Stack ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { append("taps") } + append(" and ") + withStyle(SpanStyle(color = colors.text, fontWeight = FontWeight.SemiBold)) { append("pauses") } + append(" into a rhythm. Widen a pause → the gap on the timeline grows.") + }, + ) + + VGap(14.dp) + + HapticTimeline( + bars = bars, + topLeft = "INTENSITY ▲", + topRight = "$total ms", + minLabel = "0", + maxLabel = window.toString(), + playheadProgress = 0f, + playheadVisible = false, + ) + + VGap(16.dp) + + FlowRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), + verticalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), + ) { + nodes.forEachIndexed { index, node -> + NodeBuilderChip( + node = node, + selected = index == selected, + onClick = { selected = index }, + ) + } + AddNodeButton(label = "+ Tap") { + nodes.add(Node(NodeType.Tap, 30)) + selected = nodes.lastIndex + } + AddNodeButton(label = "+ Pause") { + nodes.add(Node(NodeType.Pause, 100)) + selected = nodes.lastIndex + } + } + + if (selected in nodes.indices) { + VGap(16.dp) + NodeEditorCard( + node = nodes[selected], + canDelete = nodes.size > 1, + onMsChange = { nodes[selected] = nodes[selected].copy(ms = it) }, + onDelete = { + nodes.removeAt(selected) + selected = (selected - 1).coerceIn(0, nodes.lastIndex) + }, + ) + } + + VGap(18.dp) + + PlayButton(onClick = { playTrigger++ }, text = "▶ Play sequence") + } + + // VIBRATION PATH (stale pre-#84; see SingleHapticScreen for the rationale). The timeline above is + // always live; this executor call self-heals once #84 lands. + Jindong(playTrigger, nodes.toList()) { + Sequence { + nodes.toList().forEach { node -> + when (node.type) { + NodeType.Tap -> Haptic(node.ms.ms, HapticIntensity.Custom(TAP_INTENSITY)) + NodeType.Pause -> Delay(node.ms.ms) + } + } + } + } +} + +/** A tap or pause node chip; taps render a round accent marker, pauses a small square. */ +@Composable +private fun NodeBuilderChip( + node: Node, + selected: Boolean, + onClick: () -> Unit, +) { + io.github.compose.jindong.sample.components.NodeChip( + label = if (node.type == NodeType.Tap) "Tap" else "Pause", + msText = "${node.ms}ms", + isTap = node.type == NodeType.Tap, + selected = selected, + onClick = onClick, + ) +} + +/** Dashed-style add button for appending a tap or pause node. */ +@Composable +private fun AddNodeButton( + label: String, + onClick: () -> Unit, +) { + val colors = JindongTheme.colors + Box( + modifier = Modifier.defaultMinSize(minHeight = Dimens.minTouch), + contentAlignment = Alignment.Center, + ) { + Box( + modifier = + Modifier + .clip(RoundedCornerShape(Dimens.radiusChip)) + .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusChip)) + .clickable(onClick = onClick) + .padding(horizontal = 11.dp, vertical = 8.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = label, + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), + color = colors.text2, + ) + } + } +} + +/** Editor for the selected node: label, value, delete affordance and a step-10 slider. */ +@Composable +private fun NodeEditorCard( + node: Node, + canDelete: Boolean, + onMsChange: (Int) -> Unit, + onDelete: () -> Unit, +) { + val colors = JindongTheme.colors + val isTap = node.type == NodeType.Tap + val range = if (isTap) 10f..120f else 20f..600f + val steps = ((range.endInclusive - range.start) / 10f).toInt() - 1 + + Column( + modifier = + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(Dimens.radiusCard)) + .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusCard)) + .padding(Dimens.cardPadding), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = if (isTap) "Tap duration" else "Pause length", + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), + color = colors.text, + ) + Row( + horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapMedium), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = "${node.ms} ms", + style = JindongTheme.typography.monoValue.copy(fontSize = androidx.compose.ui.unit.TextUnit.Unspecified), + color = colors.text, + ) + if (canDelete) { + Box( + modifier = Modifier.defaultMinSize(minWidth = Dimens.minTouch, minHeight = Dimens.minTouch).clickable(onClick = onDelete), + contentAlignment = Alignment.Center, + ) { + Text(text = "✕", style = JindongTheme.typography.bodySmall, color = colors.text3) + } + } + } + } + androidx.compose.material3.Slider( + value = node.ms.toFloat(), + onValueChange = { onMsChange(it.toInt()) }, + valueRange = range, + steps = steps, + colors = + androidx.compose.material3.SliderDefaults.colors( + thumbColor = colors.accent, + activeTrackColor = colors.accent, + inactiveTrackColor = colors.border2, + ), + ) + } +} + +/** Builds the pattern for the Timing timeline: one event per tap, pauses advance the cursor. */ +internal fun timingPattern(nodes: List): HapticPattern { + var cursor = 0L + val events = mutableListOf() + nodes.forEach { node -> + when (node.type) { + NodeType.Tap -> { + events.add( + ScheduledHapticEvent( + startTimeMs = cursor, + durationMs = node.ms.toLong(), + intensity = HapticIntensity.Custom(TAP_INTENSITY), + ), + ) + cursor += node.ms + } + + NodeType.Pause -> cursor += node.ms + } + } + return HapticPattern(events) +} From 1e0b58ded845e48e94cdbaecb89b843c18e38832 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 19:19:12 +0900 Subject: [PATCH 05/12] fix(sample): apply system bar safe-area insets in JindongScaffold --- .../sample/components/JindongScaffold.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt index 4ebc1ef..9c48c13 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt @@ -23,11 +23,18 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -70,7 +77,16 @@ fun JindongScaffold( content: @Composable ColumnScope.() -> Unit, ) { val colors = JindongTheme.colors - Column(modifier = modifier.fillMaxSize().background(colors.bg)) { + // Horizontal cutout insets (landscape notch / iOS side safe area) apply to the whole frame; the + // status-bar inset is consumed by the app bar and the navigation-bar inset by the scrolling body, + // so each edge is padded exactly once. + Column( + modifier = + modifier + .fillMaxSize() + .background(colors.bg) + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)), + ) { AppBar( screen = screen, isDark = isDark, @@ -82,6 +98,7 @@ fun JindongScaffold( Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) + .windowInsetsPadding(WindowInsets.navigationBars.only(WindowInsetsSides.Bottom)) .padding( start = Dimens.screenPadH, end = Dimens.screenPadH, @@ -102,12 +119,15 @@ private fun AppBar( ) { val colors = JindongTheme.colors val strokePx = with(LocalDensity.current) { Dimens.stroke.toPx() } + // Background fills behind the status bar; the status-bar inset then pushes the 56dp bar content + // below it, and the bottom border draws at the visible bottom of that content. Box( modifier = Modifier .fillMaxWidth() - .height(Dimens.appBarHeight) .background(colors.bg) + .windowInsetsPadding(WindowInsets.statusBars.only(WindowInsetsSides.Top)) + .height(Dimens.appBarHeight) .drawBehind { drawLine( color = colors.border, From ca4a45a21ec24d7639f501c2664ee1a8ce86d8d4 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 19:34:57 +0900 Subject: [PATCH 06/12] refactor(sample): replace emoji glyphs with self-defined vector icons --- .../jindong/sample/components/JindongIcons.kt | 160 ++++++++++++++++++ .../sample/components/JindongScaffold.kt | 16 +- .../jindong/sample/components/PlayButton.kt | 32 +++- .../jindong/sample/screens/HomeScreen.kt | 11 +- .../sample/screens/IntensityLabScreen.kt | 15 +- .../sample/screens/PresetGalleryScreen.kt | 23 +-- .../jindong/sample/screens/TimingScreen.kt | 12 +- 7 files changed, 238 insertions(+), 31 deletions(-) create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongIcons.kt diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongIcons.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongIcons.kt new file mode 100644 index 0000000..7fc0057 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongIcons.kt @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.components + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.StrokeJoin +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +/** + * Self-defined [ImageVector]s for the harness, replacing emoji/text glyphs that render as inconsistent + * color emoji on iOS. All icons live on a 24x24 viewport; filled icons (Play) tint via the [Icon] + * `tint`, stroked icons (chevrons, close, theme) use a 2px stroke also driven by `tint`. + * + * Built lazily and memoized so the path is allocated once per call site. + */ +object JindongIcons { + + /** Solid right-pointing play triangle. */ + val Play: ImageVector + get() = cache("play") { + filled { + moveTo(8f, 5f) + lineTo(19f, 12f) + lineTo(8f, 19f) + close() + } + } + + /** Crescent moon (light theme indicator: tap to go dark). */ + val Moon: ImageVector + get() = cache("moon") { + filled { + // Crescent = outer circle minus an offset circle, expressed as a single subpath. + moveTo(21f, 14.5f) + arcToRelative(8f, 8f, 0f, true, true, -9.5f, -11f) + arcToRelative(6.2f, 6.2f, 0f, false, false, 9.5f, 11f) + close() + } + } + + /** Sun with rays (dark theme indicator: tap to go light). */ + val Sun: ImageVector + get() = cache("sun") { + stroked { + // Core + moveTo(12f, 8.2f) + arcToRelative(3.8f, 3.8f, 0f, true, true, 0f, 7.6f) + arcToRelative(3.8f, 3.8f, 0f, true, true, 0f, -7.6f) + close() + // Rays + moveTo(12f, 2.5f) + lineTo(12f, 4.5f) + moveTo(12f, 19.5f) + lineTo(12f, 21.5f) + moveTo(2.5f, 12f) + lineTo(4.5f, 12f) + moveTo(19.5f, 12f) + lineTo(21.5f, 12f) + moveTo(5.2f, 5.2f) + lineTo(6.6f, 6.6f) + moveTo(17.4f, 17.4f) + lineTo(18.8f, 18.8f) + moveTo(18.8f, 5.2f) + lineTo(17.4f, 6.6f) + moveTo(6.6f, 17.4f) + lineTo(5.2f, 18.8f) + } + } + + /** Left chevron (back). */ + val ChevronLeft: ImageVector + get() = cache("chevron-left") { + stroked { + moveTo(15f, 5f) + lineTo(8f, 12f) + lineTo(15f, 19f) + } + } + + /** Right chevron (navigation affordance). */ + val ChevronRight: ImageVector + get() = cache("chevron-right") { + stroked { + moveTo(9f, 5f) + lineTo(16f, 12f) + lineTo(9f, 19f) + } + } + + /** Down caret (accordion expand indicator). */ + val CaretDown: ImageVector + get() = cache("caret-down") { + stroked { + moveTo(5f, 9f) + lineTo(12f, 16f) + lineTo(19f, 9f) + } + } + + /** Close / delete (X). */ + val Close: ImageVector + get() = cache("close") { + stroked { + moveTo(6f, 6f) + lineTo(18f, 18f) + moveTo(18f, 6f) + lineTo(6f, 18f) + } + } +} + +private val iconCache = HashMap() + +private fun cache(name: String, build: ImageVector.Builder.() -> Unit): ImageVector = iconCache.getOrPut(name) { + ImageVector.Builder( + name = name, + defaultWidth = 24.dp, + defaultHeight = 24.dp, + viewportWidth = 24f, + viewportHeight = 24f, + ).apply(build).build() +} + +/** Adds a filled path tinted by the [Icon] color (fillAlpha 1). */ +private fun ImageVector.Builder.filled(pathBuilder: androidx.compose.ui.graphics.vector.PathBuilder.() -> Unit) { + path( + fill = SolidColor(Color.Black), + stroke = null, + pathBuilder = pathBuilder, + ) +} + +/** Adds a 2px stroked path tinted by the [Icon] color (no fill). */ +private fun ImageVector.Builder.stroked(pathBuilder: androidx.compose.ui.graphics.vector.PathBuilder.() -> Unit) { + path( + fill = null, + stroke = SolidColor(Color.Black), + strokeLineWidth = 2f, + strokeLineCap = StrokeCap.Round, + strokeLineJoin = StrokeJoin.Round, + pathBuilder = pathBuilder, + ) +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt index 9c48c13..5d26bc7 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt @@ -38,6 +38,7 @@ import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -50,7 +51,6 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import io.github.compose.jindong.sample.nav.Screen import io.github.compose.jindong.sample.theme.Dimens import io.github.compose.jindong.sample.theme.JindongTheme @@ -149,7 +149,12 @@ private fun AppBar( .semantics { contentDescription = "Back" }, contentAlignment = Alignment.Center, ) { - Text(text = "‹", fontSize = 20.sp, color = colors.text2) + Icon( + imageVector = JindongIcons.ChevronLeft, + contentDescription = "Back", + tint = colors.text2, + modifier = Modifier.size(22.dp), + ) } } @@ -203,7 +208,12 @@ private fun ThemeToggle( .border(Dimens.stroke, colors.border, RoundedCornerShape(Dimens.radiusIcon)), contentAlignment = Alignment.Center, ) { - Text(text = if (isDark) "☀" else "☾", fontSize = 13.sp, color = colors.text2) + Icon( + imageVector = if (isDark) JindongIcons.Sun else JindongIcons.Moon, + contentDescription = null, + tint = colors.text2, + modifier = Modifier.size(15.dp), + ) } } } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt index b54635f..1622f06 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/PlayButton.kt @@ -17,11 +17,15 @@ package io.github.compose.jindong.sample.components import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -32,14 +36,15 @@ import io.github.compose.jindong.sample.theme.Dimens import io.github.compose.jindong.sample.theme.JindongTheme /** - * Full-width primary action button. Inverted ink/white surface ([JindongColors.btnBg] / - * [JindongColors.btnText]) — not accent — per the handoff. Wrapped to a >= 48dp hit area. + * Full-width primary action button: a [JindongIcons.Play] glyph plus [text] label. Inverted ink/white + * surface ([JindongColors.btnBg] / [JindongColors.btnText]) — not accent — per the handoff. Wrapped + * to a >= 48dp hit area. */ @Composable fun PlayButton( onClick: () -> Unit, modifier: Modifier = Modifier, - text: String = "▶ Play", + text: String = "Play", ) { Box( modifier = @@ -52,10 +57,21 @@ fun PlayButton( .padding(14.dp), contentAlignment = Alignment.Center, ) { - Text( - text = text, - style = JindongTheme.typography.cardTitle, - color = JindongTheme.colors.btnText, - ) + Row( + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = JindongIcons.Play, + contentDescription = null, + tint = JindongTheme.colors.btnText, + modifier = Modifier.size(15.dp), + ) + Text( + text = text, + style = JindongTheme.typography.cardTitle, + color = JindongTheme.colors.btnText, + ) + } } } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt index a49ff4f..893abba 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/HomeScreen.kt @@ -24,8 +24,10 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -39,10 +41,10 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import io.github.compose.jindong.HapticPlatform import io.github.compose.jindong.rememberHapticCapabilities import io.github.compose.jindong.sample.components.CapabilityBadge +import io.github.compose.jindong.sample.components.JindongIcons import io.github.compose.jindong.sample.components.MonoLabel import io.github.compose.jindong.sample.components.ScreenDescription import io.github.compose.jindong.sample.components.SectionCard @@ -209,7 +211,12 @@ private fun ModuleRow( ) } } - Text(text = "›", fontSize = 16.sp, color = colors.border2) + Icon( + imageVector = JindongIcons.ChevronRight, + contentDescription = null, + tint = colors.border2, + modifier = Modifier.size(16.dp), + ) } } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt index ed7c9e1..e114631 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Slider import androidx.compose.material3.SliderDefaults import androidx.compose.material3.Text @@ -56,6 +57,7 @@ import io.github.compose.jindong.dsl.Delay import io.github.compose.jindong.dsl.Haptic import io.github.compose.jindong.dsl.Sequence import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.JindongIcons import io.github.compose.jindong.sample.components.PlayButton import io.github.compose.jindong.sample.components.ScreenDescription import io.github.compose.jindong.sample.components.TimelineMapper @@ -116,7 +118,7 @@ fun IntensityLabScreen(modifier: Modifier = Modifier) { VGap(16.dp) - PlayButton(onClick = { playAll++ }, text = "▶ Play all (ascending)") + PlayButton(onClick = { playAll++ }, text = "Play all (ascending)") VGap(18.dp) @@ -266,7 +268,7 @@ private fun CustomCard( } } -/** Small bordered "▶" affordance used on the rows and the custom card (>= 48dp hit area). */ +/** Small bordered play affordance used on the rows and the custom card (>= 48dp hit area). */ @Composable private fun PlayChip(onClick: () -> Unit) { val colors = JindongTheme.colors @@ -283,10 +285,11 @@ private fun PlayChip(onClick: () -> Unit) { .padding(horizontal = 14.dp, vertical = 7.dp), contentAlignment = Alignment.Center, ) { - Text( - text = "▶", - style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), - color = colors.text2, + Icon( + imageVector = JindongIcons.Play, + contentDescription = "Play", + tint = colors.text2, + modifier = Modifier.size(13.dp), ) } } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt index 17be064..0028d9c 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt @@ -29,6 +29,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -51,6 +52,7 @@ import io.github.compose.jindong.dsl.Delay import io.github.compose.jindong.dsl.Haptic import io.github.compose.jindong.dsl.Sequence import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.JindongIcons import io.github.compose.jindong.sample.components.ScreenDescription import io.github.compose.jindong.sample.components.TimelineMapper import io.github.compose.jindong.sample.components.VGap @@ -150,11 +152,11 @@ private fun PresetCard( ) } PresetPlayChip(onClick = onPlay) - Text( - text = "⌄", - style = JindongTheme.typography.bodySmall, - color = colors.text3, - modifier = Modifier.rotate(caretRotation), + Icon( + imageVector = JindongIcons.CaretDown, + contentDescription = if (expanded) "Collapse" else "Expand", + tint = colors.text3, + modifier = Modifier.size(16.dp).rotate(caretRotation), ) } @@ -186,7 +188,7 @@ private fun PresetTimeline( ) } -/** Small bordered "▶" affordance on each preset header (>= 48dp hit area). */ +/** Small bordered play affordance on each preset header (>= 48dp hit area). */ @Composable private fun PresetPlayChip(onClick: () -> Unit) { val colors = JindongTheme.colors @@ -203,10 +205,11 @@ private fun PresetPlayChip(onClick: () -> Unit) { .padding(horizontal = 13.dp, vertical = 7.dp), contentAlignment = Alignment.Center, ) { - Text( - text = "▶", - style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), - color = colors.text2, + Icon( + imageVector = JindongIcons.Play, + contentDescription = "Play", + tint = colors.text2, + modifier = Modifier.size(13.dp), ) } } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt index a16b0d8..bd977c7 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt @@ -26,7 +26,9 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -51,6 +53,7 @@ import io.github.compose.jindong.dsl.Delay import io.github.compose.jindong.dsl.Haptic import io.github.compose.jindong.dsl.Sequence import io.github.compose.jindong.sample.components.HapticTimeline +import io.github.compose.jindong.sample.components.JindongIcons import io.github.compose.jindong.sample.components.PlayButton import io.github.compose.jindong.sample.components.ScreenDescription import io.github.compose.jindong.sample.components.TimelineMapper @@ -145,7 +148,7 @@ fun TimingScreen(modifier: Modifier = Modifier) { VGap(18.dp) - PlayButton(onClick = { playTrigger++ }, text = "▶ Play sequence") + PlayButton(onClick = { playTrigger++ }, text = "Play sequence") } // VIBRATION PATH (stale pre-#84; see SingleHapticScreen for the rationale). The timeline above is @@ -252,7 +255,12 @@ private fun NodeEditorCard( modifier = Modifier.defaultMinSize(minWidth = Dimens.minTouch, minHeight = Dimens.minTouch).clickable(onClick = onDelete), contentAlignment = Alignment.Center, ) { - Text(text = "✕", style = JindongTheme.typography.bodySmall, color = colors.text3) + Icon( + imageVector = JindongIcons.Close, + contentDescription = "Delete node", + tint = colors.text3, + modifier = Modifier.size(14.dp), + ) } } } From 2e0f736518f8f22a37bd572642f80977579db9fd Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 20:10:44 +0900 Subject: [PATCH 07/12] fix(core): default hasAmplitudeControl and gate it on iOS support --- jindong-core/api/jindong-core.api | 6 +++++- jindong-core/api/jindong-core.klib.api | 4 ++-- .../compose/jindong/core/executor/HapticExecutor.kt | 10 +++++++--- .../jindong/core/executor/HapticExecutor.ios.kt | 7 ++++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/jindong-core/api/jindong-core.api b/jindong-core/api/jindong-core.api index d8aeedc..86c4681 100644 --- a/jindong-core/api/jindong-core.api +++ b/jindong-core/api/jindong-core.api @@ -88,11 +88,15 @@ public final class io/github/compose/jindong/core/element/VibrationElement : io/ public abstract interface class io/github/compose/jindong/core/executor/HapticExecutor { public abstract fun execute (Lio/github/compose/jindong/core/model/HapticPattern;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun executeAsync (Lio/github/compose/jindong/core/model/HapticPattern;)Lio/github/compose/jindong/core/executor/HapticHandle; - public abstract fun getHasAmplitudeControl ()Z + public fun getHasAmplitudeControl ()Z public abstract fun isSupported ()Z public abstract fun release ()V } +public final class io/github/compose/jindong/core/executor/HapticExecutor$DefaultImpls { + public static fun getHasAmplitudeControl (Lio/github/compose/jindong/core/executor/HapticExecutor;)Z +} + public final class io/github/compose/jindong/core/executor/HapticExecutor_androidKt { public static final fun createHapticExecutor (Ljava/lang/Object;)Lio/github/compose/jindong/core/executor/HapticExecutor; public static synthetic fun createHapticExecutor$default (Ljava/lang/Object;ILjava/lang/Object;)Lio/github/compose/jindong/core/executor/HapticExecutor; diff --git a/jindong-core/api/jindong-core.klib.api b/jindong-core/api/jindong-core.klib.api index 3fa1d4c..5cc58cf 100644 --- a/jindong-core/api/jindong-core.klib.api +++ b/jindong-core/api/jindong-core.klib.api @@ -19,10 +19,10 @@ abstract interface io.github.compose.jindong.core.element/HapticElement { // io. } abstract interface io.github.compose.jindong.core.executor/HapticExecutor { // io.github.compose.jindong.core.executor/HapticExecutor|null[0] - abstract val hasAmplitudeControl // io.github.compose.jindong.core.executor/HapticExecutor.hasAmplitudeControl|{}hasAmplitudeControl[0] - abstract fun (): kotlin/Boolean // io.github.compose.jindong.core.executor/HapticExecutor.hasAmplitudeControl.|(){}[0] abstract val isSupported // io.github.compose.jindong.core.executor/HapticExecutor.isSupported|{}isSupported[0] abstract fun (): kotlin/Boolean // io.github.compose.jindong.core.executor/HapticExecutor.isSupported.|(){}[0] + open val hasAmplitudeControl // io.github.compose.jindong.core.executor/HapticExecutor.hasAmplitudeControl|{}hasAmplitudeControl[0] + open fun (): kotlin/Boolean // io.github.compose.jindong.core.executor/HapticExecutor.hasAmplitudeControl.|(){}[0] abstract fun executeAsync(io.github.compose.jindong.core.model/HapticPattern): io.github.compose.jindong.core.executor/HapticHandle // io.github.compose.jindong.core.executor/HapticExecutor.executeAsync|executeAsync(io.github.compose.jindong.core.model.HapticPattern){}[0] abstract fun release() // io.github.compose.jindong.core.executor/HapticExecutor.release|release(){}[0] diff --git a/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt b/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt index 7675043..849ec0d 100644 --- a/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt +++ b/jindong-core/src/commonMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.kt @@ -40,11 +40,15 @@ interface HapticExecutor { * - **Android**: reflects `Vibrator.hasAmplitudeControl()`. ERM motors round every non-zero * amplitude up to 100%, so they report `false` and effects like fall ramps are lost; LRA * motors report `true`. - * - **iOS**: Core Haptics always renders continuous intensity, so this is always `true`. - * The "discrete vs. continuous" distinction is platform-specific; read the platform - * alongside this flag if the label matters (see the Compose `HapticCapabilities`). + * - **iOS**: Core Haptics renders continuous intensity whenever haptics are supported, so this + * tracks [isSupported]. The "discrete vs. continuous" distinction is platform-specific; read + * the platform alongside this flag if the label matters (see the Compose `HapticCapabilities`). + * + * Defaults to `false` so existing third-party [HapticExecutor] implementations remain + * source- and binary-compatible without having to declare it. */ val hasAmplitudeControl: Boolean + get() = false /** * Executes haptic pattern. Cancellable via coroutine cancellation. diff --git a/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt b/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt index 29a23c5..30ba7b1 100644 --- a/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt +++ b/jindong-core/src/iosMain/kotlin/io/github/compose/jindong/core/executor/HapticExecutor.ios.kt @@ -55,9 +55,10 @@ internal class DefaultIosHapticExecutor : HapticExecutor { CHHapticEngine.capabilitiesForHardware().supportsHaptics() } - // Core Haptics applies intensity as a continuous float on every event, so amplitude is - // always full-fidelity; there is no discrete/ERM-style gating on iOS. - override val hasAmplitudeControl: Boolean = true + // Core Haptics renders intensity as a continuous float on supported devices; gate on support so we + // never report amplitude control on a device that has no haptics at all (e.g. the simulator). + override val hasAmplitudeControl: Boolean + get() = isSupported override suspend fun execute(pattern: HapticPattern) { if (!isSupported || pattern.events.isEmpty()) return From 0cad8ed44abb942145fd91f1b7ec7f2094fda1d4 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 20:10:44 +0900 Subject: [PATCH 08/12] fix(sample): key Single Haptic playback on the play trigger only --- .../compose/jindong/sample/screens/SingleHapticScreen.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt index 57d2ad5..0658e6f 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/SingleHapticScreen.kt @@ -179,11 +179,10 @@ fun SingleHapticScreen(modifier: Modifier = Modifier) { PlayButton(onClick = { playTrigger++ }) } - // VIBRATION PATH (buggy until PR #84): every relevant state value is a key so the executor re-runs - // on any change; the play-trigger key covers the explicit Play tap. Pre-#84 rememberHapticPattern - // caches the first compile and replays stale params here — the timeline above stays correct, and - // the moment #84 merges this path self-heals with zero changes to this screen. - Jindong(playTrigger, sgDur, sgChip, sgInt) { + // VIBRATION PATH: key only on playTrigger so this stays an explicit-play screen (Reactive is the + // auto-firing one). The block reads live sgDur/resolvedIntensity, so Play always uses the current + // values. The timeline above is driven separately from state and stays live regardless of #84. + Jindong(playTrigger) { Haptic(sgDur.ms, resolvedIntensity) } } From a5938f5fc3ab897fc2bc82e26ba67289e3c70b67 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 20:10:55 +0900 Subject: [PATCH 09/12] fix(sample): align preview timelines with replayed patterns and gate play --- .../sample/screens/IntensityLabScreen.kt | 44 +++++++++---------- .../jindong/sample/screens/RepeatScreen.kt | 7 ++- .../sample/screens/RepeatWithIndexScreen.kt | 8 +++- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt index e114631..19fd5f2 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/IntensityLabScreen.kt @@ -143,20 +143,21 @@ fun IntensityLabScreen(modifier: Modifier = Modifier) { ) } - // VIBRATION PATH (stale pre-#84; see SingleHapticScreen for the rationale). The timeline above is - // always live; these executor calls self-heal once #84 lands. + // VIBRATION PATH: key only on the explicit play triggers so moving a control never auto-fires + // (Reactive is the auto-firing screen). Each block reads live state when its trigger bumps. Jindong(playAll) { Sequence { - ascendingPresets.forEach { intensity -> + // Match the rendered staircase exactly: 100ms pulses with a 20ms lead-in then 80ms gaps. + ascendingPresets.forEachIndexed { i, intensity -> + if (i == 0) Delay(20.ms) else Delay(80.ms) Haptic(100.ms, intensity) - Delay(120.ms) } } } - Jindong(rowTrigger, rowIntensity) { + Jindong(rowTrigger) { Haptic(100.ms, rowIntensity) } - Jindong(customTrigger, ilCustom) { + Jindong(customTrigger) { Haptic(100.ms, HapticIntensity.Custom(ilCustom)) } } @@ -272,26 +273,23 @@ private fun CustomCard( @Composable private fun PlayChip(onClick: () -> Unit) { val colors = JindongTheme.colors + // min-touch + clickable on the same node as the bordered pill so the full hit area is tappable. Box( - modifier = Modifier.defaultMinSize(minHeight = Dimens.minTouch), + modifier = + Modifier + .defaultMinSize(minWidth = Dimens.minTouch, minHeight = Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusSmall)) + .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusSmall)) + .clickable(onClick = onClick) + .padding(horizontal = 14.dp, vertical = 7.dp), contentAlignment = Alignment.Center, ) { - Box( - modifier = - Modifier - .clip(RoundedCornerShape(Dimens.radiusSmall)) - .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusSmall)) - .clickable(onClick = onClick) - .padding(horizontal = 14.dp, vertical = 7.dp), - contentAlignment = Alignment.Center, - ) { - Icon( - imageVector = JindongIcons.Play, - contentDescription = "Play", - tint = colors.text2, - modifier = Modifier.size(13.dp), - ) - } + Icon( + imageVector = JindongIcons.Play, + contentDescription = "Play", + tint = colors.text2, + modifier = Modifier.size(13.dp), + ) } } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt index db18d14..9bf163d 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatScreen.kt @@ -164,12 +164,15 @@ private fun UnitPreviewCard() { } } -/** Builds the Repeat timeline pattern: count bars, dur 60, intensity 0.7, start i*150+10. */ +/** + * Builds the Repeat timeline pattern: count bars, dur 60, intensity 0.7, start i*150. Start times + * mirror the replayed `Repeat { Haptic(60); Delay(90) }` (first pulse at 0ms) so the preview matches. + */ internal fun repeatPattern(count: Int): HapticPattern { val events = (0 until count).map { i -> ScheduledHapticEvent( - startTimeMs = (i * 150L + 10L), + startTimeMs = i * 150L, durationMs = 60L, intensity = HapticIntensity.Custom(UNIT_INTENSITY), ) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt index 4bde557..3c0ba33 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/RepeatWithIndexScreen.kt @@ -208,7 +208,11 @@ private fun IntendedPreviewCard(intensities: List) { } } -/** Builds the RepeatWithIndex timeline pattern: count bars, dur 70, start i*140+10, ramp intensity. */ +/** + * Builds the RepeatWithIndex timeline pattern: count bars, dur 70, start i*140, ramp intensity. + * Start times mirror the replayed `RepeatWithIndex { Haptic(70); Delay(70) }` (first pulse at 0ms) + * so the compiled preview lines up with what the screen actually plays. + */ internal fun repeatIndexPattern( count: Int, dir: RampDirection, @@ -216,7 +220,7 @@ internal fun repeatIndexPattern( val events = (0 until count).map { i -> ScheduledHapticEvent( - startTimeMs = (i * 140L + 10L), + startTimeMs = i * 140L, durationMs = 70L, intensity = HapticIntensity.Custom(ramp(i, count, dir)), ) From f22540b663bf6b22cd17d752420d621630402377 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 20:10:55 +0900 Subject: [PATCH 10/12] fix(sample): make 48dp touch targets tappable and add button roles --- .../compose/jindong/sample/components/Chip.kt | 16 +++++++--- .../sample/components/JindongScaffold.kt | 7 +++-- .../sample/components/SegmentedToggle.kt | 4 ++- .../sample/screens/PresetGalleryScreen.kt | 31 +++++++++---------- .../jindong/sample/screens/TimingScreen.kt | 29 ++++++++--------- 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt index 7cf8e7c..bb31e50 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/Chip.kt @@ -56,8 +56,14 @@ fun PresetChip( val labelColor = if (selected) colors.accent else colors.text2 val bgColor = if (selected) colors.accentBg else Color.Transparent + // Click + 48dp min-touch live on the same (outer) node so the whole hit area is tappable; the + // inner content keeps the compact chip visuals (8/11 padding). Box( - modifier = modifier.defaultMinSize(minHeight = Dimens.minTouch), + modifier = + modifier + .defaultMinSize(minHeight = Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusChip)) + .clickable(onClick = onClick), contentAlignment = Alignment.Center, ) { Column( @@ -66,7 +72,6 @@ fun PresetChip( .clip(RoundedCornerShape(Dimens.radiusChip)) .background(bgColor) .border(Dimens.stroke, borderColor, RoundedCornerShape(Dimens.radiusChip)) - .clickable(onClick = onClick) .padding(horizontal = 11.dp, vertical = 8.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { @@ -103,7 +108,11 @@ fun NodeChip( val markerColor = if (isTap) colors.accent else colors.border2 Box( - modifier = modifier.defaultMinSize(minHeight = Dimens.minTouch), + modifier = + modifier + .defaultMinSize(minHeight = Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusChip)) + .clickable(onClick = onClick), contentAlignment = Alignment.Center, ) { Row( @@ -112,7 +121,6 @@ fun NodeChip( .clip(RoundedCornerShape(Dimens.radiusChip)) .background(bgColor) .border(Dimens.stroke, borderColor, RoundedCornerShape(Dimens.radiusChip)) - .clickable(onClick = onClick) .padding(horizontal = 11.dp, vertical = 8.dp), horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), verticalAlignment = Alignment.CenterVertically, diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt index 5d26bc7..69c717d 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/JindongScaffold.kt @@ -47,6 +47,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight @@ -145,13 +146,13 @@ private fun AppBar( .align(Alignment.CenterStart) .size(Dimens.minTouch) .clip(RoundedCornerShape(Dimens.radiusSmall)) - .clickable(onClick = onBack) + .clickable(onClick = onBack, role = Role.Button) .semantics { contentDescription = "Back" }, contentAlignment = Alignment.Center, ) { Icon( imageVector = JindongIcons.ChevronLeft, - contentDescription = "Back", + contentDescription = null, tint = colors.text2, modifier = Modifier.size(22.dp), ) @@ -196,7 +197,7 @@ private fun ThemeToggle( Modifier .size(Dimens.minTouch) .clip(RoundedCornerShape(Dimens.radiusSmall)) - .clickable(onClick = onToggleTheme) + .clickable(onClick = onToggleTheme, role = Role.Button) .semantics { contentDescription = if (isDark) "Switch to light theme" else "Switch to dark theme" }, contentAlignment = Alignment.Center, ) { diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt index 88e9877..246a209 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/SegmentedToggle.kt @@ -50,7 +50,7 @@ fun SegmentedToggle( ) { val colors = JindongTheme.colors Row( - modifier = modifier.fillMaxWidth().defaultMinSize(minHeight = Dimens.minTouch), + modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(Dimens.rowGapSmall), verticalAlignment = Alignment.CenterVertically, ) { @@ -59,10 +59,12 @@ fun SegmentedToggle( val borderColor = if (selected) colors.accent else colors.border2 val contentColor = if (selected) colors.accent else colors.text2 val bgColor = if (selected) colors.accentBg else Color.Transparent + // 48dp min-touch on the same node as clickable so each segment is independently tappable. Box( modifier = Modifier .weight(1f) + .defaultMinSize(minHeight = Dimens.minTouch) .clip(RoundedCornerShape(Dimens.radiusChip)) .background(bgColor) .border(Dimens.stroke, borderColor, RoundedCornerShape(Dimens.radiusChip)) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt index 0028d9c..11c0faa 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/PresetGalleryScreen.kt @@ -192,25 +192,22 @@ private fun PresetTimeline( @Composable private fun PresetPlayChip(onClick: () -> Unit) { val colors = JindongTheme.colors + // min-touch + clickable on the same node as the bordered pill so the full hit area is tappable. Box( - modifier = Modifier.defaultMinSize(minHeight = Dimens.minTouch), + modifier = + Modifier + .defaultMinSize(minWidth = Dimens.minTouch, minHeight = Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusSmall)) + .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusSmall)) + .clickable(onClick = onClick) + .padding(horizontal = 13.dp, vertical = 7.dp), contentAlignment = Alignment.Center, ) { - Box( - modifier = - Modifier - .clip(RoundedCornerShape(Dimens.radiusSmall)) - .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusSmall)) - .clickable(onClick = onClick) - .padding(horizontal = 13.dp, vertical = 7.dp), - contentAlignment = Alignment.Center, - ) { - Icon( - imageVector = JindongIcons.Play, - contentDescription = "Play", - tint = colors.text2, - modifier = Modifier.size(13.dp), - ) - } + Icon( + imageVector = JindongIcons.Play, + contentDescription = "Play", + tint = colors.text2, + modifier = Modifier.size(13.dp), + ) } } diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt index bd977c7..d76ceb1 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/TimingScreen.kt @@ -188,25 +188,22 @@ private fun AddNodeButton( onClick: () -> Unit, ) { val colors = JindongTheme.colors + // min-touch + clickable on the same node as the bordered pill so the full hit area is tappable. Box( - modifier = Modifier.defaultMinSize(minHeight = Dimens.minTouch), + modifier = + Modifier + .defaultMinSize(minHeight = Dimens.minTouch) + .clip(RoundedCornerShape(Dimens.radiusChip)) + .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusChip)) + .clickable(onClick = onClick) + .padding(horizontal = 11.dp, vertical = 8.dp), contentAlignment = Alignment.Center, ) { - Box( - modifier = - Modifier - .clip(RoundedCornerShape(Dimens.radiusChip)) - .border(Dimens.stroke, colors.border2, RoundedCornerShape(Dimens.radiusChip)) - .clickable(onClick = onClick) - .padding(horizontal = 11.dp, vertical = 8.dp), - contentAlignment = Alignment.Center, - ) { - Text( - text = label, - style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), - color = colors.text2, - ) - } + Text( + text = label, + style = JindongTheme.typography.bodySmall.copy(fontWeight = FontWeight.SemiBold), + color = colors.text2, + ) } } From 69d1ab454c5351a3b3c493bdac6e1ad1f0649e97 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 20:11:05 +0900 Subject: [PATCH 11/12] fix(sample): return to Home on Android system back via PlatformBackHandler --- sample/shared/build.gradle.kts | 4 +++ .../sample/nav/PlatformBackHandler.android.kt | 27 +++++++++++++++++ .../compose/jindong/sample/nav/AppRoot.kt | 11 +++---- .../jindong/sample/nav/PlatformBackHandler.kt | 29 +++++++++++++++++++ .../sample/nav/PlatformBackHandler.ios.kt | 25 ++++++++++++++++ 5 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 sample/shared/src/androidMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.android.kt create mode 100644 sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.kt create mode 100644 sample/shared/src/iosMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.ios.kt diff --git a/sample/shared/build.gradle.kts b/sample/shared/build.gradle.kts index b7ae48a..2d887ea 100644 --- a/sample/shared/build.gradle.kts +++ b/sample/shared/build.gradle.kts @@ -58,6 +58,10 @@ kotlin { implementation(compose.ui) implementation(compose.components.resources) } + androidMain.dependencies { + // System back handling on Android (PlatformBackHandler actual). + implementation(libs.androidx.activity.compose) + } } } diff --git a/sample/shared/src/androidMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.android.kt b/sample/shared/src/androidMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.android.kt new file mode 100644 index 0000000..41b3283 --- /dev/null +++ b/sample/shared/src/androidMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.android.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.nav + +import androidx.activity.compose.BackHandler +import androidx.compose.runtime.Composable + +@Composable +actual fun PlatformBackHandler( + enabled: Boolean, + onBack: () -> Unit, +) { + BackHandler(enabled = enabled, onBack = onBack) +} diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt index 8153034..e579703 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/AppRoot.kt @@ -38,11 +38,10 @@ import io.github.compose.jindong.sample.theme.JindongTheme * bar back chevron returns to Home. The theme follows the system preference unless [darkOverride] is * set by the app-bar toggle. * - * Back handling: the app-bar back chevron (in [JindongScaffold]) is the sole back affordance. In - * Compose Multiplatform 1.10 the only commonMain back API is the deprecated, `@ExperimentalComposeUiApi` - * `androidx.compose.ui.backhandler.BackHandler`, which also requires a navigation-event dispatcher - * owner that `ComposeUIViewController` does not provide on iOS (it would `error(...)` at runtime). - * Relying on the chevron keeps both targets safe without pulling in the new navigation-event artifact. + * Back handling: on a module screen the Android system back gesture/button returns to Home via + * [PlatformBackHandler] (a no-op on iOS, where the app-bar chevron is the affordance). This avoids + * the deprecated `androidx.compose.ui.backhandler.BackHandler`, which on iOS requires a + * navigation-event dispatcher owner that `ComposeUIViewController` does not provide. */ @Composable fun AppRoot() { @@ -52,6 +51,8 @@ fun AppRoot() { var darkOverride by rememberSaveable { mutableStateOf(null) } val dark = darkOverride ?: isSystemInDarkTheme() + PlatformBackHandler(enabled = current != Screen.Home) { current = Screen.Home } + JindongTheme(darkTheme = dark) { JindongScaffold( screen = current, diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.kt new file mode 100644 index 0000000..912e869 --- /dev/null +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.nav + +import androidx.compose.runtime.Composable + +/** + * Intercepts the platform back action while [enabled]. On Android this is the system back + * gesture/button (via `androidx.activity.compose.BackHandler`); on iOS there is no system back, so + * the actual is a no-op and the app-bar chevron remains the affordance. + */ +@Composable +expect fun PlatformBackHandler( + enabled: Boolean, + onBack: () -> Unit, +) diff --git a/sample/shared/src/iosMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.ios.kt b/sample/shared/src/iosMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.ios.kt new file mode 100644 index 0000000..9977ec7 --- /dev/null +++ b/sample/shared/src/iosMain/kotlin/io/github/compose/jindong/sample/nav/PlatformBackHandler.ios.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2026 compose-jindong + * + * 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 io.github.compose.jindong.sample.nav + +import androidx.compose.runtime.Composable + +// iOS has no system back gesture in this single-view host; the app-bar chevron is the back affordance. +@Composable +actual fun PlatformBackHandler( + enabled: Boolean, + onBack: () -> Unit, +) = Unit From 6e858ded002ab41c7bcc279e72be79d03430b5f3 Mon Sep 17 00:00:00 2001 From: HyunWoo Lee Date: Sun, 28 Jun 2026 20:11:05 +0900 Subject: [PATCH 12/12] fix(sample): round formatFixed zero-decimals and derive Reactive Actual from bars --- .../jindong/sample/components/ScreenPieces.kt | 3 +- .../jindong/sample/screens/ReactiveScreen.kt | 43 ++++++++++++++----- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt index fa71984..bcda8ea 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/components/ScreenPieces.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.Dp import io.github.compose.jindong.sample.theme.Dimens import io.github.compose.jindong.sample.theme.JindongTheme +import kotlin.math.roundToLong /** * Intro / description paragraph at the top of every module screen. 13sp, [text2], line-height 1.55. @@ -86,7 +87,7 @@ fun formatFixed( value: Float, decimals: Int, ): String { - if (decimals <= 0) return value.toLong().toString() + if (decimals <= 0) return value.roundToLong().toString() var scale = 1 repeat(decimals) { scale *= 10 } val scaled = (value * scale + if (value >= 0f) 0.5f else -0.5f).toLong() diff --git a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt index a6a3e3f..a9521ea 100644 --- a/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt +++ b/sample/shared/src/commonMain/kotlin/io/github/compose/jindong/sample/screens/ReactiveScreen.kt @@ -61,6 +61,7 @@ import io.github.compose.jindong.sample.components.formatFixed import io.github.compose.jindong.sample.components.timelineAccentColor import io.github.compose.jindong.sample.theme.Dimens import io.github.compose.jindong.sample.theme.JindongTheme +import kotlin.math.roundToLong /** * Reactive / State-driven (handoff 07): the one differentiator — moving a control re-fires the @@ -114,7 +115,11 @@ private fun ThresholdCard() { val accent = timelineAccentColor() val pattern = remember(intensity) { singleBar(start = 20L, dur = 120L, intensity = intensity) } val bars = TimelineMapper.toBars(pattern, 600L) { accent } - val expectedActual = if (strong) "tall bar (0.90)" else "short bar (0.30)" + // EXPECTED comes from the control logic; ACTUAL is read back from the rendered bar, so the two + // diverge if singleBar / TimelineMapper ever stops tracking state (a real regression oracle). + val expected = if (strong) "tall bar (0.90)" else "short bar (0.30)" + val actualHeight = bars.firstOrNull()?.let { barIntensity(it) } ?: 0f + val actual = (if (actualHeight >= 0.5f) "tall bar (" else "short bar (") + formatFixed(actualHeight, 2) + ")" CaseCard( title = "Threshold branch", @@ -124,8 +129,8 @@ private fun ThresholdCard() { bars = bars, topRight = if (strong) "STRONG" else "soft", maxLabel = "600", - expected = expectedActual, - actual = expectedActual, + expected = expected, + actual = actual, controls = { LabeledSlider( label = "Value", @@ -152,7 +157,9 @@ private fun CountCard() { val window = 700L // (60 + 80) * 5 val pattern = remember(rxCount) { reactiveCountPattern(rxCount) } val bars = TimelineMapper.toBars(pattern, window) { accent } - val expectedActual = "$rxCount bars" + // ACTUAL counts the rendered bars, not the slider value, so a mapping regression would show up. + val expected = "$rxCount bars" + val actual = "${bars.size} bars" CaseCard( title = "Count reaction", @@ -162,8 +169,8 @@ private fun CountCard() { bars = bars, topRight = "× $rxCount", maxLabel = window.toString(), - expected = expectedActual, - actual = expectedActual, + expected = expected, + actual = actual, controls = { LabeledSlider( label = "Repeat count", @@ -191,9 +198,16 @@ private fun MultiInputCard() { var rxDur by remember { mutableIntStateOf(160) } var rxInt by remember { mutableFloatStateOf(0.6f) } val accent = timelineAccentColor() + val window = 600L val pattern = remember(rxDur, rxInt) { singleBar(start = 20L, dur = rxDur.toLong(), intensity = rxInt) } - val bars = TimelineMapper.toBars(pattern, 600L) { accent } - val expectedActual = "width ${rxDur}ms, height ${formatFixed(rxInt, 1)}" + val bars = TimelineMapper.toBars(pattern, window) { accent } + // ACTUAL is reconstructed from the rendered bar fractions (width*window, height/0.98), so it only + // matches EXPECTED while the bar genuinely tracks both faders. + val expected = "width ${rxDur}ms, height ${formatFixed(rxInt, 1)}" + val actual = + bars.firstOrNull()?.let { bar -> + "width ${(bar.widthFraction * window).roundToLong()}ms, height ${formatFixed(barIntensity(bar), 1)}" + } ?: "no bar" CaseCard( title = "Multiple inputs", @@ -202,9 +216,9 @@ private fun MultiInputCard() { flashKey = rxDur * 1000 + (rxInt * 100).toInt(), bars = bars, topRight = "${rxDur}ms · ${formatFixed(rxInt, 1)}", - maxLabel = "600", - expected = expectedActual, - actual = expectedActual, + maxLabel = window.toString(), + expected = expected, + actual = actual, controls = { LabeledSlider( label = "Duration", @@ -356,6 +370,13 @@ private inline fun androidx.compose.ui.text.AnnotatedString.Builder.withStyleSem ) { block() } } +/** + * Reconstructs an event intensity from a rendered [TimelineBar]. Inverse of `TimelineMapper`'s + * `heightFraction = max(0.06, intensity * 0.98)`; used by the Reactive cards so ACTUAL is read from + * the rendered bar rather than re-derived from the same state as EXPECTED. + */ +internal fun barIntensity(bar: io.github.compose.jindong.sample.components.TimelineBar): Float = (bar.heightFraction / 0.98f).coerceIn(0f, 1f) + /** A one-bar pattern at [start]/[dur]/[intensity] (Cards A and C). */ internal fun singleBar( start: Long,