# RMF-Codegen

RAML API client code generators based on the [RMF (REST Modeling Framework)](https://github.com/vrapio/rest-modeling-framework).
The code generators are written in [kotlin](https://kotlinlang.org/).

## Supported output targets

- `JAVA_CLIENT`:
  - Java types for JSON serialization/deserialization of RAML types via [Jackson](https://github.com/FasterXML/jackson)
  - Java client for accessing RAML resources via [Spring RestTemplate](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#webmvc-resttemplate)
- `TYPESCRIPT_CLIENT`:
  - TypeScript types generated from RAML types
  - TypeScript types for validating JSON payloads via [hapijs/joi](https://github.com/hapijs/joi)
- `CSHARP_CLIENT`
- `PHP_CLIENT`
- `POSTMAN`: Collection file for the [Postman API Client](https://www.postman.com/product/api-client/)
- `RAML_DOC`: Emits RAML files targeted at generating robust and stable API documentation. Fully flattens and resolves types and resources. The output RAML has a fixed canonical filesystem structure and every type or resource file contains all information to fully document it. It's used by the [commercetools-docs-kit](https://github.com/commercetools/commercetools-docs-kit/tree/master/packages/gatsby-theme-api-docs)

## Install `rmf-codegen` CLI

To install the rmf-codegen cli, run the following command

```
curl -o- -s https://raw.githubusercontent.com/commercetools/rmf-codegen/main/scripts/install.sh | bash
```

You will find a new command available `rmf-codegen`, you can check that all is good by executing `rmf-codegen -v`

## NPM wrapper package

The [`commercetools-docs-kit`](https://github.com/commercetools/commercetools-docs-kit) provides an NPM package that automates the download of the JAR and provides the `rmf-codegen` command to JavaScript projects without global installation. (find at [NPM](https://www.npmjs.com/login?next=/package/@commercetools-docs/rmf-codegen))

## Docker

Docker images for the code generator are available in the Github Container Registry

```
docker pull docker.pkg.github.com/commercetools/rmf-codegen/codegen:latest
```
## Usage

General Usage:

```
Usage: rmf-codegen [-hv] [COMMAND]
Allows to validate RAML files and generate code from them
  -h, --help                display this help message
  -v, --version             print version information and exit
Commands:
  generate                  Generate source code from a RAML specification.
  verify                    Allows to verify if a raml spec is valid.
  validate                  Validate the raml spec against defined rules and generate a validation report.

```

Generating Client SDKs or normalized RAML for documentation:

```
Usage: rmf-codegen generate [-hvw] [-b=<basePackageName>]
                            [-c=<clientPackageName>] [-m=<modelPackageName>]
                            -o=<outputFolder> [-s=<sharedPackage>] -t=<target>
                            <ramlFileLocation>
Generate source code from a RAML specification.
  <ramlFileLocation>        Api file location
  -b, --base-package=<basePackageName>
                            The base package, this package in case the model or
                            client models aren't provided
  -c, --client-package=<clientPackageName>
                            The client package, This will be used as the package
                            for the client stub.
  -h, --help                display this help message
  -m, --model-package=<modelPackageName>
                            The models package, this will be used as the model
                            package in the generated code.
  -o, --output-folder=<outputFolder>
                            Output folder for generated files.
  -s, --shared-package=<sharedPackage>
                            The shared package to be used for the generated code.
  -t, --target=<target>     Specifies the code generation target
                            Valid values: JAVA_CLIENT, TYPESCRIPT_CLIENT,
                            CSHARP_CLIENT, PHP_CLIENT, PHP_BASE, PHP_TEST,
                            POSTMAN, RAML_DOC
  -v, --verbose             If set, this would move the verbosity level to debug.
  -w, --watch               Watches the files for changes

```

Verifying a RAML API:

```
Usage: rmf-codegen verify [-hw] <ramlFileLocation>
Allows to verify if a RAML spec is valid.
  <ramlFileLocation>        Api file location
  -h, --help                display this help message
  -w, --watch               Watches the files for changes
```

Validating a RAML API and generating a validity report:

```
Usage: <main class> validate [-hvw] [--list-rules] [-f=<outputFormat>]
[-l=<linkBase>] [-lf=<linkFormat>]
[-o=<outputTarget>] [-r=<rulesetFile>]
[-s=<checkSeverity>] [-t=<tempFile>]
<ramlFileLocation>

Allows to verify if a raml spec is valid according to CT guidelines and generates a validation report

  <ramlFileLocation>   Api file location
  -f, --format=<outputFormat> Specifies the output format. Valid values: CLI, JSON, MARKDOWN
  -h, --help               display this help message
  -l, --link-base=<linkBase>
  -lf, --link-format=<linkFormat> Specifies the link format. Valid values: CLI, GITHUB
  --list-rules         Show all rules
  -o, --outputTarget=<outputTarget>
  -r, --ruleset=<rulesetFile> Ruleset configuration
  -s, --severity=<checkSeverity> Diagnostic severity. Valid values: info, warn, error
  -t, --temp=<tempFile>    Temporary folder
  -v, --verbose            Verbose
  -w, --watch              Watches the files for changes
```

## Development

### Build the "fat jar"

A single "fat jar" is built with the following commands:

```sh
cd tools/cli-application/
../../gradlew build
```

The JAR can then be found at `./rmf-codegen.jar`

### Build a native executable with GraalVM

A native executable is built with the following commands:

```sh
cd tools/cli-application/
../../gradlew nativeImage
```

The native executable can then be found at `./tools/cli-application/build/graal/rmf-codegen`.
It's currently only tested with Mac OS X. It emits error messages but the functionality works.

### Why did we choose kotlin for writing our code generators?

We choose kotlin because of the following features:

- extension methods, which allow us to add methods to our RMF model types
- multi-line template string with embedded expressions, which allows us to keep the templates and the code in the same file
- it integrates very well with our RMF Java types
- it has very good IDE support, which makes writing code generators very easy

These features help in developing code generators for different programming languges/frameworks.

# Running tests against your own RAML files

Our `TestCodeGenerator` test can be run against a user provided RAML file by setting
the `TEST_RAML_FILE` environment variable to the file path.


# supabase-kt

A Kotlin Multiplatform Client for Supabase.

For information about supported Kotlin targets, see the corresponding module README.

[Migrating from version 1.4.X to 2.0.0](/MIGRATION.md)

*Note: [WASM](https://github.com/supabase-community/supabase-kt/issues/86) build available: [2.4.2-wasm0](https://github.com/supabase-community/supabase-kt/releases/tag/2.4.1-wasm0)*

[![](https://img.shields.io/github/release/supabase-community/supabase-kt?label=stable)](https://github.com/supabase-community/supabase-kt/releases)
[![](https://badgen.net/github/release/supabase-community/supabase-kt?label=prerelease)](https://central.sonatype.com/search?q=io.github.jan.supabase&smo=true)
[![Kotlin](https://img.shields.io/badge/kotlin-2.0.0-blue.svg?logo=kotlin)](http://kotlinlang.org)
![https://img.shields.io/badge/ktor-2.3.11-blue](https://img.shields.io/badge/ktor-2.3.11-blue)
[![slack](https://img.shields.io/badge/slack-%23supabase--kt-purple.svg?logo=slack)](https://kotlinlang.slack.com/archives/C06QXPC7064)

### Links

[Documentation](https://supabase.com/docs/reference/kotlin/introduction)

[Getting started with Android and Supabase [Video]](https://www.youtube.com/watch?v=_iXUVJ6HTHU)

[Quickstart](https://supabase.com/docs/guides/getting-started/quickstarts/kotlin)

[Tutorial: Build a Product Management Android App with Jetpack Compose](https://supabase.com/docs/guides/getting-started/tutorials/with-kotlin)

[Dokka documentation for the latest version](https://supabase-community.github.io/supabase-kt/)

[Troubleshooting](/TROUBLESHOOTING.MD)

# Installation

### Add one or more modules to your project

**Available modules**: `gotrue-kt`, `postgrest-kt`, `functions-kt`, `storage-kt`, `realtime-kt`, `apollo-graphql`, `compose-auth`, `compose-auth-ui`, `coil-integration`, `imageloader-integration`

```kotlin
dependencies {
    implementation("io.github.jan-tennert.supabase:[module]:VERSION")
}
```

If you use multiple modules, you can use the bom dependency to get the correct versions for all
modules:

```kotlin
implementation(platform("io.github.jan-tennert.supabase:bom:VERSION"))
implementation("io.github.jan-tennert.supabase:[module]")
```

### Add a Ktor Client Engine to each of your Kotlin targets

You can find a list of available engines [here](https://ktor.io/docs/http-client-engines.html).
If you plan to use the Realtime dependency, make sure to check if the engine supports WebSockets. See the [Ktor docs](https://ktor.io/docs/http-client-engines.html#limitations) for more information.

```kotlin
implementation("io.ktor:ktor-client-[engine]:VERSION")
```

<details>
<summary>Multiplatform Example</summary>

For targets: `jvm`, `android`, `js`, `ios`

```kotlin
val commonMain by getting {
    dependencies {
        //supabase modules
    }
}
val jvmMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-cio:KTOR_VERSION")
    }
}
val androidMain by getting {
    dependsOn(jvmMain)
}
val jsMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-js:KTOR_VERSION")
    }
}
val iosMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-darwin:KTOR_VERSION")
    }
}
```
</details>

**Note:** It is recommended to use the same Ktor version as supabase-kt:

![https://img.shields.io/badge/ktor-2.3.11-blue](https://img.shields.io/badge/ktor-2.3.11-blue)

# Main Modules

#### [Authentication](/GoTrue)

#### [Database/Postgrest](/Postgrest)

#### [Storage](/Storage)

#### [Realtime](/Realtime)

#### [Functions (Edge Functions)](/Functions)

### Plugins

#### [Apollo GraphQL integration](/plugins/ApolloGraphQL) - Creates an [Apollo GraphQL Client](https://github.com/apollographql/apollo-kotlin) for interacting with the Supabase API.

#### [Compose Auth](/plugins/ComposeAuth) - Provides easy Native Google & Apple Auth for Compose Multiplatform targets.

#### [Compose Auth UI](/plugins/ComposeAuthUI) - Provides UI Components for Compose Multiplatform.

#### [Coil Integration](/plugins/CoilIntegration) - Provides a [Coil](https://github.com/coil-kt/coil) Integration for displaying images stored in Supabase Storage.

#### [Compose-ImageLoader Integration](/plugins/ImageLoaderIntegration) - Provides a [Compose ImageLoader](https://github.com/qdsfdhvh/compose-imageloader) Integration for displaying images stored in Supabase Storage.

# Samples

- [Chat Demo (Desktop/Android/iOS/Browser)](https://github.com/supabase-community/supabase-kt/tree/master/demos/chat-demo-mpp)
- [File Upload Demo (Desktop/Android)](https://github.com/supabase-community/supabase-kt/tree/master/demos/file-upload)
- [Android Native Google login & in-app OAuth (Android)](https://github.com/supabase-community/supabase-kt/tree/master/demos/android-login)
- [Multi-Factor Authentication (Desktop/Android/Browser)](https://github.com/supabase-community/supabase-kt/tree/master/demos/multi-factor-authentication)
- [Multiplatform Deep Linking (Desktop/Android)](https://github.com/supabase-community/supabase-kt/tree/master/demos/multiplatform-deeplinks)
- [Groceries Store App (Android)](https://github.com/hieuwu/android-groceries-store)

# Need help?

- Join the [#supabase-kt](https://kotlinlang.slack.com/archives/C06QXPC7064) Kotlin Slack channel
- [Join the Supabase Discord](https://discord.supabase.com) and create a new post with the 'Kotlin' tag under `help-and-questions`
- [Create a discussion](https://github.com/supabase-community/supabase-kt/discussions/new/choose)
- [Create an issue](https://github.com/supabase-community/supabase-kt/issues/new/choose)

# Videos

- [Getting started with Android and Supabase](https://www.youtube.com/watch?v=_iXUVJ6HTHU) by the official Supabase YouTube channel
- [Getting started with Supabase on Android](https://www.youtube.com/watch?v=SGr73sWMX6w) (by [Eric Ampire](https://www.youtube.com/@eric-ampire))
- [Supabase | Jetpack Compose | Android | 2023](https://www.youtube.com/playlist?list=PL91kV_wdjTlcGQdcZzkuid094as5eUlwU) (by [YoursSohailYT](https://www.youtube.com/@YoursSohailYT))

# Contribution

### How to contribute

1. Fork the repository
2. Create a branch
3. Make your changes
4. Submit a pull request with your new branch

# Credits

- Postgres Syntax inspired by https://github.com/supabase-community/postgrest-kt
- Plugin system inspired by ktor


# LibChecker

[![Android CI](https://github.com/LibChecker/LibChecker/actions/workflows/android.yml/badge.svg)](https://github.com/LibChecker/LibChecker/actions/workflows/android.yml)
[![License](https://img.shields.io/github/license/LibChecker/LibChecker?label=License)](https://choosealicense.com/licenses/apache-2.0/)
[![Discussion](https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram)](https://t.me/libcheckerr)
[![Crowdin](https://badges.crowdin.net/libchecker/localized.svg)](https://crowdin.com/project/libchecker)

![Header](./source/header.png)

## What's this?
This app is used to view the third-party libraries used by applications in your device. It can view the ABI architecture of the application's native library (in general, whether the application is 64-bit or 32-bit). It can also view well-known libraries marked by [The Rule Repository](https://github.com/LibChecker/LibChecker-Rules), and can even sort and view them according to the number of libraries references.

## Supported Versions
Android 7.0 ~ 15

Android 6 [Marshmallow](https://github.com/LibChecker/LibChecker/tree/marshmallow)

## Document
[LibChecker-Docs](https://github.com/LibChecker/LibChecker-Docs)

## Download

[](https://play.google.com/store/apps/details?id=com.absinthe.libchecker)
[](https://f-droid.org/packages/com.absinthe.libchecker/)

## Discussions
[Github Discussions](https://github.com/LibChecker/LibChecker/discussions)

### Telegram Group


# Vico

![](https://img.shields.io/maven-central/v/com.patrykandpatrick.vico/core)
![](https://img.shields.io/github/actions/workflow/status/patrykandpatrick/vico/build-debug-apk.yml?branch=master)
![](https://www.codefactor.io/repository/github/patrykandpatrick/vico/badge)
![](https://kotlin-version.aws.icerock.dev/kotlin-version?group=com.patrykandpatrick.vico&name=core)

![](cover.png)

Vico is a light and extensible chart library for Android. It’s compatible with both Jetpack Compose and the view system,
but its two main modules—`compose` and `views`—are independent.

Learn more in [the wiki](https://patrykandpatrick.com/vico/wiki).


# Roborazzi

**Make JVM Android Integration Test Visible**

## Roborazzi now supports [Robolectric Native Graphics (RNG)](https://github.com/robolectric/robolectric/releases/tag/robolectric-4.10) and enables screenshot testing.📣

## Why Choose Roborazzi?

### Why is screenshot testing important?

Screenshot testing is key to validate your app's appearance and functionality. It efficiently
detects visual issues and tests the app as users would use it, making it easier to spot problems.
It's quicker than writing many assert statements, ensuring your app looks right and behaves
correctly.

### What are JVM tests and why test with JVM instead of on Android?

JVM tests, also known as local tests, are placed in the test/ directory and are run on a developer's
PC or CI environment. On the other hand, device tests, also known as Instrumentation tests, are
written in the androidTest/ directory and are run on real devices or emulators. Device testing can
result in frequent failures due to the device environment, leading to false negatives. These
failures are often hard to reproduce, making them tough to resolve.

### Paparazzi and Roborazzi: A Comparison

Paparazzi is a great tool for visualizing displays within the JVM. However, it's incompatible with
Robolectric, which also mocks the Android framework.

Roborazzi fills this gap. It integrates with Robolectric, allowing tests to run with Hilt and
interact with components. Essentially, Roborazzi enhances Paparazzi's capabilities, providing a more
efficient and reliable testing process by capturing screenshots with Robolectric.

**Leveraging Roborazzi in Test Architecture: An Example**

**Integrating Roborazzi into the Architecture: An Example from DroidKaigi 2023 App**

In the DroidKaigi 2023 app, Roborazzi was introduced from the early stages of development as part of the architectural design. This integration allowed the team to verify changes throughout the development process. The specific architectural decisions and how they were implemented can be found [README](https://github.com/DroidKaigi/conference-app-2023#screenshot-testing-with-robolectric-native-graphics-rng-and-roborazzi).

# Try it out

Available on Maven Central.

### Add Robolectric

This is an example of adding Robolectric to your project:
https://github.com/takahirom/roborazzi-usage-examples/compare/b697...5c12

This library is dependent on Robolectric. Please see below to add Robolectric.

https://robolectric.org/getting-started/

### Add Roborazzi

This is an example of adding Roborazzi to your project:
https://github.com/takahirom/roborazzi-usage-examples/commit/3a02

To take screenshots, please use Robolectric 4.10 alpha 1 or later and please
add `@GraphicsMode(GraphicsMode.Mode.NATIVE)` to your test class.

```kotlin
@GraphicsMode(GraphicsMode.Mode.NATIVE)
```

# Build setup

Roborazzi is available on maven central.

This plugin simply creates Gradle tasks record, verify, compare and passes the configuration to the
test.

**build.gradle.kts**

plugins	buildscript

Define plugin in root build.gradle.kts

```kotlin
plugins {
  ...
  id("io.github.takahirom.roborazzi") version "[version]" apply false
}
```

Apply plugin in module build.gradle.kts

```kotlin
plugins {
  ...
  id("io.github.takahirom.roborazzi")
}
```

root build.gradle.kts

```kotlin
buildscript {
  dependencies {
    ...
    classpath("io.github.takahirom.roborazzi:roborazzi-gradle-plugin:[version]")
  }
}
```

module build.gradle.kts

```kotlin
plugins {
    ...
    id("io.github.takahirom.roborazzi")
}
```

build.gradle version

plugins	buildscript

Define plugin in root build.gradle

```groovy
plugins {
  ...
  id "io.github.takahirom.roborazzi" version "[version]" apply false
}
```

Apply plugin in module build.gradle

```groovy
plugins {
  ...
  id 'io.github.takahirom.roborazzi'
}
```

root build.gradle

```groovy
buildscript {
  dependencies {
    ...
    classpath "io.github.takahirom.roborazzi:roborazzi-gradle-plugin:[version]"
  }
}
```

module build.gradle

```groovy
apply plugin: "io.github.takahirom.roborazzi"
```

 Use Roborazzi task 	  Use default unit test task 	  Description

`./gradlew recordRoborazziDebug`

`./gradlew testDebugUnitTest` after adding `roborazzi.test.record=true` to your gradle.properties file.

or

`./gradlew testDebugUnitTest -Proborazzi.test.record=true`

Record a screenshot
Default output directory is `build/outputs/roborazzi`
You can check a report under `build/reports/roborazzi/index.html`

`./gradlew compareRoborazziDebug`

`./gradlew testDebugUnitTest` after adding `roborazzi.test.compare=true` to your gradle.properties file.

or

`./gradlew testDebugUnitTest -Proborazzi.test.compare=true`

Review changes made to an image. This action will
compare the current image with the saved one, generating a comparison image labeled
as `[original]_compare.png`. It also produces a JSON file containing the diff information, which can
be found under `build/test-results/roborazzi`.

`./gradlew verifyRoborazziDebug`

`./gradlew testDebugUnitTest` after adding `roborazzi.test.verify=true` to your gradle.properties file.

or

`./gradlew testDebugUnitTest -Proborazzi.test.verify=true`

Validate changes made to an image. If there is any difference between the current image and the
saved one, the test will fail.

`./gradlew verifyAndRecordRoborazziDebug`

`./gradlew testDebugUnitTest` after adding  `roborazzi.test.verify=true` and `roborazzi.test.record=true` to your gradle.properties file.

or

`./gradlew testDebugUnitTest -Proborazzi.test.verify=true -Proborazzi.test.record=true`

This task will first verify the images and, if differences are detected, it will record a new
baseline.

The comparison image, saved as `[original]_compare.png`, is shown below:

![image](https://github.com/takahirom/roborazzi/assets/1386930/722090ff-77c4-4a04-a0e3-8ce562ffa6be)

You can check the test report in `build/reports/roborazzi/index.html`

This
uses [JetNew from Compose Samples](https://github.com/android/compose-samples/tree/main/JetNews).
You can check the pull request introducing Roborazzi to the
compose-samples [here](https://github.com/takahirom/compose-samples/pull/1/files).

### Add dependencies

| Description     | Dependencies                                                                         |
|-----------------|--------------------------------------------------------------------------------------|
| Core functions  | `testImplementation("io.github.takahirom.roborazzi:roborazzi:[version]")`            |
| Jetpack Compose | `testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:[version]")`    |
| JUnit rules     | `testImplementation("io.github.takahirom.roborazzi:roborazzi-junit-rule:[version]")` |

# How to use

### Take a screenshot manually

You can take a screenshot by calling captureRoboImage().

app/src/test/java/../ManualTest.kt

```kotlin
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.GraphicsMode

// All you need to do is use the captureRoboImage function in the test!
import com.github.takahirom.roborazzi.captureRoboImage

// Tips: You can use Robolectric while using AndroidJUnit4
@RunWith(AndroidJUnit4::class)
// Enable Robolectric Native Graphics (RNG)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class ManualTest {
  @get:Rule
  val composeTestRule = createAndroidComposeRule<MainActivity>()

  @Test
  fun captureRoboImageSample() {
    // Tips: You can use Robolectric with Espresso API
    // launch
    ActivityScenario.launch(MainActivity::class.java)

    // Capture screen
    onView(ViewMatchers.isRoot())
      // If you don't specify a screenshot file name, Roborazzi will automatically use the method name as the file name for you.
      // The format of the file name will be as follows:
      // build/outputs/roborazzi/com_..._ManualTest_captureRoboImageSample.png
      .captureRoboImage()

    // Capture Jetpack Compose Node
    composeTestRule.onNodeWithTag("AddBoxButton")
      .onParent()
      .captureRoboImage("build/compose.png")
  }
}
```

Roborazzi supports the following APIs.

Capture	Code

✅ Jetpack Compose's onNode()

```kotlin
composeTestRule.onNodeWithTag("AddBoxButton")
  .captureRoboImage()
```

✅ Espresso's onView()

```kotlin
onView(ViewMatchers.isRoot())
  .captureRoboImage()
```

```kotlin
onView(withId(R.id.button_first))
  .captureRoboImage()
```

✅ View

```kotlin
val view: View = composeTestRule.activity.findViewById<View>(R.id.button_second)
view.captureRoboImage()
```

✅ Jetpack Compose lambda

```kotlin
captureRoboImage() {
  Text("Hello Compose!")
}
```

Experimental🧪

✅ Captures the entire screen, including dialogs

```kotlin
captureScreenRoboImage()
```

✅ Bitmap

```kotlin
val bitmap: Bitmap = createBitmap(100, 100, Bitmap.Config.ARGB_8888)
  .apply {
    applyCanvas {
      drawColor(android.graphics.Color.YELLOW)
    }
  }
bitmap.captureRoboImage()
```

### Device configuration

You can configure the device by using the `@Config` annotation and `RobolectricDeviceQualifiers`.

Configuration	Code

✅ Predefined device configuration

You can change the device configuration by adding `@Config` to the class or method.

```kotlin
@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(qualifiers = RobolectricDeviceQualifiers.Pixel5)
class RoborazziTest {
```

```kotlin
@Test
@Config(qualifiers = RobolectricDeviceQualifiers.Pixel5)
fun test() {
```

✅ Night mode

```kotlin
@Config(qualifiers = "+night")
```

✅ Locale

```kotlin
@Config(qualifiers = "+ja")
```

✅ Screen size

```kotlin
@Config(qualifiers = RobolectricDeviceQualifiers.MediumTablet)
```

### Integrate to your GitHub Actions

It is easy to integrate Roborazzi to your GitHub Actions.

#### Add a job to store screenshots

```yaml
name: store screenshots

on:
  push

env:
  GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false"

jobs:
  test:
    runs-on: macos-latest

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3.9.0
        with:
          distribution: 'zulu'
          java-version: 19

      - name: Gradle cache
        uses: gradle/gradle-build-action@v2

      - name: test
        run: |
          # Create screenshots
          ./gradlew app:recordRoborazziDebug --stacktrace

      # Upload screenshots to GitHub Actions Artifacts
      - uses: actions/upload-artifact@v3
        with:
          name: screenshots
          path: app/build/outputs/roborazzi
          retention-days: 30
```

#### Add a job to verify screenshots

```yaml
name: verify test

on:
  push

env:
  GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false"

jobs:
  test:
    runs-on: macos-latest

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3.9.0
        with:
          distribution: 'zulu'
          java-version: 19

      - name: Gradle cache
        uses: gradle/gradle-build-action@v2

      # Download screenshots from main branch
      - uses: dawidd6/action-download-artifact@v2
        with:
          name: screenshots
          path: app/build/outputs/roborazzi
          workflow: test.yaml
          branch: main

      - name: verify test
        id: verify-test
        run: |
          # If there is a difference between the screenshots, the test will fail.
          ./gradlew app:verifyRoborazziDebug --stacktrace

      - uses: actions/upload-artifact@v3
        if: ${{ always() }}
        with:
          name: screenshot-diff
          path: app/build/outputs/roborazzi
          retention-days: 30

      - uses: actions/upload-artifact@v3
        if: ${{ always() }}
        with:
          name: screenshot-diff-reports
          path: app/build/reports
          retention-days: 30

      - uses: actions/upload-artifact@v3
        if: ${{ always() }}
        with:
          name: screenshot-diff-test-results
          path: app/build/test-results
          retention-days: 30

```

#### Advanced workflow Sample: Compare Snapshot Results on Pull Requests

For those who are looking for a more advanced example, we have prepared a sample repository that
demonstrates how to use Roborazzi to compare snapshot results on GitHub pull requests. This sample
showcases the integration of Roborazzi with GitHub Actions workflows, making it easy to visualize
and review the differences between snapshots directly in the pull request comments.

Check out
the [roborazzi-compare-on-github-comment-sample](https://github.com/takahirom/roborazzi-compare-on-github-comment-sample)
repository to see this powerful feature in action and learn how to implement it in your own
projects.

Example of the comment

## RoborazziRule (Optional)

RoborazziRule is a JUnit rule for Roborazzi.
RoborazziRule is **optional**. You can use `captureRoboImage()` without this rule.

RoborazziRule has two features.

1. Provide context such as `RoborazziOptions` and `outputDirectoryPath` etc for `captureRoboImage()`.
2. Capture screenshots for each test when specifying RoborazziRule.options.captureType.

For example, The following code generates an output file
named `**custom_outputDirectoryPath**/**custom_outputFileProvider**-com.github.takahirom.roborazzi.sample.RuleTestWithPath.captureRoboImage.png` :

```kotlin
@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class RuleTestWithPath {
  @get:Rule
  val roborazziRule = RoborazziRule(
    options = Options(
      outputDirectoryPath = "$DEFAULT_ROBORAZZI_OUTPUT_DIR_PATH/custom_outputDirectoryPath",
      outputFileProvider = { description, outputDirectory, fileExtension ->
        File(
          outputDirectory,
          "custom_outputFileProvider-${description.testClass.name}.${description.methodName}.$fileExtension"
        )
      }
    ),
  )

  @Test
  fun captureRoboImage() {
    launch(MainActivity::class.java)
    // The file will be saved using the rule's outputDirectoryPath and outputFileProvider
    onView(isRoot()).captureRoboImage()
  }
}
```

### Generate gif image

```kotlin
@Test
fun captureRoboGifSample() {
  onView(ViewMatchers.isRoot())
    .captureRoboGif("build/test.gif") {
      // launch
      ActivityScenario.launch(MainActivity::class.java)
      // move to next page
      onView(withId(R.id.button_first))
        .perform(click())
      // back
      pressBack()
      // move to next page
      onView(withId(R.id.button_first))
        .perform(click())
    }
}
```

### Automatically generate gif with test rule

> **Note**
> You **don't need to use RoborazziRule** if you're using captureRoboImage().

With the JUnit test rule, you do not need to name the gif image,
and if you prefer, you can output the gif image **only if the test fails**.

This test will output this file.

`build/outputs/roborazzi/com.github.takahirom.roborazzi.sample.RuleTestWithOnlyFail_captureRoboGifSampleFail.gif`

```kotlin
@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class RuleTestWithOnlyFail {
  @get:Rule
  val roborazziRule = RoborazziRule(
    captureRoot = onView(isRoot()),
    options = Options(
      onlyFail = true,
      captureType = RoborazziRule.CaptureType.Gif,
    )
  )

  @Test
  fun captureRoboLastImageSampleFail() {
    // launch
    ActivityScenario.launch(MainActivity::class.java)
    // move to next page
    onView(withId(R.id.button_first))
      .perform(click())
    // should fail because the button does not exist
    // Due to failure, the gif image will be saved in the outputs folder.
    onView(withId(R.id.button_first))
      .perform(click())
  }
}
```

### Automatically generate Jetpack Compose gif with test rule

Test target

```kotlin
@Composable
fun SampleComposableFunction() {
  var count by remember { mutableStateOf(0) }
  Column(
    Modifier
      .size(300.dp)
  ) {
    Box(
      Modifier
        .testTag("AddBoxButton")
        .size(50.dp)
        .clickable {
          count++
        }
    )
    (0..count).forEach {
      Box(
        Modifier
          .size(30.dp)
      )
    }
  }
}
```

Test (Just add RoborazziRule)

```kotlin
@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class ComposeTest {
  @get:Rule
  val composeTestRule = createAndroidComposeRule<ComponentActivity>()

  @get:Rule
  val roborazziRule = RoborazziRule(
    composeRule = composeTestRule,
    captureRoot = composeTestRule.onRoot(),
    options = RoborazziRule.Options(
      RoborazziRule.CaptureType.Gif()
    )
  )

  @Test
  fun composable() {
    composeTestRule.setContent {
      SampleComposableFunction()
    }
    (0 until 3).forEach { _ ->
      composeTestRule
        .onNodeWithTag("AddBoxButton")
        .performClick()
    }
  }
}
```

![com github takahirom roborazzi sample ComposeTest_composable](https://user-images.githubusercontent.com/1386930/226366224-b9950b60-26a2-489e-bc03-08bfb86c533a.gif)

### RoborazziRule options

You can use some RoborazziRule options

```kotlin
/**
 * This rule is a JUnit rule for roborazzi.
 * This rule is optional. You can use [captureRoboImage] without this rule.
 *
 * This rule have two features.
 * 1. Provide context such as `RoborazziOptions` and `outputDirectoryPath` etc for [captureRoboImage].
 * 2. Capture screenshots for each test when specifying RoborazziRule.options.captureType.
 */
class RoborazziRule private constructor(
  private val captureRoot: CaptureRoot,
  private val options: Options = Options()
) : TestWatcher() {
  /**
   * If you add this annotation to the test, the test will be ignored by
   * roborazzi's CaptureType.LastImage, CaptureType.AllImage and CaptureType.Gif.
   */
  annotation class Ignore

  data class Options(
    val captureType: CaptureType = CaptureType.None,
    /**
     * output directory path
     */
    val outputDirectoryPath: String = provideRoborazziContext().outputDirectory,

    val outputFileProvider: FileProvider = provideRoborazziContext().fileProvider
      ?: defaultFileProvider,
    val roborazziOptions: RoborazziOptions = provideRoborazziContext().options,
  )

  sealed interface CaptureType {
    /**
     * Do not generate images. Just provide the image path to [captureRoboImage].
     */
    object None : CaptureType

    /**
     * Generate last images for each test
     */
    data class LastImage(
      /**
       * capture only when the test fail
       */
      val onlyFail: Boolean = false,
    ) : CaptureType

    /**
     * Generate images for Each layout change like TestClass_method_0.png for each test
     */
    data class AllImage(
      /**
       * capture only when the test fail
       */
      val onlyFail: Boolean = false,
    ) : CaptureType

    /**
     * Generate gif images for each test
     */
    data class Gif(
      /**
       * capture only when the test fail
       */
      val onlyFail: Boolean = false,
    ) : CaptureType
  }
```

### Roborazzi options

```kotlin
data class RoborazziOptions(
  val captureType: CaptureType = if (isNativeGraphicsEnabled()) CaptureType.Screenshot() else CaptureType.Dump(),
  val compareOptions: CompareOptions = CompareOptions(),
  val recordOptions: RecordOptions = RecordOptions(),
) {
  sealed interface CaptureType {
    class Screenshot : CaptureType

    data class Dump(
      val takeScreenShot: Boolean = isNativeGraphicsEnabled(),
      val basicSize: Int = 600,
      val depthSlideSize: Int = 30,
      val query: ((RoboComponent) -> Boolean)? = null,
      val explanation: ((RoboComponent) -> String?) = DefaultExplanation,
    ) : CaptureType {
      companion object {
        val DefaultExplanation: ((RoboComponent) -> String) = {
          it.text
        }
        val AccessibilityExplanation: ((RoboComponent) -> String) = {
          it.accessibilityText
        }
      }
    }
  }

  data class CompareOptions(
    val roborazziCompareReporter: RoborazziCompareReporter = RoborazziCompareReporter(),
    val resultValidator: (result: ImageComparator.ComparisonResult) -> Boolean,
  ) {
    constructor(
      roborazziCompareReporter: RoborazziCompareReporter = RoborazziCompareReporter(),
      /**
       * This value determines the threshold of pixel change at which the diff image is output or not.
       * The value should be between 0 and 1
       */
      changeThreshold: Float = 0.01F,
    ) : this(roborazziCompareReporter, ThresholdValidator(changeThreshold))
  }

  interface RoborazziCompareReporter {
    fun report(compareReportCaptureResult: CompareReportCaptureResult)

    companion object {
      operator fun invoke(): RoborazziCompareReporter {
        ...
      }
    }

    class JsonOutputRoborazziCompareReporter : RoborazziCompareReporter {
      ...

      override fun report(compareReportCaptureResult: CompareReportCaptureResult) {
        ...
      }
    }

    class VerifyRoborazziCompareReporter : RoborazziCompareReporter {
      override fun report(compareReportCaptureResult: CompareReportCaptureResult) {
        ...
      }
    }
  }

  data class RecordOptions(
    val resizeScale: Double = roborazziDefaultResizeScale(),
    val applyDeviceCrop: Boolean = false,
    val pixelBitConfig: PixelBitConfig = PixelBitConfig.Argb8888,
  )

  enum class PixelBitConfig {
    Argb8888,
    Rgb565;

    fun toBitmapConfig(): Bitmap.Config {
      ...
    }

    fun toBufferedImageType(): Int {
      ...
    }
  }
}
```

### Dump mode

If you are having trouble debugging your test, try Dump mode as follows.

![image](https://user-images.githubusercontent.com/1386930/226364158-a07a0fb0-d8e7-46b7-a495-8dd217faaadb.png)

# Roborazzi IntelliJ IDEA and Android Studio Plugin

https://plugins.jetbrains.com/plugin/24561-roborazzi

Demo of Roborazzi IntelliJ IDEA and Android Studio Plugin.

https://github.com/takahirom/roborazzi/assets/1386930/bd3e8106-1971-4ec4-b764-3f1831999228

The Roborazzi plugin enhances your development workflow by automatically displaying screenshots related to Roborazzi's screenshot tests within IntelliJ IDEA. Easily view and verify visual outputs directly in your IDE, streamlining your testing and development process.

# Multiplatform support

### Experimental feature: iOS support

Roborazzi supports Compose Multiplatform iOS. You can use Roborazzi with Compose iOS as follows:

Gradle settings

```kotlin
plugins {
  kotlin("multiplatform")
  id("org.jetbrains.compose")
  id("io.github.takahirom.roborazzi")
}

kotlin {
  sourceSets {
    ...
    val appleTest by getting {
      dependencies {
        implementation(project("io.github.takahirom.roborazzi:roborazzi-compose-ios:[1.13.0 or higher]"))
        implementation(kotlin("test"))
      }
    }
  ...

```

Test with Roborazzi

```kotlin
class IosTest {
  @OptIn(ExperimentalTestApi::class)
  @Test
  fun test() {
    runComposeUiTest {
      setContent {
        MaterialTheme {
          Column {
            Button(
              modifier = Modifier.alpha(alpha),
              onClick = { }) {
              Text("Hello World")
            }
            Box(
              modifier = Modifier
                .background(Color.Red.copy(alpha = alpha), MaterialTheme.shapes.small)
                .size(100.dp),
            )
          }
        }
      }
      onRoot().captureRoboImage(this, filePath = "ios.png")
      onNodeWithText("Hello World").captureRoboImage(
        this,
        filePath = "ios_button.png"
      )
    }
  }
}
```

Then, you can run the Gradle tasks for iOS Support, just like you do for Android Support.

```
./gradlew recordRoborazzi[SourceSet]
```

```
./gradlew recordRoborazziIosSimulatorArm64
./gradlew compareRoborazziIosSimulatorArm64
./gradlew verifyRoborazziIosSimulatorArm64
...
```

The currently implemented features for iOS support are as follows:

| Feature | status |
|---|---|
| Record | supported |
| Compare | supported |
| Verify | supported |
| Report | supported |
| Dropbox/Differ comparison | 🆖  |
| dump | 🆖  |
| resizing image | 🆖  |
| context data | 🆖  |
| custom reporter | 🆖  |
| RoborazziRecordFilePathStrategy  | 🆖  |
| ComparisonStyle  | 🆖  |
| resultValidator  | 🆖  |
| resultValidator  | 🆖  |
| applyDeviceCrop | 🆖 |
| pixelBitConfig | 🆖 |

We are migrating JVM implementation to Multiplatform implementation. So, some features are not supported yet.
We are looking for contributors to help us implement these features.

### Experimental feature: Compose Desktop support

Roborazzi supports Compose Desktop. You can use Roborazzi with Compose Desktop as follows:

Gradle settings

```kotlin
plugins {
  kotlin("multiplatform")
  id("org.jetbrains.compose")
  id("io.github.takahirom.roborazzi")
}

kotlin {
  // You can use your source set name
  jvm("desktop")
  sourceSets {
    ...
    val desktopTest by getting {
      dependencies {
        implementation(project("io.github.takahirom.roborazzi:roborazzi-compose-desktop:[1.6.0-alpha-2 or higher]"))
        implementation(kotlin("test"))
      }
    }
    ...

// Roborazzi Desktop support uses Context Receivers
    tasks.withType<KotlinCompile>().configureEach {
      kotlinOptions {
        freeCompilerArgs += "-Xcontext-receivers"
      }
    }
```

Test target Composable function

```kotlin
@Composable
fun App() {
  var text by remember { mutableStateOf("Hello, World!") }

  MaterialTheme {
    Button(
      modifier = Modifier.testTag("button"),
      onClick = {
        text = "Hello, Desktop!"
      }) {
      Text(
        style = MaterialTheme.typography.h2,
        text = text
      )
    }
  }
}
```

Test with Roborazzi

```kotlin
class MainKmpTest {
  @OptIn(ExperimentalTestApi::class)
  @Test
  fun test() = runDesktopComposeUiTest {
    setContent {
      App()
    }
    val roborazziOptions = RoborazziOptions(
      recordOptions = RoborazziOptions.RecordOptions(
        resizeScale = 0.5
      ),
      compareOptions = RoborazziOptions.CompareOptions(
        changeThreshold = 0F
      )
    )
    onRoot().captureRoboImage(roborazziOptions = roborazziOptions)

    onNodeWithTag("button").performClick()

    onRoot().captureRoboImage(roborazziOptions = roborazziOptions)
  }
}
```

Then, you can run the Gradle tasks for Desktop Support, just like you do for Android Support.

```
./gradlew recordRoborazzi[SourceSet]
```

```
./gradlew recordRoborazziDesktop
./gradlew compareRoborazziDesktop
./gradlew verifyRoborazziDesktop
...
```

If you use the Kotlin JVM plugin, the task will be `recordRoborazzi**Jvm**`.

The sample image

![MainJvmTest test](https://github.com/takahirom/roborazzi/assets/1386930/41287c29-26ae-4539-b387-de570ae3f2b3)
![MainJvmTest test_2](https://github.com/takahirom/roborazzi/assets/1386930/2edc828c-6fd8-4a9a-8f3d-b0e7baa85f0d)

# Roborazzi gradle.properties Options and Recommendations

You can configure the following options in your `gradle.properties` file:

## roborazzi.test

This option enables you to configure the behavior of Roborazzi. By default, all settings are set to false.
For additional configuration options, please refer to the 'Apply Roborazzi Gradle Plugin' section.

```
roborazzi.test.record=true
# roborazzi.test.compare=true
# roborazzi.test.verify=true
```

## roborazzi.record

### roborazzi.record.resizeScale

This option lets you set the resize scale for the image being recorded. The default value is 1.0.

```
roborazzi.record.resizeScale=0.5
```

### roborazzi.record.filePathStrategy

This setting allows you to specify the file path strategy for the recorded image. The default strategy is `relativePathFromCurrentDirectory`. If you choose `relativePathFromRoborazziContextOutputDirectory`, the file will be saved in the output directory specified by `RoborazziRule.Options.outputDirectoryPath`.

```
roborazzi.record.filePathStrategy=relativePathFromRoborazziContextOutputDirectory
```

### roborazzi.record.namingStrategy

This option enables you to define the naming strategy for the recorded image. The default strategy is `testPackageAndClassAndMethod`.

- If you choose `testPackageAndClassAndMethod`, the file name will be `com.example.MyTest.testMethod.png`.
- If you choose `escapedTestPackageAndClassAndMethod`, the file name will be `com_example_MyTest.testMethod.png`.
- If you choose `testClassAndMethod`, the file name will be `MyTest.testMethod.png`.

```
roborazzi.record.namingStrategy=testClassAndMethod
```

## Robolectric Options

### robolectric.pixelCopyRenderMode

I recommend setting `it.systemProperties["robolectric.pixelCopyRenderMode"] = "hardware"` in your `build.gradle` file to enhance the accuracy of your screenshots. For more details, please refer to the [issue](https://github.com/takahirom/roborazzi/issues/296).

```
android {
    testOptions {
    ...
        unitTests {
            isIncludeAndroidResources = true
            isReturnDefaultValues = true
            all {
                it.systemProperties["robolectric.pixelCopyRenderMode"] = "hardware"
            }
```

# FAQ

### Q: How can I run only screenshot tests using Roborazzi?

**A:** To run only screenshot tests, you can configure your project with the following:

```groovy
android {
    testOptions {
        unitTests {
            all {
                // -Pscreenshot to filter screenshot tests
                it.useJUnit {
                    if (project.hasProperty("screenshot")) {
                        includeCategories("io.github.takahirom.roborazzi.testing.category.ScreenshotTests")
                    }
                }
            }
        }
    }
}
```

Include the `-Pscreenshot` property, and only the screenshot tests will be run.

Note: This feature is not provided in the Roborazzi library itself, to keep it simple and utilize JUnit's built-in features for test filtering.

You can also annotate your tests like this:

```kotlin
/**
 * You can filter ScreenshotTests using -Pscreenshot parameter
 */
interface ScreenshotTests

@Test
@Category(ScreenshotTests::class)
fun checkLaunchShot() {
  onRoot().captureRoboImage(roborazziOptions = roborazziOptions)
}
```

This allows you to create a category of screenshot tests and filter them using the `-Pscreenshot` property, thus making it easier to run only those specific tests.

### Q: How can I debug screenshot tests in Android Studio?
### Q: How can I execute screenshot tests using Android Studio's Run button?

A: To execute screenshot tests using Android Studio's Run button, configure your project as follows:

`gradle.properties`

```groovy
roborazzi.test.record=true
```

After that, you can execute screenshot tests using either Android Studio's Run or Debug button as you normally would.

### Q: My screenshot tests are not capturing images. What could be the issue?

**A:** If your screenshot tests are not capturing images, there may be several patterns that are causing this issue. Please follow these troubleshooting steps:

- **Enable Debugging**: Set `ROBORAZZI_DEBUG = true` to see logs.
- **Check Plugin**: Ensure that the plugin is properly applied.
- **Run Task**: Verify that the `recordRoborazziDebug` task is running.
- **Call Method**: Confirm that `captureRoboImage()` is being called.

By following these steps, you should be able to identify and resolve the issue causing the screenshot tests to not capture images.

### Q: I'm seeing an optimization warning related to Java lambdas in Gradle. What can I do?

**A:** This warning may occur with Gradle 7.5. Upgrade to Gradle 7.6.2 to resolve this issue. Change the distribution URL in `gradle-wrapper.properties`:

```
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
```

### Q: Can I run Roborazzi with Bazel?

**A:** As of now, there is no direct support for running Roborazzi with Bazel. However, it is possible to do so. Please refer to the following comment for more details:
[Roborazzi Bazel Support Comment](https://github.com/takahirom/roborazzi/issues/63#issuecomment-1531990825)

### Q: My tests are being skipped or, conversely, are being run when they should be skipped. How can I handle caching to address this?

**A:** The behavior you are experiencing may be related to caching issues. Although it's
experimental, you can set the `outputDir` parameter in your `build.gradle` file to handle caching
and improve the stability of your tests. This parameter allows you to specify the output directory
for your screenshots, which can help in managing the cache. Here is how you can set it up:
If you use the default output directory(module/build/outputs/roborazzi), specifying the `outputDir`
parameter is not necessary. For more reference, you can check
out [the issue](https://github.com/takahirom/roborazzi/issues/193#issuecomment-1782073746).

```gradle
roborazzi {
    outputDir = "src/your/screenshot/folder"
}
```

### Q: Why do my screenshot tests fail inconsistently across different operating systems like MacOS, Ubuntu, and Windows?

**A:** This is a known issue caused by variations in how graphics libraries render components on different platforms.
This issue is due to variations in how graphics libraries render components on different platforms.
As we've seen with [Now in Android](https://github.com/android/nowinandroid/issues/1242#issuecomment-2032962982), there are no guarantees for identical rendering across all environments.
To ensure more consistent results, consider configuring your continuous integration (CI) environment to both record and test screenshots. This setup minimizes discrepancies by using the same settings and resources for all tests.

### Q: The images taken from Roborazzi seem broken

**A:** First, please check if you are using the correct version of the Android SDK. Consider using API level 28 or higher because it seems that Robolectric Native Graphics doesn't work property on older SDK versions.

You can specify the SDK version like `@Config(sdk = [33])` or by using `robolectric.properties` with `sdk=33`.
[https://robolectric.org/configuring/](https://robolectric.org/configuring/)

If your images are mostly fine but there are some drawing issues like shadows or shape graphics, you can try using Robolectric's Hardware Rendering mode. Please refer to [this issue](https://github.com/takahirom/roborazzi/issues/255#issuecomment-1972838571).

### Q: I am seeing Out Of Memory errors.

**A:** You may solve this by using `unitTests.maxHeapSize` to adjust the unit test heap size as follows:
```groovy
android {
  ...
  testOptions {
    unitTests.all {
      maxHeapSize = "4096m"
    }
  }
}
```
It is discussed in [this issue](https://github.com/takahirom/roborazzi/issues/272).
Additionally, it might be worth trying to run your tests with VisualVM to monitor memory usage and identify potential leaks.

### LICENSE

```
Copyright 2023 takahirom
Copyright 2019 Square, Inc.
Copyright The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```


EVMap [![Build Status](https://github.com/ev-map/EVMap/actions/workflows/tests.yml/badge.svg)](https://github.com/ev-map/EVMap/actions)
=====

Android app to find electric vehicle charging stations.

Features
--------

- [Material Design](https://material.io/)
- Shows all charging stations from the community-maintained [GoingElectric.de](https://www.goingelectric.de/stromtankstellen/) and [Open Charge Map](https://openchargemap.org) directories
- Realtime availability information (only in Europe)
- Search for places
- Advanced filtering options, including saved filter profiles
- Favorites list, also with availability information
- Integrated price comparison using [Chargeprice.app](https://chargeprice.app) (only in Europe)
- Android Auto & Android Automotive OS integration
- No ads, fully open source
- Compatible with Android 5.0 and above
- Can use Google Maps or OpenStreetMap as map backends - the version available on F-Droid only uses
  OSM.

Screenshots
-----------

Development setup
-----------------

The App is developed using Android Studio and should pretty much work out-of-the-box when you clone
the Git repository and open the project with Android Studio.

The only exception is that you need to obtain some API keys for the different data sources that
EVMap uses and put them into the app in the form of a resource file called `apikeys.xml` under
`app/src/main/res/values`. You can find more information on which API keys are necessary for which
features and how they can be obtained in our [documentation page](doc/api_keys.md).

There are four different build flavors, `googleNormal`, `fossNormal`, `googleAutomotive`, and
`fossAutomotive`.

- The `foss` variants only use OSM data and should run on most Android devices, even without
  Google Play Services.
    - `fossNormal` is intended to run on smartphones and tablets, and also includes the Android
      Auto app for use on the car display (however Android Auto may not work if the app is not
      installed from Google Play, see https://github.com/ev-map/EVMap/issues/319).
    - `fossAutomotive` can be installed directly on
      [Android Automotive OS (AAOS)](https://source.android.com/docs/automotive/start/what_automotive)
      headunits without Google services.
      It does not provide the usual smartphone UI, and requires an implementation of the
      [AOSP template app host](https://source.android.com/docs/automotive/hmi/aosp_host)
      to be installed. If you are an OEM and would like to distribute EVMap to your AAOS vehicles,
      please [get in touch](mailto:evmap@vonforst.net).
- The `google` variants also include access to Google Maps data.
    - `googleNormal` is intended to run on smartphones and tablets, and also includes the Android
      Auto app for use on the car display.
    - `googleAutomotive` can be installed directly on car infotainment systems running the
      Google-flavored Android Automotive OS (Google Automotive Services /
      ["Google built-in"](https://built-in.google/cars/)).
      It does not provide the usual smartphone UI, and requires the
      [Google Automotive App Host](https://play.google.com/store/apps/details?id=com.google.android.apps.automotive.templates.host)
      to run, which should be preinstalled on those cars and can be updated through the Play Store.

We also have a special [documentation page](doc/android_auto.md) on how to test the Android Auto
app.

Translations
------------

You can use our [Weblate page](https://hosted.weblate.org/projects/evmap/) to help translate EVMap
into new languages.

Sponsors
--------

Many users currently support the development EVMap with their donations. You can find more
information on the [Donate page](https://ev-map.app/donate/) on the EVMap website.

Since May 2024, **JawgMaps** provides their OpenStreetMap vector map tiles service to EVMap for
free, i.e. the background map displayed in the app if OpenStreetMap is selected as the data source.

Since April 2021, **Chargeprice.app** provide their price comparison API at a greatly reduced
price for EVMap. This data is used in EVMap's price comparison feature.

Since September 2022, for certain charging stations, **Fronyx** provide us free access to their API
for availability predictions.


# Easylauncher Gradle Plugin for Android

[![build](https://github.com/usefulness/easylauncher-gradle-plugin/actions/workflows/default.yml/badge.svg)](https://github.com/usefulness/easylauncher-gradle-plugin/actions/workflows/default.yml)
 [![ktlint](https://img.shields.io/badge/code%20style-%E2%9D%A4-FF4081.svg)](https://ktlint.github.io/)

[![version](https://img.shields.io/maven-metadata/v/https/plugins.gradle.org/m2/com/project/starter/easylauncher/maven-metadata.xml?label=gradle)](https://plugins.gradle.org/search?term=com.starter)

Modify the launcher icon of each of your app-variants using simple Gradle rules. Add ribbons of any color, overlay your own images, customize it according to your needs!

| Circle | RoundedRectangle | Teardrop |
| --- | --- | --- |
| ![](icons/launcher_circle.png) | ![](icons/launcher_rectangle.png) | ![](icons/launcher_teardrop.png) |

This library heavily relies on the original [Akaita's easylauncher](https://github.com/akaita/easylauncher-gradle-plugin) plugin, but introduces supports for modern build tools and **Vector icons**

## Usage

### Basic usage

```groovy
// in app/build.gradle
plugins {
    id "com.starter.easylauncher" version "${{version}}"
}
```
see [Gradle Plugin Portal] for the details

  What should I do if I get `Could not resolve all artifacts` error?

  In some configurations a dependency resolution error might be thrown with a message:
  > Could not find com.android.tools.build:gradle:x.x.x`.

  As a solution apply the plugin to the root project using:

```groovy
// in root project's build.gradle
buildscript {
    repositories.google()
}
plugins {
    id "com.starter.easylauncher" version "${{version}}" apply false
}
  ```
then apply the plugin in your application module:
```groovy
// in app/build.gradle
plugins {
    id "com.starter.easylauncher"
}
```

Alternatively, if using Version Catalog:
```toml
[plugins]
starter-easylauncher = { id = "com.starter.easylauncher", version.ref = "easylauncher" }
```

See [related issue](https://github.com/usefulness/easylauncher-gradle-plugin/issues/80) for more information.

### Advanced usage

By default, the plugin applies green ribbon for all debuggable build variants.
You can customize the filters applied to each type, flavor and variant of your app.

Imagine these are the type and flavors of your app:

```groovy
// in app/build.gradle
android {
    buildTypes {
        named("debug") {
            //Debuggable, will get a default ribbon in the launcher icon
        }
        named("release") {
            //Non-debuggable, will not get any default ribbon
        }
        register("beta") {
            //Debuggable, will get a default ribbon in the launcher icon
            debuggable true
        }
        register('canary') {
            //Non-debuggable, will not get any default ribbon
            debuggable false
        }
    }
    productFlavors {
        register("local") {}
        register("qa") {}
        register("staging") {}
        register("production") {}
    }
}
```

You could customize the plugin's behaviour like this:

```groovy
easylauncher {
    defaultFlavorNaming = true // Use flavor name for default ribbon, instead of the type name
    showWarnings = true // Defines if the plugins should show warnings at configuration time

    productFlavors {
        register("local") {}
        register("qa") {
            // Add one more filter to all `qa` variants
            filters redRibbonFilter()
        }
        register("staging") {}
        register("production") {}
    }

    buildTypes {
        register("beta") {
            // Add two more filters to all `beta` variants
            filters = [
                    customRibbon(ribbonColor: "#0000FF"),
                    overlayFilter(file("example-custom/launcherOverlay/beta.png"))
            ]
        }
        register("canary") {
            // Remove ALL filters to `canary` variants
            enable = false
        }
        register("release") {}
    }

    variants {
        register("productionDebug") {
            // OVERRIDE all previous filters defined for `productionDebug` variant
            filters = orangeRibbonFilter("custom")
        }
    }
}
```

#### Providing Icon Names
By default, the plugin **automatically** discovers launcher icon and applies provided filters.
Custom icon names, useful i.e. when defining multiple activity aliases, can be provided using `iconNames` property as follows:

```groovy
easylauncher {
    iconNames = ["@mipmap/custom_launcher_icon"] // optional, disables automatic launcher icon discovery and will use provided icons only

    buildTypes {
        register("beta") {
            // icon names can also be provided per each configuration (buildType, productFlavor or variant)
            iconNames = ["@mipmap/beta_launcher"]
        }
    }
}
```

## Available filters

## Overlay filter

| Command | Result |
| --- | --- |
| `overlayFilter(file("example-custom/launcherOverlay/beta.png"))` | ![](icons/overlay.png) |

## Ribbon filters

| Filter | Command | Result |
| --- | --- | --- |
| Gray ribbon | `grayRibbonFilter()` | ![](icons/ribbon_grey.png) |
| Green ribbon | `greenRibbonFilter()` | ![](icons/ribbon_green.png) |
| Yellow ribbon | `yellowRibbonFilter()` | ![](icons/ribbon_yellow.png) |
| Orange ribbon | `orangeRibbonFilter()` | ![](icons/ribbon_orange.png) |
| Red ribbon | `redRibbonFilter()` | ![](icons/ribbon_red.png) |
| Blue ribbon | `blueRibbonFilter()` | ![](icons/ribbon_blue.png) |

## Advanced Ribbon filter

| Description | Command | Result |
| --- | --- | --- |
| Custom background color  | `customRibbon(ribbonColor: "#6600CC")` | ![](icons/ribbon_custom_background.png) |
| Custom label | `customRibbon(label: "label", ribbonColor: "#DCDCDC")` | ![](icons/ribbon_custom_label.png) |
| Custom text color | `customRibbon(label: "label", ribbonColor: "#DCDCDC", labelColor: "#000000")` | ![](icons/ribbon_custom_textcolor.png) |
| Custom gravity - Top | `customRibbon(label: "custom", position: "top")` | ![](icons/ribbon_custom_top.png) |
| Custom gravity - Bottom | `customRibbon(position: "bottom")` | ![](icons/ribbon_custom_bottom.png) |
| Custom gravity - TopLeft | `customRibbon(position: "topLeft")` | ![](icons/ribbon_custom_topleft.png) |
| Custom gravity - TopRight | `customRibbon(position: "topRight")` | ![](icons/ribbon_custom_topright.png) |
| Custom text size (relative to the icon size) | `customRibbon(position: "bottom", textSizeRatio: 0.2)` | ![](icons/ribbon_custom_textsizeratio.png) |
| Custom font (locally installed) | `customRibbon(position: "top", font: "ComicSansMs")` | ![](icons/ribbon_custom_font.png) |
| Custom font (using font pack) | `customRibbon(position: "top", font: file("fonts/CustomFont.ttf"))` | ![](icons/ribbon_custom_font.png) |

  Troubleshooting on "Problem reading font data."

When using docker or a _minimalistic_ environment one might encounter above error message when loading Fonts.
The solution is to make sure font support was installed i.e. by calling:
```
apk add --no-cache freetype fontconfig ttf-dejavu
```

See [related issue](https://github.com/usefulness/easylauncher-gradle-plugin/issues/201) for more information.

## Chrome-like filters

| Filter | Command | Result |
| --- | --- | --- |
| Default | `chromeLike()` | ![](icons/chromelike_default.png) |
| Custom appearance | `chromeLike(label: "Custom", ribbonColor: "#FF00FF", labelColor: "#FFFFFF")` | ![](icons/chromelike_custom.png) |
| Custom font (locally installed) | `chromeLike(label: "Custom", font: "ComicSansMS-Bold")` | ![](icons/chromelike_font.png) |
| Custom gravity - Top (with additional padding)| `chromeLike(label: "Top", gravity: "Top", labelPadding: 10)` | ![](icons/chromelike_top.png) |
| Custom overlay/label alignment| `chromeLike(label: "Tall", overlayHeight: 0.6, textSizeRatio: 0.3)` | ![](icons/chromelike_tall.png) |

## Available options

 - `defaultFlavorNaming`: use _flavor_ name in default ribbons, instead of using _buildType_
 - `enable`: enable/disable **all** filters for a flavor/type/variant
 - `productFlavors`: define filters for flavors (will be **added** to filters defined for types)
 - `buildTypes`: define filters for types (will be **added** to filter defined for flavors)
 - `variants`: define filters for variants (will **override** any other filters)
 - `iconNames`: provides a list of icons which will have the filters applied

## Requirements
Minimal requirements for the plugin are:
- Gradle: **8.2.1**
- Android Gradle Plugin: **8.2.2**
- Java Version: **11**
- minSdkVersion: **26** _(theoretically there should be no lower boundary - it just hasn't been tested)_

## Project Structure

```
easylauncher/   - source code of Gradle plugin
sample/         - root directory of supported Android applications which serve as test projects
```

## Credits
Credits to [Akaita's easylauncher plugin](https://github.com/akaita/easylauncher-gradle-plugin) which this project heavily relies on

[Gradle Plugin Portal]: https://plugins.gradle.org/plugin/com.starter.easylauncher

---

YourKit supports open source projects with innovative and intelligent tools
for monitoring and profiling Java and .NET applications.
YourKit is the creator of YourKit Java Profiler,
YourKit .NET Profiler,
and YourKit YouMonitor.


[//]: # (
 Partly Sane Skies
)

  A Quality of Life SkyBlock Mod

## About

Partly Sane Skies is a Minecraft mod for Hypixel SkyBlock, designed, built, and programmed by **Su386** and **FlagMaster**.

 >📋 - Credits including third party programs can be [found here](CREDITS.md)

 >📝 - Previous changelogs can be [found here](pages/changelogs/previous_changelogs.md)

 >🗃 - Some other really cool mods can be [found here](https://sbmw.ca/mod-lists/skyblock-mod-list/)

###  Discord
[Click here to join the Discord](https://discord.gg/v4PU3WeH7z) for help, support, giveaways, and updates as they happen.

## Download:
### Official Download Links:

    Modrinth: Download "Featured Version" on sidebar

    Github: Open the assets drop down for the latest version and download "partly-sane-skies".jar file.

Place that mod in the mods folder of your Minecraft and you are good to go!

*There is no "reborn" or "revamped" version of Partly Sane Skies. If you do find one, please report it in the [Discord](https://discord.gg/v4PU3WeH7z).*

## Usage:

*Click the arrows to toggle the full list of information*

    ⌨ Commands

[``/pss``:](pages/commands.md#pss) A help command for Partly Sane Skies

[``/pss config``, ``/pssconfig``:](pages/commands.md#pssconfig) A command to open the PSS Config menu. The keybinding can also be changed in the vanilla options' menu. Default: ``F7``

[``/pssdisc``, ``/pssdiscord``:](pages/commands.md#pssdiscord) Sends a link to the discord. [Or you can just join here (https://discord.gg/v4PU3WeH7z)](https://discord.gg/v4PU3WeH7z)

[``/skillup <username>``, ``/su <username>``:](pages/commands.md#skillup) Command to use the skill upgrade recommendation feature. (See Features)

[``/pm``, ``/partymanager``:](pages/commands.md#partymanager) Command to open the Party Manager. The keybinding can also be changed in the vanilla options' menu.

[``/permparty``, ``/permp``, ``/pp``:](pages/commands.md#permparty) Command to use Permanent Dungeon Party Selector. (See Features)

[``/fp``, ``/pf``:](pages/commands.md#friendparty) Command to use Party All Friends. (See Features)

[``/chatalert``, ``/ca``, ``/chal``:](pages/commands.md#chatalerts) Command to use the Chat Alerts System. (See Features)

[``//farmnotifier``, ``//fn``, ``//farmnotif``:](pages/commands.md#farmnotfier) Command to use the farm notifier system.

[``/wordeditor``, ``/wordedit``, ``/wr``, ``/wordreplace``, ``/wr``] Command to replace a word in the chat with another word or a phrase.

To view more information about commands, including how to use them, **[click here to visit the command page.](pages/commands.md)**

    🛠Config

  ![Config Menu](images/config_menu.png)

***Almost all features can be enabled and modified through the config menu.***

- Config Menu Command:  /pss config

- Default Config Keybinding:  F7.

- The config menu can also be accessed through the [custom main menu, with the 'options' button.](pages/features/general/custom_main_menu.md)

## Top Features:

***Note: the features below are just a small selection all PSS features: these are just some of the more popular/liked features.***

*To view the complete list of all features, **[click here to visit the complete features page.](pages/features/list.md)***

   ⚙ General/Miscellaneous Features

## ⚙ General/Miscellaneous Features

General and Miscellaneous features.

### Mods Checker
When enabled, Mod Checker automatically will check your mods list for outdated, suspicious, or unknown mods. These mods may not be on the list of verified mods.
If you believe a mod is being falsely flagged, please report it in the PSS discord (/pssdiscord)

### Privacy Mode
When enabled, Privacy Mode blocks other mods wanting to send data to their servers. Currently supported mods are Essentials & Dungeon Guide. If you know more mods that send that kind of data, feel free to report that in our discord server. ```/pssdiscord```

### Custom Main Menu

*For more information, [see the Custom Main Menu page](pages/features/general/custom_main_menu.md)*

Upon start up of Minecraft, a nice, SkyBlock themed main menu will display.
There are various configurable options from SkyBlock-themed backgrounds,
along with an option to select a random background.

### RNG Drop Banner and Sound

When you get a rare drop, a Pumpkin Dicer or Melon Slicer like pop-up banner will appear, along with a sound, celebrating your drop.

### Custom Themes

This mod supports a variety of different themes, including dark themes, very dark themes, colorful themes, and controversially, light themes. You can also choose your own accent color, and create your own themes in the OneConfig menu under the theme section.

### Custom Sounds for SkyBlock

Instead of the normal note blocks, there is now the option to use computer generated, discord sounds or even live instruments to play sounds such as SkyBlock music and sound effects.

### Location Banner

When switching to a new location region on SkyBlock, an MMO RPG style banner will appear, informing you that you have switched to a new region.

   💬 Chat Features

### 💬 Chat Alerts

Using ``/ca``, you can add and remove specific phrases that will be highlighted when someone says them. Example: If you add the word "``flag``" (using ``/ca add flag``) to Chat Alerts, it will highlight the word and play a notification when someone says it.

![Chat Alerts](images/chat_alerts.png)

### Chat Color

Private messages and messages that are sent in the Party, Guild, Guild Officer, or SkyBlock Co-op channels will now have the color of the channel they are sent in.

![Chat Colors](images/chat_color.png)

### OwO Wanguage

This feature basically changes all chat messages to use the owo language. Please don't use this; it literally breaks the chat completely. If you do, be warned.

### Pet for Minion Information Display

When opening the minion, your current pet selected will appear, along with the pet that you have set as favorite.

### Nons Chat Color

Messages sent by nons (non-ranked players) can be configured to have the same white as the rest of the chat.
This option is off by default but can be turned on in the PSS Config menu.

### Word Editor for in game chat

Replace any word in chat to any other word, such as rp to reparty, FlagMaster to FlagHater or juju to nonbow

![Word Editor 1](images/word_editor_1.png)

![Word Editor 2](images/word_editor_2.png)

![Word Editor 3](images/word_editor_3.png)

![Word Editor 4](images/word_editor_4.png)

   💀 Dungeons Features

## 💀 Dungeon Features

### Party Manager

Manage your party and join dungeons with a helpful party manager, with features such as viewing stats,
kicking, party transfer buttons, etc. Included in the Party Manager GUI.
You can open it by typing the command ``/pm`` or by using the keybinding.
Default: ``M``

### Custom Themes

This mod supports a variety of different themes, including dark themes, very dark themes, colorful themes, and controversially, light themes. You can also choose your own accent color, and create your own themes in the OneConfig menu under the theme section. These themes only affect the PSS user interface.

### Pearl Refill

Do you use pearls for your Dungeon runs and want to refill them backup to 16? With the Pearl Refill command you can automatically refill it back up to 16 from any other stack size, there is also a hot key (Default ``P``) and an option to enable auto refill at Dungeon start (use at your own risk)

### Watcher Ready, Message, Warning, Siren and Sound

When the watcher is done spawning mobs, a message will appear on your screen, along with an optional sound,
party message and World War II (1939-1945) air raid siren in case the previous two don't get your attention.

### Permanent Dungeon Party Selector

Automatically parties everyone in a permanent dungeon party. Using ``/pp`` or ``/permparty``, you have the option to create, party, delete, and add and remove members from your permanent party. You can even add different parties such as an f6Party or a jujuNonCarry party.

### Dungeon Player Rater

At the end of the dungeon, the mod will calculate what percentage of the dungeon was cleared by each player,
and how much they contributed, showing you how useful each player was.
In a perfectly balanced 5-player party, each player should get 20%.

### Required Secrets Notifier

Your teammates are throwing because they don't know you don't need 100% of secrets on lower floors? This feature sends a warning to yourself with a banner and sound (which can be an air raid siren) and a party message for your teammates when all the required secrets are found for an S+ run.

   🌾Farming and Garden Features

## 🌾 Farming

### End of Farm Notifier

Create a region where you will be notified when you reach it, using the same commands as world edit. See ``/farmnotif`` under the Commands section for more information.

### Top Crops to Compost

Shows you information about which crops are the best to use for the composter at the current moment in time.

### Best SkyMart Profit

Shows which items are the most profitable for the copper cost. (Which ones give the most coins per copper?)

   ⛏ Mining Features

## ⛏ Mining Features

### Worm Warning

When you are mining in the Crystal Hollows and a worm or Scatha spawns, you get a message on screen, along with a sound, warning you that a worm has spawned.

### Mining Events Reminder

The mining events reminder has a selective list of all Dwarven mines & crystal hollows events. These events can be enabled separately. You can be reminded with either a banner or a banner and sound. You can choose the banner's color and display time yourself. You can also get reminded 20 seconds before the event starts.

### Pickaxe Ability Reminder

Not always aware when the pickaxe cooldown is over? Not anymore! With the new pickaxe cooldown reminder, this won't happen anymore. Need a banner? We have that! Want color in it? It's already available! Sound? Of course. It also includes PTSD, the best feature of it all—the Air Raid Siren! You can also block right-clicks on your private island, so you'll never accidentally pickoboculus your island again.

   🪙 Economy Features

## 🪙 Economy

### No Cookie Warning

Never lose your coins to the void again! When the mod detects you do not have a cookie active, it will warn you to buy a new one. Optionally, it can warn you only if you have a lot of coins in your purse.

### Enhanced Auction Menu and BIN Sniper

A brand-new auction house menu that gives you more information on prices, instant inflation, and mark up.
Using that information, the menu highlights BIN items that are significantly below their value (Default: 13% below).

### Best Minion Profit Calculator

Using real time data, the mod will now display which configurations will result in the most profitable minions. Type of Fuel, Minion Upgrades, and type of minion can be filtered.

### Best Bit Shop Profit

A lot of people use the bits accumulated from booster cookies to convert to items to sell on the auction house. Instead of having to guess which items are the best and for what price, it will now recommend to you the items that sell for the most coins per bit.

   ⌨ Shortcuts

## ⌨  Shortcuts

### Open Wiki Keybinding

Using the keybinding, it will automatically look up the wiki article for the item you are hovering over.
(``NONE`` key by default)

### Pets Menu Keybinding

A keybinding shortcut to open the pet menu. Customizable in the vanilla options' menu. (``NONE`` key by default)

### Crafting Table Menu Keybinding

A keybinding shortcut to open the crafting table menu.
Customizable in the vanilla options' menu.
(``NONE`` key by default)

### Wardrobe Menu Keybinding

A keybinding shortcut to open the wardrobe menu. Customizable in the vanilla options' menu. (``NONE`` key by default)

### Storage Menu Keybinding

A keybinding shortcut to open the storage menu. Customizable in the vanilla options' menu. (``NONE`` key by default)

### Hoe Right Click

A Keybinding shortcut to allow Hoe Right Click for one time or for some minutes, depending on your setting. Customizable in the vanilla options' menu. (``NONE`` by default)

### Party All Friends

A command to party all of your active friends. Using ``/fp``, it will party every online member on your friends' list.


# Kotlin compiler server

[![official JetBrains project](https://jb.gg/badges/official-plastic.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
![Build status](https://buildserver.labs.intellij.net/app/rest/builds/buildType:id:Kotlin_KotlinSites_Deployments_PlayKotlinlangOrg_Backend_BuildMaster/statusIcon.svg)
![Java CI](https://github.com/AlexanderPrendota/kotlin-compiler-server/workflows/Java%20CI/badge.svg)
![TC status](https://img.shields.io/teamcity/build/s/Kotlin_KotlinPlayground_KotlinCompilerServer_Build?label=TeamCity%20build)
[![Kotlin](https://img.shields.io/badge/Kotlin-1.7.20-orange.svg) ](https://kotlinlang.org/)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)

A REST server for compiling and executing Kotlin code.
The server provides the API for [Kotlin Playground](https://github.com/JetBrains/kotlin-playground) library.

## How to start :checkered_flag:

### Simple Spring Boot application

Download Kotlin dependencies and build an executor before starting the server:

```shell script
$ ./gradlew build -x test
```

Start the Spring Boot project. The main class: `com.compiler.server.CompilerApplication`

### With Docker

To build the app inside a Docker container, run the following command from the project directory:
```shell
$ ./docker-image-build.sh
```

### From Amazon lambda

Based on [aws-serverless-container](https://github.com/awslabs/aws-serverless-java-container).

```shell script
$ ./gradlew buildLambda
```

Getting `.zip` file from `build/distributions`.

Lambda handler: `com.compiler.server.lambdas.StreamLambdaHandler::handleRequest`.

Publish your Lambda function: you can follow the instructions
in [AWS Lambda's documentation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-java-how-to-create-deployment-package.html)
on how to package your function for deployment.

### From Kotless

Add [Kotless](https://github.com/JetBrains/kotless) and
remove [aws-serverless-container](https://github.com/awslabs/aws-serverless-java-container) =)

## API Documentation :page_with_curl:

### Execute Kotlin code on JVM

```shell script
curl -X POST \
  http://localhost:8080/api/compiler/run \
  -H 'Content-Type: application/json' \
  -d '{
    "args": "1 2 3",
    "files": [
        {
            "name": "File.kt",
            "text": "fun main() {\n    println(\"123\")\n}"
        }
    ]
}'
```

### Translate Kotlin code to JavaScript code

```shell script
curl -X POST \
    http://localhost:8080/api/compiler/translate \
    -H 'Content-Type: application/json' \
    -d '{
      "args": "1 2 3",
      "files": [
        {
          "name": "File.kt",
          "text": "fun main(args: Array<String>) {\n    println(args[0])\n }"
        }
      ]
}'
```

### Run Kotlin tests

```shell script
curl -X POST \
  http://localhost:8080/api/compiler/test \
  -H 'Content-Type: application/json' \
  -d '{
  "files": [
    {
      "name": "File.kt",
      "text": "fun start(): String = \"OK\""
    },
    {
      "name": "test0.kt",
      "text": "import org.junit.Assert\nimport org.junit.Test\n\nclass TestStart {\n    @Test fun testOk() {\n        Assert.assertEquals(\"OK\", start())\n    }\n}"
    },
    {
      "name": "test1.kt",
      "text": "package koans.util\n\nfun String.toMessage() = \"The function '\''$this'\'' is implemented incorrectly\"\n\nfun String.toMessageInEquals() = toMessage().inEquals()\n\nfun String.inEquals() = this"
    }
  ]
}'
```

### Get code completions for a specified place in code

```shell script
curl -X POST \
  'http://localhost:8080/api/compiler/complete?line=2&ch=15' \
  -H 'Content-Type: application/json' \
  -d '{
  "files": [
    {
      "name": "File.kt",
      "text": "fun main() {\n    val sinusoid = \"sinusoid\"\n    val s = sin\n}"
    }
  ]
}'
```

### Get code analysis results

```shell script
curl -X POST \
  http://localhost:8080/api/compiler/highlight \
  -H 'Content-Type: application/json' \
  -d '{
  "files": [
    {
      "name": "File.kt",
      "text": "fun main() {\n    println(\"Hello, world!!!\")ass\n    val random = Random\n}"
    }
  ]
}'
```

### Get the current Kotlin version

```shell script
curl -X GET http://localhost:8080/versions
```

The server also supports an [API](https://github.com/JetBrains/kotlin-playground) for the Kotlin Playground library.

## How to add your dependencies to kotlin compiler :books:

Just put whatever you need as dependencies
to [build.gradle.kts](https://github.com/AlexanderPrendota/kotlin-compiler-server/blob/master/build.gradle.kts) via a
task called `kotlinDependency`:

```
 kotlinDependency "your dependency"
```

NOTE: If the library you're adding uses reflection, accesses the file system, or performs any other type of
security-sensitive operations, don't forget to
configure
the [executors.policy](https://github.com/AlexanderPrednota/kotlin-compiler-server/blob/master/executors.policy)
. [Click here](https://docs.oracle.com/javase/7/docs/technotes/guides/security/PolicyFiles.html) for more information
about *Java Security Policy*.

**How to set Java Security Policy in `executors.policy`**

If you want to configure a custom dependency, use the marker `@LIB_DIR@`:

```
grant codeBase "file:%%LIB_DIR%%/junit-4.12.jar"{
  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
  permission java.lang.RuntimePermission "setIO";
  permission java.io.FilePermission "<<ALL FILES>>", "read";
  permission java.lang.RuntimePermission "accessDeclaredMembers";
};
```

## CORS configuration

Set the environment variables

| ENV                               | Default value |
|-----------------------------------|---------------|
| ACCESS_CONTROL_ALLOW_ORIGIN_VALUE | *             |
| ACCESS_CONTROL_ALLOW_HEADER_VALUE | *             |

## Configure logging

We use `prod` spring active profile to stream logs as JSON format.
You can set the spring profile by supplying `-Dspring.profiles.active=prod` or set env variable `SPRING_PROFILES_ACTIVE` to `prod` value.

### Unsuccessful execution logs

In case of an unsuccessful execution in the standard output will be the event with INFO level:

```json
{
  "date_time": "31/Aug/2021:11:49:45 +03:00",
  "@version": "1",
  "message": "Code execution is complete.",
  "logger_name": "com.compiler.server.service.KotlinProjectExecutor",
  "thread_name": "http-nio-8080-exec-1",
  "level": "INFO",
  "level_value": 20000,
  "hasErrors": true,
  "confType": "JAVA",
  "kotlinVersion": "$koltinVersion"
}
```

## Kotlin release guide :rocket:

1) Update the kotlin version
   in [gradle.properties](https://github.com/AlexanderPrendota/kotlin-compiler-server/blob/master/gradle.properties)
2) Make sure everything is going well via the task:

```shell script
$ ./gradlew build
```

3) Save branch with the name of the kotlin version. Pattern: `/^[0-9.]+$/`  (optional)
4) Bump version on GitHub [releases](https://github.com/AlexanderPrendota/kotlin-compiler-server/releases) (optional)


[![official project](http://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![Latest release](https://img.shields.io/github/v/release/JetBrains/compose-multiplatform?color=brightgreen&label=latest%20release)](https://github.com/JetBrains/compose-multiplatform/releases/latest)
[![Latest build](https://img.shields.io/github/v/release/JetBrains/compose-multiplatform?color=orange&include_prereleases&label=latest%20build)](https://github.com/JetBrains/compose-multiplatform/releases)

# Compose Multiplatform

[**Compose Multiplatform**](https://jb.gg/cmp) is a declarative framework for sharing UIs across multiple platforms with Kotlin.
It is based on [Jetpack Compose](https://developer.android.com/jetpack/compose) and developed by [JetBrains](https://www.jetbrains.com/) and open-source contributors.

You can choose the platforms across which to share your UIs using Compose Multiplatform:

* [iOS](https://jb.gg/start-cmp) (Beta)
* [Android](https://jb.gg/start-cmp)
* [Desktop](https://jb.gg/start-cmp) (Windows, MacOS, Linux)
* [Web](https://jb.gg/start-cmp) (Alpha)

For example, you can share UIs between iOS and Android or Windows and MacOS.

![Shared UIs of the iOS, Android, desktop, and web apps](artwork/readme/apps.png)

## iOS

> iOS support is in Beta. It is feature complete, and migration issues should be minimal. You may still encounter bugs, performance and developer experience issues, but not as much as in the Alpha stage.
> We would appreciate your feedback on it in the public Slack channel [#compose-ios](https://kotlinlang.slack.com/archives/C0346LWVBJ4/p1678888063176359).
> If you face any issues, please report them on [GitHub](https://github.com/JetBrains/compose-multiplatform/issues).

Compose Multiplatform shares most of its API with Jetpack Compose, the Android UI framework developed by Google.
You can use the same APIs to build user interfaces for both Android and iOS.

Since Compose is built on top of [Kotlin Multiplatform](https://jb.gg/kmp),
you can easily access native APIs, such as the [Camera API](https://developer.apple.com/documentation/avfoundation/capture_setup/avcam_building_a_camera_app),
and embed complex native UI views, such as [MKMapView](https://developer.apple.com/documentation/mapkit/mkmapview).

**[Get started with Compose Multiplatform](https://jb.gg/start-cmp)**

## Android

When Android is one of your targets, you can get the same experience for Android as if you were developing an Android app
using [Jetpack Compose](https://developer.android.com/jetpack/compose).

**[Get started with Compose Multiplatform](https://jb.gg/start-cmp)**

## Desktop

Compose Multiplatform targets the JVM and supports high-performance hardware-accelerated UI rendering on all major desktop
platforms – macOS, Windows, and Linux.

It has desktop extensions for menus, keyboard shortcuts, window manipulation, and notification management.

**[Get started with Compose Multiplatform](https://jb.gg/start-cmp)**

> We would appreciate your feedback on Compose Multiplatform in the public Slack channel [#compose](https://kotlinlang.slack.com/archives/CJLTWPH7S/p1678882768039969).

## Web

> Web support is in Alpha. It may change incompatibly and require manual migration in the future.
> We would appreciate your feedback on it in the public Slack channel [#compose-web](https://kotlinlang.slack.com/archives/C01F2HV7868/p1678887590205449).
> If you face any issues, please report them on [GitHub](https://github.com/JetBrains/compose-multiplatform/issues).

You can experiment with sharing your mobile or desktop UIs with the web. Compose for Web is based on [Kotlin/Wasm](https://kotl.in/wasm),
the newest target for Kotlin Multiplatform projects. It allows Kotlin developers to run their code in the browser with
all the benefits that WebAssembly has to offer, such as good and predictable performance for your applications.

**[Get started with Compose for Web](https://jb.gg/start-cmp)**

## Libraries

### Compose HTML

Compose HTML is a library targeting [Kotlin/JS](https://kotlinlang.org/docs/js-overview.html) that provides Composable building blocks
for creating web user interfaces with HTML and CSS.

> Note that Compose HTML is not a multiplatform library. It can be used only with Kotlin/JS.

## Learn more

* [FAQ](https://jb.gg/cmp-faq)
* [Samples](https://jb.gg/cmp-samples)
* [Tutorials](tutorials/README.md)
* [Compatibility and versioning](https://jb.gg/cmp-versioning)
* [Changelog](CHANGELOG.md)


# What is refreshVersions?

**refreshVersions** helps **Gradle** users with the **tedious manual work** usually involved in adding and updating **dependencies and their versions**.

[![](https://raw.githubusercontent.com/jmfayard/refreshVersions/main/docs/img/screencast.png)](http://www.youtube.com/watch?v=VhYERonB8co "Gradle refreshVersions")

## Documentation

- [Start here](https://splitties.github.io/refreshVersions/)
- [Setup refreshVersions](https://splitties.github.io/refreshVersions/setup/)
- [Migrate your project](https://splitties.github.io/refreshVersions/migrate/)
- [Find Available Dependencies Updates](https://splitties.github.io/refreshVersions/update-dependencies/)
- [Add Dependencies](https://splitties.github.io/refreshVersions/add-dependencies/)
- [Explore built-in Dependencies Notations](https://splitties.github.io/refreshVersions/dependency-notations/)
- [Schedule the RefreshVersionsBot](https://splitties.github.io/refreshVersions/refreshversions-bot/)
- [Use the buildSrc](https://splitties.github.io/refreshVersions/gradle-buildsrcversions/)
- [Changelog](https://splitties.github.io/refreshVersions/CHANGELOG/)

[**See documentation at https://splitties.github.io/refreshVersions**](https://splitties.github.io/refreshVersions/)

## Setup

```kotlin
// settings.gradle(.kts)
plugins {
    // See https://splitties.github.io/refreshVersions
    id("de.fayard.refreshVersions") version "0.60.5"
}

refreshVersions { // Optional: configure the plugin
    // ...
}
```

[Read the friendly documentation](https://splitties.github.io/refreshVersions/setup/)

## Usage

Make sure the project is correctly set up (see just above).

**Migrate project:**

The `refreshVersionsMigrate` task can help you migrate your project in a few minutes, or less.

In version 0.50.0, support for Gradle's Versions Catalogs was added ([see discussion thread here](https://github.com/Splitties/refreshVersions/discussions/592)), so a `--mode` option is now required.

Run it without it to see the complete list and the full description of each mode:

```shell
./gradlew refreshVersionsMigrate
```

Examples (click to expand)

If you want to use only `versions.properties` and the [built-in dependencies notations](https://splitties.github.io/refreshVersions/dependency-notations/), run:

`./gradlew refreshVersionsMigrate --mode=VersionsPropertiesOnly`

To also use a versions catalog for non-built-in dependency notations, run:

`./gradlew refreshVersionsMigrate --mode=VersionCatalogAndVersionProperties`

**Find available updates in `versions.properties` and the default versions catalog, if any:**

`./gradlew refreshVersions`

**Cleanup versions availability comments:**

`./gradlew refreshVersionsCleanup`