Merge branch 'javalin-3.5' into 'master'

Upgrade headless to Javalin 3.5

See merge request briar/briar!1162
This commit is contained in:
akwizgran
2019-12-10 10:11:55 +00:00
20 changed files with 146 additions and 126 deletions

View File

@@ -1,8 +1,8 @@
plugins { plugins {
id 'java' id 'java'
id 'idea' id 'idea'
id 'org.jetbrains.kotlin.jvm' version '1.3.31' id 'org.jetbrains.kotlin.jvm' version '1.3.40'
id 'org.jetbrains.kotlin.kapt' version '1.3.31' id 'org.jetbrains.kotlin.kapt' version '1.3.40'
id 'witness' id 'witness'
} }
apply from: 'witness.gradle' apply from: 'witness.gradle'
@@ -14,11 +14,11 @@ dependencies {
implementation project(path: ':briar-core', configuration: 'default') implementation project(path: ':briar-core', configuration: 'default')
implementation project(path: ':bramble-java', configuration: 'default') implementation project(path: ':bramble-java', configuration: 'default')
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.31' implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.40'
implementation 'io.javalin:javalin:2.8.0' implementation 'io.javalin:javalin:3.5.0'
implementation 'org.slf4j:slf4j-simple:1.7.26' implementation 'org.slf4j:slf4j-simple:1.7.26'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8' implementation 'com.fasterxml.jackson.core:jackson-databind:2.10.0'
implementation 'com.github.ajalt:clikt:2.0.0' implementation 'com.github.ajalt:clikt:2.2.0'
def daggerVersion = '2.24' def daggerVersion = '2.24'
kapt "com.google.dagger:dagger-compiler:$daggerVersion" kapt "com.google.dagger:dagger-compiler:$daggerVersion"
@@ -27,7 +27,7 @@ dependencies {
testImplementation project(path: ':bramble-core', configuration: 'testOutput') testImplementation project(path: ':bramble-core', configuration: 'testOutput')
testImplementation project(path: ':briar-core', configuration: 'testOutput') testImplementation project(path: ':briar-core', configuration: 'testOutput')
def junitVersion = '5.4.2' def junitVersion = '5.5.2'
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
testRuntime "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testRuntime "org.junit.jupiter:junit-jupiter-engine:$junitVersion"

View File

@@ -8,10 +8,10 @@ import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK
import org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH import org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH
import org.briarproject.bramble.api.lifecycle.LifecycleManager import org.briarproject.bramble.api.lifecycle.LifecycleManager
import java.lang.System.exit
import javax.annotation.concurrent.Immutable import javax.annotation.concurrent.Immutable
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.system.exitProcess
interface BriarService { interface BriarService {
fun start() fun start()
@@ -36,7 +36,7 @@ constructor(
?: throw UsageError("Could not get password. Is STDIN connected?") ?: throw UsageError("Could not get password. Is STDIN connected?")
if (!accountManager.signIn(password)) { if (!accountManager.signIn(password)) {
echo("Error: Password invalid") echo("Error: Password invalid")
exit(1) exitProcess(1)
} }
} }
val dbKey = accountManager.databaseKey ?: throw AssertionError() val dbKey = accountManager.databaseKey ?: throw AssertionError()

View File

@@ -2,14 +2,13 @@ package org.briarproject.briar.headless
import com.fasterxml.jackson.core.JsonParseException import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.javalin.BadRequestResponse
import io.javalin.Context
import io.javalin.Javalin import io.javalin.Javalin
import io.javalin.JavalinEvent.SERVER_START_FAILED
import io.javalin.JavalinEvent.SERVER_STOPPED
import io.javalin.NotFoundResponse
import io.javalin.apibuilder.ApiBuilder.* import io.javalin.apibuilder.ApiBuilder.*
import io.javalin.core.security.AccessManager
import io.javalin.core.util.Header.AUTHORIZATION import io.javalin.core.util.Header.AUTHORIZATION
import io.javalin.http.BadRequestResponse
import io.javalin.http.Context
import io.javalin.http.NotFoundResponse
import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.contact.ContactId
import org.briarproject.briar.headless.blogs.BlogController import org.briarproject.briar.headless.blogs.BlogController
import org.briarproject.briar.headless.contact.ContactController import org.briarproject.briar.headless.contact.ContactController
@@ -17,13 +16,16 @@ import org.briarproject.briar.headless.event.WebSocketController
import org.briarproject.briar.headless.forums.ForumController import org.briarproject.briar.headless.forums.ForumController
import org.briarproject.briar.headless.messaging.MessagingController import org.briarproject.briar.headless.messaging.MessagingController
import java.lang.Runtime.getRuntime import java.lang.Runtime.getRuntime
import java.lang.System.exit
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.logging.Level import java.util.logging.Level.INFO
import java.util.logging.Logger.getLogger import java.util.logging.Logger.getLogger
import javax.annotation.concurrent.Immutable import javax.annotation.concurrent.Immutable
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.system.exitProcess
private const val VERSION = "v1"
private const val WS = "/$VERSION/ws"
@Immutable @Immutable
@Singleton @Singleton
@@ -41,27 +43,29 @@ constructor(
private val logger = getLogger(Router::javaClass.name) private val logger = getLogger(Router::javaClass.name)
private val stopped = AtomicBoolean(false) private val stopped = AtomicBoolean(false)
internal fun start(authToken: String, port: Int, debug: Boolean) : Javalin { internal fun start(authToken: String, port: Int, debug: Boolean): Javalin {
briarService.start() briarService.start()
getRuntime().addShutdownHook(Thread(this::stop)) getRuntime().addShutdownHook(Thread(this::stop))
val app = Javalin.create() val accessManager = AccessManager { handler, ctx, _ ->
.port(port) when {
.disableStartupBanner() ctx.header(AUTHORIZATION) == "Bearer $authToken" -> handler.handle(ctx)
.enableCaseSensitiveUrls() ctx.matchedPath() == WS -> handler.handle(ctx) // websockets use their own auth
.event(SERVER_START_FAILED) {serverStopped() } else -> ctx.status(401).result("Unauthorized")
.event(SERVER_STOPPED) { serverStopped() }
if (debug) app.enableDebugLogging()
app.accessManager { handler, ctx, _ ->
if (ctx.header(AUTHORIZATION) == "Bearer $authToken") {
handler.handle(ctx)
} else {
ctx.status(401).result("Unauthorized")
} }
} }
val app = Javalin.create { config ->
config.showJavalinBanner = false
config.accessManager(accessManager)
if (debug) config.enableDevLogging()
}.events { event ->
event.serverStartFailed { serverStopped() }
event.serverStopped { serverStopped() }
}
app.routes { app.routes {
path("/v1") { path("/$VERSION") {
path("/contacts") { path("/contacts") {
get { ctx -> contactController.list(ctx) } get { ctx -> contactController.list(ctx) }
path("add") { path("add") {
@@ -94,32 +98,33 @@ constructor(
} }
} }
} }
app.ws("/v1/ws") { ws -> app.ws(WS) { ws ->
if (logger.isLoggable(Level.INFO)) ws.onConnect { session -> if (logger.isLoggable(INFO)) ws.onConnect { ctx ->
logger.info("Received websocket connection from ${session.remoteAddress}") logger.info("Received websocket connection from ${ctx.session.remoteAddress}")
logger.info("Waiting for authentication") logger.info("Waiting for authentication")
} }
ws.onMessage { session, msg -> ws.onMessage { ctx ->
if (msg == authToken && !webSocketController.sessions.contains(session)) { val session = ctx.session
if (ctx.message() == authToken && !webSocketController.sessions.contains(ctx)) {
logger.info("Authenticated websocket session with ${session.remoteAddress}") logger.info("Authenticated websocket session with ${session.remoteAddress}")
webSocketController.sessions.add(session) webSocketController.sessions.add(ctx)
} else { } else {
logger.info("Invalid message received: $msg") logger.info("Invalid message received: ${ctx.message()}")
logger.info("Closing websocket connection with ${session.remoteAddress}") logger.info("Closing websocket connection with ${session.remoteAddress}")
session.close(1008, "Invalid Authentication Token") session.close(1008, "Invalid Authentication Token")
} }
} }
ws.onClose { session, _, _ -> ws.onClose { ctx ->
logger.info("Removing websocket connection with ${session.remoteAddress}") logger.info("Removing websocket connection with ${ctx.session.remoteAddress}")
webSocketController.sessions.remove(session) webSocketController.sessions.remove(ctx)
} }
} }
return app.start() return app.start(port)
} }
private fun serverStopped() { private fun serverStopped() {
stop() stop()
exit(1) exitProcess(1)
} }
internal fun stop() { internal fun stop() {
@@ -148,7 +153,7 @@ fun Context.getContactIdFromPathParam(): ContactId {
/** /**
* Returns a String from the JSON field or throws [BadRequestResponse] if null or empty. * Returns a String from the JSON field or throws [BadRequestResponse] if null or empty.
*/ */
fun Context.getFromJson(objectMapper: ObjectMapper, field: String) : String { fun Context.getFromJson(objectMapper: ObjectMapper, field: String): String {
try { try {
val jsonNode = objectMapper.readTree(body()) val jsonNode = objectMapper.readTree(body())
if (!jsonNode.hasNonNull(field)) throw BadRequestResponse("'$field' missing in JSON") if (!jsonNode.hasNonNull(field)) throw BadRequestResponse("'$field' missing in JSON")

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.headless.blogs package org.briarproject.briar.headless.blogs
import io.javalin.Context import io.javalin.http.Context
interface BlogController { interface BlogController {

View File

@@ -1,8 +1,8 @@
package org.briarproject.briar.headless.blogs package org.briarproject.briar.headless.blogs
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.javalin.Context import io.javalin.http.Context
import org.briarproject.bramble.api.identity.IdentityManager import org.briarproject.bramble.api.identity.IdentityManager
import org.briarproject.bramble.api.system.Clock import org.briarproject.bramble.api.system.Clock
import org.briarproject.bramble.util.StringUtils.utf8IsTooLong import org.briarproject.bramble.util.StringUtils.utf8IsTooLong

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.headless.contact package org.briarproject.briar.headless.contact
import io.javalin.Context import io.javalin.http.Context
interface ContactController { interface ContactController {

View File

@@ -1,9 +1,9 @@
package org.briarproject.briar.headless.contact package org.briarproject.briar.headless.contact
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.javalin.Context import io.javalin.http.Context
import io.javalin.NotFoundResponse import io.javalin.http.NotFoundResponse
import org.briarproject.bramble.api.contact.ContactManager import org.briarproject.bramble.api.contact.ContactManager
import org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX import org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX
import org.briarproject.bramble.api.contact.PendingContactId import org.briarproject.bramble.api.contact.PendingContactId

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.headless.event package org.briarproject.briar.headless.event
import io.javalin.websocket.WsSession import io.javalin.websocket.WsContext
import org.briarproject.bramble.api.lifecycle.IoExecutor import org.briarproject.bramble.api.lifecycle.IoExecutor
import org.briarproject.briar.headless.json.JsonDict import org.briarproject.briar.headless.json.JsonDict
import javax.annotation.concurrent.ThreadSafe import javax.annotation.concurrent.ThreadSafe
@@ -8,7 +8,7 @@ import javax.annotation.concurrent.ThreadSafe
@ThreadSafe @ThreadSafe
interface WebSocketController { interface WebSocketController {
val sessions: MutableSet<WsSession> val sessions: MutableSet<WsContext>
/** /**
* Sends an event to all open sessions using the [IoExecutor]. * Sends an event to all open sessions using the [IoExecutor].

View File

@@ -1,7 +1,7 @@
package org.briarproject.briar.headless.event package org.briarproject.briar.headless.event
import io.javalin.json.JavalinJson.toJson import io.javalin.plugin.json.JavalinJson.toJson
import io.javalin.websocket.WsSession import io.javalin.websocket.WsContext
import org.briarproject.bramble.api.lifecycle.IoExecutor import org.briarproject.bramble.api.lifecycle.IoExecutor
import org.briarproject.bramble.util.LogUtils.logException import org.briarproject.bramble.util.LogUtils.logException
import org.briarproject.briar.headless.json.JsonDict import org.briarproject.briar.headless.json.JsonDict
@@ -23,7 +23,7 @@ constructor(@IoExecutor private val ioExecutor: Executor) : WebSocketController
private val logger = getLogger(WebSocketControllerImpl::javaClass.name) private val logger = getLogger(WebSocketControllerImpl::javaClass.name)
override val sessions: MutableSet<WsSession> = ConcurrentHashMap.newKeySet<WsSession>() override val sessions: MutableSet<WsContext> = ConcurrentHashMap.newKeySet<WsContext>()
override fun sendEvent(name: String, obj: JsonDict) { override fun sendEvent(name: String, obj: JsonDict) {
val event = toJson(OutputEvent(name, obj)) val event = toJson(OutputEvent(name, obj))

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.headless.forums package org.briarproject.briar.headless.forums
import io.javalin.Context import io.javalin.http.Context
interface ForumController { interface ForumController {

View File

@@ -1,8 +1,8 @@
package org.briarproject.briar.headless.forums package org.briarproject.briar.headless.forums
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.javalin.Context import io.javalin.http.Context
import org.briarproject.bramble.util.StringUtils.utf8IsTooLong import org.briarproject.bramble.util.StringUtils.utf8IsTooLong
import org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH import org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH
import org.briarproject.briar.api.forum.ForumManager import org.briarproject.briar.api.forum.ForumManager

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.headless.messaging package org.briarproject.briar.headless.messaging
import io.javalin.Context import io.javalin.http.Context
interface MessagingController { interface MessagingController {

View File

@@ -1,9 +1,9 @@
package org.briarproject.briar.headless.messaging package org.briarproject.briar.headless.messaging
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.javalin.Context import io.javalin.http.Context
import io.javalin.NotFoundResponse import io.javalin.http.NotFoundResponse
import org.briarproject.bramble.api.contact.Contact import org.briarproject.bramble.api.contact.Contact
import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.contact.ContactId
import org.briarproject.bramble.api.contact.ContactManager import org.briarproject.bramble.api.contact.ContactManager

View File

@@ -1,8 +1,8 @@
package org.briarproject.briar.headless package org.briarproject.briar.headless
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.javalin.Context import io.javalin.http.Context
import io.javalin.core.util.ContextUtil import io.javalin.http.util.ContextUtil
import io.mockk.mockk import io.mockk.mockk
import org.briarproject.bramble.api.contact.Contact import org.briarproject.bramble.api.contact.Contact
import org.briarproject.bramble.api.contact.ContactManager import org.briarproject.bramble.api.contact.ContactManager

View File

@@ -1,7 +1,7 @@
package org.briarproject.briar.headless.blogs package org.briarproject.briar.headless.blogs
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.javalin.json.JavalinJson.toJson import io.javalin.plugin.json.JavalinJson.toJson
import io.mockk.Runs import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just

View File

@@ -1,8 +1,8 @@
package org.briarproject.briar.headless.contact package org.briarproject.briar.headless.contact
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.javalin.NotFoundResponse import io.javalin.http.NotFoundResponse
import io.javalin.json.JavalinJson.toJson import io.javalin.plugin.json.JavalinJson.toJson
import io.mockk.Runs import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just

View File

@@ -1,8 +1,11 @@
package org.briarproject.briar.headless.event package org.briarproject.briar.headless.event
import io.javalin.json.JavalinJson.toJson import io.javalin.plugin.json.JavalinJson.toJson
import io.javalin.websocket.WsSession import io.javalin.websocket.WsContext
import io.mockk.* import io.mockk.CapturingSlot
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.briarproject.bramble.api.identity.AuthorInfo import org.briarproject.bramble.api.identity.AuthorInfo
import org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED import org.briarproject.bramble.api.identity.AuthorInfo.Status.VERIFIED
import org.briarproject.bramble.test.ImmediateExecutor import org.briarproject.bramble.test.ImmediateExecutor
@@ -16,14 +19,15 @@ import org.briarproject.briar.headless.ControllerTest
import org.briarproject.briar.headless.messaging.EVENT_CONVERSATION_MESSAGE import org.briarproject.briar.headless.messaging.EVENT_CONVERSATION_MESSAGE
import org.briarproject.briar.headless.messaging.output import org.briarproject.briar.headless.messaging.output
import org.eclipse.jetty.websocket.api.WebSocketException import org.eclipse.jetty.websocket.api.WebSocketException
import org.eclipse.jetty.websocket.common.io.FutureWriteCallback
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import java.io.IOException import java.io.IOException
internal class WebSocketControllerTest : ControllerTest() { internal class WebSocketControllerTest : ControllerTest() {
private val session1 = mockk<WsSession>() private val session1 = mockk<WsContext>()
private val session2 = mockk<WsSession>() private val session2 = mockk<WsContext>()
private val controller = WebSocketControllerImpl(ImmediateExecutor()) private val controller = WebSocketControllerImpl(ImmediateExecutor())
@@ -46,7 +50,7 @@ internal class WebSocketControllerTest : ControllerTest() {
fun testSendEvent() { fun testSendEvent() {
val slot = CapturingSlot<String>() val slot = CapturingSlot<String>()
every { session1.send(capture(slot)) } just Runs every { session1.send(capture(slot)) } returns FutureWriteCallback()
controller.sessions.add(session1) controller.sessions.add(session1)
controller.sendEvent(EVENT_CONVERSATION_MESSAGE, event.output(text)) controller.sendEvent(EVENT_CONVERSATION_MESSAGE, event.output(text))
@@ -68,7 +72,7 @@ internal class WebSocketControllerTest : ControllerTest() {
val slot = CapturingSlot<String>() val slot = CapturingSlot<String>()
every { session1.send(capture(slot)) } throws throwable every { session1.send(capture(slot)) } throws throwable
every { session2.send(capture(slot)) } just Runs every { session2.send(capture(slot)) } returns FutureWriteCallback()
controller.sessions.add(session1) controller.sessions.add(session1)
controller.sessions.add(session2) controller.sessions.add(session2)
@@ -99,7 +103,7 @@ internal class WebSocketControllerTest : ControllerTest() {
OutputEvent(EVENT_CONVERSATION_MESSAGE, introductionRequestEvent.output()) OutputEvent(EVENT_CONVERSATION_MESSAGE, introductionRequestEvent.output())
val slot = CapturingSlot<String>() val slot = CapturingSlot<String>()
every { session1.send(capture(slot)) } just Runs every { session1.send(capture(slot)) } returns FutureWriteCallback()
controller.sessions.add(session1) controller.sessions.add(session1)
controller.sendEvent(EVENT_CONVERSATION_MESSAGE, introductionRequestEvent.output()) controller.sendEvent(EVENT_CONVERSATION_MESSAGE, introductionRequestEvent.output())

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.headless.forums package org.briarproject.briar.headless.forums
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import org.briarproject.bramble.test.TestUtils.getRandomBytes import org.briarproject.bramble.test.TestUtils.getRandomBytes

View File

@@ -1,9 +1,9 @@
package org.briarproject.briar.headless.messaging package org.briarproject.briar.headless.messaging
import io.javalin.BadRequestResponse import io.javalin.http.BadRequestResponse
import io.javalin.Context import io.javalin.http.Context
import io.javalin.NotFoundResponse import io.javalin.http.NotFoundResponse
import io.javalin.json.JavalinJson.toJson import io.javalin.plugin.json.JavalinJson.toJson
import io.mockk.* import io.mockk.*
import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.contact.ContactId
import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.bramble.api.db.NoSuchContactException

View File

@@ -1,10 +1,11 @@
dependencyVerification { dependencyVerification {
verify = [ verify = [
'com.fasterxml.jackson.core:jackson-annotations:2.9.0:jackson-annotations-2.9.0.jar:45d32ac61ef8a744b464c54c2b3414be571016dd46bfc2bec226761cf7ae457a', 'com.fasterxml.jackson.core:jackson-annotations:2.10.0:jackson-annotations-2.10.0.jar:3fa91d84956594824552f2316b79b287532c1dd362bfafff9f5056632c81ba17',
'com.fasterxml.jackson.core:jackson-core:2.9.8:jackson-core-2.9.8.jar:d934dab0bd48994eeea2c1b493cb547158a338a80b58c4fbc8e85fb0905e105f', 'com.fasterxml.jackson.core:jackson-core:2.10.0:jackson-core-2.10.0.jar:69e7695b1e40834fa1242fc328a4010607911ced3706ab79abc769d451197513',
'com.fasterxml.jackson.core:jackson-databind:2.9.8:jackson-databind-2.9.8.jar:2351c3eba73a545db9079f5d6d768347ad72666537362c8220fe3e950a55a864', 'com.fasterxml.jackson.core:jackson-databind:2.10.0:jackson-databind-2.10.0.jar:8e6c566c67fc61a96c5dfc4a71d430f2565765778ec9a6ef216c5460a9911b60',
'com.github.ajalt:clikt:2.0.0:clikt-2.0.0.jar:c247adb96337e0799bf6d84f4c494df9d8f1e46e9157eacaf438d03323ee9475', 'com.github.ajalt:clikt:2.2.0:clikt-2.2.0.jar:beb3136d06764ec8ce0810a8fd6c8b7b49d04287d1deef3a07c016e43a458d33',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', 'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81',
'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f', 'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f',
'com.google.dagger:dagger-producers:2.24:dagger-producers-2.24.jar:f10f45b95191954d5d6b043fca9e62fb621d21bf70634b8f8476c7988b504c3a', 'com.google.dagger:dagger-producers:2.24:dagger-producers-2.24.jar:f10f45b95191954d5d6b043fca9e62fb621d21bf70634b8f8476c7988b504c3a',
'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718', 'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718',
@@ -18,7 +19,10 @@ dependencyVerification {
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6', 'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90', 'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.vaadin.external.google:android-json:0.0.20131108.vaadin1:android-json-0.0.20131108.vaadin1.jar:dfb7bae2f404cfe0b72b4d23944698cb716b7665171812a0a4d0f5926c0fac79', 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1:android-json-0.0.20131108.vaadin1.jar:dfb7bae2f404cfe0b72b4d23944698cb716b7665171812a0a4d0f5926c0fac79',
'io.javalin:javalin:2.8.0:javalin-2.8.0.jar:1f2f8e60ba06b2d65058a4ca430fe74ba74c27c93b35c96a9c883bd960d6fb3f', 'commons-codec:commons-codec:1.9:commons-codec-1.9.jar:ad19d2601c3abf0b946b5c3a4113e226a8c1e3305e395b90013b78dd94a723ce',
'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'de.undercouch:gradle-download-task:3.4.3:gradle-download-task-3.4.3.jar:453637054b08115122b7c7b2acf87e912e1613a78f37be3e9e6779cd0830d43e',
'io.javalin:javalin:3.5.0:javalin-3.5.0.jar:6618f99ad4c241eefcaf3a02c85adc52ec346c9710e8eb5a3f1a916e3d7acec4',
'io.mockk:mockk-agent-api:1.9.3:mockk-agent-api-1.9.3.jar:90b9b54158ad31aafa414cb7889bd5a9b70b23e990c5a72eb0c17c3322e6d12d', 'io.mockk:mockk-agent-api:1.9.3:mockk-agent-api-1.9.3.jar:90b9b54158ad31aafa414cb7889bd5a9b70b23e990c5a72eb0c17c3322e6d12d',
'io.mockk:mockk-agent-common:1.9.3:mockk-agent-common-1.9.3.jar:a9ddd89f1e1393aa4b7e99d0032b961088bb8d51e48ff188ada3d1fa05696c88', 'io.mockk:mockk-agent-common:1.9.3:mockk-agent-common-1.9.3.jar:a9ddd89f1e1393aa4b7e99d0032b961088bb8d51e48ff188ada3d1fa05696c88',
'io.mockk:mockk-agent-jvm:1.9.3:mockk-agent-jvm-1.9.3.jar:4e0661778c531d2849d9636f7896bbba314307fb45b47a0107f6a7ad31d1d531', 'io.mockk:mockk-agent-jvm:1.9.3:mockk-agent-jvm-1.9.3.jar:4e0661778c531d2849d9636f7896bbba314307fb45b47a0107f6a7ad31d1d531',
@@ -33,52 +37,59 @@ dependencyVerification {
'net.bytebuddy:byte-buddy-agent:1.9.10:byte-buddy-agent-1.9.10.jar:8ed739d29132103250d307d2e8e3c95f07588ef0543ab11d2881d00768a5e182', 'net.bytebuddy:byte-buddy-agent:1.9.10:byte-buddy-agent-1.9.10.jar:8ed739d29132103250d307d2e8e3c95f07588ef0543ab11d2881d00768a5e182',
'net.bytebuddy:byte-buddy:1.9.10:byte-buddy-1.9.10.jar:2936debc4d7b6c534848d361412e2d0f8bd06f7f27a6f4e728a20e97648d2bf3', 'net.bytebuddy:byte-buddy:1.9.10:byte-buddy-1.9.10.jar:2936debc4d7b6c534848d361412e2d0f8bd06f7f27a6f4e728a20e97648d2bf3',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd', 'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'org.apiguardian:apiguardian-api:1.0.0:apiguardian-api-1.0.0.jar:1f58b77470d8d147a0538d515347dd322f49a83b9e884b8970051160464b65b3', 'org.apache.httpcomponents:httpclient:4.5.3:httpclient-4.5.3.jar:db3d1b6c2d6a5e5ad47577ad61854e2f0e0936199b8e05eb541ed52349263135',
'org.apache.httpcomponents:httpcore:4.4.6:httpcore-4.4.6.jar:d7f853dee87680b07293d30855b39b9eb56c1297bd16ff1cd6f19ddb8fa745fb',
'org.apiguardian:apiguardian-api:1.1.0:apiguardian-api-1.1.0.jar:a9aae9ff8ae3e17a2a18f79175e82b16267c246fbbd3ca9dfbbb290b08dcfdd4',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d', 'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a', 'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53', 'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53',
'org.eclipse.jetty.websocket:websocket-api:9.4.15.v20190215:websocket-api-9.4.15.v20190215.jar:dd02de2d37c6ab4f96a2dfe0a54890dbd43731a9a42ce6e1c27cbc173283de85', 'org.eclipse.jetty.websocket:websocket-api:9.4.20.v20190813:websocket-api-9.4.20.v20190813.jar:779a29060cc17bdeeeba147efc884ebff972cfff93dad2d37b11c93f95d4f67b',
'org.eclipse.jetty.websocket:websocket-client:9.4.15.v20190215:websocket-client-9.4.15.v20190215.jar:b1ebbd22278233db8536cf0a7743b31dd12d7ce31b01546895588ed8f6c132df', 'org.eclipse.jetty.websocket:websocket-client:9.4.20.v20190813:websocket-client-9.4.20.v20190813.jar:df5df7ea0b2d40e1011946cfa5fe27c86047f0c4e77ccc0b8c0c7f5518278bf3',
'org.eclipse.jetty.websocket:websocket-common:9.4.15.v20190215:websocket-common-9.4.15.v20190215.jar:ccfafda2d235e5dd1a665f8010d8c022a7d1f959e0f3eb6ee4acb92bd0047450', 'org.eclipse.jetty.websocket:websocket-common:9.4.20.v20190813:websocket-common-9.4.20.v20190813.jar:a66eb0a5299e2f33addb0dca827cc95a0773c41a12ea70c0d52d51beabaecf65',
'org.eclipse.jetty.websocket:websocket-server:9.4.15.v20190215:websocket-server-9.4.15.v20190215.jar:d5a6bb7b228eb96b172f403f2b9418f13a5a91e028e56605d4a7223119b41a98', 'org.eclipse.jetty.websocket:websocket-server:9.4.20.v20190813:websocket-server-9.4.20.v20190813.jar:6454c671ce25e23f2acf332d378bab02398e5998a6358469fbfdf49d2a9e0530',
'org.eclipse.jetty.websocket:websocket-servlet:9.4.15.v20190215:websocket-servlet-9.4.15.v20190215.jar:db5d0dca8593763c74dee2816e593b0c66ead64e6dce634794670f8aa47cf3e1', 'org.eclipse.jetty.websocket:websocket-servlet:9.4.20.v20190813:websocket-servlet-9.4.20.v20190813.jar:c39142e197b7f9a16bab2b4b28340bf4f84d715971245a808a21ee6941aefb66',
'org.eclipse.jetty:jetty-client:9.4.15.v20190215:jetty-client-9.4.15.v20190215.jar:17f5912b2b90c3a1398cce1c76f2e99910c2c3444932dd9a2b941a8fecf484ef', 'org.eclipse.jetty:jetty-client:9.4.20.v20190813:jetty-client-9.4.20.v20190813.jar:31a88bfc59acb1716646d8211209f42e8b4c175be3b1dd5c3794dec8882dae50',
'org.eclipse.jetty:jetty-http:9.4.15.v20190215:jetty-http-9.4.15.v20190215.jar:c95711e9759a2bfa43ad5e7eadbbbf86152acba065e38121181bc41596647f9a', 'org.eclipse.jetty:jetty-http:9.4.20.v20190813:jetty-http-9.4.20.v20190813.jar:242523f49e54f2b14f25ba129fefe182497404a81f2d579865442ee885df5996',
'org.eclipse.jetty:jetty-io:9.4.15.v20190215:jetty-io-9.4.15.v20190215.jar:6f40f4162739ebf1c89a96165f31598bae4101b264098017af563853af8a662a', 'org.eclipse.jetty:jetty-io:9.4.20.v20190813:jetty-io-9.4.20.v20190813.jar:6dfcfd560135c3059547ef33c4a89317db2f94b9eb934ec1514d6967ea0a294b',
'org.eclipse.jetty:jetty-security:9.4.15.v20190215:jetty-security-9.4.15.v20190215.jar:2ae35c6be04d3f47d82fc75e337f6c4cf43ae6e04046cc8b9d6b4b2bb679f507', 'org.eclipse.jetty:jetty-security:9.4.20.v20190813:jetty-security-9.4.20.v20190813.jar:7f00b107465206902733e85cfed3d0174784f929ddcc72b8027ce8f225bc0c95',
'org.eclipse.jetty:jetty-server:9.4.15.v20190215:jetty-server-9.4.15.v20190215.jar:7dda78de3ba23e0c9f7599fb295d5d861fe0ada615b856ce345cf2b8f4e5975f', 'org.eclipse.jetty:jetty-server:9.4.20.v20190813:jetty-server-9.4.20.v20190813.jar:8600151e85a2380df716df641c90d3b9a0de4b00d0ef1c3426be892771ea584d',
'org.eclipse.jetty:jetty-servlet:9.4.15.v20190215:jetty-servlet-9.4.15.v20190215.jar:f817eaeb1d65cc27decf3db3b18f9a8e7d67f4b4587e323bf0f6be9ed0515e96', 'org.eclipse.jetty:jetty-servlet:9.4.20.v20190813:jetty-servlet-9.4.20.v20190813.jar:0c00257ea8ad3423b23894b2a99f54bedfc5e9c55baf491c86134a977c98f6ff',
'org.eclipse.jetty:jetty-util:9.4.15.v20190215:jetty-util-9.4.15.v20190215.jar:f3deed4141b4595971f504f6b516e7302f307032bc45403a720213e46ca87464', 'org.eclipse.jetty:jetty-util:9.4.20.v20190813:jetty-util-9.4.20.v20190813.jar:5816ef44f73e76b8ef1c1ea848cc34c7b1f24771f3675353e2ef23eb920121d8',
'org.eclipse.jetty:jetty-webapp:9.4.15.v20190215:jetty-webapp-9.4.15.v20190215.jar:81b56aa7c29513654827adc48e786f121b54183791c132255195b9a45d83a0f3', 'org.eclipse.jetty:jetty-webapp:9.4.20.v20190813:jetty-webapp-9.4.20.v20190813.jar:59d9b5f238acb14eac3bf90f755eeabd9fc16c630217d0e7e01b99a38194036c',
'org.eclipse.jetty:jetty-xml:9.4.15.v20190215:jetty-xml-9.4.15.v20190215.jar:c6d97a70572d5400e9ff3b7e32d4a4fd1c61319cbf997655a608064a75466082', 'org.eclipse.jetty:jetty-xml:9.4.20.v20190813:jetty-xml-9.4.20.v20190813.jar:f4411ad9998e4cc202c849bb9b9e93aa2aa761b89a27cc746ca025849d659fd0',
'org.jetbrains.intellij.deps:trove4j:1.0.20181211:trove4j-1.0.20181211.jar:affb7c85a3c87bdcf69ff1dbb84de11f63dc931293934bc08cd7ab18de083601', 'org.jetbrains.intellij.deps:trove4j:1.0.20181211:trove4j-1.0.20181211.jar:affb7c85a3c87bdcf69ff1dbb84de11f63dc931293934bc08cd7ab18de083601',
'org.jetbrains.kotlin:kotlin-android-extensions:1.3.31:kotlin-android-extensions-1.3.31.jar:2f849616dcf5a5aa372e6c11ccd196607f0c3d42dd0a9be6d49ee3732ca050ba', 'org.jetbrains.kotlin:kotlin-android-extensions:1.3.40:kotlin-android-extensions-1.3.40.jar:5d5f55451d632ca834e8a2929b9d0e1c2a642f6d78a3b24963138a766139a456',
'org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.3.31:kotlin-annotation-processing-gradle-1.3.31.jar:29a5fb59416226e2326f9fcb3ad0974915a424eec9125449981e1b9bbd9b79d6', 'org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.3.40:kotlin-annotation-processing-gradle-1.3.40.jar:c8bd591244ece76cbc88ca9f59661c13f04b5d48a13ee115629b3777fdca4ddc',
'org.jetbrains.kotlin:kotlin-build-common:1.3.31:kotlin-build-common-1.3.31.jar:a37bace5fce25dade884ea75972fcf2a67d6f1326bf300eca27d052423773267', 'org.jetbrains.kotlin:kotlin-build-common:1.3.40:kotlin-build-common-1.3.40.jar:a140f3d6dd1fca3c8b4fb7dab621e36ab15946f0ae9f16efe46f77cfefb8fb06',
'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.31:kotlin-compiler-embeddable-1.3.31.jar:b7918cbce747683905486ae54e664fe5d5db60e8ed1cbfebc00c79912b9aaffd', 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.40:kotlin-compiler-embeddable-1.3.40.jar:9412b5c572068d0435a09278d3faa2cf21574542916ac67490c11205c44b9802',
'org.jetbrains.kotlin:kotlin-compiler-runner:1.3.31:kotlin-compiler-runner-1.3.31.jar:f8ab33e2ec54a1c62a189c0cab04fbadb58dfd1bdda6a8ade0849a7a9a598b7c', 'org.jetbrains.kotlin:kotlin-compiler-runner:1.3.40:kotlin-compiler-runner-1.3.40.jar:769a193f0c0d944664569aaef4bd6f7f1c793a77c69b54f2044986ed58f7cde7',
'org.jetbrains.kotlin:kotlin-daemon-client:1.3.31:kotlin-daemon-client-1.3.31.jar:f658006ac301cae33e2a6cb1afd3cc41e82d98b12876de8fbe70a202434162de', 'org.jetbrains.kotlin:kotlin-daemon-client:1.3.40:kotlin-daemon-client-1.3.40.jar:ea82475e00ef4c60126d3ef21eb2a87cf6fd94468e277a847abd19802b79089b',
'org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.3.31:kotlin-gradle-plugin-api-1.3.31.jar:e40152d09ec45eb9fd4c0a8340de46793ae3beeb0f70f8ab15dc0097767fc61c', 'org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.3.40:kotlin-gradle-plugin-api-1.3.40.jar:ba316e66aa532b98b1a3ecff43d081930d68aceb614ec55ac81164d4ed5b8c09',
'org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.3.31:kotlin-gradle-plugin-model-1.3.31.jar:9bbe7b3afebb43e81ef4e6a3202eb86d51dee34ddb305090d5cf0f2861ce87be', 'org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.3.40:kotlin-gradle-plugin-model-1.3.40.jar:103112f1049945b74e10f35458c0dc30defb2f7caa46e572942f57fa2ace1778',
'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31:kotlin-gradle-plugin-1.3.31.jar:307ced92080a1d7a887fd7f71eef7b297b514a205ecf947220bd7ce8391a5594', 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.40:kotlin-gradle-plugin-1.3.40.jar:0dfa1fd9dd807ecebcf262293e750071697e15867aaf3f6d7efd1e9f560fe718',
'org.jetbrains.kotlin:kotlin-native-utils:1.3.31:kotlin-native-utils-1.3.31.jar:00af02020516eed7942ace3811cacd9fa3b1de2b66c6498e17dbe3a3e9bacce1',
'org.jetbrains.kotlin:kotlin-reflect:1.3.0:kotlin-reflect-1.3.0.jar:f3231ac1c612fe72de6ffcc4f0b4c5d85ad1ad4c808fb01a1981eab1ee1202c3', 'org.jetbrains.kotlin:kotlin-reflect:1.3.0:kotlin-reflect-1.3.0.jar:f3231ac1c612fe72de6ffcc4f0b4c5d85ad1ad4c808fb01a1981eab1ee1202c3',
'org.jetbrains.kotlin:kotlin-reflect:1.3.31:kotlin-reflect-1.3.31.jar:a0172daf57e511e8e0df9251b508db8aa6b885cdf0c5849addc9b840db4814f0', 'org.jetbrains.kotlin:kotlin-reflect:1.3.40:kotlin-reflect-1.3.40.jar:b8df6abfd928a723b146d48174ba10c63f65a978a5b816c0d8ef702e20450fa3',
'org.jetbrains.kotlin:kotlin-script-runtime:1.3.31:kotlin-script-runtime-1.3.31.jar:633692186b292292e41ea60d5170e811845b78aba88e20260ba70f7ce3a3ef32', 'org.jetbrains.kotlin:kotlin-script-runtime:1.3.40:kotlin-script-runtime-1.3.40.jar:32290da5f29bd3b167647ffb2ba7bff77e4647903ace1e4522ba4ed293874524',
'org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.3.31:kotlin-scripting-compiler-embeddable-1.3.31.jar:4dff2f683f8ceee0e834aeb0ca2686774da6c010ad1faf671dcaf73f071de954', 'org.jetbrains.kotlin:kotlin-scripting-common:1.3.40:kotlin-scripting-common-1.3.40.jar:0f2ff17b2d30897345c30b3290a3c59d3caaef3965056a0910171f23275e654e',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.31:kotlin-stdlib-common-1.3.31.jar:d6e9c54c1e6c4df21be9395de558665544c6bdc8f8076ea7518f089f82cd34fc', 'org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.3.40:kotlin-scripting-compiler-embeddable-1.3.40.jar:8c512eb035c8261bb23cd6e767243ccac6f960ac682b6a22e4001e30901b46a1',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31:kotlin-stdlib-jdk7-1.3.31.jar:dbf77e6a5626d941450fdc59cbfe24165858403c12789749a2497265269859a3', 'org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.3.40:kotlin-scripting-compiler-impl-embeddable-1.3.40.jar:183e3ec7673b9486e501efc62a38fba8588f4e1b06d0cd7c707d0ec67d7b5cc9',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.31:kotlin-stdlib-jdk8-1.3.31.jar:ad6acd219b468a532ac3b3c5aacbfd5db02d0ffcf967e2113e4677e2429490f6', 'org.jetbrains.kotlin:kotlin-scripting-jvm:1.3.40:kotlin-scripting-jvm-1.3.40.jar:21f17b8b815a49b62bb2d4f72feb0696067c9000268ebc6d61f9fcca7c7964e7',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.31:kotlin-stdlib-1.3.31.jar:f38c84326543e66ed4895b20fb3ea0fca527fd5a040e1f49d0946ecf3d2b3b23', 'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.40:kotlin-stdlib-common-1.3.40.jar:5f551a3ffe7683f4741d96fdc49835864aa08ddfc63d38109884973e19eed1cb',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50:kotlin-stdlib-common-1.3.50.jar:8ce678e88e4ba018b66dacecf952471e4d7dfee156a8a819760a5a5ff29d323c',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.40:kotlin-stdlib-jdk7-1.3.40.jar:f79d84613679095d17518dd8fb4249183f334cf80e4d7a25a7e0ed519ee993ab',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.40:kotlin-stdlib-jdk8-1.3.40.jar:05e11f693719aa515e6946f51eacc88cb53437cc685d914c114f090792ba9ba1',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.40:kotlin-stdlib-1.3.40.jar:f76f9812a703ba5085af8f51769e60e8ecd5e99b55b2ced097cf2343e972ad7b',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.50:kotlin-stdlib-1.3.50.jar:e6f05746ee0366d0b52825a090fac474dcf44082c9083bbb205bd16976488d6c',
'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1:kotlinx-coroutines-core-1.1.1.jar:ac423f8a0aa4b4e74529696ff82c0171f81a8c8ab182a1965dff25e69c1f7844',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.json:json:20150729:json-20150729.jar:38c21b9c3d6d24919cd15d027d20afab0a019ac9205f7ed9083b32bdd42a2353', 'org.json:json:20150729:json-20150729.jar:38c21b9c3d6d24919cd15d027d20afab0a019ac9205f7ed9083b32bdd42a2353',
'org.junit.jupiter:junit-jupiter-api:5.4.2:junit-jupiter-api-5.4.2.jar:cdfb355fee661633f15f2763b8c2029c2e1958585b97b9162d38a36b1754dc3e', 'org.junit.jupiter:junit-jupiter-api:5.5.2:junit-jupiter-api-5.5.2.jar:249a2fdbd3931987c0298d00ca08ed248496e0fc11e0463c08c4f82e0cc79b1c',
'org.junit.jupiter:junit-jupiter-engine:5.4.2:junit-jupiter-engine-5.4.2.jar:42aead7c5c1b74e0ef775c374a9fc07c771fd61a3621e66df1793dba14e534fd', 'org.junit.jupiter:junit-jupiter-engine:5.5.2:junit-jupiter-engine-5.5.2.jar:6d777da9876e2ef7a0336e8f098f8d74a5a64f810aa3a4a2f5f3b766ce97837b',
'org.junit.jupiter:junit-jupiter-params:5.4.2:junit-jupiter-params-5.4.2.jar:13f89bca59fb6931a0ca9e3f4dc74e1a3054e0c63863e091a5df4855605ae4ce', 'org.junit.jupiter:junit-jupiter-params:5.5.2:junit-jupiter-params-5.5.2.jar:fd49c7fd9d0f7f1e5b5f6982254cee79177fa2e76a37fdee0466e64f975567b5',
'org.junit.platform:junit-platform-commons:1.4.2:junit-platform-commons-1.4.2.jar:104bfa65b30ceb425a6de19d66b976caf38443ff5978ae931c103fa0f99d04ce', 'org.junit.platform:junit-platform-commons:1.5.2:junit-platform-commons-1.5.2.jar:fc44afdfc0f20c85e71a66e7943281aef3bc1e0fd62d2d69a36cb6901e682c10',
'org.junit.platform:junit-platform-engine:1.4.2:junit-platform-engine-1.4.2.jar:7edb2ad879a338a84dbb09202b1399640ec0cacc5a95168539a9a74b5a2302e1', 'org.junit.platform:junit-platform-engine:1.5.2:junit-platform-engine-1.5.2.jar:ff20ba4ad8c00ef17baef9c55512f9c02d9a68740f7f1ac01a9a6aa0239931f8',
'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984', 'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984',
'org.opentest4j:opentest4j:1.1.1:opentest4j-1.1.1.jar:f106351abd941110226745ed103c85863b3f04e9fa82ddea1084639ae0c5336c', 'org.opentest4j:opentest4j:1.2.0:opentest4j-1.2.0.jar:58812de60898d976fb81ef3b62da05c6604c18fd4a249f5044282479fc286af2',
'org.skyscreamer:jsonassert:1.5.0:jsonassert-1.5.0.jar:a310bc79c3f4744e2b2e993702fcebaf3696fec0063643ffdc6b49a8fb03ef39', 'org.skyscreamer:jsonassert:1.5.0:jsonassert-1.5.0.jar:a310bc79c3f4744e2b2e993702fcebaf3696fec0063643ffdc6b49a8fb03ef39',
'org.slf4j:slf4j-api:1.7.26:slf4j-api-1.7.26.jar:6d9e5b86cfd1dd44c676899285b5bb4fa0d371cf583e8164f9c8a0366553242b', 'org.slf4j:slf4j-api:1.7.26:slf4j-api-1.7.26.jar:6d9e5b86cfd1dd44c676899285b5bb4fa0d371cf583e8164f9c8a0366553242b',
'org.slf4j:slf4j-simple:1.7.26:slf4j-simple-1.7.26.jar:4b8ed75e2273850bf4eeb411ae5de5e0c0a44da59a96ca68d284749a6a373678', 'org.slf4j:slf4j-simple:1.7.26:slf4j-simple-1.7.26.jar:4b8ed75e2273850bf4eeb411ae5de5e0c0a44da59a96ca68d284749a6a373678',