diff --git a/.DS_Store b/.DS_Store
index 3d690aa..e5cecbc 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/Coroutines/.DS_Store b/Coroutines/.DS_Store
new file mode 100644
index 0000000..600f9c7
Binary files /dev/null and b/Coroutines/.DS_Store differ
diff --git a/CoroutineLiveCoding/.gitignore b/Coroutines/CoroutineLiveCoding/.gitignore
similarity index 100%
rename from CoroutineLiveCoding/.gitignore
rename to Coroutines/CoroutineLiveCoding/.gitignore
diff --git a/CoroutineLiveCoding/.idea/.gitignore b/Coroutines/CoroutineLiveCoding/.idea/.gitignore
similarity index 100%
rename from CoroutineLiveCoding/.idea/.gitignore
rename to Coroutines/CoroutineLiveCoding/.idea/.gitignore
diff --git a/CoroutineLiveCoding/.idea/compiler.xml b/Coroutines/CoroutineLiveCoding/.idea/compiler.xml
similarity index 100%
rename from CoroutineLiveCoding/.idea/compiler.xml
rename to Coroutines/CoroutineLiveCoding/.idea/compiler.xml
diff --git a/CoroutineLiveCoding/.idea/gradle.xml b/Coroutines/CoroutineLiveCoding/.idea/gradle.xml
similarity index 100%
rename from CoroutineLiveCoding/.idea/gradle.xml
rename to Coroutines/CoroutineLiveCoding/.idea/gradle.xml
diff --git a/CoroutineLiveCoding/.idea/misc.xml b/Coroutines/CoroutineLiveCoding/.idea/misc.xml
similarity index 100%
rename from CoroutineLiveCoding/.idea/misc.xml
rename to Coroutines/CoroutineLiveCoding/.idea/misc.xml
diff --git a/CoroutineLiveCoding/app/.gitignore b/Coroutines/CoroutineLiveCoding/app/.gitignore
similarity index 100%
rename from CoroutineLiveCoding/app/.gitignore
rename to Coroutines/CoroutineLiveCoding/app/.gitignore
diff --git a/CoroutineLiveCoding/app/build.gradle b/Coroutines/CoroutineLiveCoding/app/build.gradle
similarity index 100%
rename from CoroutineLiveCoding/app/build.gradle
rename to Coroutines/CoroutineLiveCoding/app/build.gradle
diff --git a/CoroutineLiveCoding/app/proguard-rules.pro b/Coroutines/CoroutineLiveCoding/app/proguard-rules.pro
similarity index 100%
rename from CoroutineLiveCoding/app/proguard-rules.pro
rename to Coroutines/CoroutineLiveCoding/app/proguard-rules.pro
diff --git a/CoroutineLiveCoding/app/src/androidTest/java/com/example/coroutinetestviewmodel/ExampleInstrumentedTest.kt b/Coroutines/CoroutineLiveCoding/app/src/androidTest/java/com/example/coroutinetestviewmodel/ExampleInstrumentedTest.kt
similarity index 100%
rename from CoroutineLiveCoding/app/src/androidTest/java/com/example/coroutinetestviewmodel/ExampleInstrumentedTest.kt
rename to Coroutines/CoroutineLiveCoding/app/src/androidTest/java/com/example/coroutinetestviewmodel/ExampleInstrumentedTest.kt
diff --git a/CoroutineLiveCoding/app/src/main/AndroidManifest.xml b/Coroutines/CoroutineLiveCoding/app/src/main/AndroidManifest.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/AndroidManifest.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/AndroidManifest.xml
diff --git a/CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/MainActivity.kt b/Coroutines/CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/MainActivity.kt
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/MainActivity.kt
rename to Coroutines/CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/MainActivity.kt
diff --git a/CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/ui/main/BackendApi.kt b/Coroutines/CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/ui/main/BackendApi.kt
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/ui/main/BackendApi.kt
rename to Coroutines/CoroutineLiveCoding/app/src/main/java/com/example/coroutinetestviewmodel/ui/main/BackendApi.kt
diff --git a/CoroutineLiveCoding/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/drawable/ic_launcher_background.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/drawable/ic_launcher_background.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/drawable/ic_launcher_background.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/drawable/ic_launcher_background.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/layout/main_activity.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/layout/main_activity.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/layout/main_activity.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/layout/main_activity.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/layout/main_fragment.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/layout/main_fragment.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/layout/main_fragment.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/layout/main_fragment.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/layout/test_layout.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/layout/test_layout.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/layout/test_layout.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/layout/test_layout.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
diff --git a/CoroutineLiveCoding/app/src/main/res/values-night/themes.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/values-night/themes.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/values-night/themes.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/values-night/themes.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/values/colors.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/values/colors.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/values/colors.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/values/colors.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/values/strings.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/values/strings.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/values/strings.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/values/strings.xml
diff --git a/CoroutineLiveCoding/app/src/main/res/values/themes.xml b/Coroutines/CoroutineLiveCoding/app/src/main/res/values/themes.xml
similarity index 100%
rename from CoroutineLiveCoding/app/src/main/res/values/themes.xml
rename to Coroutines/CoroutineLiveCoding/app/src/main/res/values/themes.xml
diff --git a/CoroutineLiveCoding/app/src/test/java/com/example/coroutinetestviewmodel/ExampleUnitTest.kt b/Coroutines/CoroutineLiveCoding/app/src/test/java/com/example/coroutinetestviewmodel/ExampleUnitTest.kt
similarity index 100%
rename from CoroutineLiveCoding/app/src/test/java/com/example/coroutinetestviewmodel/ExampleUnitTest.kt
rename to Coroutines/CoroutineLiveCoding/app/src/test/java/com/example/coroutinetestviewmodel/ExampleUnitTest.kt
diff --git a/CoroutineLiveCoding/build.gradle b/Coroutines/CoroutineLiveCoding/build.gradle
similarity index 100%
rename from CoroutineLiveCoding/build.gradle
rename to Coroutines/CoroutineLiveCoding/build.gradle
diff --git a/CoroutineLiveCoding/gradle.properties b/Coroutines/CoroutineLiveCoding/gradle.properties
similarity index 100%
rename from CoroutineLiveCoding/gradle.properties
rename to Coroutines/CoroutineLiveCoding/gradle.properties
diff --git a/CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.jar b/Coroutines/CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.jar
rename to Coroutines/CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.jar
diff --git a/CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.properties b/Coroutines/CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.properties
rename to Coroutines/CoroutineLiveCoding/gradle/wrapper/gradle-wrapper.properties
diff --git a/CoroutineLiveCoding/gradlew b/Coroutines/CoroutineLiveCoding/gradlew
similarity index 100%
rename from CoroutineLiveCoding/gradlew
rename to Coroutines/CoroutineLiveCoding/gradlew
diff --git a/CoroutineLiveCoding/gradlew.bat b/Coroutines/CoroutineLiveCoding/gradlew.bat
similarity index 100%
rename from CoroutineLiveCoding/gradlew.bat
rename to Coroutines/CoroutineLiveCoding/gradlew.bat
diff --git a/CoroutineLiveCoding/settings.gradle b/Coroutines/CoroutineLiveCoding/settings.gradle
similarity index 100%
rename from CoroutineLiveCoding/settings.gradle
rename to Coroutines/CoroutineLiveCoding/settings.gradle
diff --git a/Coroutines/CoroutinesLive2/.idea/.gitignore b/Coroutines/CoroutinesLive2/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/Coroutines/CoroutinesLive2/.idea/compiler.xml b/Coroutines/CoroutinesLive2/.idea/compiler.xml
new file mode 100644
index 0000000..fb7f4a8
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Coroutines/CoroutinesLive2/.idea/gradle.xml b/Coroutines/CoroutinesLive2/.idea/gradle.xml
new file mode 100644
index 0000000..5404067
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Coroutines/CoroutinesLive2/.idea/jarRepositories.xml b/Coroutines/CoroutinesLive2/.idea/jarRepositories.xml
new file mode 100644
index 0000000..fdc392f
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Coroutines/CoroutinesLive2/.idea/misc.xml b/Coroutines/CoroutinesLive2/.idea/misc.xml
new file mode 100644
index 0000000..62269df
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Coroutines/CoroutinesLive2/build.gradle.kts b/Coroutines/CoroutinesLive2/build.gradle.kts
new file mode 100644
index 0000000..51f2c89
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/build.gradle.kts
@@ -0,0 +1,30 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ kotlin("jvm") version "1.5.10"
+ application
+}
+
+group = "me.sshex"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation(kotlin("test"))
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
+}
+
+tasks.test {
+ useJUnitPlatform()
+}
+
+tasks.withType {
+ kotlinOptions.jvmTarget = "1.8"
+}
+
+application {
+ mainClass.set("MainKt")
+}
\ No newline at end of file
diff --git a/Coroutines/CoroutinesLive2/gradle.properties b/Coroutines/CoroutinesLive2/gradle.properties
new file mode 100644
index 0000000..7fc6f1f
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/gradle.properties
@@ -0,0 +1 @@
+kotlin.code.style=official
diff --git a/Coroutines/CoroutinesLive2/gradle/wrapper/gradle-wrapper.jar b/Coroutines/CoroutinesLive2/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7454180
Binary files /dev/null and b/Coroutines/CoroutinesLive2/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Coroutines/CoroutinesLive2/gradle/wrapper/gradle-wrapper.properties b/Coroutines/CoroutinesLive2/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..69a9715
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/Coroutines/CoroutinesLive2/gradlew b/Coroutines/CoroutinesLive2/gradlew
new file mode 100755
index 0000000..744e882
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MSYS* | MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/Coroutines/CoroutinesLive2/gradlew.bat b/Coroutines/CoroutinesLive2/gradlew.bat
new file mode 100644
index 0000000..ac1b06f
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/Coroutines/CoroutinesLive2/settings.gradle.kts b/Coroutines/CoroutinesLive2/settings.gradle.kts
new file mode 100644
index 0000000..9f73e7e
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/settings.gradle.kts
@@ -0,0 +1,3 @@
+
+rootProject.name = "CoroutinesLive2"
+
diff --git a/Coroutines/CoroutinesLive2/src/main/kotlin/Flow.kt b/Coroutines/CoroutinesLive2/src/main/kotlin/Flow.kt
new file mode 100644
index 0000000..6c9c239
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/src/main/kotlin/Flow.kt
@@ -0,0 +1,67 @@
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import kotlinx.coroutines.flow.Flow
+import kotlin.coroutines.CoroutineContext
+
+class Flow {
+ private val coroutineContext: CoroutineContext = SupervisorJob() + Dispatchers.IO
+ private val scope = CoroutineScope(coroutineContext)
+ fun main() {
+ runBlocking {
+ /**
+ * Подписка на flow #1
+ */
+ scope.launch {
+ createFlow().collect { value ->
+ println("Emit $value")
+ }
+ }.join()
+
+
+ createFlow()
+ .onEach { println("Emit $it") }
+ .launchIn(scope)
+
+ /**
+ * Operators
+ */
+ createFlow()
+ .filter { it % 2 == 0 }
+ .onEach { println("Emit $it") }
+ .launchIn(scope)
+
+ /**
+ * FLow on
+ */
+ createFlow()
+ .filter { it % 2 == 0 }
+ .flowOn(Dispatchers.IO)
+ .onEach { println("Emit $it Thread = ${Thread.currentThread().name}") }
+ .flowOn(Dispatchers.Default)
+ .launchIn(scope)
+
+ /**
+ * Shared flow
+ */
+ val sharedFlow = MutableSharedFlow(1)
+ sharedFlow.emit("Moscow")
+ scope.launch {
+ sharedFlow
+ .onEach {
+ println("City $it")
+ }
+ .launchIn(scope)
+ }.join()
+ }
+ }
+
+ fun createFlow(): Flow {
+ var counter = 0
+ return flow {
+ repeat(100) {
+ delay(1000)
+ emit(counter++)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Coroutines/CoroutinesLive2/src/main/kotlin/Main.kt b/Coroutines/CoroutinesLive2/src/main/kotlin/Main.kt
new file mode 100644
index 0000000..3aa90d4
--- /dev/null
+++ b/Coroutines/CoroutinesLive2/src/main/kotlin/Main.kt
@@ -0,0 +1,176 @@
+import kotlinx.coroutines.*
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
+
+val coroutineContext: CoroutineContext = SupervisorJob() + Dispatchers.IO
+val coroutineScope = CoroutineScope(coroutineContext)
+fun main(args: Array) {
+ println("Start program!")
+ runBlocking {
+ /**
+ * Run blocking
+ */
+ //printHello()
+ /* coroutineScope.launch {
+ printHello()
+ }.join()*/
+
+ /**
+ * Cancel coroutine on same thread
+ */
+ /*val job = launch {
+ repeat(1000) { i ->
+ println("Номер $i")
+ delay(500L)
+ }
+ }
+ delay(1300L) // delay a bit
+ println("Остановитесь!")
+ job.cancel() // отмена джобы
+ println("Расчет окончен")*/
+
+ /**
+ * Cancel coroutine with Dispatchers.IO
+ */
+ /*val job = launch(Dispatchers.IO) {
+ repeat(1000) { i ->
+ println("Номер $i")
+ delay(500L)
+ }
+ }
+ delay(1300L) // delay a bit
+ println("Остановитесь!")
+ job.cancel() // отмена джобы
+ job.join() //??
+ println("Расчет окончен")*/
+
+ /**
+ * Cancel scope vs cancel children
+ */
+ /*val scope = CoroutineScope(Job())
+ scope.launch {
+ println("First job complete")
+ }
+ scope.launch {
+ println("Second job complete")
+ }
+ scope.cancel()
+ scope.coroutineContext.cancelChildren()
+ scope.launch {
+ println("Third job complete")
+ }*/
+
+ /* */
+ /**
+ * Job vs SupervisorJob
+ *//*
+ val coroutineExceptionHandler = CoroutineExceptionHandler { _, _ ->
+ // exception will be given here
+ }
+ val scope = CoroutineScope(Job() + coroutineExceptionHandler)
+ val job1 = scope.launch {
+ delay(3000)
+ println("First job complete")
+ }
+ val job2 = scope.launch {
+ delay(2000)
+ println("Second job complete")
+ }
+ val job3 = scope.launch {
+ println("Third job complete")
+ throw java.lang.IllegalStateException("Ops")
+ }
+ job1.join()
+ job2.join()
+ job3.join()*/
+
+
+ /**
+ * Callback
+ */
+ /*createUser(object : ResultCallback {
+ override fun onSuccess(user: User) {
+
+ }
+
+ override fun onError() {
+
+ }
+ })
+
+ launch {
+ val user2 = createUser()
+ println(user.name)
+
+ val user = createUserSuspend()
+ user.name
+ }*/
+
+ /**
+ * Cancellation exception
+ */
+ /* val job = launch(Dispatchers.IO) {
+ try {
+ repeat(1000) { i ->
+ println("Загрузка файла $i")
+ delay(1000L)
+ }
+ } catch (e: CancellationException) {
+ println("Корутину отменили")
+ } finally {
+ println("удаляем скаченные файлы...")
+ }
+ }
+ delay(3000L) // delay a bit
+ println("Отмена загрузки")
+ job.cancel() // отмена джобы
+ job.join() //??*/
+ Flow().main()
+ }
+}
+
+suspend fun createUserSuspend(): User {
+ /**
+ * suspendCoroutine нельзя отменить job.cancel()
+ */
+ return suspendCoroutine { continuation ->
+ createUser(object : ResultCallback {
+ override fun onSuccess(user: User) {
+ continuation.resume(user)
+ }
+
+ override fun onError() {
+ continuation.resumeWithException(java.lang.Exception())
+ }
+ })
+ }
+}
+
+fun createUser(callback: ResultCallback) {
+ Thread.sleep(2000)
+ callback.onSuccess(User("Петя"))
+}
+
+interface ResultCallback {
+ fun onSuccess(user: User)
+ fun onError()
+}
+
+data class User(val name: String)
+
+suspend fun printHello() {
+ delay(3000)
+ println("Hello world!")
+}
+
+suspend fun downloadFile(): Int {
+ delay(5000)
+ println("Success download!")
+ return 0
+}
+
+fun cancelDownload() {
+
+}
\ No newline at end of file
diff --git a/HomeWorkNetwork/.idea/gradle.xml b/HomeWorkNetwork/.idea/gradle.xml
index 526b4c2..e9969a1 100644
--- a/HomeWorkNetwork/.idea/gradle.xml
+++ b/HomeWorkNetwork/.idea/gradle.xml
@@ -7,6 +7,7 @@
+
diff --git a/HomeWorkNetwork/app/build.gradle b/HomeWorkNetwork/app/build.gradle
index d5e6ad0..2db6927 100644
--- a/HomeWorkNetwork/app/build.gradle
+++ b/HomeWorkNetwork/app/build.gradle
@@ -7,11 +7,18 @@ plugins {
android {
compileSdk 31
+ packagingOptions {
+ pickFirst 'META-INF/DEPENDENCIES'
+ pickFirst 'META-INF/INDEX.LIST'
+ pickFirst 'META-INF/io.netty.versions.properties'
+ }
+
defaultConfig {
buildConfigField "String", "API_BASE_URL", '"api.themoviedb.org"'
- buildConfigField "String", "API_KEY", '"/*ваш ap_key*/"'
+ buildConfigField "String", "API_KEY", '"31f9ea6be897d37ff7a70e2aa1d78184"'
buildConfigField "String", "API_IMAGE_BASE_URL", '"https://image.tmdb.org/t/p/w500"'
+ buildConfigField "Integer", "API_VERSION", '3'
applicationId "com.pg.homeworknetwork"
minSdk 30
@@ -27,6 +34,10 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
+ debug {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@@ -37,6 +48,10 @@ android {
}
}
+ext {
+ ktor_version = '1.6.8'
+}
+
dependencies {
//Coil (загрузка постеров)
implementation "io.coil-kt:coil-compose:2.0.0-rc02"
@@ -46,4 +61,15 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
+
+ //Serialization
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2"
+
+ // Ktor
+ implementation("io.ktor:ktor-server-core:${ktor_version}")
+ implementation("io.ktor:ktor-server-netty:${ktor_version}")
+ implementation("ch.qos.logback:logback-classic:1.2.5")
+ implementation("io.ktor:ktor-client-logging:${ktor_version}")
+ implementation("io.ktor:ktor-client-serialization:${ktor_version}")
+ implementation("io.ktor:ktor-client-cio:${ktor_version}")
}
\ No newline at end of file
diff --git a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Models.kt b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Models.kt
index 69df05a..35a19a2 100644
--- a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Models.kt
+++ b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Models.kt
@@ -1,5 +1,31 @@
package com.pg.homeworknetwork
-class Movies
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
-class Movie
\ No newline at end of file
+@Serializable
+data class Movies(
+ @SerialName("page")
+ val page: Int,
+ @SerialName("results")
+ val results: List = ArrayList()
+)
+
+@Serializable
+data class Movie (
+ @SerialName("id")
+ val id: Int,
+ @SerialName("title")
+ val title: String? = null,
+ @SerialName("poster_path")
+ val posterPath: String? = null,
+ @SerialName("overview")
+ val overview: String? = null,
+ @SerialName("popularity")
+ val popularity: Double? = null,
+ @SerialName("original_title")
+ val originalTitle: String? = null,
+ @SerialName("release_date")
+ val releaseDate: String? = null
+
+)
\ No newline at end of file
diff --git a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieDetailFragment.kt b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieDetailFragment.kt
index 338ddc7..6cd0f6f 100644
--- a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieDetailFragment.kt
+++ b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieDetailFragment.kt
@@ -10,6 +10,8 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import coil.load
import coil.transform.RoundedCornersTransformation
+import kotlinx.coroutines.*
+import kotlin.coroutines.CoroutineContext
class MovieDetailFragment : Fragment(R.layout.fragment_movie_preview) {
lateinit var poster: ImageView
@@ -18,6 +20,9 @@ class MovieDetailFragment : Fragment(R.layout.fragment_movie_preview) {
lateinit var popularity: TextView
lateinit var releaseDate: TextView
+ private val context: CoroutineContext = SupervisorJob() + Dispatchers.Main
+ private val scope = CoroutineScope(context)
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(view) {
@@ -28,24 +33,29 @@ class MovieDetailFragment : Fragment(R.layout.fragment_movie_preview) {
releaseDate = findViewById(R.id.releaseDate)
}
- val movieId = arguments?.getInt(ARG_ID) ?: 550
- val movie = //получаем фильм
- poster.load("${BuildConfig.API_IMAGE_BASE_URL}${movie.posterPath}") {
- transformations(RoundedCornersTransformation(16f))
+ scope.launch {
+ val movieId = arguments?.getInt(ARG_ID) ?: 550
+ val movie: Movie = Api().getMovie(movieId)
+ //получаем фильм
+ poster.load("${BuildConfig.API_IMAGE_BASE_URL}${movie.posterPath}") {
+ transformations(RoundedCornersTransformation(16f))
+ }
+ originalTitle.text = movie.originalTitle
+ overview.text = movie.overview
+ popularity.text = movie.popularity.toString()
+ releaseDate.text = movie.releaseDate
}
- originalTitle.text = movie.originalTitle
- overview.text = movie.overview
- popularity.text = movie.popularity.toString()
- releaseDate.text = movie.releaseDate
- activity?.onBackPressedDispatcher?.addCallback(this.viewLifecycleOwner, object : OnBackPressedCallback(true) {
- override fun handleOnBackPressed() {
- val manager: FragmentManager = parentFragmentManager
- val transaction: FragmentTransaction = manager.beginTransaction()
- transaction.replace(R.id.mainFragment, MovieListFragment())
- transaction.commit()
- }
- })
+ activity?.onBackPressedDispatcher?.addCallback(
+ this.viewLifecycleOwner,
+ object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ val manager: FragmentManager = parentFragmentManager
+ val transaction: FragmentTransaction = manager.beginTransaction()
+ transaction.replace(R.id.mainFragment, MovieListFragment())
+ transaction.commit()
+ }
+ })
}
companion object {
diff --git a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieListFragment.kt b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieListFragment.kt
index 762a176..37428e6 100644
--- a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieListFragment.kt
+++ b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/MovieListFragment.kt
@@ -7,10 +7,15 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import kotlinx.coroutines.*
+import kotlin.coroutines.CoroutineContext
class MovieListFragment : Fragment(R.layout.fragment_movie_list) {
lateinit var recycler: RecyclerView
+ private val context: CoroutineContext = SupervisorJob() + Dispatchers.Main
+ private val scope = CoroutineScope(context)
+
private val goToDetails = object : MovieItemAdapter.IOnItemClick {
override fun onItemClick(movie: Movie) {
val manager: FragmentManager = parentFragmentManager
@@ -31,8 +36,10 @@ class MovieListFragment : Fragment(R.layout.fragment_movie_list) {
}
}
val adapter = (recycler.adapter as MovieItemAdapter)
- val movies = //получаем фильмы
- adapter.submitList(movies)
+ scope.launch (Dispatchers.IO) {
+ val movies: Movies = Api().getMovies()
+ adapter.submitList(movies.results)
+ }
super.onViewCreated(view, savedInstanceState)
}
diff --git a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Network.kt b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Network.kt
index af25f9f..928bbd2 100644
--- a/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Network.kt
+++ b/HomeWorkNetwork/app/src/main/java/com/pg/homeworknetwork/Network.kt
@@ -1,5 +1,56 @@
package com.pg.homeworknetwork
+import io.ktor.client.*
+import io.ktor.client.features.json.*
+import io.ktor.client.features.json.serializer.*
+import io.ktor.client.features.logging.*
+import io.ktor.client.request.*
+
class Api {
+ private val baseUrl = "api.themoviedb.org"
+ private val movies = "${BuildConfig.API_VERSION}/movie/popular"
+ private val movie = "${BuildConfig.API_VERSION}/movie/"
+
+ val ktorLogger = object : Logger {
+ override fun log(message: String) {
+ if (message.contains("api_key=")) {
+ println("${message.split("=").first()}=BuildConfig.API_KEY")
+ } else {
+ println(message)
+ }
+ }
+ }
+
+ private val ktorClient = HttpClient() {
+ install(Logging) {
+ logger = ktorLogger
+ level = LogLevel.BODY
+ }
+
+ install(JsonFeature) {
+ serializer = KotlinxSerializer(kotlinx.serialization.json.Json {
+ prettyPrint = true
+ isLenient = true
+ ignoreUnknownKeys = true
+ })
+ }
+ }
+
+ suspend fun getMovie(movieId: Int): Movie = ktorClient.use {
+ it.get(
+ host = baseUrl,
+ path = movie + movieId.toString()
+ ) {
+ parameter("api_key", BuildConfig.API_KEY)
+ }
+ }
+ suspend fun getMovies(): Movies = ktorClient.use {
+ it.get(
+ host = baseUrl,
+ path = movies
+ ) {
+ parameter("api_key", BuildConfig.API_KEY)
+ }
+ }
}
\ No newline at end of file