
Offers modular tools for cross-platform mobile app development, including features like MVVM architecture, location services, permissions management, Bluetooth communication, and more, using coroutines and `Flow` for efficient design.
This project is named after the Kaluga, the world's biggest freshwater fish, which is found in the icy Amur river.
Kaluga's main goal is to provide access to common features used in cross-platform mobile app development, separated into modules such as architecture (MVVM), location, permissions, bluetooth etc.
To reach this goal it uses Kotlin, specifically Kotlin Multiplatform which allows running Kotlin code not just on JVM+Android, but also iOS/iPadOS, amongst others (inndeed some kaluga modules also work for Kotlin.js and/or JVM standalone).
Where appropriate coroutines and Flow are used in the API. This enables developers to use cold streams for a modern and efficient design.
While Kaluga modules can be used individually, together they form a comprehensive approach to cross-platform development with shared native code and native UIs, including SwiftUI and Compose.
With Kaluga it is possible to create cross-platform functionality in a few lines of code, that would normally take many lines of code even on just one platform.
Below are some examples, using a commonMain source-set:
Scanning for nearby devices with Bluetooth LE:
// will auto request permissions and try to enable bluetooth
BluetoothClientBuilder().createClient().devices().collect {
i("discovered device: $it") // log found device
}Showing a spinner while doing some work:
suspend fun doWork(hudBuilder: HUD.Builder) {
hudBuilder.presentDuring { // shows spinner while code in this block is running
// simulate doing work
delay(1000)
}
}
in this case, since HUD is a UI component the builder needs to be configured on the platform side:
val builder = HUD.Builder() // same for iOS and Android
// ...
builder.subscribe(activity) // this needs be done in the Android source-set to bind the HUD to the lifecycle of the Activity
// ...
builder.unsubscribe(activity) // when the Activity is stoppedHowever Kaluga's architecture module offers a cross-platform LifecycleViewModel class (which extends androidx.lifecycle.ViewModel on Android) that will automatically bind the builder to its lifecycle:
// this can just be in the commonMain source
class HudViewModel(private val hudBuilder: HUD.Builder): BaseLifecycleViewModel(hudBuilder) {
suspend fun doWork() =
hudBuilder.presentDuring {
delay(1000)
}
}Kaluga contains an example project that is used to test the developed modules.
For starting a new project based on Kaluga see the kaluga-starter repo, which shows how to do this step by step.
Kaluga is available on Maven Central. For example the Kaluga Alerts can be imported like this:
repositories {
mavenCentral()
}
dependencies {
implementation("com.splendo.kaluga.alerts:alerts:$kalugaVersion")
}You can also use the SNAPSHOT version based on the latest in the develop branch:
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
implementation("com.splendo.kaluga.alerts:alerts:$kalugaDevelopVersion-SNAPSHOT")
}To use kaluga with SwiftUI and/or Combine we have a repo with Sourcery templates to generate some Swift code to help get you started.
Modules are organized into feature groups; each group directory has its own README with more detail. The table below lists every published module, its artifact coordinate, and the platforms it supports.
| Module | Usage | Artifact | Android | iOS | JVM | JS | WasmJS | macOS | tvOS | watchOS |
|---|---|---|---|---|---|---|---|---|---|---|
| alerts/alerts | Showing alert dialogs | com.splendo.kaluga.alerts:alerts |
✅ | ✅ | ||||||
| alerts/test-utils | Test helpers for the alerts module | com.splendo.kaluga.alerts:test |
✅ | ✅ | ||||||
| architecture/architecture | MVVM architecture | com.splendo.kaluga.architecture:architecture |
✅ | ✅ | ||||||
| architecture/compose | Compose extensions for architecture | com.splendo.kaluga.architecture:compose |
✅ | |||||||
| architecture/test-utils | Test helpers for the architecture module | com.splendo.kaluga.architecture:test |
✅ | ✅ | ||||||
| architecture/test-koin | Koin-based test helpers | com.splendo.kaluga.architecture:test-koin |
✅ | ✅ | ||||||
| base/base | Core components of Kaluga: threading, flowables and localization | com.splendo.kaluga.base:base |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| base/test-utils | Test helpers built on top of base | com.splendo.kaluga.base:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| bluetooth/core | Shared Bluetooth attributes and the BluetoothFormat (de)serialization framework | com.splendo.kaluga.bluetooth:core |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/client | Scanning for and connecting to BLE devices as a Client | com.splendo.kaluga.bluetooth:client |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/server | Advertising and exposing GATT attributes as a Server | com.splendo.kaluga.bluetooth:server |
✅ | ✅ | ✅ | |||||
| bluetooth/beacons | Tracking the availability of Beacons using the Eddystone protocol | com.splendo.kaluga.bluetooth:beacons |
✅ | ✅ | ✅ | ✅ | ✅ | |||
| bluetooth/test-utils/core | Test helpers for the Bluetooth core module | com.splendo.kaluga.bluetooth:test-core |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/test-utils/client | Test helpers for the Bluetooth client module | com.splendo.kaluga.bluetooth:test-client |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/test-utils/server | Test helpers for the Bluetooth server module | com.splendo.kaluga.bluetooth:test-server |
✅ | ✅ | ✅ | |||||
| date-time | Multiplatform classes to work with date and time | com.splendo.kaluga:date-time |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| date-time-picker/date-time-picker | Showing a Date or Time Picker | com.splendo.kaluga.date-time-picker:date-time-picker |
✅ | ✅ | ||||||
| date-time-picker/test-utils | Test helpers for the Date Time Picker module | com.splendo.kaluga.date-time-picker:test |
✅ | ✅ | ||||||
| hud/hud | Showing a loading-indicator HUD | com.splendo.kaluga.hud:hud |
✅ | ✅ | ||||||
| hud/test-utils | Test helpers for the HUD module | com.splendo.kaluga.hud:test |
✅ | ✅ | ||||||
| keyboard/keyboard | Showing and hiding the keyboard | com.splendo.kaluga.keyboard:keyboard |
✅ | ✅ | ||||||
| keyboard/compose | Compose extensions for keyboard | com.splendo.kaluga.keyboard:compose |
✅ | |||||||
| keyboard/test-utils | Test helpers for the keyboard module | com.splendo.kaluga.keyboard:test |
✅ | ✅ | ||||||
| lifecycle/lifecycle | Platform-host lifecycle bindings for service builders | com.splendo.kaluga.lifecycle:lifecycle |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| lifecycle/compose | Compose extensions for lifecycle | com.splendo.kaluga.lifecycle:compose |
✅ | ✅ | ✅ | ✅ | ||||
| lifecycle/test-utils | Test helpers for the lifecycle module | com.splendo.kaluga.lifecycle:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| links | Decoding a url into an object | com.splendo.kaluga:links |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| location/location | Provides the user's geolocation | com.splendo.kaluga.location:location |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| location/test-utils | Test helpers for the location module | com.splendo.kaluga.location:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| logging | Shared console logging | com.splendo.kaluga:logging |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| media/media | Playing audio/video | com.splendo.kaluga.media:media |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
| media/compose | Compose extensions for media | com.splendo.kaluga.media:compose |
✅ | ✅ | ✅ | ✅ | ||||
| media/test-utils | Test helpers for the media module | com.splendo.kaluga.media:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
| permissions/core | The permissions framework, used in conjunction with the per-type modules | com.splendo.kaluga.permissions:core |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/bluetooth | Managing Bluetooth permissions | com.splendo.kaluga.permissions:bluetooth |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/calendar | Managing calendar permissions | com.splendo.kaluga.permissions:calendar |
✅ | ✅ | ✅ | ✅ | ||||
| permissions/camera | Managing camera permissions | com.splendo.kaluga.permissions:camera |
✅ | ✅ | ✅ | ✅ | ✅ | |||
| permissions/contacts | Managing contacts permissions | com.splendo.kaluga.permissions:contacts |
✅ | ✅ | ✅ | ✅ | ||||
| permissions/location | Managing location permissions | com.splendo.kaluga.permissions:location |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/microphone | Managing microphone permissions | com.splendo.kaluga.permissions:microphone |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/notifications | Managing notifications permissions | com.splendo.kaluga.permissions:notifications |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/storage | Managing storage permissions | com.splendo.kaluga.permissions:storage |
✅ | ✅ | ✅ | ✅ | ||||
| permissions/test-utils | Test helpers for the Permissions modules | com.splendo.kaluga.permissions:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| resources/resources | Shared Strings, Images, Colors and Fonts | com.splendo.kaluga.resources:resources |
✅ | ✅ | ||||||
| resources/compose | Compose extensions for resources | com.splendo.kaluga.resources:compose |
✅ | |||||||
| resources/databinding | Data Binding extensions for resources | com.splendo.kaluga.resources:databinding |
✅ | |||||||
| resources/test-utils | Test helpers for the resources module | com.splendo.kaluga.resources:test |
✅ | ✅ | ||||||
| review | Requesting the user to review the app | com.splendo.kaluga:review |
✅ | ✅ | ✅ | |||||
| scientific/scientific | Scientific units and conversions | com.splendo.kaluga.scientific:scientific |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| scientific/converters | Converters between scientific units | com.splendo.kaluga.scientific:converters |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| service/service | Adding services to Kaluga | com.splendo.kaluga.service:service |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| service/test-utils | Test helpers for the service module | com.splendo.kaluga.service:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| system/system | System APIs such as network, audio, battery | com.splendo.kaluga.system:system |
✅ | ✅ | ✅ | ✅ | ✅ | |||
| system/test-utils | Test helpers for the system module | com.splendo.kaluga.system:test |
✅ | ✅ | ✅ | ✅ | ✅ |
Of course not every possible functionality is provided by kaluga. However, this is often because other good multiplatform libraries that work nicely with kaluga already exist. These use similar patterns such as coroutines and Flow, and include the following:
| Project | Usage |
|---|---|
| kotlin-firebase-sdk | wraps most of the Firebase SDK APIs |
| multiplatform-settings | store key/value data |
| SQLDelight | access SQLite (and other SQL database) |
Kaluga also uses some multiplatform libraries itself, so our thanks to:
| Project | Usage |
|---|---|
| Napier | powers the logging module |
| Koin | dependency injection |
see DEVELOP.
This project is named after the Kaluga, the world's biggest freshwater fish, which is found in the icy Amur river.
Kaluga's main goal is to provide access to common features used in cross-platform mobile app development, separated into modules such as architecture (MVVM), location, permissions, bluetooth etc.
To reach this goal it uses Kotlin, specifically Kotlin Multiplatform which allows running Kotlin code not just on JVM+Android, but also iOS/iPadOS, amongst others (inndeed some kaluga modules also work for Kotlin.js and/or JVM standalone).
Where appropriate coroutines and Flow are used in the API. This enables developers to use cold streams for a modern and efficient design.
While Kaluga modules can be used individually, together they form a comprehensive approach to cross-platform development with shared native code and native UIs, including SwiftUI and Compose.
With Kaluga it is possible to create cross-platform functionality in a few lines of code, that would normally take many lines of code even on just one platform.
Below are some examples, using a commonMain source-set:
Scanning for nearby devices with Bluetooth LE:
// will auto request permissions and try to enable bluetooth
BluetoothClientBuilder().createClient().devices().collect {
i("discovered device: $it") // log found device
}Showing a spinner while doing some work:
suspend fun doWork(hudBuilder: HUD.Builder) {
hudBuilder.presentDuring { // shows spinner while code in this block is running
// simulate doing work
delay(1000)
}
}
in this case, since HUD is a UI component the builder needs to be configured on the platform side:
val builder = HUD.Builder() // same for iOS and Android
// ...
builder.subscribe(activity) // this needs be done in the Android source-set to bind the HUD to the lifecycle of the Activity
// ...
builder.unsubscribe(activity) // when the Activity is stoppedHowever Kaluga's architecture module offers a cross-platform LifecycleViewModel class (which extends androidx.lifecycle.ViewModel on Android) that will automatically bind the builder to its lifecycle:
// this can just be in the commonMain source
class HudViewModel(private val hudBuilder: HUD.Builder): BaseLifecycleViewModel(hudBuilder) {
suspend fun doWork() =
hudBuilder.presentDuring {
delay(1000)
}
}Kaluga contains an example project that is used to test the developed modules.
For starting a new project based on Kaluga see the kaluga-starter repo, which shows how to do this step by step.
Kaluga is available on Maven Central. For example the Kaluga Alerts can be imported like this:
repositories {
mavenCentral()
}
dependencies {
implementation("com.splendo.kaluga.alerts:alerts:$kalugaVersion")
}You can also use the SNAPSHOT version based on the latest in the develop branch:
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
implementation("com.splendo.kaluga.alerts:alerts:$kalugaDevelopVersion-SNAPSHOT")
}To use kaluga with SwiftUI and/or Combine we have a repo with Sourcery templates to generate some Swift code to help get you started.
Modules are organized into feature groups; each group directory has its own README with more detail. The table below lists every published module, its artifact coordinate, and the platforms it supports.
| Module | Usage | Artifact | Android | iOS | JVM | JS | WasmJS | macOS | tvOS | watchOS |
|---|---|---|---|---|---|---|---|---|---|---|
| alerts/alerts | Showing alert dialogs | com.splendo.kaluga.alerts:alerts |
✅ | ✅ | ||||||
| alerts/test-utils | Test helpers for the alerts module | com.splendo.kaluga.alerts:test |
✅ | ✅ | ||||||
| architecture/architecture | MVVM architecture | com.splendo.kaluga.architecture:architecture |
✅ | ✅ | ||||||
| architecture/compose | Compose extensions for architecture | com.splendo.kaluga.architecture:compose |
✅ | |||||||
| architecture/test-utils | Test helpers for the architecture module | com.splendo.kaluga.architecture:test |
✅ | ✅ | ||||||
| architecture/test-koin | Koin-based test helpers | com.splendo.kaluga.architecture:test-koin |
✅ | ✅ | ||||||
| base/base | Core components of Kaluga: threading, flowables and localization | com.splendo.kaluga.base:base |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| base/test-utils | Test helpers built on top of base | com.splendo.kaluga.base:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| bluetooth/core | Shared Bluetooth attributes and the BluetoothFormat (de)serialization framework | com.splendo.kaluga.bluetooth:core |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/client | Scanning for and connecting to BLE devices as a Client | com.splendo.kaluga.bluetooth:client |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/server | Advertising and exposing GATT attributes as a Server | com.splendo.kaluga.bluetooth:server |
✅ | ✅ | ✅ | |||||
| bluetooth/beacons | Tracking the availability of Beacons using the Eddystone protocol | com.splendo.kaluga.bluetooth:beacons |
✅ | ✅ | ✅ | ✅ | ✅ | |||
| bluetooth/test-utils/core | Test helpers for the Bluetooth core module | com.splendo.kaluga.bluetooth:test-core |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/test-utils/client | Test helpers for the Bluetooth client module | com.splendo.kaluga.bluetooth:test-client |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| bluetooth/test-utils/server | Test helpers for the Bluetooth server module | com.splendo.kaluga.bluetooth:test-server |
✅ | ✅ | ✅ | |||||
| date-time | Multiplatform classes to work with date and time | com.splendo.kaluga:date-time |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| date-time-picker/date-time-picker | Showing a Date or Time Picker | com.splendo.kaluga.date-time-picker:date-time-picker |
✅ | ✅ | ||||||
| date-time-picker/test-utils | Test helpers for the Date Time Picker module | com.splendo.kaluga.date-time-picker:test |
✅ | ✅ | ||||||
| hud/hud | Showing a loading-indicator HUD | com.splendo.kaluga.hud:hud |
✅ | ✅ | ||||||
| hud/test-utils | Test helpers for the HUD module | com.splendo.kaluga.hud:test |
✅ | ✅ | ||||||
| keyboard/keyboard | Showing and hiding the keyboard | com.splendo.kaluga.keyboard:keyboard |
✅ | ✅ | ||||||
| keyboard/compose | Compose extensions for keyboard | com.splendo.kaluga.keyboard:compose |
✅ | |||||||
| keyboard/test-utils | Test helpers for the keyboard module | com.splendo.kaluga.keyboard:test |
✅ | ✅ | ||||||
| lifecycle/lifecycle | Platform-host lifecycle bindings for service builders | com.splendo.kaluga.lifecycle:lifecycle |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| lifecycle/compose | Compose extensions for lifecycle | com.splendo.kaluga.lifecycle:compose |
✅ | ✅ | ✅ | ✅ | ||||
| lifecycle/test-utils | Test helpers for the lifecycle module | com.splendo.kaluga.lifecycle:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| links | Decoding a url into an object | com.splendo.kaluga:links |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| location/location | Provides the user's geolocation | com.splendo.kaluga.location:location |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| location/test-utils | Test helpers for the location module | com.splendo.kaluga.location:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| logging | Shared console logging | com.splendo.kaluga:logging |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| media/media | Playing audio/video | com.splendo.kaluga.media:media |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
| media/compose | Compose extensions for media | com.splendo.kaluga.media:compose |
✅ | ✅ | ✅ | ✅ | ||||
| media/test-utils | Test helpers for the media module | com.splendo.kaluga.media:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
| permissions/core | The permissions framework, used in conjunction with the per-type modules | com.splendo.kaluga.permissions:core |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/bluetooth | Managing Bluetooth permissions | com.splendo.kaluga.permissions:bluetooth |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/calendar | Managing calendar permissions | com.splendo.kaluga.permissions:calendar |
✅ | ✅ | ✅ | ✅ | ||||
| permissions/camera | Managing camera permissions | com.splendo.kaluga.permissions:camera |
✅ | ✅ | ✅ | ✅ | ✅ | |||
| permissions/contacts | Managing contacts permissions | com.splendo.kaluga.permissions:contacts |
✅ | ✅ | ✅ | ✅ | ||||
| permissions/location | Managing location permissions | com.splendo.kaluga.permissions:location |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/microphone | Managing microphone permissions | com.splendo.kaluga.permissions:microphone |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/notifications | Managing notifications permissions | com.splendo.kaluga.permissions:notifications |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| permissions/storage | Managing storage permissions | com.splendo.kaluga.permissions:storage |
✅ | ✅ | ✅ | ✅ | ||||
| permissions/test-utils | Test helpers for the Permissions modules | com.splendo.kaluga.permissions:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| resources/resources | Shared Strings, Images, Colors and Fonts | com.splendo.kaluga.resources:resources |
✅ | ✅ | ||||||
| resources/compose | Compose extensions for resources | com.splendo.kaluga.resources:compose |
✅ | |||||||
| resources/databinding | Data Binding extensions for resources | com.splendo.kaluga.resources:databinding |
✅ | |||||||
| resources/test-utils | Test helpers for the resources module | com.splendo.kaluga.resources:test |
✅ | ✅ | ||||||
| review | Requesting the user to review the app | com.splendo.kaluga:review |
✅ | ✅ | ✅ | |||||
| scientific/scientific | Scientific units and conversions | com.splendo.kaluga.scientific:scientific |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| scientific/converters | Converters between scientific units | com.splendo.kaluga.scientific:converters |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| service/service | Adding services to Kaluga | com.splendo.kaluga.service:service |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| service/test-utils | Test helpers for the service module | com.splendo.kaluga.service:test |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| system/system | System APIs such as network, audio, battery | com.splendo.kaluga.system:system |
✅ | ✅ | ✅ | ✅ | ✅ | |||
| system/test-utils | Test helpers for the system module | com.splendo.kaluga.system:test |
✅ | ✅ | ✅ | ✅ | ✅ |
Of course not every possible functionality is provided by kaluga. However, this is often because other good multiplatform libraries that work nicely with kaluga already exist. These use similar patterns such as coroutines and Flow, and include the following:
| Project | Usage |
|---|---|
| kotlin-firebase-sdk | wraps most of the Firebase SDK APIs |
| multiplatform-settings | store key/value data |
| SQLDelight | access SQLite (and other SQL database) |
Kaluga also uses some multiplatform libraries itself, so our thanks to:
| Project | Usage |
|---|---|
| Napier | powers the logging module |
| Koin | dependency injection |
see DEVELOP.