module 2 lesson 1

This commit is contained in:
Александр Веденёв
2025-01-16 14:01:40 +07:00
parent 9cb8ecfe4e
commit 086a08954d
71 changed files with 1823 additions and 9 deletions

5
.gitignore vendored
View File

@ -7,4 +7,7 @@
.idea
### Mac OS ###
.DS_Store
.DS_Store
### Kotlin ###
.kotlin

View File

@ -0,0 +1,32 @@
plugins {
`kotlin-dsl`
}
gradlePlugin {
plugins {
register("build-jvm") {
id = "build-jvm"
implementationClass = "ru.otus.build.plugin.BuildPluginJvm"
}
register("build-kmp") {
id = "build-kmp"
implementationClass = "ru.otus.build.plugin.BuildPluginMultiplatform"
}
}
}
repositories {
mavenCentral()
}
dependencies {
// enable Ktlint formatting
// add("detektPlugins", libs.plugin.detektFormatting)
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
implementation(libs.plugin.kotlin)
// implementation(libs.plugin.dokka)
implementation(libs.plugin.binaryCompatibilityValidator)
// implementation(libs.plugin.mavenPublish)
}

View File

@ -0,0 +1 @@
kotlin.code.style=official

View File

@ -0,0 +1,9 @@
rootProject.name = "backend-build"
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

View File

@ -0,0 +1,19 @@
package ru.otus.build.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.repositories
@Suppress("unused")
internal class BuildPluginJvm : Plugin<Project> {
override fun apply(project: Project) = with(project) {
pluginManager.apply("org.jetbrains.kotlin.jvm")
// pluginManager.apply(KotlinPlatformJvmPlugin::class.java)
group = rootProject.group
version = rootProject.version
repositories {
mavenCentral()
}
}
}

View File

@ -0,0 +1,62 @@
package ru.otus.build.plugin
import org.gradle.accessors.dm.LibrariesForLibs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.repositories
import org.gradle.kotlin.dsl.the
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
@Suppress("unused")
internal class BuildPluginMultiplatform : Plugin<Project> {
override fun apply(project: Project) = with(project) {
pluginManager.apply("org.jetbrains.kotlin.multiplatform")
group = rootProject.group
version = rootProject.version
plugins.withId("org.jetbrains.kotlin.multiplatform") {
extensions.configure<KotlinMultiplatformExtension> {
configureTargets(this@with)
sourceSets.configureEach {
languageSettings.apply {
languageVersion = "1.9"
progressiveMode = true
optIn("kotlin.time.ExperimentalTime")
}
}
}
}
repositories {
mavenCentral()
}
}
}
@Suppress("LongMethod", "MagicNumber")
private fun KotlinMultiplatformExtension.configureTargets(project: Project) {
val libs = project.the<LibrariesForLibs>()
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(libs.versions.jvm.language.get()))
// vendor.set(JvmVendorSpec.AZUL)
}
jvm {
compilations.configureEach {
compilerOptions.configure {
jvmTarget.set(JvmTarget.valueOf("JVM_${libs.versions.jvm.compiler.get()}"))
}
}
}
linuxX64()
macosArm64()
macosX64()
project.tasks.withType(JavaCompile::class.java) {
sourceCompatibility = libs.versions.jvm.language.get()
targetCompatibility = libs.versions.jvm.compiler.get()
}
}

View File

@ -1,2 +1,2 @@
kotlin.code.style=official
kotlinVersion=2.0.20
kotlinVersion=2.1.0

29
gradle/libs.versions.toml Normal file
View File

@ -0,0 +1,29 @@
[versions]
kotlin = "2.1.0"
coroutines = "1.9.0"
datetime = "0.6.1"
okhhtp = "4.12.0"
jackson-module = "2.18.2"
slf4j = "2.0.9"
logback-classic = "1.4.11"
# BASE
jvm-compiler = "17"
jvm-language = "21"
[plugins]
jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
java-gradle-plugin = { id = "java-gradle-plugin" }
[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
kotlin-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
kotlin-jackson-module = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson-module" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhhtp" }
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback-classic" }
plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
plugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx:binary-compatibility-validator:0.13.2"

View File

@ -0,0 +1,12 @@
plugins {
alias(libs.plugins.jvm) apply false
alias(libs.plugins.multiplatform) apply false
}
group = "ru.otus"
version = "0.0.1"
subprojects {
group = rootProject.group
version = rootProject.version
}

View File

@ -0,0 +1,3 @@
kotlin.code.style=official
kotlin.mpp.enableCInteropCommonization=true
kotlin.native.ignoreDisabledTargets=true

View File

@ -1,5 +1,5 @@
plugins {
kotlin("jvm")
alias(libs.plugins.jvm)
}
group = "ru.otus"

View File

@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.jvm)
}
group = "ru.otus"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}

View File

@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.jvm)
}
group = "ru.otus"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}

View File

@ -0,0 +1,20 @@
package ru.otus
fun mapToFML(fml: Map<String, String>): String = "${fml["last"]} ${fml["first"]} ${fml["middle"]}"
fun mapToFL(fl: Map<String, String>): String = "${fl["last"]} ${fl["first"]}"
fun mapToF(f: Map<String, String>): String = "${f["first"]}"
fun mapListToNames(mapList: List<Map<String, String>>): List<String> {
val result = mutableListOf<String>()
mapList.forEach {
when(it.keys) {
setOf("first") -> result.add(mapToF(it))
setOf("first", "last") -> result.add(mapToFL(it))
setOf("first", "middle", "last") -> result.add(mapToFML(it))
}
}
return result.toList()
}

View File

@ -0,0 +1,40 @@
package ru.otus
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
/*
* Реализовать функцию, которая преобразует список словарей строк в ФИО
* Функцию сделать с использованием разных функций для разного числа составляющих имени
* Итого, должно получиться 4 функции
*
* Для успешного решения задания, требуется раскомментировать тест, тест должен выполняться успешно
* */
class HomeWorkFunc {
@Test
fun mapListToNamesTest() {
val input = listOf(
mapOf(
"first" to "Иван",
"middle" to "Васильевич",
"last" to "Рюрикович",
),
mapOf(
"first" to "Петька",
),
mapOf(
"first" to "Сергей",
"last" to "Королев",
),
)
val expected = listOf(
"Рюрикович Иван Васильевич",
"Петька",
"Королев Сергей",
)
val res = mapListToNames(input)
assertEquals(expected, res)
}
}

View File

@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.jvm)
}
group = "ru.otus"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}

View File

@ -0,0 +1,5 @@
package ru.otus
interface Figure {
fun area(): Int
}

View File

@ -0,0 +1,3 @@
package ru.otus
fun diffArea(a: Figure, b: Figure): Int = a.area() - b.area()

View File

@ -0,0 +1,24 @@
package ru.otus
class Rectangle(val width: Int, val height: Int): Figure {
override fun area() = width * height
override fun equals(other: Any?): Boolean {
if (other?.javaClass != javaClass) {
return false
}
other as Rectangle
if (width != other.width) return false
if (height != other.height) return false
return true
}
override fun hashCode(): Int {
return javaClass.hashCode()
}
override fun toString() = "Rectangle(${width}x$height)"
}

View File

@ -0,0 +1,21 @@
package ru.otus
import kotlin.math.pow
class Square(val x: Int): Figure {
override fun area(): Int = x.toDouble().pow(2.0).toInt()
override fun equals(other: Any?): Boolean {
if (other?.javaClass != javaClass) {
return false
}
other as Square
return x == other.x
}
override fun hashCode(): Int {
return javaClass.hashCode()
}
}

View File

@ -0,0 +1,74 @@
package ru.otus
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertNotEquals
class HomeWorkOOP {
// task 1 - make a Rectangle class that will have width and height
// as well as the area calculation method - area()
// the test below should pass - uncomment the code in it
@Test
fun rectangleArea() {
val r = Rectangle(10, 20)
assertEquals(200, r.area())
assertEquals(10, r.width)
assertEquals(20, r.height)
}
// task 2 - make the Rectangle.toString() method
// the test below should pass - uncomment the code in it
@Test
fun rectangleToString() {
val r = Rectangle(10, 20)
assertEquals("Rectangle(10x20)", r.toString())
}
// task 3 - make Rectangle.equals() and Rectangle.hashCode() methods
// the test below should pass - uncomment the code in it
@Test
fun rectangleEquals() {
val a = Rectangle(10, 20)
val b = Rectangle(10, 20)
val c = Rectangle(20, 10)
assertEquals(a, b)
assertEquals(a.hashCode(), b.hashCode())
assertFalse (a === b)
assertNotEquals(a, c)
}
// task 4 - make the Square class
// the test below should pass - uncomment the code in it
@Test
fun squareEquals() {
val a = Square(10)
val b = Square(10)
val c = Square(20)
assertEquals(a, b)
assertEquals(a.hashCode(), b.hashCode())
assertFalse (a === b)
assertNotEquals(a, c)
println(a)
}
// task 5 - make the Figure interface with the area() method, inherit Rectangle and Square from it
// the test below should pass - uncomment the code in it
@Test
fun figureArea() {
var f : Figure = Rectangle(10, 20)
assertEquals(f.area(), 200)
f = Square(10)
assertEquals(f.area(), 100)
}
// task 6 - make the diffArea(a, b) method
// the test below should pass - uncomment the code in it
@Test
fun diffArea() {
val a = Rectangle(10, 20)
val b = Square(10)
assertEquals(diffArea(a, b), 100)
}
}

View File

@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.jvm)
}
group = "ru.otus"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}

View File

@ -0,0 +1,3 @@
package ru.otus
fun query(block: SqlSelectBuilder.() -> Unit) = SqlSelectBuilder().apply(block)

View File

@ -0,0 +1,59 @@
package ru.otus
class SqlSelectBuilder {
private var table: String? = null
private val columns = mutableListOf<String>()
private var whereClause: String? = null
fun select(vararg columns: String) = apply {
this.columns.addAll(columns)
}
fun from(table: String) = apply {
this.table = table
}
fun where(conditionBuilder: ConditionBuilder.() -> Unit) = apply {
val condition = ConditionBuilder().apply(conditionBuilder).build()
whereClause = condition
}
fun build(): String {
requireNotNull(table) { "Table name must be specified." }
val columnsPart = if (columns.isEmpty()) "*" else columns.joinToString(", ")
val wherePart = whereClause?.let { " where $it" } ?: ""
return "select $columnsPart from $table$wherePart"
}
class ConditionBuilder {
private val conditions = mutableListOf<String>()
infix fun String.eq(value: Any?): String {
val formattedValue = formatValue(value)
conditions.add("$this = $formattedValue")
return this
}
infix fun String.nonEq(value: Any?): String {
val formattedValue = formatValue(value)
conditions.add(if (value == null) "$this !is null" else "$this != $formattedValue")
return this
}
fun or(block: ConditionBuilder.() -> Unit): ConditionBuilder {
val nestedConditions = ConditionBuilder().apply(block).build()
conditions.add("($nestedConditions)")
return this
}
fun build(): String {
return conditions.joinToString(" or ")
}
private fun formatValue(value: Any?): String = when (value) {
is String -> "'$value'"
null -> "null"
else -> value.toString()
}
}
}

View File

@ -0,0 +1,110 @@
package ru.otus
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class HomeWorkDSL {
private fun checkSQL(expected: String, sql: SqlSelectBuilder) {
assertEquals(expected, sql.build())
}
@Test
fun `simple select all from table`() {
val expected = "select * from table"
val real = query {
from("table")
}
checkSQL(expected, real)
}
@Test
fun `check that select can't be used without table`() {
assertFailsWith<Exception> {
query {
select("col_a")
}.build()
}
}
@Test
fun `select certain columns from table`() {
val expected = "select col_a, col_b from table"
val real = query {
select("col_a", "col_b")
from("table")
}
checkSQL(expected, real)
}
@Test
fun `select certain columns from table 1`() {
val expected = "select col_a, col_b from table"
val real = query {
select("col_a", "col_b")
from("table")
}
checkSQL(expected, real)
}
/**
* __eq__ is "equals" function. Must be one of char:
* - for strings - "="
* - for numbers - "="
* - for null - "is"
*/
@Test
fun `select with complex where condition with one condition`() {
val expected = "select * from table where col_a = 'id'"
val real = query {
from("table")
where { "col_a" eq "id" }
}
checkSQL(expected, real)
}
/**
* __nonEq__ is "non equals" function. Must be one of chars:
* - for strings - "!="
* - for numbers - "!="
* - for null - "!is"
*/
@Test
fun `select with complex where condition with two conditions`() {
val expected = "select * from table where col_a != 0"
val real = query {
from("table")
where {
"col_a" nonEq 0
}
}
checkSQL(expected, real)
}
@Test
fun `when 'or' conditions are specified then they are respected`() {
val expected = "select * from table where (col_a = 4 or col_b !is null)"
val real = query {
from("table")
where {
or {
"col_a" eq 4
"col_b" nonEq null
}
}
}
checkSQL(expected, real)
}
}

View File

@ -0,0 +1,24 @@
plugins {
alias(libs.plugins.jvm)
}
group = "ru.otus"
repositories {
mavenCentral()
}
dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.kotlin.coroutines)
// Homework Hard
implementation(libs.okhttp) // http client
implementation(libs.kotlin.jackson.module) // from string to object
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}

View File

@ -0,0 +1,8 @@
package ru.otus.easy
import kotlinx.coroutines.delay
suspend fun findNumberInList(toFind: Int, numbers: List<Int>): Int {
delay(2000L)
return numbers.firstOrNull { it == toFind } ?: -1
}

View File

@ -0,0 +1,5 @@
package ru.otus.easy
fun generateNumbers() = (0..10000).map {
(0..100).random()
}

View File

@ -0,0 +1,30 @@
package ru.otus.hard
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import okhttp3.Response
import ru.otus.hard.dto.Dictionary
class DictionaryApi(
private val objectMapper: ObjectMapper = jacksonObjectMapper()
) {
fun findWord(locale: Locale, word: String): Dictionary? { // make something with context
val url = "$DICTIONARY_API/${locale.code}/$word"
println("Searching $url")
return getBody(HttpClient.get(url).execute())?.firstOrNull()
}
private fun getBody(response: Response): List<Dictionary>? {
if (!response.isSuccessful) {
return emptyList()
}
return response.body?.let {
objectMapper.readValue(it.string())
}
}
}

View File

@ -0,0 +1,12 @@
package ru.otus.hard
import okhttp3.OkHttpClient
import okhttp3.Request
object HttpClient : OkHttpClient() {
fun get(uri: String) =
Request.Builder().url(uri).build()
.let {
newCall(it)
}
}

View File

@ -0,0 +1,7 @@
package ru.otus.hard
@Suppress("unused")
enum class Locale(val code: String) {
EN("en_US"),
RU("ru")
}

View File

@ -0,0 +1,3 @@
package ru.otus.hard
internal const val DICTIONARY_API = "https://api.dictionaryapi.dev/api/v2/entries"

View File

@ -0,0 +1,9 @@
package ru.otus.hard.dto
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
@JsonIgnoreProperties(ignoreUnknown = true)
data class Dictionary(
val word: String,
val meanings: List<Meaning>
)

View File

@ -0,0 +1,14 @@
package ru.otus.hard.dto
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
@JsonIgnoreProperties(ignoreUnknown = true)
data class Meaning(
val definitions: List<Definition>
)
@JsonIgnoreProperties(ignoreUnknown = true)
data class Definition(
val definition: String,
val example: String? = ""
)

View File

@ -0,0 +1,4 @@
Jack shook his head whisked the second and first Lobby level Here in the center the registration desk Behind it are the offices The lobby runs for eighty feet in either direction from the desk Over here in the west the Overlook Dining Room and the Colorado Lounge The banquet and ballroom facility in the
Only about the basement Jack said For the winter caretaker the most important level of all Where the action
will show you all that The basement floor plan is on the room wall frowned impressively perhaps show that as manager he did not concern himself with such mundane aspects of the operation as the and the plumbing Might not be a bad idea put some traps down there too Just a
scrawled a note on a pad he took from his inner coat pocket each sheet bore the legend From the Desk of Stuart in bold black script tore it off and dropped it into the out basket It sat there looking lonesome The pad disappeared back jacket pocket like the conclusion of a magician trick you see it now you don't This guy is a real heavyweight

View File

@ -0,0 +1,99 @@
package ru.otus
import java.io.File
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import ru.otus.easy.findNumberInList
import ru.otus.easy.generateNumbers
import ru.otus.hard.DictionaryApi
import ru.otus.hard.Locale
import ru.otus.hard.dto.Dictionary
class HomeWorkCoroutines {
@Test
fun easyHw() = runBlocking {
val numbers = generateNumbers()
val toFind = 10
val toFindOther = 1000
val foundNumbers = mutableListOf<Deferred<Int>>()
foundNumbers.add(async(Dispatchers.Default) { findNumberInList(toFind, numbers) })
foundNumbers.add(async(Dispatchers.Default) { findNumberInList(toFindOther, numbers) })
foundNumbers.awaitAll().forEach {
if (it != -1) {
println("Your number $it found!")
} else {
println("Not found number $toFind || $toFindOther")
}
}
}
@Test
fun hardHw(): Unit = runBlocking {
val dictionaryApi = DictionaryApi()
val words = FileReader.readFile().split(" ", "\n").toSet()
// Асинхронный поиск значений
val deferredDictionaries = findWordsAsync(dictionaryApi, words, Locale.EN)
val dictionaries = deferredDictionaries.awaitAll()
dictionaries.filterNotNull().map { dictionary ->
print("For word ${dictionary.word} i found examples: ")
println(
dictionary.meanings
.mapNotNull { definition ->
val r = definition.definitions
.mapNotNull { it.example.takeIf { it?.isNotBlank() == true } }
.takeIf { it.isNotEmpty() }
r
}
.takeIf { it.isNotEmpty() }
)
}
}
private fun findWords(
dictionaryApi: DictionaryApi,
words: Set<String>,
@Suppress("SameParameterValue") locale: Locale
) =
// make some suspensions and async
words.map {
dictionaryApi.findWord(locale, it)
}
@OptIn(DelicateCoroutinesApi::class)
private fun findWordsAsync(
dictionaryApi: DictionaryApi,
words: Set<String>,
@Suppress("SameParameterValue") locale: Locale
): List<Deferred<Dictionary?>> {
return words.map { word ->
GlobalScope.async(Dispatchers.IO) {
try {
dictionaryApi.findWord(locale, word)
} catch (e: Exception) {
println("Error searching word $word: ${e.message}")
null // Игнорируем ошибку
}
}
}
}
object FileReader {
fun readFile(): String =
File(
this::class.java.classLoader.getResource("words.txt")?.toURI()
?: throw RuntimeException("Can't read file")
).readText()
}
}

View File

@ -0,0 +1,22 @@
plugins {
alias(libs.plugins.jvm)
}
group = "ru.otus"
repositories {
mavenCentral()
}
dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.kotlin.coroutines)
implementation(libs.slf4j)
implementation(libs.logback.classic)
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}

View File

@ -0,0 +1,71 @@
package ru.otus
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.*
import java.time.Instant
import java.util.*
import kotlin.concurrent.schedule
data class Sample(
val serialNumber: String,
val value: Double,
val timestamp: Instant = Instant.now()
)
interface Detector {
fun samples(): Flow<Sample>
}
class CoroutineDetector(
private val serialNumber: String,
private val sampleDistribution: Sequence<Double>,
private val samplePeriod: Long
) : Detector {
override fun samples(): Flow<Sample> =
flow {
val values = sampleDistribution.iterator()
while (true) {
emit(Sample(serialNumber, values.next()))
delay(samplePeriod)
}
}
}
class BlockingDetector(
private val serialNumber: String,
private val sampleDistribution: Sequence<Double>,
private val samplePeriod: Long
) : Detector {
override fun samples(): Flow<Sample> =
flow {
val values = sampleDistribution.iterator()
while (true) {
emit(Sample(serialNumber, values.next()))
Thread.sleep(samplePeriod)
}
}.flowOn(Dispatchers.IO)
}
class CallbackDetector(
private val serialNumber: String,
private val sampleDistribution: Sequence<Double>,
private val samplePeriod: Long
) : Detector {
override fun samples(): Flow<Sample> =
callbackFlow {
val values = sampleDistribution.iterator()
val timer = Timer()
timer.schedule(0L, samplePeriod) {
trySendBlocking(Sample(serialNumber, values.next()))
}
timer.schedule(10_000L) { close() }
awaitClose { timer.cancel() }
}
}
fun <T> Flow<T>.rollingMax(comparator: Comparator<T>): Flow<T> =
runningReduce { max, current -> maxOf(max, current, comparator) }

View File

@ -0,0 +1,81 @@
package ru.otus
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import java.math.BigDecimal
/**
* Задание.
* Добавить необходимые фильтры для того, чтоб тесты заработали как надо.
*
* Описание. У нас БД в памяти. В ней нужно найти объект, описанный фильтром SearchFilter.
*/
class HomeWorkFlow {
@Test
fun filter() = runBlocking {
val flt = SearchFilter(
title = "шнурки",
type = AdType.DEMAND,
visibilitiesOr = setOf(AdVisibility.OWNER, AdVisibility.GROUP),
priceMin = BigDecimal("10.00"),
)
val res = LIST
.asFlow()
.run {
// Фильтр по названию
flt.title?.let { title -> this.filter { it.title == title } } ?: this
}
.run {
// Фильтр по типу объявления
flt.type?.let { type -> this.filter { it.type == type } } ?: this
}
.run {
// Фильтр по видимости (OR условие)
flt.visibilitiesOr?.let { visibilities -> this.filter { it.visibility in visibilities } } ?: this
}
.run {
// Фильтр по минимальной цене
flt.priceMin?.let { minPrice -> this.filter { it.price >= minPrice } } ?: this
}
.toList()
assertEquals(1, res.size)
assertEquals("5", res.first().id)
}
companion object {
data class SearchFilter(
val title: String? = null,
val visibilitiesOr: Set<AdVisibility>? = null,
val priceMin: BigDecimal? = null,
val priceMax: BigDecimal? = null,
val type: AdType? = null,
)
data class Ad(
val id: String,
val title: String,
val visibility: AdVisibility,
val price: BigDecimal,
val type: AdType,
)
enum class AdVisibility { PUBLIC, GROUP, OWNER }
enum class AdType { DEMAND, SUPPLY }
val LIST = listOf(
Ad("1", "носок", AdVisibility.PUBLIC, BigDecimal("22.13"), AdType.SUPPLY),
Ad("2", "носок", AdVisibility.PUBLIC, BigDecimal("22.13"), AdType.DEMAND),
Ad("3", "носок", AdVisibility.PUBLIC, BigDecimal("40.13"), AdType.DEMAND),
Ad("4", "носок", AdVisibility.OWNER, BigDecimal("40.13"), AdType.DEMAND),
Ad("5", "шнурки", AdVisibility.OWNER, BigDecimal("40.13"), AdType.DEMAND),
Ad("6", "шнурки", AdVisibility.OWNER, BigDecimal("40.13"), AdType.SUPPLY),
Ad("7", "шнурки", AdVisibility.GROUP, BigDecimal("9.99"), AdType.DEMAND),
)
}
}

View File

@ -0,0 +1,93 @@
plugins {
alias(libs.plugins.multiplatform)
// Только для lombock!!
java
}
repositories {
google()
mavenCentral()
}
kotlin {
jvm {
withJava()
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
js {
browser {
testTask {
// useKarma {
// // Выбираем браузеры, на которых будет тестироваться
// useChrome()
// useFirefox()
// }
// Без этой настройки длительные тесты не отрабатывают
useMocha {
timeout = "100s"
}
}
}
}
// linuxX64()
macosX64 {
binaries {
executable()
}
}
val coroutinesVersion: String by project
val datetimeVersion: String by project
// Description of modules corresponding to our target platforms
// common - common code that we can use on different platforms
// for each target platform, we can specify our own specific dependencies
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
implementation(libs.kotlin.coroutines)
implementation(libs.kotlin.datetime)
}
}
commonTest {
dependencies {
implementation(kotlin("test"))
implementation(libs.kotlin.coroutines.test)
}
}
jvmMain {
}
jvmTest {
dependencies {
implementation(kotlin("test"))
}
}
// dependencies from npm
jsMain {
dependencies {
implementation(npm("js-big-decimal", "~1.3.4"))
implementation(npm("is-sorted", "~1.0.5"))
}
}
jsTest {
dependencies {
implementation(kotlin("test"))
}
}
// С 1.9.20 можно так
nativeMain {
}
nativeTest {
}
}
}
// Только для lombock!!
dependencies {
compileOnly("org.projectlombok:lombok:1.18.34")
annotationProcessor("org.projectlombok:lombok:1.18.34")
}

View File

@ -0,0 +1,85 @@
plugins {
alias(libs.plugins.multiplatform)
}
kotlin {
js {
browser {
testTask {
// useKarma {
// // Выбираем браузеры, на которых будет тестироваться
// useChrome()
// useFirefox()
// }
// Без этой настройки длительные тесты не отрабатывают
useMocha {
timeout = "100s"
}
}
}
binaries.library()
generateTypeScriptDefinitions()
}
listOf(
linuxX64(),
macosArm64(),
).forEach {
it.apply {
compilations.getByName("main") {
cinterops {
// настраиваем cinterop в файле src/nativeInterop/cinterop/libcurl.def
val libcurl by creating
// create("libcurl")
}
}
binaries {
executable {
entryPoint = "main"
}
}
}
}
val coroutinesVersion: String by project
val datetimeVersion: String by project
// Description of modules corresponding to our target platforms
// common - common code that we can use on different platforms
// for each target platform, we can specify our own specific dependencies
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
implementation(libs.kotlin.coroutines)
implementation(libs.kotlin.datetime)
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
implementation(libs.kotlin.coroutines.test)
}
}
// dependencies from npm
val jsMain by getting {
dependencies {
implementation(npm("js-big-decimal", "~1.3.4"))
implementation(npm("is-sorted", "~1.0.5"))
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
// С 1.9.20 можно так
nativeMain {
}
nativeTest {
dependencies {
implementation(kotlin("test"))
}
}
}
}

View File

@ -0,0 +1,25 @@
@file:Suppress("UNUSED_PARAMETER", "unused")
// calling JS code through a js function, awkward to maintain
fun useMathRound(value: Double) = js("Math.round(value)")
// using annotations for JS modules
@JsModule("is-sorted")
@JsNonModule
external fun <T> sorted(array: Array<T>): Boolean
// Using wrappers for JS modules.
// Can be generated from TS using dukat (External tool).
@JsModule("js-big-decimal")
@JsNonModule
@JsName("BigDecimal")
external class JsBigDecimal(value: Any) {
fun getValue(): String
fun getPrettyValue(digits: Int, separator: String)
fun round(precision: Int = definedExternally, mode: dynamic = definedExternally): JsBigDecimal
companion object {
fun getPrettyValue(number: Any, digits: Int, separator: String)
}
}

View File

@ -0,0 +1,40 @@
@file:Suppress("unused")
@JsModule("js-big-decimal")
@JsNonModule
open external class BigDecimal {
open var value: Any
constructor(number: Number = definedExternally)
constructor()
constructor(number: String = definedExternally)
open fun getValue(): String
open fun getPrettyValue(digits: Any, separator: Any): String
open fun round(precision: Number = definedExternally, mode: RoundingModes = definedExternally): BigDecimal
open fun floor(): BigDecimal
open fun ceil(): BigDecimal
open fun add(number: BigDecimal): BigDecimal
open fun subtract(number: BigDecimal): BigDecimal
open fun multiply(number: BigDecimal): BigDecimal
open fun divide(number: BigDecimal, precision: Any): BigDecimal
open fun modulus(number: BigDecimal): BigDecimal
open fun compareTo(number: BigDecimal): dynamic /* 1 | 0 | "-1" */
open fun negate(): BigDecimal
companion object {
var RoundingModes: Any
var validate: Any
fun getPrettyValue(number: Any, digits: Any, separator: Any): String
fun round(number: Any, precision: Number = definedExternally, mode: RoundingModes = definedExternally): String
fun floor(number: Any): Any
fun ceil(number: Any): Any
fun add(number1: Any, number2: Any): String
fun subtract(number1: Any, number2: Any): String
fun multiply(number1: Any, number2: Any): String
fun divide(number1: Any, number2: Any, precision: Any): String
fun modulus(number1: Any, number2: Any): String
fun compareTo(number1: Any, number2: Any): dynamic /* 1 | 0 | "-1" */
fun negate(number: Any): String
}
}

View File

@ -0,0 +1,15 @@
@file:OptIn(ExperimentalJsExport::class)
@JsExport
fun fromKotlin() {
println("From Kotlin function")
}
@JsExport
data class FromKotlinClass(
val some: String = "",
val id: Int = 0,
)
@JsExport
val jsonApp = kotlin.js.json(Pair("name", "App1"))

View File

@ -0,0 +1,13 @@
@file:Suppress("unused")
@Suppress("ENUM_CLASS_IN_EXTERNAL_DECLARATION_WARNING") // temporary solution
external enum class RoundingModes {
CEILING /* = 0 */,
DOWN /* = 1 */,
FLOOR /* = 2 */,
HALF_DOWN /* = 3 */,
HALF_EVEN /* = 4 */,
HALF_UP /* = 5 */,
UNNECESSARY /* = 6 */,
UP /* = 7 */
}

View File

@ -0,0 +1,42 @@
package ru.otus.otuskotlin.m1l7
import BigDecimal
import JsBigDecimal
import sorted
import useMathRound
import kotlin.math.PI
import kotlin.test.Test
import kotlin.test.assertEquals
class InteroperabilityJSTest {
@Test
fun mathRoundTest() {
assertEquals(3, useMathRound(PI))
}
@Test
fun sortTest() {
assertEquals(true, sorted(arrayOf(1, 2, 3)))
assertEquals(false, sorted(arrayOf(4, 1, 2, 3)))
}
@Test
fun bigDecimalTest() {
val bd = JsBigDecimal("${PI * 10000}")
println("BigDecimal: ${bd.getValue()}")
println("Pretty: ${bd.getPrettyValue(3, ",")}")
println("Pretty static: ${JsBigDecimal.getPrettyValue(bd.getValue(), 3, ",")}")
assertEquals("31416", bd.round().getValue())
}
@Test
fun dukatLibraryTest() {
val bd = BigDecimal("${PI * 10000}")
println("BigDecimal: ${bd.getValue()}")
println("Pretty: ${bd.getPrettyValue(3, ",")}")
println("Pretty static: ${BigDecimal.getPrettyValue(bd.getValue(), 3, ",")}")
assertEquals("31416", bd.round().getValue())
}
}

View File

@ -0,0 +1,30 @@
# list of header files to generate Kotlin stubs
headers = curl/curl.h
# You also need to specify linking parameters for different platforms
compilerOpts.linux_x64 = -I/usr/include -I/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/
linkerOpts.osx = -L/opt/homebrew/Cellar/curl/8.11.1/lib -L/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/ -lcurl
linkerOpts.linux_x64 = -L/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/ -lcurl
---
// Структура на СИ, которую будем использовать в Kotlin-коде
typedef struct {
int a;
double b;
} MySumStruct;
// Функция на СИ, принимающая саму структуру в качестве аргумента
double sum_struct(MySumStruct s) {
return (double)s.a + s.b;
}
// Функция на СИ, принимающая ссылку на структуру в качестве аргумента
double sum_ref(MySumStruct *s) {
return (double)s->a + s->b;
}
// Функция на СИ, принимающая ссылку на структуру и вызывающую код из Котлин
double sum_fun(MySumStruct *s, double (*callback)(int a, double b)) {
return callback(s->a, s->b);
}

View File

@ -0,0 +1,20 @@
@file:OptIn(ExperimentalForeignApi::class)
import kotlinx.cinterop.*
import libcurl.*
@OptIn(ExperimentalForeignApi::class)
fun main() {
val curl = curl_easy_init()
if (curl != null) {
curl_easy_setopt(curl, CURLOPT_URL, "http://info.cern.ch")
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L)
val res = curl_easy_perform(curl)
if (res != CURLE_OK) {
println("curl_easy_perform() failed ${curl_easy_strerror(res)?.toKString()}")
} else {
println("curl_easy_perform() succeeded $res")
}
curl_easy_cleanup(curl)
}
}

View File

@ -0,0 +1,61 @@
@file:OptIn(ExperimentalForeignApi::class)
import kotlinx.cinterop.*
import libcurl.MySumStruct
import libcurl.sum_fun
import libcurl.sum_ref
import libcurl.sum_struct
// Использование структур в c-функциях
fun sumStruct(a: Int, b: Double): Double {
// Инициализируем экземпляр c-структуры
val s: CValue<MySumStruct> = cValue<MySumStruct> {
this.a = a
this.b = b
}
// передаем в функцию саму структуру
return sum_struct(s)
}
// Использование c-ссылок на структуры в Котлин
fun sumRef(a: Int, b: Double): Double = cValue<MySumStruct> {
this.a = a
this.b = b
}.usePinned { // фиксируем положение структуры в памяти на время вызова
// передаем в c-функцию ссылку на структуру
sum_ref(it.get())
}
// Аллоцирование памяти для использования в c-функциях
fun sumAlloc(a: Int, b: Double): Double = memScoped {
// Это блок со скоупом памяти. По выходу из этого скоупа, память автоматически очистится
// Это избавляет нас от явного освобождения памяти через free(mem)
// Выделяем динамическую память
alloc<MySumStruct> {
this.a = a
this.b = b
}.usePinned {// фиксируем положение структуры в памяти на время вызова
// вызываем функцию с сылкой на аллоцированную структуру
sum_ref(it.get().ptr)
}
}
// Аллоцирование памяти для использования в c-функциях
fun sumCallback(a: Int, b: Double): Double {
return cValue<MySumStruct> {
this.a = a
this.b = b
}.usePinned { // фиксируем положение структуры в памяти на время вызова
// Для демонстрации non-capturing природы колбэков для СИ
@Suppress("UNUSED_VARIABLE") val capturingVariable = a.toString()
// передаем в c-функцию специально подготовленную функцию
sum_fun(it.get(), staticCFunction { a: Int, b: Double ->
// println("Эта строка не сработает: функция должна быть non-capturing, т.е. не ссылаться наружу -> $capturingVariable")
a.toDouble() + b
})
}
}

View File

@ -0,0 +1,25 @@
import kotlin.test.Test
import kotlin.test.assertEquals
class Ex2_memory_managementKtTest {
@Test
fun sumStruct() {
assertEquals(5.0, sumStruct(2, 3.0))
}
@Test
fun sumRef() {
assertEquals(5.0, sumRef(2, 3.0))
}
@Test
fun sumAlloc() {
assertEquals(5.0, sumAlloc(2, 3.0))
}
@Test
fun sumCallback() {
assertEquals(5.0, sumCallback(2, 3.0))
}
}

View File

@ -0,0 +1,7 @@
Работа с JNI
1. Создать Kotlin-класс
2. Сгенерировать из котлин-класса заголовочный файл языка C. Этот файл будет описывать обертку, которую нам нужно написать.
3. Написать код на C библиотеки-обертки, соответствующий сгенерированному заголовку. В этом коде можно вызывать целевую нативную библиотеку.
Т.е. еще раз. Для интеграции с JVM требуется написать библиотеку-обертку, которую будет вызывать JRE. В библиотеке-обертке вы выполните вызов вашей целевой нативной библиотеки.

View File

@ -0,0 +1,122 @@
import org.gradle.internal.jvm.Jvm
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
import java.io.ByteArrayOutputStream
plugins {
alias(libs.plugins.multiplatform)
}
kotlin {
jvm {
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
// Description of modules corresponding to our target platforms
// common - common code that we can use on different platforms
// for each target platform, we can specify our own specific dependencies
sourceSets {
val jvmMain by getting {
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
}
}
tasks {
val pathToLib: String = project.layout.buildDirectory.dir("c/lib").get().toString()
println("PATH TO LIB: $pathToLib")
val jniHeaderDirectory = layout.buildDirectory.dir("jniIncludes").get().asFile
val generateJniHeaders by creating {
group = "interop"
dependsOn(getByName("compileKotlinJvm"))
// For caching
inputs.dir("src/jvmMain/kotlin")
// outputs.dir("src/jvmMain/generated/jni")
outputs.dir(jniHeaderDirectory)
doLast {
val javaHome = Jvm.current().javaHome
val javap = javaHome.resolve("bin").walk().firstOrNull { it.name.startsWith("javap") }?.absolutePath ?: error("javap not found")
val javac = javaHome.resolve("bin").walk().firstOrNull { it.name.startsWith("javac") }?.absolutePath ?: error("javac not found")
val buildDir = file("build/classes/kotlin/jvm/main")
val tmpDir = file("build/tmp/jvmJni").apply { mkdirs() }
val bodyExtractingRegex = """^.+\Rpublic \w* ?class ([^\s]+).*\{\R((?s:.+))\}\R$""".toRegex()
val nativeMethodExtractingRegex = """.*\bnative\b.*""".toRegex()
buildDir.walkTopDown()
.filter { "META" !in it.absolutePath }
.forEach { file ->
if (!file.isFile) return@forEach
println("FILE: $file")
val output = ByteArrayOutputStream().use {
project.exec {
commandLine(javap, "-private", "-cp", buildDir.absolutePath, file.absolutePath)
standardOutput = it
}.assertNormalExitValue()
it.toString()
}
val (qualifiedName, methodInfo) = bodyExtractingRegex.find(output)?.destructured ?: return@forEach
val lastDot = qualifiedName.lastIndexOf('.').takeIf { it >= 0 } ?: return@forEach
val packageName = qualifiedName.substring(0, lastDot)
val className = qualifiedName.substring(lastDot+1, qualifiedName.length)
val nativeMethods = nativeMethodExtractingRegex
.findAll(methodInfo)
.map { it.groups }
.flatMap { it.asSequence().mapNotNull { group -> group?.value } }
.toList()
if (nativeMethods.isEmpty()) return@forEach
val source = buildString {
appendLine("package $packageName;")
appendLine("public class $className {")
for (method in nativeMethods) {
if ("()" in method) appendLine(method)
else {
val updatedMethod = StringBuilder(method).apply {
var count = 0
var i = 0
while (i < length) {
if (this[i] == ',' || this[i] == ')') insert(i, " arg${count++}".also { i += it.length + 1 })
else i++
}
}
appendLine(updatedMethod)
}
}
appendLine("}")
}
val outputFile = tmpDir.resolve(packageName.replace(".", "/")).apply { mkdirs() }.resolve("$className.java").apply { delete() }.apply { createNewFile() }
outputFile.writeText(source)
project.exec {
commandLine(javac, "-h", jniHeaderDirectory.absolutePath, outputFile.absolutePath)
}.assertNormalExitValue()
}
}
}
val makeCLib by creating(Exec::class) {
dependsOn(generateJniHeaders)
group = "build"
commandLine("make")
workingDir(layout.projectDirectory.dir("c-jni"))
}
withType(KotlinJvmTest::class) {
dependsOn(makeCLib)
systemProperty("java.library.path", pathToLib)
}
}

View File

@ -0,0 +1,31 @@
JDK=/opt/homebrew/opt/openjdk@23
INC=-I../build/jniIncludes -I/usr/include -I/Library/Developer/CommandLineTools/SDKs/MacOSX15.sdk/usr/include/ -I$(JDK)/include
CC = gcc
OUT_FILE_NAME = libc_jni.so
CFLAGS= -fPIC -O0 -g -Wall -c
OBJ_DIR=../build/c/obj
OUT_DIR=../build/c/lib
.PHONY: rebuild all clean
all: $(OUT_FILE_NAME)
#Compiling every *.cpp to *.o
$(OBJ_DIR)/%.o: %.c dirmake
$(CC) -c $(INC) $(CFLAGS) -o $@ $<
$(OUT_FILE_NAME): $(patsubst %.c,$(OBJ_DIR)/%.o,$(wildcard *.c))
$(CC) -shared -o $(OUT_DIR)/$(OUT_FILE_NAME) $^
dirmake:
@mkdir -p $(OUT_DIR)
@mkdir -p $(OBJ_DIR)
clean:
rm -f $(OBJ_DIR)/*.o $(OUT_DIR)/$(OUT_FILE_NAME) Makefile.bak
rebuild: clean all

View File

@ -0,0 +1,6 @@
#include "ru_otus_otuskotlin_interop_NativeExample.h"
JNIEXPORT jint JNICALL Java_ru_otus_otuskotlin_interop_NativeExample_native_1add
(JNIEnv *env, jobject jo, jint a, jint b) {
return a + b;
}

View File

@ -0,0 +1,11 @@
package ru.otus.otuskotlin.interop
class NativeExample {
external fun native_add(a: Int, b: Int): Int
companion object {
init {
System.loadLibrary("c_jni")
}
}
}

View File

@ -0,0 +1,12 @@
package ru.otus.otuskotlin.interop
import kotlin.test.Test
import kotlin.test.assertEquals
class NativeExampleTest {
@Test
fun cExampleTest() {
val re = NativeExample()
assertEquals(5, re.native_add(3, 2))
}
}

View File

@ -0,0 +1,66 @@
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
plugins {
alias(libs.plugins.jvm)
}
repositories {
mavenCentral()
}
tasks {
// Таска для создания файла
val myCustomTask by creating {
group = "my group"
val dir = layout.buildDirectory.dir("my-in")
outputs.dir(dir)
doFirst {
val fileContent = """
package my.x
const val MY_VERSION: String = "${project.version}"
""".trimIndent()
dir
.get()
.file("my-version.kt")
.asFile
.apply {
ensureParentDirsCreated()
writeText(fileContent)
}
}
}
val myCopyTask by creating(Copy::class) {
dependsOn(myCustomTask)
group = "my group"
from(myCustomTask.outputs)
into(layout.buildDirectory.dir("tmp"))
}
compileKotlin {
println(layout.projectDirectory.dir("src/jvmMain/kotlin"))
source(layout.buildDirectory.dir("my-in"), layout.projectDirectory.dir("src/jvmMain/kotlin"))
dependsOn(myCopyTask)
}
}
tasks {
create("myTask") {
println("Configuration stage")
doFirst { println("At task starts") }
doLast { println("At task ends") }
}
}
afterEvaluate {
tasks {
create("myOtherTask") {
println("After other tasks initialized")
}
forEach { println("TASK $it") }
}
}

View File

@ -0,0 +1,13 @@
package ru.otus.otuskotlin.interop
class RustExample {
external fun rust_add(a: Int, b: Int): Int
init {
System.loadLibrary("c_jni")
}
}
fun main() {
println(my.x.MY_VERSION)
}

View File

@ -0,0 +1,12 @@
package ru.otus.otuskotlin.interop
import kotlin.test.Test
import kotlin.test.assertEquals
class RustExampleTest {
@Test
fun rustExampleTest() {
val re = RustExample()
assertEquals(5, re.rust_add(3, 2))
}
}

View File

@ -0,0 +1,7 @@
plugins {
kotlin("jvm")
}
repositories {
mavenCentral()
}

View File

@ -0,0 +1,7 @@
plugins {
kotlin("jvm")
}
repositories {
mavenCentral()
}

View File

@ -0,0 +1,15 @@
plugins {
kotlin("jvm")
}
dependencies {
// implementation(project(":m2l5-gradle:sub1:ssub1"))
// implementation(project(":m2l5-gradle:sub1:ssub2"))
implementation(projects.m2l5Gradle.sub1.ssub1)
implementation(projects.m2l5Gradle.sub1.ssub2)
}
repositories {
mavenCentral()
}

View File

@ -0,0 +1,26 @@
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "ok-lessons"
include("m1l1-first")
include("m1l2-basic")
include("m1l3-func")
include("m1l4-oop")
include("m2l1-dsl")
include("m2l2-coroutines")
include("m2l3-flows")
include("m2l4-kmp")
include("m2l5-1-interop")
include("m2l5-2-jni")
include("m2l6-gradle")

View File

@ -0,0 +1,7 @@
plugins {
alias(libs.plugins.jvm) apply false
alias(libs.plugins.multiplatform) apply false
}
group = "ru.otus.messenger"
version = "0.0.1"

View File

@ -0,0 +1,2 @@
kotlin.code.style=official
kotlin.native.ignoreDisabledTargets=true

View File

@ -0,0 +1,3 @@
plugins {
id("build-jvm")
}

View File

@ -0,0 +1,3 @@
fun main() {
print("Hello world")
}

View File

@ -0,0 +1,26 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
pluginManagement {
includeBuild("../build-plugin")
plugins {
id("build-jvm") apply false
id("build-kmp") apply false
}
repositories {
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "ok-messenger-be"
//enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
include(":ok-messenger-tmp")

View File

@ -1,10 +1,13 @@
pluginManagement {
val kotlinVersion: String by settings
plugins {
kotlin("jvm") version kotlinVersion
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}
rootProject.name = "otus-kotlin-developer"
include("m1l1-first")
includeBuild("build-plugin")
includeBuild("ok-lessons")
includeBuild("ok-messenger-be")