├── .idea ├── .name ├── .gitignore ├── compiler.xml ├── misc.xml └── inspectionProfiles │ └── Project_Default.xml ├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── ic_chat_launcher_background.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── themes.xml │ │ │ │ └── splash.xml │ │ │ ├── font │ │ │ │ ├── karla_bold.ttf │ │ │ │ ├── karla_regular.ttf │ │ │ │ ├── montserrat_light.ttf │ │ │ │ ├── montserrat_medium.ttf │ │ │ │ ├── montserrat_regular.ttf │ │ │ │ └── montserrat_semibold.ttf │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_chat_launcher.png │ │ │ │ └── ic_chat_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_chat_launcher.png │ │ │ │ └── ic_chat_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_chat_launcher.png │ │ │ │ └── ic_chat_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_chat_launcher.png │ │ │ │ └── ic_chat_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_chat_launcher.png │ │ │ │ └── ic_chat_launcher_round.png │ │ │ ├── values-night │ │ │ │ ├── themes.xml │ │ │ │ └── splash.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_chat_launcher.xml │ │ │ │ └── ic_chat_launcher_round.xml │ │ │ ├── values-v23 │ │ │ │ └── splash.xml │ │ │ ├── drawable │ │ │ │ ├── ic_launcher_foreground.xml │ │ │ │ ├── ic_chat_launcher_foreground.xml │ │ │ │ └── ic_chat.xml │ │ │ └── raw │ │ │ │ └── chat_dark.json │ │ ├── ic_launcher-playstore.png │ │ ├── ic_chat_launcher-playstore.png │ │ ├── java │ │ │ └── me │ │ │ │ └── siddheshkothadi │ │ │ │ └── chat │ │ │ │ ├── ChatApplication.kt │ │ │ │ ├── domain │ │ │ │ ├── model │ │ │ │ │ ├── Message.kt │ │ │ │ │ ├── UserData.kt │ │ │ │ │ └── User.kt │ │ │ │ └── repository │ │ │ │ │ ├── DataStoreRepository.kt │ │ │ │ │ ├── FirebaseRepository.kt │ │ │ │ │ └── UserRepository.kt │ │ │ │ ├── ui │ │ │ │ ├── theme │ │ │ │ │ ├── Shape.kt │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── Theme.kt │ │ │ │ │ └── Type.kt │ │ │ │ ├── components │ │ │ │ │ ├── DayHeader.kt │ │ │ │ │ ├── Messages.kt │ │ │ │ │ ├── ChatCard.kt │ │ │ │ │ └── ChatBubble.kt │ │ │ │ ├── screens │ │ │ │ │ ├── ProfileScreen.kt │ │ │ │ │ ├── MyProfileScreen.kt │ │ │ │ │ ├── LoginScreen.kt │ │ │ │ │ ├── ChatListScreen.kt │ │ │ │ │ └── ChatScreen.kt │ │ │ │ └── viewmodel │ │ │ │ │ └── MainViewModel.kt │ │ │ │ ├── data │ │ │ │ ├── repository │ │ │ │ │ ├── DataStoreRepositoryImpl.kt │ │ │ │ │ ├── FirebaseRepositoryImpl.kt │ │ │ │ │ └── UserRepositoryImpl.kt │ │ │ │ └── UserDataSerializer.kt │ │ │ │ ├── utils │ │ │ │ ├── AESUtils.kt │ │ │ │ └── RSAUtils.kt │ │ │ │ ├── di │ │ │ │ └── AppModule.kt │ │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── me │ │ │ └── siddheshkothadi │ │ │ └── chat │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── me │ │ └── siddheshkothadi │ │ └── chat │ │ └── ExampleInstrumentedTest.kt ├── release │ └── output-metadata.json ├── proguard-rules.pro ├── google-services.json └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── README.md ├── .gitignore ├── gradle.properties ├── gradlew.bat └── gradlew /.idea/.name: -------------------------------------------------------------------------------- 1 | Chat -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Chat 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/font/karla_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/font/karla_bold.ttf -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/res/font/karla_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/font/karla_regular.ttf -------------------------------------------------------------------------------- /app/src/main/ic_chat_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/ic_chat_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/font/montserrat_light.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/font/montserrat_medium.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/font/montserrat_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/montserrat_semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/font/montserrat_semibold.ttf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_chat_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-hdpi/ic_chat_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_chat_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-mdpi/ic_chat_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_chat_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-xhdpi/ic_chat_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_chat_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-xxhdpi/ic_chat_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_chat_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_chat_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_chat_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-hdpi/ic_chat_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_chat_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-mdpi/ic_chat_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_chat_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-xhdpi/ic_chat_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_chat_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-xxhdpi/ic_chat_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_chat_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Based-Learning-IT/e2ee-chat/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_chat_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/ic_chat_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #EEEEEE 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FBFDFD 4 | #191C1D 5 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ChatApplication.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat 2 | 3 | import android.app.Application 4 | import dagger.hilt.android.HiltAndroidApp 5 | 6 | @HiltAndroidApp 7 | class ChatApplication: Application() {} -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Apr 01 12:06:05 IST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_chat_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_chat_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/domain/model/Message.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.domain.model 2 | 3 | data class Message( 4 | val from: String = "", 5 | val to: String = "", 6 | val timestamp: String = "", 7 | val date: String = "", 8 | val time: String = "", 9 | val content: String = "", 10 | val secretKey: String = "" 11 | ) 12 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/domain/model/UserData.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.domain.model 2 | 3 | import kotlinx.serialization.Serializable 4 | import me.siddheshkothadi.chat.domain.model.User 5 | 6 | @Serializable 7 | data class UserData( 8 | val user: User = User(), 9 | val privateKey: String = "", 10 | val secretKey: String = "" 11 | ) 12 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/domain/model/User.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.domain.model 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class User( 7 | val uid: String = "", 8 | val displayName: String = "", 9 | val email: String = "", 10 | val photoUrl: String = "", 11 | val publicKey: String = "" 12 | ) 13 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/domain/repository/DataStoreRepository.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.domain.repository 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | import me.siddheshkothadi.chat.domain.model.UserData 5 | 6 | interface DataStoreRepository { 7 | val userData: Flow 8 | 9 | suspend fun updateUserData( 10 | userData: UserData 11 | ) 12 | } -------------------------------------------------------------------------------- /app/src/main/res/values/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | } 14 | } 15 | rootProject.name = "Chat" 16 | include ':app' 17 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/theme/Shape.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.theme 2 | 3 | import androidx.compose.foundation.shape.RoundedCornerShape 4 | import androidx.compose.material.Shapes 5 | import androidx.compose.ui.unit.dp 6 | 7 | val Shapes = Shapes( 8 | small = RoundedCornerShape(4.dp), 9 | medium = RoundedCornerShape(4.dp), 10 | large = RoundedCornerShape(0.dp) 11 | ) -------------------------------------------------------------------------------- /app/src/main/res/values-v23/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/test/java/me/siddheshkothadi/chat/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /app/release/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "me.siddheshkothadi.chat", 8 | "variantName": "release", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "attributes": [], 14 | "versionCode": 1, 15 | "versionName": "1.0", 16 | "outputFile": "app-release.apk" 17 | } 18 | ], 19 | "elementType": "File" 20 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/me/siddheshkothadi/chat/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("me.siddheshkothadi.chat", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -keep class me.siddheshkothadi.chat.domain.model.** { *; } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/domain/repository/FirebaseRepository.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.domain.repository 2 | 3 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions 4 | import com.google.firebase.auth.FirebaseAuth 5 | import kotlinx.coroutines.flow.Flow 6 | import me.siddheshkothadi.chat.domain.model.Message 7 | import me.siddheshkothadi.chat.domain.model.User 8 | 9 | interface FirebaseRepository { 10 | val auth: FirebaseAuth 11 | val users: Flow> 12 | val encryptedChats: Flow>> 13 | val isUserListLoading: Flow 14 | suspend fun deleteUser(uid: String) 15 | suspend fun deleteChatsOfUser(uid: String) 16 | suspend fun saveNewUser(user: User) 17 | suspend fun addChat(key: String, date: String, chatList: List) 18 | suspend fun signOut(gso: GoogleSignInOptions) 19 | fun isSignedIn(): Boolean 20 | fun addMessageEventListener(key: String) 21 | fun removeMessageEventListener(key: String) 22 | fun clearChats() 23 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/data/repository/DataStoreRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.data.repository 2 | 3 | import android.content.Context 4 | import android.util.Log 5 | import androidx.datastore.dataStore 6 | import kotlinx.coroutines.flow.Flow 7 | import me.siddheshkothadi.chat.ChatApplication 8 | import me.siddheshkothadi.chat.data.UserDataSerializer 9 | import me.siddheshkothadi.chat.domain.model.UserData 10 | import me.siddheshkothadi.chat.domain.repository.DataStoreRepository 11 | import javax.inject.Inject 12 | 13 | 14 | class DataStoreRepositoryImpl @Inject constructor( 15 | context: ChatApplication 16 | ) : DataStoreRepository { 17 | private val Context.dataStore by dataStore("user-data.json", UserDataSerializer) 18 | private val userDataStore = context.dataStore 19 | 20 | override val userData: Flow 21 | get() = userDataStore.data 22 | 23 | override suspend fun updateUserData( 24 | userData: UserData 25 | ) { 26 | userDataStore.updateData { 27 | userData 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/data/UserDataSerializer.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.data 2 | 3 | import androidx.datastore.core.Serializer 4 | import kotlinx.serialization.json.Json 5 | import me.siddheshkothadi.chat.domain.model.UserData 6 | import java.io.InputStream 7 | import java.io.OutputStream 8 | 9 | @Suppress("BlockingMethodInNonBlockingContext") 10 | object UserDataSerializer: Serializer { 11 | override val defaultValue: UserData 12 | get() = UserData() 13 | 14 | override suspend fun readFrom(input: InputStream): UserData { 15 | return try { 16 | Json.decodeFromString( 17 | deserializer = UserData.serializer(), 18 | string = input.readBytes().decodeToString() 19 | ) 20 | } catch (e: Exception) { 21 | e.printStackTrace() 22 | defaultValue 23 | } 24 | } 25 | 26 | override suspend fun writeTo(t: UserData, output: OutputStream) { 27 | output.write( 28 | Json.encodeToString( 29 | serializer = UserData.serializer(), 30 | value = t 31 | ).encodeToByteArray() 32 | ) 33 | } 34 | } -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/domain/repository/UserRepository.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.domain.repository 2 | 3 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions 4 | import com.google.firebase.auth.AuthCredential 5 | import com.google.firebase.auth.FirebaseAuth 6 | import com.google.firebase.auth.FirebaseUser 7 | import kotlinx.coroutines.flow.Flow 8 | import me.siddheshkothadi.chat.domain.model.Message 9 | import me.siddheshkothadi.chat.domain.model.User 10 | import me.siddheshkothadi.chat.domain.model.UserData 11 | 12 | interface UserRepository { 13 | val firebaseAuth: FirebaseAuth 14 | val userData: Flow 15 | val chats: Flow>> 16 | val users: Flow> 17 | val isUserListLoading: Flow 18 | fun clearChats() 19 | fun addMessageEventListener(key: String) 20 | fun removeMessageEventListener(key: String) 21 | suspend fun deleteAllData(uid: String) 22 | suspend fun saveNewUser(firebaseUser: FirebaseUser) 23 | suspend fun getCurrentUser(): User 24 | suspend fun updateUserData(userData: UserData) 25 | suspend fun addChat(text: String, from: String, to: User, key: String) 26 | suspend fun signWithCredential(credential: AuthCredential) 27 | suspend fun signOut(gso: GoogleSignInOptions) 28 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Background](https://user-images.githubusercontent.com/55179845/162902635-e7a23844-4995-46dd-b59d-52b6a07e3183.png)](https://youtu.be/wzlQP0u0Nk0) 2 | 3 | # End-to-End Encrypted Chat 🔒 4 | 5 | Chat App is built to demonstrate a simple end-to-end chat encryption using RSA and AES algorithms 6 | 7 | # Built With ⚒️ 8 | 9 | - Jetpack Compose: Android's modern toolkit for building native UI 10 | - Accompanist: Utils for Jetpack Compose 11 | - Material 3: Google’s most expressive and adaptable design system yet with dynamic colors 12 | - Firebase: For Google OAuth authentication and Realtime Database 13 | - Lottie: An open source animation file format that's tiny, high quality, interactive, and can be manipulated at runtime 14 | - Coil: An image loading library for Android backed by Kotlin Coroutines 15 | - DataStore: A data storage solution that allows you to store key-value pairs or typed objects with protocol buffers. DataStore uses Kotlin coroutines and Flow to store data asynchronously, consistently, and transactionally. 16 | - Hilt: Hilt is a dependency injection library for Android that reduces the boilerplate of doing manual dependency injection 17 | 18 | # App Architecture 19 | 20 |

21 | 22 |

23 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Blue10 = Color(0xFF000F5E) 6 | val Blue20 = Color(0xFF001E92) 7 | val Blue30 = Color(0xFF002ECC) 8 | val Blue40 = Color(0xFF1546F6) 9 | val Blue80 = Color(0xFFB8C3FF) 10 | val Blue90 = Color(0xFFDDE1FF) 11 | 12 | val DarkBlue10 = Color(0xFF00036B) 13 | val DarkBlue20 = Color(0xFF000BA6) 14 | val DarkBlue30 = Color(0xFF1026D3) 15 | val DarkBlue40 = Color(0xFF3648EA) 16 | val DarkBlue80 = Color(0xFFBBC2FF) 17 | val DarkBlue90 = Color(0xFFDEE0FF) 18 | 19 | val Yellow10 = Color(0xFF261900) 20 | val Yellow20 = Color(0xFF402D00) 21 | val Yellow30 = Color(0xFF5C4200) 22 | val Yellow40 = Color(0xFF7A5900) 23 | val Yellow80 = Color(0xFFFABD1B) 24 | val Yellow90 = Color(0xFFFFDE9C) 25 | 26 | val Red10 = Color(0xFF410001) 27 | val Red20 = Color(0xFF680003) 28 | val Red30 = Color(0xFF930006) 29 | val Red40 = Color(0xFFBA1B1B) 30 | val Red80 = Color(0xFFFFB4A9) 31 | val Red90 = Color(0xFFFFDAD4) 32 | 33 | val Grey10 = Color(0xFF191C1D) 34 | val Grey20 = Color(0xFF2D3132) 35 | val Grey80 = Color(0xFFC4C7C7) 36 | val Grey90 = Color(0xFFE0E3E3) 37 | val Grey95 = Color(0xFFEFF1F1) 38 | val Grey99 = Color(0xFFFBFDFD) 39 | 40 | val BlueGrey30 = Color(0xFF45464F) 41 | val BlueGrey50 = Color(0xFF767680) 42 | val BlueGrey60 = Color(0xFF90909A) 43 | val BlueGrey80 = Color(0xFFC6C5D0) 44 | val BlueGrey90 = Color(0xFFE2E1EC) -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/components/DayHeader.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.components 2 | 3 | import androidx.compose.foundation.layout.Row 4 | import androidx.compose.foundation.layout.RowScope 5 | import androidx.compose.foundation.layout.height 6 | import androidx.compose.foundation.layout.padding 7 | import androidx.compose.material3.Divider 8 | import androidx.compose.material3.MaterialTheme 9 | import androidx.compose.material3.Text 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.unit.dp 14 | 15 | @Composable 16 | fun DayHeader(dayString: String) { 17 | Row( 18 | modifier = Modifier 19 | .padding(16.dp) 20 | .height(16.dp) 21 | ) { 22 | DayHeaderLine() 23 | Text( 24 | text = dayString, 25 | modifier = Modifier.padding(horizontal = 16.dp), 26 | style = MaterialTheme.typography.labelSmall, 27 | color = MaterialTheme.colorScheme.onSurfaceVariant 28 | ) 29 | DayHeaderLine() 30 | } 31 | } 32 | 33 | @Composable 34 | private fun RowScope.DayHeaderLine() { 35 | // TODO (M3): No Divider, replace when available 36 | Divider( 37 | modifier = Modifier 38 | .weight(1f) 39 | .align(Alignment.CenterVertically), 40 | color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f) 41 | ) 42 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 13 | 16 | 19 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_chat_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 13 | 16 | 19 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_chat.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 15 | 18 | 21 | 24 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "91794365719", 4 | "firebase_url": "https://e2ee-chat-5d24e-default-rtdb.asia-southeast1.firebasedatabase.app", 5 | "project_id": "e2ee-chat-5d24e", 6 | "storage_bucket": "e2ee-chat-5d24e.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:91794365719:android:be0a0a74c7be1b8322ab52", 12 | "android_client_info": { 13 | "package_name": "me.siddheshkothadi.chat" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "91794365719-6nogk63vbj6etnfgio9mblh5rk80fmpk.apps.googleusercontent.com", 19 | "client_type": 1, 20 | "android_info": { 21 | "package_name": "me.siddheshkothadi.chat", 22 | "certificate_hash": "6e6d7224b5bf770289cc193c6327b3ff027703d1" 23 | } 24 | }, 25 | { 26 | "client_id": "91794365719-fn0c30j3sqfstf3bf50ilkbmtfs3crl0.apps.googleusercontent.com", 27 | "client_type": 3 28 | } 29 | ], 30 | "api_key": [ 31 | { 32 | "current_key": "AIzaSyD9y9PPoF5rfD5j95UWOGgZOUsREG6wi9M" 33 | } 34 | ], 35 | "services": { 36 | "appinvite_service": { 37 | "other_platform_oauth_client": [ 38 | { 39 | "client_id": "91794365719-fn0c30j3sqfstf3bf50ilkbmtfs3crl0.apps.googleusercontent.com", 40 | "client_type": 3 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | ], 47 | "configuration_version": "1" 48 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/utils/AESUtils.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.utils 2 | 3 | import android.util.Base64 4 | import java.nio.charset.StandardCharsets 5 | import java.security.Key 6 | import javax.crypto.Cipher 7 | import javax.crypto.KeyGenerator 8 | import javax.crypto.spec.IvParameterSpec 9 | import javax.crypto.spec.SecretKeySpec 10 | 11 | object AESUtils { 12 | private val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") 13 | private val keyGenerator = KeyGenerator.getInstance("AES") 14 | 15 | init { 16 | keyGenerator.init(128) 17 | } 18 | 19 | fun encrypt(text: String, keyStr: String): String { 20 | val secretKeySpec = generateKeySpec(keyStr) 21 | cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, IvParameterSpec(ByteArray(16))) 22 | 23 | return Base64.encodeToString( 24 | cipher.doFinal(text.toByteArray(StandardCharsets.UTF_8)), 25 | Base64.DEFAULT 26 | ) 27 | } 28 | 29 | fun decrypt(encryptedText: String, keyStr: String): String { 30 | val secretKeySpec = generateKeySpec(keyStr) 31 | cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, IvParameterSpec(ByteArray(16))) 32 | 33 | return String(cipher.doFinal(Base64.decode(encryptedText, Base64.DEFAULT))) 34 | } 35 | 36 | fun getSecretKey(): String { 37 | val secretKey = keyGenerator.generateKey() 38 | return keyToEncodedString(secretKey) 39 | } 40 | 41 | private fun keyToEncodedString(key: Key): String { 42 | return Base64.encodeToString(key.encoded, Base64.DEFAULT) 43 | } 44 | 45 | private fun generateKeySpec(keyStr: String): SecretKeySpec { 46 | return SecretKeySpec(Base64.decode(keyStr, Base64.DEFAULT), "AES") 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/di/AppModule.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.di 2 | 3 | import android.content.Context 4 | import dagger.Module 5 | import dagger.Provides 6 | import dagger.hilt.InstallIn 7 | import dagger.hilt.android.qualifiers.ApplicationContext 8 | import dagger.hilt.components.SingletonComponent 9 | import me.siddheshkothadi.chat.ChatApplication 10 | import me.siddheshkothadi.chat.data.repository.DataStoreRepositoryImpl 11 | import me.siddheshkothadi.chat.data.repository.FirebaseRepositoryImpl 12 | import me.siddheshkothadi.chat.data.repository.UserRepositoryImpl 13 | import me.siddheshkothadi.chat.domain.repository.DataStoreRepository 14 | import me.siddheshkothadi.chat.domain.repository.FirebaseRepository 15 | import me.siddheshkothadi.chat.domain.repository.UserRepository 16 | import javax.inject.Singleton 17 | 18 | @Module 19 | @InstallIn(SingletonComponent::class) 20 | object AppModule { 21 | @Singleton 22 | @Provides 23 | fun provideApplication(@ApplicationContext context: Context): ChatApplication { 24 | return context as ChatApplication 25 | } 26 | 27 | @Singleton 28 | @Provides 29 | fun provideFirebaseRepository(context: ChatApplication): FirebaseRepository { 30 | return FirebaseRepositoryImpl(context) 31 | } 32 | 33 | @Singleton 34 | @Provides 35 | fun provideDataStoreRepository(context: ChatApplication): DataStoreRepository { 36 | return DataStoreRepositoryImpl(context) 37 | } 38 | 39 | @Singleton 40 | @Provides 41 | fun providesUserRepository(context: ChatApplication, firebaseRepository: FirebaseRepository, dataStoreRepository: DataStoreRepository): UserRepository { 42 | return UserRepositoryImpl(context, firebaseRepository, dataStoreRepository) 43 | } 44 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/components/Messages.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.components 2 | 3 | import androidx.compose.foundation.ExperimentalFoundationApi 4 | import androidx.compose.foundation.layout.PaddingValues 5 | import androidx.compose.foundation.lazy.LazyColumn 6 | import androidx.compose.foundation.lazy.items 7 | import androidx.compose.foundation.lazy.rememberLazyListState 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.DisposableEffect 10 | import androidx.compose.runtime.collectAsState 11 | import androidx.compose.runtime.getValue 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.unit.dp 14 | import me.siddheshkothadi.chat.domain.model.Message 15 | import me.siddheshkothadi.chat.ui.viewmodel.MainViewModel 16 | 17 | @OptIn(ExperimentalFoundationApi::class) 18 | @Composable 19 | fun Messages( 20 | modifier: Modifier, 21 | mainViewModel: MainViewModel, 22 | fromUid: String, 23 | key: String 24 | ) { 25 | val chats: Map> by mainViewModel.chats.collectAsState(emptyMap()) 26 | val scrollState = rememberLazyListState() 27 | 28 | DisposableEffect(key) { 29 | mainViewModel.addMessageEventListener(key) 30 | onDispose { 31 | mainViewModel.removeMessageEventListener(key) 32 | mainViewModel.clearChats() 33 | } 34 | } 35 | 36 | LazyColumn( 37 | modifier = modifier, 38 | state = scrollState, 39 | contentPadding = PaddingValues(horizontal = 16.dp, vertical = 24.dp), 40 | reverseLayout = true 41 | ) { 42 | chats.forEach { (date, messages) -> 43 | items(messages) { message -> 44 | ChatBubble(message = message.content, isUserMe = fromUid == message.from, time = message.time) 45 | } 46 | item { 47 | DayHeader(dayString = date) 48 | } 49 | } 50 | item { 51 | DayHeader(dayString = "\uD83D\uDD12 Chats are end-to-end encrypted \uD83D\uDD12") 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/utils/RSAUtils.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.utils 2 | 3 | import android.util.Base64 4 | import java.nio.charset.StandardCharsets 5 | import java.security.* 6 | import java.security.spec.PKCS8EncodedKeySpec 7 | import java.security.spec.X509EncodedKeySpec 8 | import javax.crypto.Cipher 9 | 10 | object RSAUtils { 11 | private val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding") 12 | private val keyFactory: KeyFactory = KeyFactory.getInstance("RSA") 13 | private val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("RSA") 14 | 15 | fun encrypt(text: String, publicStr: String): String { 16 | val publicKey = generatePublicKey(publicStr) 17 | cipher.init(Cipher.ENCRYPT_MODE, publicKey) 18 | val encryptedBytes = cipher.doFinal(text.toByteArray(StandardCharsets.UTF_8)) 19 | return Base64.encodeToString(encryptedBytes, Base64.DEFAULT) 20 | } 21 | 22 | fun decrypt(result: String?, privateStr: String): String { 23 | val privateKey = generatePrivateKey(privateStr) 24 | cipher.init(Cipher.DECRYPT_MODE, privateKey) 25 | val decryptedBytes = cipher.doFinal(Base64.decode(result, Base64.DEFAULT)) 26 | return String(decryptedBytes) 27 | } 28 | 29 | private fun generatePrivateKey(privateStr: String): PrivateKey { 30 | val privateKeySpec = PKCS8EncodedKeySpec(Base64.decode(privateStr, Base64.DEFAULT)) 31 | return keyFactory.generatePrivate(privateKeySpec) 32 | } 33 | 34 | private fun generatePublicKey(publicStr: String): PublicKey { 35 | val pubKeySpec = X509EncodedKeySpec(Base64.decode(publicStr, Base64.DEFAULT)) 36 | return keyFactory.generatePublic(pubKeySpec) 37 | } 38 | 39 | fun getKeyPair(): Pair { 40 | val keyPair = keyPairGenerator.generateKeyPair() 41 | val publicKey = keyToEncodedString(keyPair.public) 42 | val privateKey = keyToEncodedString(keyPair.private) 43 | 44 | return Pair(publicKey, privateKey) 45 | } 46 | 47 | private fun keyToEncodedString(key: Key): String { 48 | return Base64.encodeToString(key.encoded, Base64.DEFAULT) 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/components/ChatCard.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.components 2 | 3 | import androidx.compose.foundation.clickable 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.shape.CircleShape 6 | import androidx.compose.foundation.shape.RoundedCornerShape 7 | import androidx.compose.material3.ExperimentalMaterial3Api 8 | import androidx.compose.material3.Surface 9 | import androidx.compose.material3.Text 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.draw.clip 14 | import androidx.compose.ui.text.font.FontWeight 15 | import androidx.compose.ui.unit.dp 16 | import androidx.compose.ui.unit.sp 17 | import coil.compose.AsyncImage 18 | import me.siddheshkothadi.chat.domain.model.User 19 | 20 | @OptIn(ExperimentalMaterial3Api::class) 21 | @Composable 22 | fun ChatCard( 23 | user: User, 24 | onClickAction: () -> Unit, 25 | navigateToProfile: () -> Unit 26 | ) { 27 | Box( 28 | Modifier 29 | .fillMaxWidth() 30 | .padding(vertical = 8.dp, horizontal = 8.dp)) { 31 | Surface( 32 | modifier = Modifier 33 | .fillMaxWidth().clip(RoundedCornerShape(16)).clickable { onClickAction() }, 34 | tonalElevation = 1.5.dp 35 | ) { 36 | Row( 37 | modifier = Modifier 38 | .fillMaxWidth() 39 | .padding(18.dp), 40 | verticalAlignment = Alignment.CenterVertically 41 | ) { 42 | AsyncImage( 43 | model = user.photoUrl, 44 | contentDescription = "User Image", 45 | modifier = Modifier 46 | .width(50.dp) 47 | .height(50.dp) 48 | .clip(CircleShape).clickable { 49 | navigateToProfile() 50 | } 51 | ) 52 | Spacer(modifier = Modifier.width(24.dp)) 53 | Text(user.displayName, modifier = Modifier.weight(1f), fontSize = 20.sp, fontWeight = FontWeight.W500) 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | 25 | alicePublic="MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgEac6cgM4Ch5vY2Rqvzw2ARaNEHvPCbXWW1nPy3ft8CNFyLoIltwrnouY0azYECclONARh48qQUQ+UG62wNUtciLq9yX3m0ePE7u/RYmNUnGWok6LMNZK1gGBu6TBnzNjDWi3CuR00xFzZ2TBtUMDowOa/+btfGTywGDLPJjgbtPAgMBAAE=" 26 | alicePrivate="MIICWgIBAAKBgEac6cgM4Ch5vY2Rqvzw2ARaNEHvPCbXWW1nPy3ft8CNFyLoIltwrnouY0azYECclONARh48qQUQ+UG62wNUtciLq9yX3m0ePE7u/RYmNUnGWok6LMNZK1gGBu6TBnzNjDWi3CuR00xFzZ2TBtUMDowOa/+btfGTywGDLPJjgbtPAgMBAAECgYAAxTd7ukA70NAzmjI+XjZNHdrSGVUTq2fLXMQAsR8lF6T3+YZebwVISfdFTzGuosaxEANz0v+ZEY1WnT5EdAkjqwtYauj0tDnYmuciju2uVnEYLPOaOvpkmM7e9y+aNWTvG/C0qAXtTT/EJgAwfCyrhuigyxzwUIyqhW2xgQ8MKQJBAIgM5xPKd30HU98tjOHzouwSjsv5NIFOM9RnLPGA6HazQGu/0h2S27UnzaU8KKjln1X2q22GMa1cSvILq06e+MsCQQCE3oZudjOBgJaKtk7iETiIIoVVk3K1RMSGT/56SrglB1K1kNuFOpg+obs+8j366gQk47ZgaIZwSRfro0VhTysNAkBiLEVWv6QHgZEhG6Jsrb1j8mQ+hd5AbGj0HVuODYIxnVmgJvP8yStnhohbcpS4g7G9e1jqmIoiWdXu4ULFYeuPAkAIcKYzcBi3ejaV2xzJqXRg2WiE1hfsQdEGAyDUHdjyqTNsyyXWobE4EUf2qKadQK5AtaJJH3qiuVHmqvlmRAQlAkB4Cl2nYBpK1IdusfwtjfaKppLa/r5k1D35cybxLn1uS3XzwwqRUuXrDkb4+TCD3B7Lkuym/kfFE2iIpANAVkeN" -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/screens/ProfileScreen.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.screens 2 | 3 | import androidx.compose.animation.rememberSplineBasedDecay 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.shape.CircleShape 6 | import androidx.compose.material.icons.Icons 7 | import androidx.compose.material.icons.filled.ArrowBack 8 | import androidx.compose.material3.* 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.runtime.remember 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.draw.alpha 14 | import androidx.compose.ui.draw.clip 15 | import androidx.compose.ui.input.nestedscroll.nestedScroll 16 | import androidx.compose.ui.text.font.FontWeight 17 | import androidx.compose.ui.text.style.TextOverflow 18 | import androidx.compose.ui.unit.dp 19 | import androidx.compose.ui.unit.sp 20 | import androidx.navigation.NavHostController 21 | import coil.compose.AsyncImage 22 | import me.siddheshkothadi.chat.domain.model.User 23 | 24 | @OptIn(ExperimentalMaterial3Api::class) 25 | @Composable 26 | fun ProfileScreen( 27 | navHostController: NavHostController, 28 | user: User 29 | ) { 30 | val decayAnimationSpec = rememberSplineBasedDecay() 31 | val scrollBehavior = remember(decayAnimationSpec) { 32 | TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec) 33 | } 34 | 35 | Scaffold( 36 | modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), 37 | topBar = { 38 | Surface(tonalElevation = 2.dp) { 39 | LargeTopAppBar( 40 | title = { 41 | Text( 42 | text = user.displayName, 43 | fontSize = 30.sp, 44 | maxLines = 1, 45 | overflow = TextOverflow.Ellipsis 46 | ) 47 | }, 48 | modifier = Modifier.windowInsetsPadding( 49 | WindowInsets.statusBars.only( 50 | WindowInsetsSides.Top 51 | ) 52 | ), 53 | navigationIcon = { 54 | IconButton(onClick = { 55 | navHostController.popBackStack() 56 | }) { 57 | Icon(Icons.Default.ArrowBack, null) 58 | } 59 | }, 60 | scrollBehavior = scrollBehavior 61 | ) 62 | } 63 | } 64 | ) { _ -> 65 | Column( 66 | modifier = Modifier.fillMaxWidth(), 67 | horizontalAlignment = Alignment.CenterHorizontally 68 | ) { 69 | Spacer(Modifier.height(24.dp)) 70 | AsyncImage( 71 | model = user.photoUrl, 72 | contentDescription = "User Photo", 73 | modifier = Modifier 74 | .height(128.dp) 75 | .width(128.dp) 76 | .clip(CircleShape) 77 | ) 78 | Spacer(Modifier.height(24.dp)) 79 | Text( 80 | text = user.email, 81 | fontSize = 20.sp, 82 | fontWeight = FontWeight.W600, 83 | modifier = Modifier.alpha(0.75f) 84 | ) 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/screens/MyProfileScreen.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.screens 2 | 3 | import androidx.compose.animation.rememberSplineBasedDecay 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.shape.CircleShape 6 | import androidx.compose.material.icons.Icons 7 | import androidx.compose.material.icons.filled.ArrowBack 8 | import androidx.compose.material3.* 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.runtime.remember 11 | import androidx.compose.ui.Alignment 12 | import androidx.compose.ui.Modifier 13 | import androidx.compose.ui.draw.alpha 14 | import androidx.compose.ui.draw.clip 15 | import androidx.compose.ui.input.nestedscroll.nestedScroll 16 | import androidx.compose.ui.text.font.FontWeight 17 | import androidx.compose.ui.text.style.TextOverflow 18 | import androidx.compose.ui.unit.dp 19 | import androidx.compose.ui.unit.sp 20 | import androidx.navigation.NavHostController 21 | import coil.compose.AsyncImage 22 | import me.siddheshkothadi.chat.ui.viewmodel.MainViewModel 23 | 24 | @OptIn(ExperimentalMaterial3Api::class) 25 | @Composable 26 | fun MyProfile( 27 | navHostController: NavHostController, 28 | mainViewModel: MainViewModel 29 | ) { 30 | val decayAnimationSpec = rememberSplineBasedDecay() 31 | val scrollBehavior = remember(decayAnimationSpec) { 32 | TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec) 33 | } 34 | 35 | val user = mainViewModel.getCurrentUser() 36 | 37 | Scaffold( 38 | modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), 39 | topBar = { 40 | Surface(tonalElevation = 2.dp) { 41 | LargeTopAppBar( 42 | title = { 43 | Text( 44 | text = user.displayName, 45 | fontSize = 30.sp, 46 | maxLines = 1, 47 | overflow = TextOverflow.Ellipsis 48 | ) 49 | }, 50 | modifier = Modifier.windowInsetsPadding( 51 | WindowInsets.statusBars.only( 52 | WindowInsetsSides.Top 53 | ) 54 | ), 55 | navigationIcon = { 56 | IconButton(onClick = { 57 | navHostController.popBackStack() 58 | }) { 59 | Icon(Icons.Default.ArrowBack, null) 60 | } 61 | }, 62 | scrollBehavior = scrollBehavior 63 | ) 64 | } 65 | } 66 | ) { _ -> 67 | Column( 68 | modifier = Modifier.fillMaxWidth(), 69 | horizontalAlignment = Alignment.CenterHorizontally 70 | ) { 71 | Spacer(Modifier.height(24.dp)) 72 | AsyncImage( 73 | model = user.photoUrl, 74 | contentDescription = "User Photo", 75 | modifier = Modifier 76 | .height(128.dp) 77 | .width(128.dp) 78 | .clip(CircleShape) 79 | ) 80 | Spacer(Modifier.height(24.dp)) 81 | Text( 82 | text = user.email, 83 | fontSize = 20.sp, 84 | fontWeight = FontWeight.W600, 85 | modifier = Modifier.alpha(0.75f) 86 | ) 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | id 'kotlin-kapt' 5 | id 'dagger.hilt.android.plugin' 6 | id 'org.jetbrains.kotlin.plugin.serialization' 7 | } 8 | 9 | apply plugin: 'com.google.gms.google-services' 10 | 11 | android { 12 | compileSdk 32 13 | 14 | defaultConfig { 15 | applicationId "me.siddheshkothadi.chat" 16 | minSdk 21 17 | targetSdk 32 18 | versionCode 1 19 | versionName "1.0" 20 | 21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 22 | vectorDrawables { 23 | useSupportLibrary true 24 | } 25 | } 26 | 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 31 | } 32 | 33 | debug { 34 | minifyEnabled false 35 | } 36 | } 37 | compileOptions { 38 | sourceCompatibility JavaVersion.VERSION_1_8 39 | targetCompatibility JavaVersion.VERSION_1_8 40 | } 41 | kotlinOptions { 42 | jvmTarget = '1.8' 43 | } 44 | buildFeatures { 45 | compose true 46 | } 47 | composeOptions { 48 | kotlinCompilerExtensionVersion compose_version 49 | } 50 | packagingOptions { 51 | resources { 52 | excludes += '/META-INF/{AL2.0,LGPL2.1}' 53 | } 54 | } 55 | } 56 | 57 | dependencies { 58 | 59 | implementation 'androidx.core:core-ktx:1.7.0' 60 | implementation "androidx.compose.ui:ui:$compose_version" 61 | implementation "androidx.compose.material:material:1.1.1" 62 | implementation "androidx.compose.ui:ui-tooling-preview:1.1.1" 63 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' 64 | implementation 'androidx.activity:activity-compose:1.4.0' 65 | testImplementation 'junit:junit:4.13.2' 66 | androidTestImplementation 'androidx.test.ext:junit:1.1.3' 67 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' 68 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.1.1" 69 | debugImplementation "androidx.compose.ui:ui-tooling:1.1.1" 70 | implementation "androidx.compose.runtime:runtime:1.2.0-alpha07" 71 | 72 | implementation "androidx.compose.foundation:foundation:1.2.0-alpha06" 73 | implementation "androidx.compose.foundation:foundation-layout:1.2.0-alpha06" 74 | implementation "com.google.accompanist:accompanist-navigation-animation:0.24.5-alpha" 75 | 76 | implementation "androidx.compose.material3:material3:1.0.0-alpha08" 77 | implementation "androidx.core:core-splashscreen:1.0.0-beta02" 78 | implementation "com.google.accompanist:accompanist-systemuicontroller:0.24.5-alpha" 79 | implementation "com.google.accompanist:accompanist-flowlayout:0.24.5-alpha" 80 | 81 | implementation platform('com.google.firebase:firebase-bom:29.3.0') 82 | implementation 'com.google.firebase:firebase-database-ktx' 83 | implementation 'com.google.firebase:firebase-auth-ktx' 84 | implementation 'com.google.android.gms:play-services-auth:20.1.0' 85 | 86 | implementation "com.airbnb.android:lottie-compose:5.0.3" 87 | implementation("io.coil-kt:coil-compose:2.0.0-rc02") 88 | 89 | implementation "com.google.dagger:hilt-android:2.38.1" 90 | kapt "com.google.dagger:hilt-compiler:2.38.1" 91 | 92 | implementation "androidx.datastore:datastore:1.0.0" 93 | implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2' 94 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.4.1' 95 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.theme 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Build 5 | import androidx.compose.foundation.LocalIndication 6 | import androidx.compose.foundation.isSystemInDarkTheme 7 | import androidx.compose.material.ripple.rememberRipple 8 | import androidx.compose.material3.MaterialTheme 9 | import androidx.compose.material3.darkColorScheme 10 | import androidx.compose.material3.dynamicDarkColorScheme 11 | import androidx.compose.material3.dynamicLightColorScheme 12 | import androidx.compose.material3.lightColorScheme 13 | import androidx.compose.runtime.Composable 14 | import androidx.compose.runtime.CompositionLocalProvider 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.compose.ui.platform.LocalContext 17 | 18 | private val ChatDarkColorScheme = darkColorScheme( 19 | primary = Blue80, 20 | onPrimary = Blue20, 21 | primaryContainer = Blue30, 22 | onPrimaryContainer = Blue90, 23 | inversePrimary = Blue40, 24 | secondary = DarkBlue80, 25 | onSecondary = DarkBlue20, 26 | secondaryContainer = DarkBlue30, 27 | onSecondaryContainer = DarkBlue90, 28 | tertiary = Yellow80, 29 | onTertiary = Yellow20, 30 | tertiaryContainer = Yellow30, 31 | onTertiaryContainer = Yellow90, 32 | error = Red80, 33 | onError = Red20, 34 | errorContainer = Red30, 35 | onErrorContainer = Red90, 36 | background = Grey10, 37 | onBackground = Grey90, 38 | surface = Grey10, 39 | onSurface = Grey80, 40 | inverseSurface = Grey90, 41 | inverseOnSurface = Grey20, 42 | surfaceVariant = BlueGrey30, 43 | onSurfaceVariant = BlueGrey80, 44 | outline = BlueGrey60 45 | ) 46 | 47 | private val ChatLightColorScheme = lightColorScheme( 48 | primary = Blue40, 49 | onPrimary = Color.White, 50 | primaryContainer = Blue90, 51 | onPrimaryContainer = Blue10, 52 | inversePrimary = Blue80, 53 | secondary = DarkBlue40, 54 | onSecondary = Color.White, 55 | secondaryContainer = DarkBlue90, 56 | onSecondaryContainer = DarkBlue10, 57 | tertiary = Yellow40, 58 | onTertiary = Color.White, 59 | tertiaryContainer = Yellow90, 60 | onTertiaryContainer = Yellow10, 61 | error = Red40, 62 | onError = Color.White, 63 | errorContainer = Red90, 64 | onErrorContainer = Red10, 65 | background = Grey99, 66 | onBackground = Grey10, 67 | surface = Grey99, 68 | onSurface = Grey10, 69 | inverseSurface = Grey20, 70 | inverseOnSurface = Grey95, 71 | surfaceVariant = BlueGrey90, 72 | onSurfaceVariant = BlueGrey30, 73 | outline = BlueGrey50 74 | ) 75 | 76 | @SuppressLint("NewApi") 77 | @Composable 78 | fun ChatTheme( 79 | isDarkTheme: Boolean = isSystemInDarkTheme(), 80 | isDynamicColor: Boolean = true, 81 | content: @Composable () -> Unit 82 | ) { 83 | val dynamicColor = isDynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S 84 | val myColorScheme = when { 85 | dynamicColor && isDarkTheme -> { 86 | dynamicDarkColorScheme(LocalContext.current) 87 | } 88 | dynamicColor && !isDarkTheme -> { 89 | dynamicLightColorScheme(LocalContext.current) 90 | } 91 | isDarkTheme -> ChatDarkColorScheme 92 | else -> ChatLightColorScheme 93 | } 94 | 95 | MaterialTheme( 96 | colorScheme = myColorScheme, 97 | typography = ChatTypography 98 | ) { 99 | // TODO (M3): MaterialTheme doesn't provide LocalIndication, remove when it does 100 | val rippleIndication = rememberRipple() 101 | CompositionLocalProvider( 102 | LocalIndication provides rippleIndication, 103 | content = content 104 | ) 105 | } 106 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.theme 2 | 3 | import androidx.compose.material3.Typography 4 | import androidx.compose.ui.text.TextStyle 5 | import androidx.compose.ui.text.font.Font 6 | import androidx.compose.ui.text.font.FontFamily 7 | import androidx.compose.ui.text.font.FontWeight 8 | import androidx.compose.ui.unit.sp 9 | import me.siddheshkothadi.chat.R 10 | 11 | private val MontserratFontFamily = FontFamily( 12 | Font(R.font.montserrat_regular), 13 | Font(R.font.montserrat_light, FontWeight.Light), 14 | Font(R.font.montserrat_medium, FontWeight.Medium), 15 | Font(R.font.montserrat_semibold, FontWeight.SemiBold) 16 | ) 17 | 18 | private val KarlaFontFamily = FontFamily( 19 | Font(R.font.karla_regular), 20 | Font(R.font.karla_bold, FontWeight.Bold) 21 | ) 22 | 23 | val ChatTypography = Typography( 24 | displayLarge = TextStyle( 25 | fontFamily = MontserratFontFamily, 26 | fontWeight = FontWeight.Light, 27 | fontSize = 57.sp, 28 | lineHeight = 64.sp, 29 | letterSpacing = 0.sp 30 | ), 31 | displayMedium = TextStyle( 32 | fontFamily = MontserratFontFamily, 33 | fontWeight = FontWeight.Light, 34 | fontSize = 45.sp, 35 | lineHeight = 52.sp, 36 | letterSpacing = 0.sp 37 | ), 38 | displaySmall = TextStyle( 39 | fontFamily = MontserratFontFamily, 40 | fontWeight = FontWeight.Normal, 41 | fontSize = 36.sp, 42 | lineHeight = 44.sp, 43 | letterSpacing = 0.sp 44 | ), 45 | headlineLarge = TextStyle( 46 | fontFamily = MontserratFontFamily, 47 | fontWeight = FontWeight.SemiBold, 48 | fontSize = 32.sp, 49 | lineHeight = 40.sp, 50 | letterSpacing = 0.sp 51 | ), 52 | headlineMedium = TextStyle( 53 | fontFamily = MontserratFontFamily, 54 | fontWeight = FontWeight.SemiBold, 55 | fontSize = 28.sp, 56 | lineHeight = 36.sp, 57 | letterSpacing = 0.sp 58 | ), 59 | headlineSmall = TextStyle( 60 | fontFamily = MontserratFontFamily, 61 | fontWeight = FontWeight.SemiBold, 62 | fontSize = 24.sp, 63 | lineHeight = 32.sp, 64 | letterSpacing = 0.sp 65 | ), 66 | titleLarge = TextStyle( 67 | fontFamily = MontserratFontFamily, 68 | fontWeight = FontWeight.SemiBold, 69 | fontSize = 22.sp, 70 | lineHeight = 28.sp, 71 | letterSpacing = 0.sp 72 | ), 73 | titleMedium = TextStyle( 74 | fontFamily = MontserratFontFamily, 75 | fontWeight = FontWeight.SemiBold, 76 | fontSize = 16.sp, 77 | lineHeight = 24.sp, 78 | letterSpacing = 0.15.sp 79 | ), 80 | titleSmall = TextStyle( 81 | fontFamily = KarlaFontFamily, 82 | fontWeight = FontWeight.Bold, 83 | fontSize = 14.sp, 84 | lineHeight = 20.sp, 85 | letterSpacing = 0.1.sp 86 | ), 87 | bodyLarge = TextStyle( 88 | fontFamily = KarlaFontFamily, 89 | fontWeight = FontWeight.Normal, 90 | fontSize = 16.sp, 91 | lineHeight = 24.sp, 92 | letterSpacing = 0.15.sp 93 | ), 94 | bodyMedium = TextStyle( 95 | fontFamily = MontserratFontFamily, 96 | fontWeight = FontWeight.Medium, 97 | fontSize = 14.sp, 98 | lineHeight = 20.sp, 99 | letterSpacing = 0.25.sp 100 | ), 101 | bodySmall = TextStyle( 102 | fontFamily = KarlaFontFamily, 103 | fontWeight = FontWeight.Bold, 104 | fontSize = 12.sp, 105 | lineHeight = 16.sp, 106 | letterSpacing = 0.4.sp 107 | ), 108 | labelLarge = TextStyle( 109 | fontFamily = MontserratFontFamily, 110 | fontWeight = FontWeight.SemiBold, 111 | fontSize = 14.sp, 112 | lineHeight = 20.sp, 113 | letterSpacing = 0.1.sp 114 | ), 115 | labelMedium = TextStyle( 116 | fontFamily = MontserratFontFamily, 117 | fontWeight = FontWeight.SemiBold, 118 | fontSize = 12.sp, 119 | lineHeight = 16.sp, 120 | letterSpacing = 0.5.sp 121 | ), 122 | labelSmall = TextStyle( 123 | fontFamily = MontserratFontFamily, 124 | fontWeight = FontWeight.SemiBold, 125 | fontSize = 11.sp, 126 | lineHeight = 16.sp, 127 | letterSpacing = 0.5.sp 128 | ) 129 | ) -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/screens/LoginScreen.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.screens 2 | 3 | import android.util.Log 4 | import androidx.activity.compose.rememberLauncherForActivityResult 5 | import androidx.activity.result.contract.ActivityResultContracts 6 | import androidx.compose.foundation.isSystemInDarkTheme 7 | import androidx.compose.foundation.layout.* 8 | import androidx.compose.material3.CircularProgressIndicator 9 | import androidx.compose.material3.OutlinedButton 10 | import androidx.compose.material3.Text 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.runtime.collectAsState 13 | import androidx.compose.runtime.getValue 14 | import androidx.compose.ui.Alignment 15 | import androidx.compose.ui.Modifier 16 | import androidx.compose.ui.draw.alpha 17 | import androidx.compose.ui.platform.LocalContext 18 | import androidx.compose.ui.text.font.FontWeight 19 | import androidx.compose.ui.text.style.TextAlign 20 | import androidx.compose.ui.unit.dp 21 | import androidx.compose.ui.unit.sp 22 | import androidx.navigation.NavHostController 23 | import com.airbnb.lottie.compose.* 24 | import com.google.android.gms.auth.api.signin.GoogleSignIn 25 | import com.google.android.gms.common.api.ApiException 26 | import com.google.firebase.auth.GoogleAuthProvider 27 | import me.siddheshkothadi.chat.ui.viewmodel.MainViewModel 28 | import me.siddheshkothadi.chat.R 29 | 30 | @Composable 31 | fun LoginScreen( 32 | mainViewModel: MainViewModel 33 | ) { 34 | val context = LocalContext.current 35 | val lottieCompositionSpec = 36 | if (isSystemInDarkTheme()) LottieCompositionSpec.RawRes(R.raw.chat_dark) else LottieCompositionSpec.RawRes( 37 | R.raw.chat_light 38 | ) 39 | val composition by rememberLottieComposition(lottieCompositionSpec) 40 | val progress by animateLottieCompositionAsState( 41 | composition, 42 | iterations = LottieConstants.IterateForever, 43 | ) 44 | 45 | val isSigningIn by mainViewModel.isSigningIn.collectAsState() 46 | 47 | val launcher = 48 | rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { 49 | val task = GoogleSignIn.getSignedInAccountFromIntent(it.data) 50 | try { 51 | val account = task.getResult(ApiException::class.java)!! 52 | val credential = GoogleAuthProvider.getCredential(account.idToken!!, null) 53 | mainViewModel.signWithCredential(credential) 54 | } catch (e: ApiException) { 55 | Log.w("Auth", "Google sign in failed", e) 56 | } 57 | } 58 | 59 | fun launchGoogleSignIn() { 60 | launcher.launch(GoogleSignIn.getClient(context, mainViewModel.gso).signInIntent) 61 | } 62 | 63 | Column( 64 | modifier = Modifier.fillMaxSize(), 65 | horizontalAlignment = Alignment.CenterHorizontally, 66 | verticalArrangement = Arrangement.Center 67 | ) { 68 | Text( 69 | "\uD83D\uDD10", 70 | fontWeight = FontWeight.SemiBold, 71 | fontSize = 36.sp, 72 | textAlign = TextAlign.Center 73 | ) 74 | Text( 75 | "Chat", 76 | fontWeight = FontWeight.SemiBold, 77 | fontSize = 48.sp, 78 | textAlign = TextAlign.Center 79 | ) 80 | 81 | LottieAnimation( 82 | composition, 83 | progress, 84 | modifier = Modifier 85 | .height(300.dp) 86 | .width(300.dp) 87 | ) 88 | 89 | Row( 90 | modifier = Modifier 91 | .fillMaxWidth() 92 | .systemBarsPadding(), 93 | horizontalArrangement = Arrangement.SpaceEvenly 94 | ) { 95 | OutlinedButton( 96 | onClick = { launchGoogleSignIn() }, 97 | modifier = Modifier.width(300.dp) 98 | ) { 99 | Text("Login") 100 | } 101 | } 102 | 103 | Row( 104 | modifier = Modifier 105 | .fillMaxWidth() 106 | .padding(vertical = 24.dp), 107 | horizontalArrangement = Arrangement.Center 108 | ) { 109 | CircularProgressIndicator( 110 | Modifier 111 | .width(24.dp) 112 | .height(24.dp) 113 | .alpha(if(isSigningIn) 1f else 0f) 114 | ) 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/data/repository/FirebaseRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.data.repository 2 | 3 | import android.util.Log 4 | import com.google.android.gms.auth.api.signin.GoogleSignIn 5 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions 6 | import com.google.firebase.auth.ktx.auth 7 | import com.google.firebase.database.DataSnapshot 8 | import com.google.firebase.database.DatabaseError 9 | import com.google.firebase.database.ValueEventListener 10 | import com.google.firebase.database.ktx.database 11 | import com.google.firebase.database.ktx.getValue 12 | import com.google.firebase.ktx.Firebase 13 | import kotlinx.coroutines.flow.Flow 14 | import kotlinx.coroutines.flow.MutableStateFlow 15 | import kotlinx.coroutines.flow.flow 16 | import kotlinx.coroutines.tasks.await 17 | import me.siddheshkothadi.chat.ChatApplication 18 | import me.siddheshkothadi.chat.domain.model.Message 19 | import me.siddheshkothadi.chat.domain.model.User 20 | import me.siddheshkothadi.chat.domain.repository.FirebaseRepository 21 | import javax.inject.Inject 22 | 23 | class FirebaseRepositoryImpl @Inject constructor( 24 | private val context: ChatApplication 25 | ) : FirebaseRepository { 26 | private val database = Firebase.database 27 | private val chatRef = database.getReference("chats") 28 | private val userRef = database.getReference("users") 29 | private val _chats = MutableStateFlow>>(emptyMap()) 30 | 31 | override suspend fun addChat(key: String, date: String, chatList: List) { 32 | chatRef.child(key).child(date).setValue(chatList).await() 33 | } 34 | 35 | override suspend fun signOut(gso: GoogleSignInOptions) { 36 | val uid = auth.uid!! 37 | GoogleSignIn.getClient(context, gso).signOut().await() 38 | deleteChatsOfUser(uid) 39 | deleteUser(uid) 40 | auth.signOut() 41 | } 42 | 43 | private val messageListener = object : ValueEventListener { 44 | override fun onDataChange(dataSnapshot: DataSnapshot) { 45 | val messages = dataSnapshot.getValue>>() 46 | _chats.value = messages ?: emptyMap() 47 | } 48 | 49 | override fun onCancelled(databaseError: DatabaseError) { 50 | Log.w("onCancelled", "loadPost:onCancelled", databaseError.toException()) 51 | } 52 | } 53 | 54 | private val _isUserListLoading: MutableStateFlow = MutableStateFlow(false) 55 | override val isUserListLoading: Flow 56 | get() = _isUserListLoading 57 | 58 | override val auth = Firebase.auth 59 | 60 | override val encryptedChats: Flow>> 61 | get() = _chats 62 | 63 | override val users: Flow> = flow { 64 | _isUserListLoading.value = true 65 | val userSnapshot = userRef.get().await() 66 | val listOfUsers = userSnapshot.children.map { 67 | it.getValue(User::class.java) ?: User() 68 | } 69 | emit(listOfUsers) 70 | _isUserListLoading.value = false 71 | } 72 | 73 | override suspend fun deleteUser(uid: String) { 74 | val dataSnapshot = userRef.get().await() 75 | val filteredUsers = dataSnapshot.children.map { 76 | it.getValue(User::class.java) 77 | }.filter { 78 | it?.uid != uid 79 | } 80 | 81 | userRef.setValue(filteredUsers).await() 82 | } 83 | 84 | override suspend fun deleteChatsOfUser(uid: String) { 85 | val dataSnapshot = chatRef.get().await() 86 | val hashMap: HashMap>> = hashMapOf() 87 | 88 | for (item in dataSnapshot.children) { 89 | item.key?.let { 90 | if (!it.contains(uid)) { 91 | hashMap[it] = item.value as HashMap> 92 | } 93 | } 94 | } 95 | 96 | chatRef.setValue(hashMap).await() 97 | } 98 | 99 | override suspend fun saveNewUser(user: User) { 100 | userRef.child(user.uid).setValue(user).await() 101 | } 102 | 103 | override fun addMessageEventListener(key: String) { 104 | chatRef.child(key).addValueEventListener(messageListener) 105 | } 106 | 107 | override fun removeMessageEventListener(key: String) { 108 | chatRef.child(key).removeEventListener(messageListener) 109 | } 110 | 111 | override fun clearChats() { 112 | _chats.value = emptyMap() 113 | } 114 | 115 | override fun isSignedIn(): Boolean { 116 | return auth.currentUser != null 117 | } 118 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/screens/ChatListScreen.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.screens 2 | 3 | import androidx.compose.foundation.layout.* 4 | import androidx.compose.foundation.lazy.LazyColumn 5 | import androidx.compose.foundation.lazy.items 6 | import androidx.compose.material.icons.Icons 7 | import androidx.compose.material.icons.filled.AccountCircle 8 | import androidx.compose.material.icons.filled.ExitToApp 9 | import androidx.compose.material3.* 10 | import androidx.compose.runtime.* 11 | import androidx.compose.ui.Modifier 12 | import androidx.compose.ui.unit.dp 13 | import androidx.navigation.NavHostController 14 | import me.siddheshkothadi.chat.ui.components.ChatCard 15 | import me.siddheshkothadi.chat.ui.viewmodel.MainViewModel 16 | 17 | @OptIn(ExperimentalMaterial3Api::class) 18 | @Composable 19 | fun ChatListScreen( 20 | navHostController: NavHostController, 21 | mainViewModel: MainViewModel 22 | ) { 23 | val isUserListLoading by mainViewModel.isUserListLoading.collectAsState(false) 24 | val listOfUsers by mainViewModel.users.collectAsState(emptyList()) 25 | val isLoggingOut by mainViewModel.isLoggingOut.collectAsState() 26 | 27 | val openDialog = remember { 28 | mutableStateOf(false) 29 | } 30 | 31 | Scaffold( 32 | topBar = { 33 | Surface(tonalElevation = 2.dp) { 34 | CenterAlignedTopAppBar( 35 | title = { 36 | Text("Chat") 37 | }, 38 | modifier = Modifier.windowInsetsPadding( 39 | WindowInsets.statusBars.only( 40 | WindowInsetsSides.Top 41 | ) 42 | ), 43 | actions = { 44 | IconButton(onClick = { 45 | openDialog.value = true 46 | }) { 47 | Icon(Icons.Default.ExitToApp, null) 48 | } 49 | }, 50 | navigationIcon = { 51 | IconButton(onClick = { 52 | navHostController.navigate("myProfile") 53 | }) { 54 | Icon(Icons.Default.AccountCircle, "Account") 55 | } 56 | } 57 | ) 58 | } 59 | }, 60 | ) { 61 | if (openDialog.value) { 62 | AlertDialog( 63 | onDismissRequest = { openDialog.value = false }, 64 | confirmButton = { 65 | TextButton( 66 | onClick = { 67 | mainViewModel.signOut() 68 | }, 69 | enabled = !isLoggingOut 70 | ) { 71 | Text("Yes") 72 | } 73 | }, 74 | dismissButton = { 75 | TextButton(onClick = { openDialog.value = false }) { 76 | Text("Cancel") 77 | } 78 | }, 79 | title = { 80 | Text("Log out?") 81 | }, 82 | text = { 83 | Text("All chats and account information linked with this account will be permanently deleted.") 84 | }, 85 | icon = { 86 | Icon(Icons.Default.ExitToApp, null) 87 | } 88 | ) 89 | } 90 | LazyColumn( 91 | contentPadding = PaddingValues(vertical = 8.dp) 92 | ) { 93 | items(listOfUsers) { 94 | ChatCard( 95 | user = it, 96 | onClickAction = { 97 | navHostController.navigate("chat/${it.uid}") 98 | }, 99 | navigateToProfile = { 100 | navHostController.navigate("profile/${it.uid}") 101 | } 102 | ) 103 | } 104 | if (isUserListLoading) { 105 | item { 106 | Row( 107 | modifier = Modifier 108 | .fillMaxWidth() 109 | .padding(vertical = 24.dp), 110 | horizontalArrangement = Arrangement.Center 111 | ) { 112 | CircularProgressIndicator( 113 | Modifier 114 | .width(24.dp) 115 | .height(24.dp) 116 | ) 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/viewmodel/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.viewmodel 2 | 3 | import android.util.Log 4 | import android.widget.Toast 5 | import androidx.compose.runtime.mutableStateOf 6 | import androidx.lifecycle.ViewModel 7 | import androidx.lifecycle.viewModelScope 8 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions 9 | import com.google.firebase.auth.AuthCredential 10 | import com.google.firebase.auth.ktx.auth 11 | import com.google.firebase.ktx.Firebase 12 | import dagger.hilt.android.lifecycle.HiltViewModel 13 | import kotlinx.coroutines.flow.MutableStateFlow 14 | import kotlinx.coroutines.flow.first 15 | import kotlinx.coroutines.launch 16 | import me.siddheshkothadi.chat.ChatApplication 17 | import me.siddheshkothadi.chat.domain.model.User 18 | import me.siddheshkothadi.chat.domain.model.UserData 19 | import me.siddheshkothadi.chat.domain.repository.UserRepository 20 | import javax.inject.Inject 21 | 22 | @HiltViewModel 23 | class MainViewModel @Inject constructor( 24 | private val context: ChatApplication, 25 | private val userRepository: UserRepository 26 | ) : ViewModel() { 27 | private val clientIDWeb = 28 | "91794365719-fn0c30j3sqfstf3bf50ilkbmtfs3crl0.apps.googleusercontent.com" 29 | private val userData = userRepository.userData 30 | private val firebaseAuth = userRepository.firebaseAuth 31 | val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 32 | .requestIdToken(clientIDWeb) 33 | .requestEmail() 34 | .build() 35 | 36 | val textState = mutableStateOf("") 37 | val users = userRepository.users 38 | val chats = userRepository.chats 39 | val isUserListLoading = userRepository.isUserListLoading 40 | 41 | val isSignedIn = MutableStateFlow(userRepository.firebaseAuth.currentUser != null) 42 | val isSigningIn = MutableStateFlow(false) 43 | val areMessagesLoading = MutableStateFlow(false) 44 | val isLoggingOut = MutableStateFlow(false) 45 | 46 | init { 47 | Firebase.auth.addAuthStateListener { 48 | viewModelScope.launch { 49 | isSigningIn.value = true 50 | val currentUserData = userData.first() 51 | val currentUser = it.currentUser 52 | if (currentUser == null) { 53 | // Not logged in 54 | if(currentUserData.privateKey.isNotEmpty()) { 55 | userRepository.updateUserData(UserData()) 56 | } 57 | } else if(currentUserData.privateKey.isEmpty()) { 58 | // New login 59 | userRepository.deleteAllData(currentUser.uid) 60 | userRepository.saveNewUser(currentUser) 61 | Toast.makeText(context, "Login Successful", Toast.LENGTH_LONG).show() 62 | } 63 | // Else already logged in so do nothing 64 | 65 | isSigningIn.value = false 66 | isSignedIn.value = firebaseAuth.currentUser != null 67 | } 68 | } 69 | } 70 | 71 | fun addTextToChat(text: String, from: String, to: User, key: String) = viewModelScope.launch { 72 | if (text.isNotBlank()) { 73 | userRepository.addChat(text, from, to, key) 74 | textState.value = "" 75 | } 76 | } 77 | 78 | fun setTextState(it: String) { 79 | textState.value = it 80 | } 81 | 82 | fun signWithCredential(credential: AuthCredential) = viewModelScope.launch { 83 | try { 84 | isSigningIn.value = true 85 | userRepository.signWithCredential(credential) 86 | isSignedIn.value = false 87 | } catch (e: Exception) { 88 | Log.e("Auth Error", e.toString()) 89 | isSigningIn.value = false 90 | } 91 | } 92 | 93 | fun signOut() = viewModelScope.launch { 94 | isLoggingOut.value = true 95 | userRepository.signOut(gso) 96 | isLoggingOut.value = false 97 | } 98 | 99 | fun clearChats() { 100 | userRepository.clearChats() 101 | } 102 | 103 | fun getCurrentUserUid(): String { 104 | return firebaseAuth.currentUser?.uid ?: "" 105 | } 106 | 107 | fun getCurrentUser(): User { 108 | return User( 109 | displayName = firebaseAuth.currentUser?.displayName.toString(), 110 | photoUrl = firebaseAuth.currentUser?.photoUrl.toString(), 111 | email = firebaseAuth.currentUser?.email.toString() 112 | ) 113 | } 114 | 115 | fun addMessageEventListener(key: String) { 116 | userRepository.addMessageEventListener(key) 117 | } 118 | 119 | fun removeMessageEventListener(key: String) { 120 | userRepository.removeMessageEventListener(key) 121 | } 122 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.activity.viewModels 7 | import androidx.compose.foundation.isSystemInDarkTheme 8 | import androidx.compose.foundation.layout.fillMaxSize 9 | import androidx.compose.material3.ExperimentalMaterial3Api 10 | import androidx.compose.material3.Surface 11 | import androidx.compose.runtime.SideEffect 12 | import androidx.compose.runtime.collectAsState 13 | import androidx.compose.runtime.getValue 14 | import androidx.compose.ui.Modifier 15 | import androidx.compose.ui.graphics.Color 16 | import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen 17 | import androidx.core.view.WindowCompat 18 | import com.google.accompanist.navigation.animation.AnimatedNavHost 19 | import com.google.accompanist.navigation.animation.composable 20 | import com.google.accompanist.navigation.animation.rememberAnimatedNavController 21 | import com.google.accompanist.systemuicontroller.rememberSystemUiController 22 | import dagger.hilt.android.AndroidEntryPoint 23 | import me.siddheshkothadi.chat.ui.screens.* 24 | import me.siddheshkothadi.chat.ui.theme.ChatTheme 25 | import me.siddheshkothadi.chat.ui.viewmodel.MainViewModel 26 | 27 | @AndroidEntryPoint 28 | class MainActivity : ComponentActivity() { 29 | private val mainViewModel: MainViewModel by viewModels() 30 | 31 | @OptIn( 32 | ExperimentalMaterial3Api::class, 33 | androidx.compose.animation.ExperimentalAnimationApi::class 34 | ) 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | WindowCompat.setDecorFitsSystemWindows(window, false) 37 | installSplashScreen() 38 | super.onCreate(savedInstanceState) 39 | 40 | setContent { 41 | val systemUiController = rememberSystemUiController() 42 | val useDarkIcons = !isSystemInDarkTheme() 43 | val navController = rememberAnimatedNavController() 44 | val isSignedIn by mainViewModel.isSignedIn.collectAsState() 45 | val users by mainViewModel.users.collectAsState(initial = emptyList()) 46 | 47 | SideEffect { 48 | systemUiController.setSystemBarsColor( 49 | color = Color.Transparent, 50 | darkIcons = useDarkIcons, 51 | ) 52 | } 53 | 54 | ChatTheme { 55 | Surface( 56 | modifier = Modifier.fillMaxSize() 57 | ) { 58 | AnimatedNavHost( 59 | navController, 60 | startDestination = if (isSignedIn) "chatList" else "login" 61 | ) { 62 | composable( 63 | "login" 64 | ) { 65 | LoginScreen(mainViewModel) 66 | } 67 | 68 | composable( 69 | "chatList" 70 | ) { 71 | ChatListScreen(navController, mainViewModel) 72 | } 73 | 74 | composable( 75 | "myProfile" 76 | ) { 77 | MyProfile(navController, mainViewModel) 78 | } 79 | 80 | composable( 81 | "profile/{uid}" 82 | ) { 83 | val uid = 84 | navController.currentBackStackEntry?.arguments?.getString("uid") 85 | 86 | if (uid != null) { 87 | val user = users.first { 88 | it.uid == uid 89 | } 90 | ProfileScreen(navController, user) 91 | } 92 | } 93 | 94 | composable( 95 | "chat/{uid}" 96 | ) { 97 | val uid = 98 | navController.currentBackStackEntry?.arguments?.getString("uid") 99 | 100 | if (uid != null) { 101 | val user = users.first { 102 | it.uid == uid 103 | } 104 | ChatScreen( 105 | navHostController = navController, 106 | mainViewModel = mainViewModel, 107 | user = user, 108 | ) 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/components/ChatBubble.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.components 2 | 3 | import androidx.compose.foundation.layout.Column 4 | import androidx.compose.foundation.layout.fillMaxWidth 5 | import androidx.compose.foundation.layout.padding 6 | import androidx.compose.foundation.layout.widthIn 7 | import androidx.compose.foundation.shape.RoundedCornerShape 8 | import androidx.compose.foundation.text.ClickableText 9 | import androidx.compose.foundation.text.selection.SelectionContainer 10 | import androidx.compose.material3.LocalContentColor 11 | import androidx.compose.material3.MaterialTheme 12 | import androidx.compose.material3.MaterialTheme.colorScheme 13 | import androidx.compose.material3.Surface 14 | import androidx.compose.material3.Text 15 | import androidx.compose.runtime.Composable 16 | import androidx.compose.ui.Alignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.draw.alpha 19 | import androidx.compose.ui.platform.LocalUriHandler 20 | import androidx.compose.ui.text.AnnotatedString 21 | import androidx.compose.ui.text.SpanStyle 22 | import androidx.compose.ui.text.buildAnnotatedString 23 | import androidx.compose.ui.text.style.TextAlign 24 | import androidx.compose.ui.text.style.TextDecoration 25 | import androidx.compose.ui.tooling.preview.Preview 26 | import androidx.compose.ui.unit.dp 27 | import com.google.accompanist.flowlayout.FlowCrossAxisAlignment 28 | import com.google.accompanist.flowlayout.FlowRow 29 | import com.google.accompanist.flowlayout.MainAxisAlignment 30 | 31 | private val OtherChatBubbleShape = RoundedCornerShape(4.dp, 20.dp, 20.dp, 20.dp) 32 | private val MyChatBubbleShape = RoundedCornerShape(20.dp, 4.dp, 20.dp, 20.dp) 33 | 34 | @Composable 35 | fun ChatBubble( 36 | message: String, 37 | isUserMe: Boolean, 38 | time: String = "19:04" 39 | ) { 40 | val backgroundBubbleColor = if (isUserMe) { 41 | colorScheme.primary 42 | } else { 43 | colorScheme.surfaceVariant 44 | } 45 | 46 | val uriHandler = LocalUriHandler.current 47 | 48 | val styledMessage = messageFormatter( 49 | text = message, 50 | primary = isUserMe 51 | ) 52 | 53 | Column( 54 | modifier = Modifier 55 | .fillMaxWidth() 56 | .padding(3.dp), 57 | horizontalAlignment = if(isUserMe) Alignment.End else Alignment.Start 58 | ) { 59 | Surface( 60 | color = backgroundBubbleColor, 61 | shape = if(isUserMe) MyChatBubbleShape else OtherChatBubbleShape, 62 | modifier = Modifier.widthIn(20.dp, 228.dp) 63 | ) { 64 | FlowRow( 65 | mainAxisAlignment = MainAxisAlignment.End, 66 | crossAxisAlignment = FlowCrossAxisAlignment.End 67 | ) { 68 | SelectionContainer { 69 | ClickableText( 70 | text = styledMessage, 71 | style = MaterialTheme.typography.bodyLarge.copy(color = LocalContentColor.current), 72 | modifier = Modifier.padding(vertical = 12.dp, horizontal = 16.dp), 73 | onClick = { 74 | styledMessage.getStringAnnotations(start = it, end = it).firstOrNull()?.let { annotation -> 75 | when(annotation.tag) { 76 | SymbolAnnotationType.LINK.name -> uriHandler.openUri(annotation.item) 77 | else -> Unit 78 | } 79 | } 80 | } 81 | ) 82 | } 83 | Text( 84 | text = time, 85 | modifier = Modifier 86 | .padding(end = 20.dp, bottom = 10.dp) 87 | .alpha(0.4f), 88 | textAlign = TextAlign.Right, 89 | style = MaterialTheme.typography.labelSmall 90 | ) 91 | } 92 | } 93 | } 94 | } 95 | 96 | private val symbolPattern by lazy { 97 | Regex("(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]") 98 | } 99 | 100 | typealias StringAnnotation = AnnotatedString.Range 101 | // Pair returning styled content and annotation for ClickableText when matching syntax token 102 | typealias SymbolAnnotation = Pair 103 | 104 | // Accepted annotations for the ClickableTextWrapper 105 | enum class SymbolAnnotationType { 106 | LINK 107 | } 108 | 109 | @Composable 110 | private fun messageFormatter( 111 | text: String, 112 | primary: Boolean 113 | ): AnnotatedString { 114 | val tokens = symbolPattern.findAll(text) 115 | 116 | return buildAnnotatedString { 117 | var cursorPosition = 0 118 | 119 | for (token in tokens) { 120 | append(text.slice(cursorPosition until token.range.first)) 121 | 122 | val (annotatedString, stringAnnotation) = SymbolAnnotation( 123 | AnnotatedString( 124 | text = token.value, 125 | spanStyle = SpanStyle( 126 | // color = if (primary) colorScheme.inversePrimary else colorScheme.primary, 127 | textDecoration = TextDecoration.Underline 128 | ) 129 | ), 130 | StringAnnotation( 131 | item = token.value, 132 | start = token.range.first, 133 | end = token.range.last, 134 | tag = SymbolAnnotationType.LINK.name 135 | ) 136 | ) 137 | append(annotatedString) 138 | 139 | if (stringAnnotation != null) { 140 | val (item, start, end, tag) = stringAnnotation 141 | addStringAnnotation(tag = tag, start = start, end = end, annotation = item) 142 | } 143 | 144 | cursorPosition = token.range.last + 1 145 | } 146 | 147 | if (!tokens.none()) { 148 | append(text.slice(cursorPosition..text.lastIndex)) 149 | } else { 150 | append(text) 151 | } 152 | } 153 | } 154 | 155 | @Preview(showBackground = true) 156 | @Composable 157 | fun preview() { 158 | ChatBubble("Hi there I'm using WhatsApp!", true) 159 | } 160 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/ui/screens/ChatScreen.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.ui.screens 2 | 3 | import androidx.compose.foundation.clickable 4 | import androidx.compose.foundation.layout.* 5 | import androidx.compose.foundation.shape.CircleShape 6 | import androidx.compose.foundation.shape.RoundedCornerShape 7 | import androidx.compose.foundation.text.BasicTextField 8 | import androidx.compose.foundation.text.KeyboardOptions 9 | import androidx.compose.material.icons.Icons 10 | import androidx.compose.material.icons.filled.ArrowBack 11 | import androidx.compose.material.icons.filled.Send 12 | import androidx.compose.material3.* 13 | import androidx.compose.runtime.Composable 14 | import androidx.compose.runtime.collectAsState 15 | import androidx.compose.runtime.getValue 16 | import androidx.compose.ui.Alignment 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.draw.alpha 19 | import androidx.compose.ui.draw.clip 20 | import androidx.compose.ui.graphics.SolidColor 21 | import androidx.compose.ui.text.input.ImeAction 22 | import androidx.compose.ui.text.input.KeyboardType 23 | import androidx.compose.ui.text.style.TextOverflow 24 | import androidx.compose.ui.unit.dp 25 | import androidx.compose.ui.unit.sp 26 | import androidx.navigation.NavHostController 27 | import coil.compose.AsyncImage 28 | import me.siddheshkothadi.chat.domain.model.User 29 | import me.siddheshkothadi.chat.ui.components.Messages 30 | import me.siddheshkothadi.chat.ui.viewmodel.MainViewModel 31 | 32 | @OptIn(ExperimentalMaterial3Api::class) 33 | @Composable 34 | fun ChatScreen( 35 | navHostController: NavHostController, 36 | mainViewModel: MainViewModel, 37 | user: User 38 | ) { 39 | val areMessagesLoading by mainViewModel.areMessagesLoading.collectAsState() 40 | val currentUserUid = mainViewModel.getCurrentUserUid() 41 | val key = 42 | if (currentUserUid < user.uid) "${currentUserUid}__join__${user.uid}" else "${user.uid}__join__${currentUserUid}" 43 | 44 | Scaffold( 45 | topBar = { 46 | Surface(tonalElevation = 2.dp) { 47 | CenterAlignedTopAppBar( 48 | title = { 49 | Text( 50 | text = user.displayName, 51 | fontSize = 20.sp, 52 | maxLines = 1, 53 | overflow = TextOverflow.Ellipsis 54 | ) 55 | }, 56 | modifier = Modifier.windowInsetsPadding( 57 | WindowInsets.statusBars.only( 58 | WindowInsetsSides.Top 59 | ) 60 | ), 61 | navigationIcon = { 62 | IconButton(onClick = { 63 | navHostController.popBackStack() 64 | }) { 65 | Icon(Icons.Default.ArrowBack, null) 66 | } 67 | }, 68 | actions = { 69 | AsyncImage( 70 | model = user.photoUrl, 71 | contentDescription = "User Photo", 72 | modifier = Modifier 73 | .height(30.dp) 74 | .width(30.dp) 75 | .clip(CircleShape) 76 | .clickable { 77 | navHostController.navigate("profile/${user.uid}") 78 | } 79 | ) 80 | Spacer(Modifier.width(15.dp)) 81 | } 82 | ) 83 | } 84 | }, 85 | ) { 86 | val textState by mainViewModel.textState 87 | 88 | Column(Modifier.fillMaxSize()) { 89 | Messages( 90 | modifier = Modifier 91 | .fillMaxWidth() 92 | .weight(1f), 93 | mainViewModel = mainViewModel, 94 | fromUid = currentUserUid, 95 | key = key 96 | ) 97 | Surface( 98 | tonalElevation = 2.dp, 99 | shape = RoundedCornerShape(24.dp), 100 | modifier = Modifier 101 | .navigationBarsPadding() 102 | .imePadding() 103 | .padding(horizontal = 12.dp, vertical = 8.dp) 104 | ) { 105 | Row( 106 | verticalAlignment = Alignment.CenterVertically, 107 | horizontalArrangement = Arrangement.SpaceBetween 108 | ) { 109 | Spacer(Modifier.width(10.dp)) 110 | CircularProgressIndicator( 111 | modifier = Modifier 112 | .height(20.dp) 113 | .width(20.dp) 114 | .alpha(if (areMessagesLoading) 1f else 0f) 115 | ) 116 | Box(Modifier 117 | .weight(1f) 118 | .padding(horizontal = 0.dp, vertical = 18.dp)) { 119 | if(textState.isEmpty()) { 120 | Text( 121 | text = "Message", 122 | modifier = Modifier.alpha(0.5f) 123 | ) 124 | } 125 | BasicTextField( 126 | value = textState, 127 | onValueChange = { mainViewModel.setTextState(it) }, 128 | keyboardOptions = KeyboardOptions( 129 | keyboardType = KeyboardType.Text, 130 | imeAction = ImeAction.Default 131 | ), 132 | maxLines = 3, 133 | cursorBrush = SolidColor(LocalContentColor.current), 134 | textStyle = LocalTextStyle.current.copy( 135 | color = LocalContentColor.current, 136 | fontSize = 16.sp 137 | ) 138 | ) 139 | } 140 | IconButton(onClick = { 141 | mainViewModel.addTextToChat( 142 | key = key, 143 | text = textState, 144 | from = currentUserUid, 145 | to = user 146 | ) 147 | }) { 148 | Icon( 149 | Icons.Default.Send, 150 | "Send", 151 | tint = if (textState.isBlank()) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.primary 152 | ) 153 | } 154 | } 155 | } 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /app/src/main/java/me/siddheshkothadi/chat/data/repository/UserRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package me.siddheshkothadi.chat.data.repository 2 | 3 | import android.widget.Toast 4 | import com.google.android.gms.auth.api.signin.GoogleSignInOptions 5 | import com.google.firebase.auth.AuthCredential 6 | import com.google.firebase.auth.FirebaseAuth 7 | import com.google.firebase.auth.FirebaseUser 8 | import kotlinx.coroutines.flow.* 9 | import kotlinx.coroutines.tasks.await 10 | import me.siddheshkothadi.chat.ChatApplication 11 | import me.siddheshkothadi.chat.domain.model.Message 12 | import me.siddheshkothadi.chat.domain.model.User 13 | import me.siddheshkothadi.chat.domain.model.UserData 14 | import me.siddheshkothadi.chat.domain.repository.DataStoreRepository 15 | import me.siddheshkothadi.chat.domain.repository.FirebaseRepository 16 | import me.siddheshkothadi.chat.domain.repository.UserRepository 17 | import me.siddheshkothadi.chat.utils.AESUtils 18 | import me.siddheshkothadi.chat.utils.RSAUtils 19 | import java.text.SimpleDateFormat 20 | import java.util.* 21 | 22 | class UserRepositoryImpl( 23 | private val context: ChatApplication, 24 | private val firebaseRepository: FirebaseRepository, 25 | private val dataStoreRepository: DataStoreRepository, 26 | ) : UserRepository { 27 | private fun getDateValue(date: String): String { 28 | val monthToValue = hashMapOf( 29 | "Jan" to "01", 30 | "Feb" to "02", 31 | "Mar" to "03", 32 | "Apr" to "04", 33 | "May" to "05", 34 | "Jun" to "06", 35 | "Jul" to "07", 36 | "Aug" to "08", 37 | "Sep" to "09", 38 | "Oct" to "10", 39 | "Nov" to "11", 40 | "Dec" to "12", 41 | ) 42 | val (day, month, year) = date.split("-") 43 | 44 | return year + monthToValue[month] + day 45 | } 46 | 47 | private suspend fun getCurrentUserData(): UserData { 48 | return userData.first() 49 | } 50 | 51 | private fun createNewUser(firebaseUser: FirebaseUser): UserData { 52 | val (publicKeyRSA, privateKeyRSA) = RSAUtils.getKeyPair() 53 | val secretKeyAES = AESUtils.getSecretKey() 54 | 55 | val newUser = User( 56 | uid = firebaseUser.uid, 57 | displayName = firebaseUser.displayName.toString(), 58 | email = firebaseUser.email.toString(), 59 | photoUrl = firebaseUser.photoUrl.toString(), 60 | publicKey = publicKeyRSA 61 | ) 62 | 63 | return UserData( 64 | user = newUser, 65 | privateKey = privateKeyRSA, 66 | secretKey = secretKeyAES 67 | ) 68 | } 69 | 70 | override val isUserListLoading: Flow 71 | get() = firebaseRepository.isUserListLoading 72 | 73 | override val userData: Flow 74 | get() = dataStoreRepository.userData 75 | 76 | override suspend fun deleteAllData(uid: String) { 77 | firebaseRepository.deleteChatsOfUser(uid) 78 | firebaseRepository.deleteUser(uid) 79 | } 80 | 81 | override suspend fun signOut(gso: GoogleSignInOptions) { 82 | dataStoreRepository.updateUserData(UserData()) 83 | firebaseRepository.signOut(gso) 84 | Toast.makeText(context, "Logged Out", Toast.LENGTH_LONG).show() 85 | } 86 | 87 | override fun addMessageEventListener(key: String) { 88 | firebaseRepository.addMessageEventListener(key) 89 | } 90 | 91 | override fun removeMessageEventListener(key: String) { 92 | firebaseRepository.removeMessageEventListener(key) 93 | } 94 | 95 | override suspend fun updateUserData(userData: UserData) { 96 | return dataStoreRepository.updateUserData(userData) 97 | } 98 | 99 | override fun clearChats() { 100 | firebaseRepository.clearChats() 101 | } 102 | 103 | override suspend fun addChat(text: String, from: String, to: User, key: String) { 104 | val timestamp = System.currentTimeMillis().toString() 105 | val timeISTString = SimpleDateFormat("dd-MMM-yyyy HH:mm", Locale.ENGLISH).format(Date()) 106 | val (date, time) = timeISTString.split(" ") 107 | 108 | val chatList = firebaseRepository.encryptedChats.first()[date]?.toMutableList() ?: mutableListOf() 109 | val currentUserData = getCurrentUserData() 110 | val encryptedText = AESUtils.encrypt(text, currentUserData.secretKey) 111 | val encryptedSecretKey = RSAUtils.encrypt(currentUserData.secretKey, to.publicKey) 112 | 113 | chatList.add( 114 | Message( 115 | from = from, 116 | to = to.uid, 117 | timestamp = timestamp, 118 | date = date, 119 | time = time, 120 | content = encryptedText, 121 | secretKey = encryptedSecretKey 122 | ) 123 | ) 124 | 125 | firebaseRepository.addChat(key, date, chatList) 126 | } 127 | 128 | override suspend fun saveNewUser(firebaseUser: FirebaseUser) { 129 | val newUserData = createNewUser(firebaseUser) 130 | firebaseRepository.saveNewUser(newUserData.user) 131 | dataStoreRepository.updateUserData(newUserData) 132 | } 133 | 134 | override suspend fun signWithCredential(credential: AuthCredential) { 135 | firebaseRepository.auth.signInWithCredential(credential).await() 136 | } 137 | 138 | override suspend fun getCurrentUser(): User { 139 | return getCurrentUserData().user 140 | } 141 | 142 | override val chats: Flow>> 143 | get() = firebaseRepository.encryptedChats.map { dateToMessages -> 144 | val hashMap = hashMapOf>() 145 | val loggedInUser = getCurrentUserData() 146 | 147 | dateToMessages.forEach { mapEntry -> 148 | hashMap[mapEntry.key] = mapEntry.value.map { 149 | val receiver = it.to 150 | val decryptionSecretKey = 151 | if (receiver == loggedInUser.user.uid) RSAUtils.decrypt( 152 | it.secretKey, 153 | loggedInUser.privateKey 154 | ) else loggedInUser.secretKey 155 | 156 | val decryptedText = AESUtils.decrypt(it.content, decryptionSecretKey) 157 | 158 | Message( 159 | from = it.from, 160 | to = it.to, 161 | date = it.date, 162 | time = it.time, 163 | content = decryptedText, 164 | ) 165 | }.reversed() 166 | } 167 | 168 | hashMap.toSortedMap(compareByDescending { getDateValue(it) }) 169 | } 170 | 171 | override val users: Flow> 172 | get() = firebaseRepository.users.map { list -> 173 | val filteredList = list.filter { 174 | it.uid != getCurrentUser().uid 175 | } 176 | return@map filteredList 177 | } 178 | 179 | override val firebaseAuth: FirebaseAuth 180 | get() = firebaseRepository.auth 181 | } -------------------------------------------------------------------------------- /app/src/main/res/raw/chat_dark.json: -------------------------------------------------------------------------------- 1 | {"v":"5.1.13","fr":60,"ip":0,"op":120,"w":1200,"h":1200,"nm":"drawkit-grape-pack-illustration-4-prepped-for-animation","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"bottom line","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[606.153,951.891,0],"ix":2},"a":{"a":0,"k":[560.16,2.312,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.312,2.312],[1118.007,2.312]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"fig1 - right arm","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.621,163.791,0],"ix":2},"a":{"a":0,"k":[162.366,155.475,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-19.531,-11.419],[-3.385,-7.779]],"o":[[19.338,-16.605],[7.775,4.546],[0,0]],"v":[[-38.748,10.899],[22.271,-3.709],[38.748,15.128]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[127.894,25.51],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[7.504,-1.961],[5.939,15.66],[-12.924,18.914]],"o":[[-7.503,35.83],[-26.793,1.849],[-2.177,-5.738],[0,0]],"v":[[65.488,-26.02],[31.119,46.587],[-63.311,-5.907],[-44.984,-48.436]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[102.991,120.322],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-49.724,-29.074],[13.634,-3.565],[5.938,15.658]],"o":[[50.387,29.461],[-26.794,1.848],[-5.939,-15.66]],"v":[[33.019,-58.942],[16.965,86.167],[-77.466,33.674]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-197,466.155],[1003,466.155],[1003,-733.845],[-197,-733.845]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-197,-733.845],[1003,-733.845],[1003,466.155],[-197,466.155]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.11372549019607843,0.4549019607843137,0.9607843137254902,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[120.282,88.266],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.746,-2.334],[-72.848,-33.623],[-6.003,-0.201],[0,-16.212]],"o":[[-4.557,7.419],[13.997,4.089],[6.823,-7.798],[20.431,0.039],[0,0]],"v":[[-82.412,-70.232],[-117.316,-4.561],[52.672,51.42],[74.886,43.414],[117.316,70.233]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[202.79,235.983],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[8.872,-26.105]],"o":[[-1.735,3.765],[0,0]],"v":[[9.531,-26.66],[-9.531,26.66]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[37.663,150.574],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.638,-3.404],[-6.803,-3.804],[-47.014,-10.162]],"o":[[-6.663,20.984],[1.745,9.32],[3.764,2.101],[0,0]],"v":[[-45.087,-46.434],[-56.006,-4.765],[-38.212,24.785],[56.644,46.434]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[61.268,259.892],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-1.734,-9.261],[-6.804,-3.8],[-37.149,-7.977],[0,0],[17.696,0.034],[6.821,-7.796],[21.981,5.724],[0,0],[-3.076,6.302],[0.528,0.314],[0,0],[0.006,-0.013]],"o":[[0,0],[-4.404,9.874],[1.745,9.32],[3.111,1.74],[0,0],[-4.577,-11.662],[-6.003,-0.199],[-67.5,-31.153],[0,0],[7.309,-13.98],[-11.705,-5.949],[0,0],[-0.006,0.012],[-0.001,-0.002]],"v":[[-113.747,-88.579],[-113.62,-88.25],[-155.764,42.641],[-137.964,72.193],[-66.556,88.579],[157.498,88.579],[116.098,67.28],[93.883,75.287],[-71.21,20.604],[-73.62,14.377],[-41.201,-46.359],[-113.469,-88.411],[-113.51,-88.521],[-113.54,-88.457]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-240.485,336.317],[959.515,336.317],[959.515,-863.683],[-240.485,-863.683]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-240.485,-863.683],[959.515,-863.683],[959.515,336.317],[-240.485,336.317]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[163.767,218.104],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"face","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[89.428,146.349,0],"ix":2},"a":{"a":0,"k":[27.983,34.24,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.238,4.317],[-8.476,-2.16]],"o":[[-3.519,-0.479],[-4.159,1.999],[0,0]],"v":[[11.596,1.638],[-5.357,-9.155],[-3.12,9.155]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[20.788,54.7],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.117,-3.68]],"o":[[0.801,5.677],[0,0]],"v":[[-5.278,-9.436],[5.278,9.436]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[40.459,33.15],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.559],[-1.887,0],[0,-3.558],[1.889,0]],"o":[[0,-3.558],[1.889,0],[0,3.559],[-1.887,0]],"v":[[-3.417,-0.001],[-0.001,-6.443],[3.417,-0.001],[-0.001,6.443]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-353.704,663.906],[846.296,663.906],[846.296,-536.094],[-353.704,-536.094]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-353.704,-536.094],[846.296,-536.094],[846.296,663.906],[-353.704,663.906]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[52.299,9.271],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.559],[-1.888,0],[0,-3.558],[1.888,0]],"o":[[0,-3.558],[1.888,0],[0,3.559],[-1.888,0]],"v":[[-3.417,0],[0.001,-6.443],[3.417,0],[0.001,6.443]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-305.072,666.484],[894.928,666.484],[894.928,-533.516],[-305.072,-533.516]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-305.072,-533.516],[894.928,-533.516],[894.928,666.484],[-305.072,666.484]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[3.667,6.693],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":4,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"head","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[157.312,-88.907,0],"ix":2},"a":{"a":0,"k":[71.815,133.642,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.118,0],[0,11.374],[-11.373,0],[-3.45,-6.537]],"o":[[-1.069,0.172],[-11.373,0],[0,-11.372],[7.907,0],[0,0]],"v":[[4.471,20.332],[1.185,20.593],[-19.409,-0.001],[1.185,-20.593],[19.409,-9.599]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[24.041,132.688],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.117,0],[0,11.372],[-11.374,0],[-3.45,-6.537]],"o":[[-1.071,0.172],[-11.374,0],[0,-11.374],[7.907,0],[0,0]],"v":[[4.471,20.332],[1.186,20.593],[-19.409,0.001],[1.186,-20.593],[19.409,-9.599]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-266.373,650.622],[933.627,650.622],[933.627,-549.378],[-266.373,-549.378]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-266.373,-549.378],[933.627,-549.378],[933.627,650.622],[-266.373,650.622]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[26.413,134.664],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-3.953,12.498]],"o":[[0.598,-17.423],[0,0]],"v":[[-3.72,22.489],[3.72,-22.489]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[8.345,81.496],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.466,0],[0.349,-2.914],[-14.92,5.726]],"o":[[8.241,-17.286],[8.622,0],[3.15,-3.225],[0,0]],"v":[[-29.117,15.856],[-6.784,-10.593],[-1.306,1.41],[29.117,-15.856]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[47.764,26.337],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.553,0],[0,-9.459],[4.73,-4.476],[-4.346,0],[0,-7.285],[7.206,-2.536]],"o":[[2.594,-0.344],[12.526,0],[0,9.459],[6.264,-2.812],[9.161,0],[0,12.789],[0,0]],"v":[[-20.93,-44.573],[-13.196,-45.108],[9.427,-27.213],[-2.333,5.382],[10.065,1.547],[20.93,18.546],[2.967,45.108]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[117.804,49.733],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.822,0],[0,0],[0,-2.557],[4.727,-0.135],[16.169,0],[0,-6.968],[0,-3.233],[1.373,-0.579]],"o":[[-0.996,0.352],[-6.774,0],[2.557,6.264],[0,2.557],[-11.514,0.328],[-4.212,0],[0,4.703],[0,1.291],[0,0]],"v":[[39.107,-7.318],[36.363,-6.78],[18.213,-18.158],[22.304,-7.548],[14.38,-2.053],[-26.016,-18.465],[-38.458,-5.73],[-36.988,15.725],[-39.107,18.465]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[81.664,102.158],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.338,-18.375]],"o":[[0.72,3.441],[0,0]],"v":[[-0.719,-18.887],[0.381,18.887]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[20.327,171.841],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.461,-7.777],[-13.083,-1.967]],"o":[[-0.916,12.049],[4.688,5.498],[0,0]],"v":[[-10.249,-21.389],[-15.171,9.718],[15.171,21.389]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[29.891,235.885],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.592,6.692]],"o":[[-0.638,-11.794],[0,0]],"v":[[-0.338,24.614],[0.976,-24.614]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[74.984,232.358],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-14.658],[0.366,-3.348]],"o":[[5.829,11.518],[0,3.474],[0,0]],"v":[[-4.305,-24.388],[4.305,14.147],[3.749,24.388]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[124.997,119.249],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[23.068,0],[9.174,7.333]],"o":[[-9.777,24.173],[-11.68,0],[0,0]],"v":[[42.288,-20.369],[-10.543,20.369],[-42.288,8.789]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[80.63,187.395],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.664,-5.84],[-25.394,4.519],[1.275,-5.092],[-12.704,0.107],[0,-4.457],[2.729,-4.365],[-3.364,0],[0,-3.911],[7.174,0],[2.819,3.911],[-0.041,-4.464],[3.184,0],[15.307,0],[0,-4.114],[1.299,-0.673],[15.688,1.006]],"o":[[-6.784,-0.414],[-5.084,-37.58],[4.366,0.172],[15.933,-14.533],[16.47,0],[0,11.291],[4.355,-2.316],[8.47,0],[0,13.66],[-3.366,0],[0.993,2.904],[0.031,3.684],[-8.439,0],[-5.093,0],[0,4.115],[-3.951,3.114],[0,0]],"v":[[-46.811,48.365],[-64.529,59.911],[-26.507,-48.247],[-22.866,-37.196],[35.701,-59.911],[57.986,-42.47],[47.864,-9.959],[59.073,-13.12],[69.613,3.929],[47.974,31.49],[32.488,22.338],[34.624,30.52],[26.118,36.226],[-14.359,19.754],[-25.88,31.166],[-25.02,55.389],[-46.492,48.236]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-313.727,717.165],[886.273,717.165],[886.273,-482.835],[-313.727,-482.835]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-313.727,-482.835],[886.273,-482.835],[886.273,717.165],[-313.727,717.165]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933000033509,0.795999983245,0.33300000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[73.767,68.12],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":4,"cix":2,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.643,13.848],[0.727,6.632],[-14.472,12.195],[-13.132,-0.937],[0,-47.611],[10.145,-0.32],[0,-10.251]],"o":[[7.337,-19.944],[-0.877,-8.004],[14.473,-12.193],[13.132,0.938],[0,47.611],[-1.388,10.572],[-4.164,3.988]],"v":[[-56.836,91.107],[-51.361,-2.514],[-43.793,-80.438],[6.056,-105.36],[58.264,-17.488],[4.822,53.187],[3.54,102.31]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-316.526,624.55],[883.474,624.55],[883.474,-575.45],[-316.526,-575.45]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-316.526,-575.45],[883.474,-575.45],[883.474,624.55],[-316.526,624.55]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[76.566,160.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":4,"cix":2,"ix":13,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"fig1- torso","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250.766,932.868,0],"ix":2},"a":{"a":0,"k":[96.302,295.604,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-11.854,5.036]],"o":[[9.557,-9.437],[0,0]],"v":[[-16.032,10.988],[16.032,-10.988]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[87.379,15.613],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-9.514,-30.208]],"o":[[21.524,11.455],[0,0]],"v":[[-22.852,-32.794],[22.852,32.794]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[190.695,39.059],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[8.557,-38.043]],"o":[[2.995,57.156],[0,0]],"v":[[4.319,-77.363],[-7.314,77.363]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[223.431,237.221],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[103.317,0],[-3.52,-97.841],[0,0]],"o":[[-120.896,0],[0,0],[19.726,-96.885]],"v":[[20.736,-154.354],[-120.533,154.354],[101.053,154.354]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-278.766,402.091],[921.234,402.091],[921.234,-797.909],[-278.766,-797.909]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-278.766,-797.909],[921.234,-797.909],[921.234,402.091],[-278.766,402.091]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.11372549019607843,0.4549019607843137,0.9607843137254902,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[124.302,160.646],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":4,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"fig1 - left arm","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[467.155,829.274,0],"ix":2},"a":{"a":0,"k":[94.351,91.491,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-8.451,5.56],[-3.171,0.565]],"o":[[2.738,-2.302],[7.851,-5.163],[0,0]],"v":[[-19.258,12.197],[0.412,-1.821],[19.258,-12.197]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[156.375,47.017],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-9.52,6.164],[-3.57,0.627]],"o":[[3.082,-2.551],[8.841,-5.726],[0,0]],"v":[[-21.689,13.525],[0.465,-2.018],[21.689,-13.525]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[155.109,33.622],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-9.52,6.164],[-3.57,0.627]],"o":[[3.082,-2.553],[8.841,-5.727],[0,0]],"v":[[-21.69,13.526],[0.465,-2.018],[21.69,-13.526]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[147.433,24.693],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[9.039,-6.446],[12.702,-10.795]],"o":[[-9.901,5.047],[-2.579,1.841],[0,0]],"v":[[31.721,-19.791],[-6.762,-0.937],[-31.721,19.791]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[124.794,80.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.603,-3.226]],"o":[[-22.646,19.512],[0,0]],"v":[[23.371,-20.265],[-23.371,20.265]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[27.995,156.672],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.976,6.302],[-4.344,3.824],[-2.586,-2.853],[5.624,-7.505],[-8.817,3.06]],"o":[[8.121,-4.275],[5.975,-6.305],[4.343,-3.824],[2.586,2.851],[10.611,-11.015],[0,0]],"v":[[-72.639,52.023],[5.745,-6.082],[26.001,-42.059],[35.826,-45.128],[28.247,-20.47],[72.639,-52.023]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[83.517,56.648],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.196,3.961],[-3.8,4.809],[-1.147,1.793],[-0.913,-0.774],[1.075,-2.474],[-4.04,-1.267],[18.254,-9.445],[2.624,-2.289],[2.584,-1.844]],"o":[[7.198,-3.961],[3.798,-4.811],[1.147,-1.793],[5.598,4.752],[5.212,-4.756],[29.041,9.119],[-4.998,2.585],[-2.623,2.286],[-1.427,-6.612]],"v":[[-82.374,18.882],[-1.882,-41.32],[16.704,-75.404],[26.06,-79.775],[21.61,-56.37],[63.832,-85.639],[63.754,-28.316],[28.788,-12.999],[-91.446,86.906]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-468.383,366.39],[731.617,366.39],[731.617,-833.61],[-468.383,-833.61]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-468.383,-833.61],[731.617,-833.61],[731.617,366.39],[-468.383,366.39]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[95.579,95.827],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":4,"cix":2,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"speech1 - lines","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[86.535,42.025,0],"ix":2},"a":{"a":0,"k":[64.315,16.965,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.312,31.618],[45.603,31.618]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2.312,2.312],[126.317,2.312]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":90,"s":[100],"e":[0]},{"t":91}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":30,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":50,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":60,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":90,"s":[100],"e":[0]},{"t":91}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"speech1 - box","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":10,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":30,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[100],"e":[0]},{"t":90}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.101,"y":1},"o":{"x":0.333,"y":0},"n":"0p101_1_0p333_0","t":0,"s":[529.329,622.151,0],"e":[529.329,437.151,0],"to":[0,-30.8333339691162,0],"ti":[0,55.5,0]},{"i":{"x":0.038,"y":1},"o":{"x":0.293,"y":0},"n":"0p038_1_0p293_0","t":60,"s":[529.329,437.151,0],"e":[529.329,289.151,0],"to":[0,-55.5,0],"ti":[0,24.6666660308838,0]},{"t":119}],"ix":2},"a":{"a":0,"k":[91.19,67.252,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[56.656,-31.241],[-56.656,-31.241],[-56.656,31.241]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[61.348,35.866],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-85.415,38.787],[-85.448,60.786],[-39.957,14.31],[85.448,14.31],[85.448,-60.786],[67.466,-60.786]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[90.073,65.411],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-84.985,-61.052],[-84.985,-1.991],[-85.36,-1.996],[-85.36,61.052],[-41.308,13.953],[85.36,13.953],[85.36,-61.052]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[96.769,73.203],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"speech2 - lines","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[93.612,42.025,0],"ix":2},"a":{"a":0,"k":[64.315,16.965,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[46.393,31.618],[3.102,31.618]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[126.318,2.312],[2.313,2.312]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":50,"s":[100],"e":[0]},{"t":70}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":90,"s":[100],"e":[0]},{"t":110}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"speech2 - box","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":40,"s":[0],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":60,"s":[100],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":100,"s":[100],"e":[0]},{"t":120}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.057,"y":1},"o":{"x":0.333,"y":0},"n":"0p057_1_0p333_0","t":30,"s":[744.375,584.519,0],"e":[744.375,336.519,0],"to":[0,-41.3333320617676,0],"ti":[0,59.5,0]},{"i":{"x":0.057,"y":1},"o":{"x":0.333,"y":0},"n":"0p057_1_0p333_0","t":90,"s":[744.375,336.519,0],"e":[744.375,227.519,0],"to":[0,-59.5,0],"ti":[0,18.1666660308838,0]},{"t":120}],"ix":2},"a":{"a":0,"k":[91.76,66.945,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-47.28,17.985],[-47.28,-17.985],[47.28,-17.985]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[51.905,22.611],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[61.758,-60.785],[85.38,-60.785],[85.38,14.311],[85.448,60.785],[39.957,14.311],[-85.448,14.311],[-85.448,4.208]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[90.073,65.41],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[84.986,-61.052],[84.986,-1.991],[85.361,-1.996],[85.361,61.052],[41.31,13.952],[-85.361,13.952],[-85.361,-61.052]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[97.91,72.588],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"face","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[958.743,533.821,0],"ix":2},"a":{"a":0,"k":[35.403,40.664,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-8.563,1.619],[15.954,-2.287]],"o":[[3.879,0.782],[1.765,6.273],[0,0]],"v":[[-11.335,-10.833],[9.57,-11.117],[-6.384,11.117]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[42.171,65.586],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.344,-1.615]],"o":[[-2.71,3.748],[0,0]],"v":[[6.574,-6.863],[-6.574,6.863]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[22.412,35.018],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.564,-0.96],[1.329,-6.316]],"o":[[1.328,-6.314],[4.562,0.96],[0,0]],"v":[[-8.926,3.588],[1.742,-6.106],[7.597,7.066]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[57.255,21.831],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.562,-0.96],[1.329,-6.316]],"o":[[1.33,-6.314],[4.562,0.961],[0,0]],"v":[[-8.926,3.588],[1.742,-6.106],[7.598,7.066]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[13.551,11.691],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"head","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[982.226,536.702,0],"ix":2},"a":{"a":0,"k":[74.818,123.105,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.635,0],[0,-7.435],[7.435,0],[1.803,5.311]],"o":[[1.448,-0.533],[7.435,0],[0,7.435],[-5.921,0],[0,0]],"v":[[-5.003,-12.639],[-0.354,-13.464],[13.107,0],[-0.354,13.464],[-13.107,4.329]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[114.299,131.449],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-3.024,6.911]],"o":[[4.49,-4.451],[0,0]],"v":[[-5.647,8.807],[5.647,-8.807]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[130.616,115.261],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,4.473],[3.465,0],[-0.554,-5.095],[23.364,8.267]],"o":[[1.173,-5.944],[0,-31.49],[-3.463,0],[-2.101,-2.913],[0,0]],"v":[[31.769,36.132],[33.543,20.161],[11.554,-24.257],[5.003,-11.873],[-33.543,-36.132]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[111.468,47.687],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.113,0],[0,-10.918],[-3.996,-2.664],[0,-8.056],[-4.905,0],[-3.51,4.784],[-8.332,-1.31]],"o":[[-4.642,-0.52],[-13.707,0],[0,4.964],[-4.056,0.304],[0,9.207],[4.904,0],[0.999,4.82],[0,0]],"v":[[20.848,-30.003],[6.215,-30.809],[-17.337,-13.251],[-11.04,2.126],[-20.848,13.387],[-3.593,26.949],[12.086,17.079],[18.741,30.809]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30.2,35.435],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.587,1.435],[0,-7.538],[-5.328,0],[-2.844,3.268],[-1.606,-9.1],[-0.085,-5.588]],"o":[[5.02,-2.577],[-3.874,6.658],[0,7.051],[5.329,0],[0.608,4.782],[5.354,0.403],[0,0]],"v":[[-21.544,-26.545],[-10.472,-33.186],[-19.674,-15.931],[-10.896,-3.944],[12.654,-14.478],[9.534,32.783],[21.544,31.957]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[91.082,85.882],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,15.318],[3.465,0],[-0.555,-5.097],[49.48,0],[0,-10.918],[-3.996,-2.664],[0,-8.058],[-4.903,0],[-3.511,4.782],[-11.47,-0.076],[-3.815,3.451],[0,-7.537],[-5.327,0],[-2.848,3.271],[-1.605,-9.1],[-0.085,-5.588]],"o":[[13.006,-12.887],[0,-31.491],[-3.463,0],[-3.128,-4.341],[-13.706,0],[0,4.966],[-4.056,0.301],[0,9.206],[4.904,0],[1.091,5.267],[4.843,0.031],[-3.874,6.66],[0,7.05],[5.328,0],[0.604,4.784],[5.354,0.402],[0,0]],"v":[[47.787,59.721],[67.83,3.503],[45.841,-40.914],[39.29,-28.53],[-40.767,-59.721],[-64.317,-42.163],[-58.022,-26.784],[-67.83,-15.524],[-50.575,-1.964],[-34.895,-11.831],[-25.63,2.094],[3.429,-11.65],[-5.773,5.605],[3.005,17.593],[26.558,7.057],[23.434,54.32],[35.444,53.493]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-988.142,717.958],[211.858,717.958],[211.858,-482.042],[-988.142,-482.042]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-988.142,-482.042],[211.858,-482.042],[211.858,717.958],[-988.142,717.958]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.894000004787,0.616000007181,0.458999992819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.733,68.444],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":4,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.509,1.179],[-1.46,33.495]],"o":[[-5.517,1.101],[-25.791,-5.514],[0,0]],"v":[[29.416,33.323],[12.794,33.293],[-27.956,-34.472]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[34.04,148.623],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.904,7.131]],"o":[[3.232,-9.655],[0,0]],"v":[[-6.467,13.113],[6.467,-13.113]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[17.273,75.223],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.802,-8.008],[12.064,1.923]],"o":[[-2.403,6.865],[-4.944,1.778],[0,0]],"v":[[21.729,-33.712],[7.691,31.934],[-21.729,31.271]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[64.207,205.807],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.459,12.584]],"o":[[5.148,-15.102],[0,0]],"v":[[-5.31,28.823],[4.852,-28.823]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.912,198.491],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.801,-8.009],[5.263,8.008],[0.459,12.586]],"o":[[-2.403,6.864],[-10.183,3.661],[5.148,-15.101],[0,0]],"v":[[35.667,-33.439],[21.63,32.207],[-35.667,21.781],[-25.506,-35.868]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-960.824,576.31],[239.176,576.31],[239.176,-623.69],[-960.824,-623.69]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-960.824,-623.69],[239.176,-623.69],[239.176,576.31],[-960.824,576.31]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[53.416,210.092],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":4,"cix":2,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-60.15],[0,-7.661],[2.366,-5.52],[-8.336,2.253],[-2.366,3.604],[0,17.572],[26.131,0]],"o":[[0,42.24],[0,7.659],[6.195,8.673],[0.675,-8.224],[2.364,-3.604],[0,-39.312],[-31.765,0]],"v":[[-54.123,-25.176],[-35.764,32.385],[-46.464,87.578],[11.771,98.505],[25.289,33.172],[54.123,-9.18],[25.401,-100.758]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-971.163,642.246],[228.837,642.246],[228.837,-557.754],[-971.163,-557.754]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-971.163,-557.754],[228.837,-557.754],[228.837,642.246],[-971.163,642.246]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[63.754,144.156],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":4,"cix":2,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"fig2 - left arm","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1044.698,798.881,0],"ix":2},"a":{"a":0,"k":[66.103,157.677,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[6.995,-9.769],[11.255,-2.99]],"o":[[46.068,2.939],[-2.038,2.847],[0,0]],"v":[[-38.337,-66.014],[31.342,56.977],[9.662,66.014]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[88.721,72.691],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.65,3.322],[-6.203,37.785]],"o":[[-21.996,3.243],[-4.778,-4.351],[0,0]],"v":[[27.297,40.484],[-18.674,41.583],[-21.094,-44.905]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[31.921,106.03],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-42.402,9.259],[7.41,-10.347],[8.146,7.417]],"o":[[50.634,-11.056],[-7.407,10.346],[-8.146,-7.418]],"v":[[-21.495,-68.328],[56.487,54.023],[-50.324,71.967]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1046.654,479.162],[153.346,479.162],[153.346,-720.838],[-1046.654,-720.838]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1046.654,-720.838],[153.346,-720.838],[153.346,479.162],[-1046.654,479.162]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.11372549019607843,0.4549019607843137,0.9607843137254902,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[68.059,79.634],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.355,-6.93],[6.106,-8.203]],"o":[[-0.277,9.84],[-2.357,6.929],[0,0]],"v":[[16.488,-87.636],[11.085,40.837],[-16.488,87.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[93.379,223.093],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.167,35.847],[36.622,-1.278],[-2.617,-37.212],[6.632,-8.473],[0,0],[-2.002,5.374]],"o":[[-15.077,7.742],[1.017,21.506],[-5.701,8.316],[0,0],[9.77,-15.727],[3.076,-8.26]],"v":[[46.383,-83.858],[-34.276,-70.318],[-25.721,56.208],[-46.383,83.858],[16.003,83.858],[41.271,40.206]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1045.117,332.579],[154.883,332.579],[154.883,-867.421],[-1045.117,-867.421]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1045.117,-867.421],[154.883,-867.421],[154.883,332.579],[-1045.117,332.579]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[66.523,226.217],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":4,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.842,-14.195]],"o":[[0.211,3.085],[0,0]],"v":[[-0.833,-14.048],[0.833,14.048]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[29.562,163.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.393,-6.782],[0,0]],"o":[[1.668,24.601],[-7.359,8.949],[0,0]],"v":[[7.366,-42.891],[12.235,11.216],[-12.235,42.891]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[25.988,267.69],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"fig2 - torso","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[927.579,785.001,0],"ix":2},"a":{"a":0,"k":[156.818,171.483,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-3.807,29.068]],"o":[[1.123,-20.126],[0,0]],"v":[[-3.5,37.762],[3.5,-37.762]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[8.125,300.58],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-71.518,11.004]],"o":[[20.219,-84.427],[0,0]],"v":[[-64.885,88.771],[64.885,-88.771]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[91.114,93.396],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[30.021,-87.577]],"o":[[92.263,44.396],[0,0]],"v":[[-46.131,-162.732],[-7.602,162.732]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[260.104,175.519],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.633,-0.061],[6.12,-99.916],[0,0],[119.434,18.872]],"o":[[-131.863,1.204],[0,0],[31.5,-98.012],[-7.176,-1.124]],"v":[[12.071,-163.754],[-152.212,163.815],[97.423,163.815],[32.778,-162.182]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-931.935,412.537],[268.065,412.537],[268.065,-787.463],[-931.935,-787.463]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-931.935,-787.463],[268.065,-787.463],[268.065,412.537],[-931.935,412.537]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.11372549019607843,0.4549019607843137,0.9607843137254902,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[161.175,173.945],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":4,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"fig2 - right arm","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[768.893,699.522,0],"ix":2},"a":{"a":0,"k":[152.624,142.782,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.303,12.278]],"o":[[-16.717,-4.025],[0,0]],"v":[[21.539,12.711],[-21.539,-12.711]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[150.508,267.627],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.782,26.184]],"o":[[-18.082,-32.106],[0,0]],"v":[[26.104,47.033],[-26.104,-47.033]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[67.242,158.117],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-9.071,-6.149]],"o":[[1.062,5.281],[0,0]],"v":[[-8.82,-13.493],[8.82,13.493]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[13.446,92.444],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-8.683,-6.685]],"o":[[0.741,5.336],[0,0]],"v":[[-7.991,-14],[7.991,14]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[22.026,83.154],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-7.982,-7.508]],"o":[[0.211,5.383],[0,0]],"v":[[-6.57,-14.72],[6.57,14.72]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30.089,74.304],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[5.927,8.1],[0.97,6.49],[5.135,-3.393],[-6.218,-10.669]],"o":[[-2.468,3.61],[0,0],[-17.697,-24.186],[-0.917,-6.13],[-8.1,6.107],[0,0]],"v":[[79.727,59.884],[57.739,92.502],[-35.505,-18.92],[-62.613,-79.134],[-71.627,-89.109],[-68.214,-41.113]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[101.854,97.127],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.295,4.649],[-17.51,19.013]],"o":[[-16.738,-12.243],[-0.301,-4.755],[0,0]],"v":[[13.411,35.554],[-14.527,8.425],[14.828,-35.554]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[186.894,136.223],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-13.042,-8.644]],"o":[[14.448,-7.166],[0,0]],"v":[[-21.157,4.482],[21.157,4.161]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[261.245,65.513],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[32.626,24.331],[0.295,4.65],[-44.837,-29.711]],"o":[[-16.492,-12.574],[-0.699,-10.994],[19.027,13.824]],"v":[[-36.244,53.742],[-64.181,26.612],[45.853,-48.362]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-856.386,520.541],[343.614,520.541],[343.614,-679.459],[-856.386,-679.459]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-856.386,-679.459],[343.614,-679.459],[343.614,520.541],[-856.386,520.541]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.11372549019607843,0.4549019607843137,0.9607843137254902,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[240.117,122.719],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":4,"cix":2,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.95,-7.326],[4.952,-7.128],[14.482,69.15],[-10.528,-23.827],[-4.79,-7.793],[-6.842,-0.614],[-15.788,-17.671],[-35.969,-15.473],[-4.949,5.916]],"o":[[-4.951,7.328],[-53.262,-70.079],[-14.015,-8.919],[-16.437,10.516],[18.315,29.816],[6.843,0.615],[11.635,13.024],[3.866,-32.918],[-4.446,-3.182]],"v":[[78.705,16.029],[56.281,48.766],[-66.603,-131.043],[-69.285,-84.306],[-96.507,-55.45],[-65.84,-34.401],[11.596,96.234],[68.241,139.962],[101.297,23.183]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-723.759,497.909],[476.241,497.909],[476.241,-702.091],[-723.759,-702.091]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-723.759,-702.091],[476.241,-702.091],[476.241,497.909],[-723.759,497.909]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[107.49,145.351],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":4,"cix":2,"ix":10,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"base circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[805.451,427.621,0],"ix":2},"a":{"a":0,"k":[76.562,76.561,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,42.146],[-42.144,0],[0,-42.146],[42.146,0]],"o":[[0,-42.146],[42.146,0],[0,42.146],[-42.144,0]],"v":[[-76.312,0],[-0.001,-76.311],[76.312,0],[-0.001,76.311]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-805.451,772.379],[394.549,772.379],[394.549,-427.621],[-805.451,-427.621]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-805.451,-427.621],[394.549,-427.621],[394.549,772.379],[-805.451,772.379]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.842999985639,0.877999997606,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[76.562,76.561],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"base square","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[398.488,511.808,0],"ix":2},"a":{"a":0,"k":[152.923,159.975,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-152.673,-159.725],[152.673,-159.725],[152.673,159.725],[-152.673,159.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.842999985639,0.877999997606,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[152.923,159.975],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"bg circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[673.128,804.372,0],"ix":2},"a":{"a":0,"k":[80.91,80.91,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,43.028],[-43.028,0],[0,-43.028],[43.028,0]],"o":[[0,-43.028],[43.028,0],[0,43.028],[-43.028,0]],"v":[[-77.91,0.001],[0.001,-77.91],[77.91,0.001],[0.001,77.91]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.917999985639,0.941000007181,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[80.91,80.91],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"chairs","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[596.75,799.07,0],"ix":2},"a":{"a":0,"k":[565.094,157.348,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-19.95,114.986],[19.951,-114.986]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[1097.785,195.138],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[1085.007,12.389],[1014.668,12.389]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.361,-0.035],[0,0],[-0.889,-34.396],[0,0],[0,0],[18.56,0],[21.072,0.786]],"o":[[-20.435,0.507],[-0.254,21.571],[0,0],[0,0],[0,-18.56],[0,0],[-1.133,-0.037]],"v":[[-23.926,-146.492],[-88.514,-138.069],[-81.998,146.529],[44.098,146.529],[88.769,-112.888],[55.165,-146.492],[-20.18,-146.492]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1072.826,395.251],[127.174,395.251],[127.174,-804.749],[-1072.826,-804.749]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1072.826,-804.749],[127.174,-804.749],[127.174,395.251],[-1072.826,395.251]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.234999997008,0.216000007181,0.26699999641,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1041.17,163.027],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":4,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-18.561,0],[0,0]],"o":[[0,0],[0,-18.56],[0,0],[0,0]],"v":[[10.446,152.723],[-23.135,-119.117],[10.474,-152.723],[23.135,-152.723]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[27.759,157.348],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[115.405,4.625],[217.084,4.625]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.105999995213,0.234999997008,0.528999956916,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4.625,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-18.56],[-8.813,-71.352],[0,0],[1.867,46.396]],"o":[[-18.561,0],[-0.001,0],[0,0],[-0.017,-11.511],[0,0]],"v":[[-73.738,-150.339],[-107.343,-116.733],[-74.357,150.339],[107.344,150.339],[105.114,-150.339]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-148.388,398.077],[1051.612,398.077],[1051.612,-801.923],[-148.388,-801.923]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-148.388,-801.923],[1051.612,-801.923],[1051.612,398.077],[-148.388,398.077]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"mm","mm":4,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.234999997008,0.216000007181,0.26699999641,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[116.732,160.201],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":4,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"triangle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[360]},{"t":120}],"ix":10},"p":{"a":0,"k":[249.628,442.531,0],"ix":2},"a":{"a":0,"k":[95.602,93.681,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-93.602,49.201],[-28.408,-21.24],[36.786,-91.68],[65.193,0],[93.602,91.68],[0,70.44]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.698000021542,0.764999988032,0.984000052658,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":2,"lj":2,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[95.602,93.681],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0}],"markers":[]} --------------------------------------------------------------------------------