Fully functional!

This commit is contained in:
Alexander Nozik 2022-04-30 10:32:00 +03:00
parent 5f4c5b0829
commit b90ec0fef8
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
61 changed files with 389 additions and 167 deletions

View File

@ -1,15 +1,18 @@
val ktor_version: String by project import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val kotlin_version: String by project import ru.mipt.npm.gradle.KScienceVersions
val logback_version: String by project
plugins { plugins {
id("ru.mipt.npm.gradle.project") id("ru.mipt.npm.gradle.project")
application
id("ru.mipt.npm.gradle.jvm") id("ru.mipt.npm.gradle.jvm")
application
}
repositories{
mavenLocal()
} }
group = "ru.mipt.npm" group = "ru.mipt.npm"
version = "0.0.1" version = "0.0.1-SNAPSHOT"
application { application {
mainClass.set("ru.mipt.ApplicationKt") mainClass.set("ru.mipt.ApplicationKt")
@ -18,20 +21,29 @@ application {
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment") applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
} }
tasks.withType<KotlinCompile>{
kotlinOptions{
freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers"
}
}
val dataforgeVersion by extra("0.6.0-dev-3")
val ktorVersion = KScienceVersions.ktorVersion
dependencies { dependencies {
implementation("io.ktor:ktor-server-core-jvm:$ktor_version") implementation("io.ktor:ktor-server-core:$ktorVersion")
implementation("org.jetbrains.kotlinx:kotlinx-html:0.7.3") implementation("org.jetbrains.kotlinx:kotlinx-html:0.7.5")
implementation("io.ktor:ktor-server-html-builder-jvm:$ktor_version") implementation("io.ktor:ktor-server-html-builder:$ktorVersion")
implementation("org.jetbrains:kotlin-css-jvm") implementation("org.jetbrains.kotlin-wrappers:kotlin-css")
implementation("io.ktor:ktor-server-host-common-jvm:$ktor_version") implementation("io.ktor:ktor-server-host-common:$ktorVersion")
implementation("io.ktor:ktor-server-status-pages-jvm:$ktor_version") implementation("io.ktor:ktor-server-status-pages:$ktorVersion")
implementation("io.ktor:ktor-server-netty-jvm:$ktor_version") implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("ch.qos.logback:logback-classic:$logback_version") implementation("ch.qos.logback:logback-classic:1.2.11")
implementation("space.kscience:dataforge-data:0.5.2") implementation("space.kscience:dataforge-workspace:$dataforgeVersion")
implementation("space.kscience:dataforge-io-yaml:$dataforgeVersion")
implementation("org.jetbrains:markdown:0.3.1") implementation("org.jetbrains:markdown:0.3.1")
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version") testImplementation("io.ktor:ktor-server-tests:$ktorVersion")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
} }
kotlin { kotlin {

View File

@ -1,6 +1,3 @@
ktor_version=2.0.0
kotlin_version=1.6.20
logback_version=1.2.11
kotlin.code.style=official kotlin.code.style=official
toolsVersion=0.11.4-kotlin-1.6.20 toolsVersion=0.11.4-kotlin-1.6.20

View File

@ -1,13 +1,73 @@
package ru.mipt package ru.mipt
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.engine.embeddedServer import io.ktor.server.engine.embeddedServer
import io.ktor.server.html.respondHtml
import io.ktor.server.http.content.resources
import io.ktor.server.http.content.static
import io.ktor.server.netty.Netty import io.ktor.server.netty.Netty
import ru.mipt.plugins.configureRouting import io.ktor.server.plugins.statuspages.StatusPages
import io.ktor.server.response.respond
import io.ktor.server.routing.get
import io.ktor.server.routing.route
import io.ktor.server.routing.routing
import ru.mipt.plugins.configureTemplating import ru.mipt.plugins.configureTemplating
import ru.mipt.spc.magprog.DataSetSiteContext
import ru.mipt.spc.magprog.DirectoryDataTree
import ru.mipt.spc.magprog.SiteContext
import ru.mipt.spc.magprog.magProgPage
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.io.io
import space.kscience.dataforge.io.yaml.YamlPlugin
import java.nio.file.Path
class AuthenticationException : RuntimeException()
class AuthorizationException : RuntimeException()
internal fun Application.magProgSite(prefix: String = "magprog"){
val context = Context("spc-site"){
plugin(YamlPlugin)
}
val io = context.io
val directory = javaClass.getResource("/magprog/content")!!.toURI()
val content = DirectoryDataTree(io, Path.of(directory))
val magprogSiteContext: SiteContext = DataSetSiteContext(context,"magprog", content)
routing {
route(prefix){
get {
call.respondHtml {
with(magprogSiteContext){
magProgPage()
}
}
}
static {
resources("magprog/assets")
}
}
}
}
fun main() { fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") { embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
configureRouting() magProgSite()
install(StatusPages) {
exception<AuthenticationException> { call, cause ->
call.respond(HttpStatusCode.Unauthorized)
}
exception<AuthorizationException> { call, cause ->
call.respond(HttpStatusCode.Forbidden)
}
}
configureTemplating() configureTemplating()
}.start(wait = true) }.start(wait = true)
} }

View File

@ -1,36 +0,0 @@
package ru.mipt.plugins
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.http.content.resources
import io.ktor.server.http.content.static
import io.ktor.server.plugins.statuspages.StatusPages
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
fun Application.configureRouting() {
routing {
get("/") {
call.respondText("Hello World!")
}
// Static plugin. Try to access `/static/index.html`
static("/magprog") {
resources("magprog")
}
}
install(StatusPages) {
exception<AuthenticationException> { call, cause ->
call.respond(HttpStatusCode.Unauthorized)
}
exception<AuthorizationException> { call, cause ->
call.respond(HttpStatusCode.Forbidden)
}
}
}
class AuthenticationException : RuntimeException()
class AuthorizationException : RuntimeException()

View File

@ -54,7 +54,7 @@ fun Application.configureTemplating() {
} }
} }
suspend inline fun ApplicationCall.respondCss(builder: CSSBuilder.() -> Unit) { suspend inline fun ApplicationCall.respondCss(builder: CssBuilder.() -> Unit) {
this.respondText(CSSBuilder().apply(builder).toString(), ContentType.Text.CSS) this.respondText(CssBuilder().apply(builder).toString(), ContentType.Text.CSS)
} }

View File

@ -0,0 +1,101 @@
package ru.mipt.spc.magprog
import kotlinx.coroutines.runBlocking
import kotlinx.html.div
import kotlinx.html.unsafe
import kotlinx.serialization.json.Json
import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
import org.intellij.markdown.html.HtmlGenerator
import org.intellij.markdown.parser.MarkdownParser
import ru.mipt.spc.magprog.DirectoryDataTree.Companion.META_FILE_EXTENSION_KEY
import space.kscience.dataforge.context.Context
import space.kscience.dataforge.data.*
import space.kscience.dataforge.io.asBinary
import space.kscience.dataforge.io.readObject
import space.kscience.dataforge.io.yaml.YamlMetaFormat
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.meta.toMeta
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name
import kotlin.reflect.KType
import kotlin.reflect.typeOf
class DataSetSiteContext(
override val context: Context,
val prefix: String,
val dataSet: DataSet<Any>,
) : SiteContext {
override fun resolveResource(name: String): String = "$prefix/$name"
private val markdownFlavor = CommonMarkFlavourDescriptor()
private val markdownParser = MarkdownParser(markdownFlavor)
//TODO replace by a plugin
private suspend fun Data<ByteArray>.toHtmlBlock(): HtmlBlock {
val fileType = meta[META_FILE_EXTENSION_KEY].string
val src = await().decodeToString()
return when (fileType) {
"html" -> HtmlBlock(meta) {
div {
unsafe {
+src
}
}
}
"markdown", "mdown", "mkdn", "mkd", "md" -> HtmlBlock(meta) {
div("markdown") {
val parsedTree = markdownParser.buildMarkdownTreeFromString(src)
unsafe {
+HtmlGenerator(src, parsedTree, markdownFlavor).generateHtml()
}
}
}
else -> error("Can't convert a data with file extension $fileType to html")
}
}
private val Data<*>.published: Boolean get() = meta["published"].string != "false"
@DFInternal
override fun <T : Any> resolve(type: KType, name: Name): Data<T>? = when (type) {
typeOf<Meta>() -> {
val data = dataSet.selectOne<ByteArray>(name)
if( data == null) null else {
when (data.meta[META_FILE_EXTENSION_KEY].string) {
"json" -> data.map {
Json.parseToJsonElement(it.decodeToString()).toMeta()
}
"yaml" -> data.map {
YamlMetaFormat.readObject(it.asBinary())
}
else -> error("File with extension ${data.meta[META_FILE_EXTENSION_KEY]} could not be parsed as Meta")
} as Data<T>?
}
}
else -> dataSet.selectOne(type, name)
}
@DFInternal
override fun <T : Any> resolveAll(type: KType, filter: (name: Name, meta: Meta) -> Boolean): DataSet<T> =
dataSet.select(type, filter = filter)
override fun resolveHtml(name: Name): HtmlBlock? = runBlocking {
resolve<ByteArray>(name)?.takeIf { it.published }?.toHtmlBlock()
}
override fun resolveAllHtml(filter: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlBlock> = runBlocking {
buildMap {
resolveAll<ByteArray>(filter).dataSequence().filter { it.published }.forEach {
put(it.name, it.toHtmlBlock())
}
}
}
}

View File

@ -0,0 +1,78 @@
package ru.mipt.spc.magprog
import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.DataTreeItem
import space.kscience.dataforge.data.StaticData
import space.kscience.dataforge.io.IOPlugin
import space.kscience.dataforge.io.readEnvelopeFile
import space.kscience.dataforge.io.readMetaFile
import space.kscience.dataforge.io.toByteArray
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.copy
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
import java.nio.file.Path
import kotlin.io.path.extension
import kotlin.io.path.isDirectory
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.nameWithoutExtension
import kotlin.reflect.KType
import kotlin.reflect.typeOf
//internal object ByteArrayIOFormat : IOFormat<ByteArray> {
//
// override val type: KType = typeOf<ByteArray>()
//
// override fun writeObject(output: Output, obj: ByteArray) {
// output.writeFully(obj)
// }
//
// override fun readObject(input: Input): ByteArray = input.readBytes()
//
// override fun toMeta(): Meta = Meta {
// IOFormat.NAME_KEY put "ByteArray"
// }
//
//}
class DirectoryDataTree(val io: IOPlugin, val path: Path) : DataTree<ByteArray> {
override val dataType: KType
get() = typeOf<ByteArray>()
override val meta: Meta get() = io.readMetaFile(path)
private fun readFile(filePath: Path): Data<ByteArray> {
val envelope = io.readEnvelopeFile(filePath, readNonEnvelopes = true)
val meta = envelope.meta.copy {
META_FILE_PATH_KEY put filePath.toString()
META_FILE_EXTENSION_KEY put filePath.extension
//TODO add other file information
}
return StaticData(typeOf<ByteArray>(), envelope.data?.toByteArray() ?: ByteArray(0), meta)
}
override val items: Map<NameToken, DataTreeItem<ByteArray>>
get() = path.listDirectoryEntries().associate { childPath ->
val fileName = childPath.fileName.nameWithoutExtension
val item: DataTreeItem<ByteArray> = if (childPath.isDirectory()) {
DataTreeItem.Node(DirectoryDataTree(io, childPath))
} else {
DataTreeItem.Leaf(readFile(childPath))
}
NameToken(fileName) to item
}
companion object {
val META_FILE_KEY = "file".asName()
val META_FILE_PATH_KEY = META_FILE_KEY + "path"
val META_FILE_EXTENSION_KEY = META_FILE_KEY + "extension"
}
}
//TODO add transforming provider instead of ByteArray DataSet

View File

@ -13,6 +13,11 @@ interface HtmlBlock {
val content: FlowContent.() -> Unit val content: FlowContent.() -> Unit
} }
fun HtmlBlock(meta: Meta, content: FlowContent.() -> Unit ) = object: HtmlBlock{
override val meta: Meta = meta
override val content: FlowContent.() -> Unit = content
}
val HtmlBlock.id: String get() = meta["id"]?.string ?: "block[${hashCode()}]" val HtmlBlock.id: String get() = meta["id"]?.string ?: "block[${hashCode()}]"
val HtmlBlock.language: Language get() = meta["language"]?.enum<Language>() ?: Language.RU val HtmlBlock.language: Language get() = meta["language"]?.enum<Language>() ?: Language.RU

View File

@ -36,7 +36,9 @@ private fun FlowContent.personCards(list: List<Person>, prefix: String) {
context(SiteContext) context(SiteContext)
fun FlowContent.mentors() { fun FlowContent.mentors() {
val mentors = findByType("magprog_mentor").values.map { Person(it) }.sortedBy { it.order } val mentors = findByType("magprog_mentor").values.map {
Person(it)
}.sortedBy { it.order }
div("header") { div("header") {
css { css {

View File

@ -1,26 +1,28 @@
package ru.mipt.spc.magprog package ru.mipt.spc.magprog
import io.ktor.util.InternalAPI import space.kscience.dataforge.context.ContextAware
import space.kscience.dataforge.data.Data import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.DataSet import space.kscience.dataforge.data.DataSet
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
interface SiteContext { interface SiteContext: ContextAware {
/** /**
* Resolve a resource full path by its name * Resolve a resource full path by its name
*/ */
fun resolveResource(name: String): String fun resolveResource(name: String): String
@InternalAPI @DFInternal
fun <T: Any> resolve(type: KType, name: Name): Data<T>? fun <T: Any> resolve(type: KType, name: Name): Data<T>?
@InternalAPI @DFInternal
fun <T: Any> resolveAll(type: KType, filter: (name: Name, meta: Meta) -> Boolean): DataSet<T> fun <T: Any> resolveAll(type: KType, filter: (name: Name, meta: Meta) -> Boolean): DataSet<T>
/** /**
@ -34,10 +36,10 @@ interface SiteContext {
fun resolveAllHtml(filter: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlBlock> fun resolveAllHtml(filter: (name: Name, meta: Meta) -> Boolean): Map<Name, HtmlBlock>
} }
@OptIn(InternalAPI::class) @OptIn(DFInternal::class)
inline fun <reified T: Any> SiteContext.resolve(name: Name): Data<T>? = resolve(typeOf<T>(), name) inline fun <reified T: Any> SiteContext.resolve(name: Name): Data<T>? = resolve(typeOf<T>(), name)
@OptIn(InternalAPI::class) @OptIn(DFInternal::class)
inline fun <reified T:Any> SiteContext.resolveAll(noinline filter: (name: Name, meta: Meta) -> Boolean): DataSet<T> = inline fun <reified T:Any> SiteContext.resolveAll(noinline filter: (name: Name, meta: Meta) -> Boolean): DataSet<T> =
resolveAll(typeOf<T>(), filter) resolveAll(typeOf<T>(), filter)

View File

@ -1,15 +1,16 @@
package ru.mipt.spc.magprog package ru.mipt.spc.magprog
import kotlinx.coroutines.runBlocking
import kotlinx.css.* import kotlinx.css.*
import kotlinx.html.* import kotlinx.html.*
import space.kscience.dataforge.data.await
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
//fun CSSBuilder.magProgCss() { //fun CssBuilder.magProgCss() {
// rule(".magprog-body") { // rule(".magprog-body") {
// rule(".magprog-header") { // rule(".magprog-header") {
// display = Display.flex // display = Display.flex
@ -45,19 +46,21 @@ private fun wrapSection(
} }
} }
private fun wrapSection(block: HtmlBlock, idOverride: String? = null): MagProgSection = private fun wrapSection(
wrapSection( block: HtmlBlock,
idOverride: String? = null,
): MagProgSection = wrapSection(
idOverride ?: block.id, idOverride ?: block.id,
block.meta["section_title"]?.string ?: error("Section without title"), block.meta["section_title"]?.string ?: error("Section without title"),
block.content block.content
) )
private val CONTENT_NODE_NAME = "content".asName() private val CONTENT_NODE_NAME = Name.EMPTY//"content".asName()
private val INTRO_PATH: Name = TODO() private val INTRO_PATH: Name = CONTENT_NODE_NAME + "intro"
private val ENROLL_PATH: Name = TODO() private val ENROLL_PATH: Name = CONTENT_NODE_NAME + "enroll"
private val CONTACTS_PATH: Name = TODO() private val CONTACTS_PATH: Name = CONTENT_NODE_NAME + "contacts"
private val PROGRAM_PATH: Name = TODO() private val PROGRAM_PATH: Name = CONTENT_NODE_NAME + "program"
private val RECOMMENDED_COURSES_PATH: Name = TODO() private val RECOMMENDED_COURSES_PATH: Name = CONTENT_NODE_NAME + "recommendedCourses"
private val PARTNERS_PATH: Name = CONTENT_NODE_NAME + "partners" private val PARTNERS_PATH: Name = CONTENT_NODE_NAME + "partners"
context(SiteContext) private fun FlowContent.programSection() { context(SiteContext) private fun FlowContent.programSection() {
@ -67,23 +70,24 @@ context(SiteContext) private fun FlowContent.programSection() {
h2 { +"Учебная программа" } h2 { +"Учебная программа" }
with(programBlock) { content() } with(programBlock) { content() }
button(classes = "fit btn btn-primary btn-lg") { button(classes = "fit btn btn-primary btn-lg") {
attributes["data-bs-toggle"]="collapse" attributes["data-bs-toggle"] = "collapse"
attributes["data-bs-target"]="#recommended-courses-collapse-text" attributes["data-bs-target"] = "#recommended-courses-collapse-text"
attributes["aria-expanded"]="false" attributes["aria-expanded"] = "false"
attributes["aria-controls"]="recommended-courses-collapse-text" attributes["aria-controls"] = "recommended-courses-collapse-text"
+"Рекомендованные курсы" +"Рекомендованные курсы"
} }
div("collapse pt-3") { div("collapse pt-3") {
id = "recommended-courses-collapse-text" id = "recommended-courses-collapse-text"
div("card card-body") { div("card card-body") {
with(recommendedBlock){content()} with(recommendedBlock) { content() }
} }
} }
} }
} }
context(SiteContext) private fun FlowContent.partners() { context(SiteContext) private fun FlowContent.partners() {
val partnersData: Meta = resolve<Any>(PARTNERS_PATH)?.meta ?: Meta.EMPTY //val partnersData: Meta = resolve<Any>(PARTNERS_PATH)?.meta ?: Meta.EMPTY
val partnersData: Meta = runBlocking { resolve<Meta>(PARTNERS_PATH)?.await()} ?: Meta.EMPTY
div("inner") { div("inner") {
h2 { +"Партнеры" } h2 { +"Партнеры" }
div("features") { div("features") {
@ -106,8 +110,7 @@ context(SiteContext) private fun FlowContent.partners() {
} }
} }
context(SiteContext) context(SiteContext) fun HTML.magProgPage() {
fun HTML.magProgPage() {
val sections = listOf<MagProgSection>( val sections = listOf<MagProgSection>(
wrapSection(resolveHtml(INTRO_PATH)!!, "intro"), wrapSection(resolveHtml(INTRO_PATH)!!, "intro"),
MagProgSection( MagProgSection(
@ -140,7 +143,7 @@ fun HTML.magProgPage() {
) { ) {
team() team()
}, },
wrapSection(resolveHtml(CONTACTS_PATH)!!, "enroll"), wrapSection(resolveHtml(CONTACTS_PATH)!!, "contacts"),
) )
head { head {
@ -154,12 +157,12 @@ fun HTML.magProgPage() {
} }
link { link {
rel = "stylesheet" rel = "stylesheet"
href = resolveResource("assets/css/main.css") href = resolveResource("css/main.css")
} }
noScript { noScript {
link { link {
rel = "stylesheet" rel = "stylesheet"
href = resolveResource("assets/css/noscript.css") href = resolveResource("css/noscript.css")
} }
} }
} }
@ -171,7 +174,7 @@ fun HTML.magProgPage() {
ul { ul {
sections.forEach { section -> sections.forEach { section ->
li { li {
a(href = section.id) { a(href = "#${section.id}") {
+section.title +section.title
} }
} }
@ -214,25 +217,25 @@ fun HTML.magProgPage() {
} }
} }
script { script {
src = resolveResource("assets/js/jquery.min.js") src = resolveResource("js/jquery.min.js")
} }
script { script {
src = resolveResource("assets/js/jquery.scrollex.min.js") src = resolveResource("js/jquery.scrollex.min.js")
} }
script { script {
src = resolveResource("assets/js/jquery.scrolly.min.js") src = resolveResource("js/jquery.scrolly.min.js")
} }
script { script {
src = resolveResource("assets/js/browser.min.js") src = resolveResource("js/browser.min.js")
} }
script { script {
src = resolveResource("assets/js/breakpoints.min.js") src = resolveResource("js/breakpoints.min.js")
} }
script { script {
src = resolveResource("assets/js/util.js") src = resolveResource("js/util.js")
} }
script { script {
src = resolveResource("assets/js/main.js") src = resolveResource("js/main.js")
} }
} }
} }

View File

@ -1,9 +1,9 @@
package ru.mipt.spc.magprog package ru.mipt.spc.magprog
import kotlinx.css.CSSBuilder import kotlinx.css.CssBuilder
import kotlinx.html.CommonAttributeGroupFacade import kotlinx.html.CommonAttributeGroupFacade
import kotlinx.html.style import kotlinx.html.style
fun CommonAttributeGroupFacade.css(block: CSSBuilder.() -> Unit) { fun CommonAttributeGroupFacade.css(block: CssBuilder.() -> Unit) {
style = CSSBuilder().block().toString() style = CssBuilder().block().toString()
} }

View File

Before

Width:  |  Height:  |  Size: 4.2 MiB

After

Width:  |  Height:  |  Size: 4.2 MiB

View File

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 168 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 MiB

After

Width:  |  Height:  |  Size: 5.6 MiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 613 KiB

After

Width:  |  Height:  |  Size: 613 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 184 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 MiB

After

Width:  |  Height:  |  Size: 5.5 MiB

View File

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Максим Сергеевич Долгоносов name: Максим Сергеевич Долгоносов
id: Dolgonosov id: Dolgonosov
photo: Dolgonosov.jpg photo: images/mentors/Dolgonosov.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Константин Викторович Герценбергер name: Константин Викторович Герценбергер
id: Gertsenberger id: Gertsenberger
photo: Gertsenberger.jpg photo: images/mentors/Gertsenberger.jpg
language: ru language: ru
--- ---
#### Организация #### Организация

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Roland Grinis name: Roland Grinis
id: Grinis id: Grinis
photo: Grinis.jpg photo: images/mentors/Grinis.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Олег Евгеньевич Калашев name: Олег Евгеньевич Калашев
id: Kalashev id: Kalashev
photo: Kalashev.jpg photo: images/mentors/Kalashev.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Igor Khokhriakov name: Igor Khokhriakov
id: Khokhriakov id: Khokhriakov
photo: Khokhriakov.jpg photo: images/mentors/Khokhriakov.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Петр Климай name: Петр Климай
id: Klimai id: Klimai
photo: Klimai.jpg photo: images/mentors/Klimai.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Dmitriy Kostunin name: Dmitriy Kostunin
id: Kostunin id: Kostunin
photo: Kostunin.jpg photo: images/mentors/Kostunin.jpg
language: ru language: ru
published: false published: false
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Александр Нозик name: Александр Нозик
id: Nozik id: Nozik
photo: Nozik.jpg photo: images/mentors/Nozik.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Олийниченко Дмитрий Робертович name: Олийниченко Дмитрий Робертович
id: Oliinychenko id: Oliinychenko
photo: Oliinychenko.jpg photo: images/mentors/Oliinychenko.jpg
language: ru language: ru
published: false published: false
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Игорь Анатольевич Пшеничнов name: Игорь Анатольевич Пшеничнов
id: Pshenichnov id: Pshenichnov
photo: Pshenichnov.jpg photo: images/mentors/Pshenichnov.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Лев Михайлович Шагалов name: Лев Михайлович Шагалов
id: Shagalov id: Shagalov
photo: Shagalov.jpg photo: images/mentors/Shagalov.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Айно Константиновна Скасырская name: Айно Константиновна Скасырская
id: Skasyrskaya id: Skasyrskaya
photo: Skasyrskaya.jpg photo: images/mentors/Skasyrskaya.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Ильмир Усманов name: Ильмир Усманов
id: Usmanov id: Usmanov
photo: Usmanov.jpg photo: images/mentors/Usmanov.jpg
language: ru language: ru
--- ---

View File

@ -1,8 +1,8 @@
--- ---
content_type: magprog_mentor content_type: magprog_mentor
title: Полиграф Шариков name: Полиграф Шариков
id: template id: template
photo: Template.jpg photo: images/mentors/Template.jpg
published: false published: false
language: ru language: ru
--- ---

View File

@ -2,34 +2,34 @@ title: Партнеры
content: content:
- title: ЛФИ МФТИ - title: ЛФИ МФТИ
link: https://mipt.ru/education/departments/lpr/ link: https://mipt.ru/education/departments/lpr/
logo: /images/magprog/partners/LPI.jpg logo: /images/partners/LPI.jpg
- title: ФПМИ МФТИ - title: ФПМИ МФТИ
link: https://mipt.ru/education/departments/fpmi/ link: https://mipt.ru/education/departments/fpmi/
logo: /images/magprog/partners/FPMI.jpg logo: /images/partners/FPMI.jpg
- title: JetBrains Research - title: JetBrains Research
link: https://research.jetbrains.org/groups/npm/ link: https://research.jetbrains.org/groups/npm/
logo: /images/magprog/partners/JBR.png logo: /images/partners/JBR.png
- title: Таврида Электрик - title: Таврида Электрик
link: https://www.tavrida.com/ter/ link: https://www.tavrida.com/ter/
logo: /images/magprog/partners/Tavrida.png logo: /images/partners/Tavrida.png
- title: ИЯИ РАН - title: ИЯИ РАН
link: https://www.inr.ru/ link: https://www.inr.ru/
logo: /images/partners/inr_logo.png logo: /images/partners/inr_logo.png
- title: ИКИ РАН - title: ИКИ РАН
link: http://www.iki.rssi.ru/ link: http://www.iki.rssi.ru/
logo: /images/magprog/partners/iki.jpg logo: /images/partners/iki.jpg
- title: ОИЯИ - title: ОИЯИ
link: https://bmn.jinr.ru/ link: https://bmn.jinr.ru/
logo: /images/magprog/partners/jinr.png logo: /images/partners/jinr.png
# - title: ВШЭ # - title: ВШЭ
# link: https://www.hse.ru/en/ # link: https://www.hse.ru/en/
# logo: /images/magprog/partners/hse.jpg # logo: /images/partners/hse.jpg
# - title: HZG-DESY # - title: HZG-DESY
# link: https://www.desy.de/research/cooperations__institutes/hzg/index_eng.html # link: https://www.desy.de/research/cooperations__institutes/hzg/index_eng.html
# logo: /images/magprog/partners/desy.svg # logo: /images/partners/desy.svg
- title: Тинькофф - title: Тинькофф
link: https://fintech.tinkoff.ru/ link: https://fintech.tinkoff.ru/
logo: /images/magprog/partners/tink.jpg logo: /images/partners/tink.jpg
- title: ФИЦ Биотехнологии РАН - title: ФИЦ Биотехнологии РАН
link: https://www.fbras.ru/ link: https://www.fbras.ru/
logo: /images/magprog/partners/biotech.png logo: /images/partners/biotech.png

View File

@ -1,9 +1,9 @@
--- ---
content_type: magprog_team content_type: magprog_team
title: Денис Айвазов name: Денис Айвазов
id: Aivazov id: Aivazov
order: 4 order: 4
photo: /images/magprog/team/Aivazov.jpg photo: images/team/Aivazov.jpg
language: ru language: ru
--- ---
**Консультант от ФПМИ** **Консультант от ФПМИ**

View File

@ -1,9 +1,9 @@
--- ---
content_type: magprog_team content_type: magprog_team
title: Александр Нозик name: Александр Нозик
id: nozik id: nozik
order: 1 order: 1
photo: /images/members/nozik.png photo: images/mentors/Nozik.jpg
language: ru language: ru
--- ---
**Руководитель программы** **Руководитель программы**

View File

@ -1,9 +1,9 @@
--- ---
content_type: magprog_team content_type: magprog_team
title: Александр Светличный name: Александр Светличный
id: svetlichnii id: svetlichnii
order: 2 order: 2
photo: /images/members/svetlichny.jpeg photo: images/members/svetlichny.jpeg
language: ru language: ru
--- ---
**Заместитель руководителя** **Заместитель руководителя**

View File

@ -319,21 +319,21 @@ print 'It took ' + i + ' iterations to sort the deck.';</code></pre>
<h3>Fit</h3> <h3>Fit</h3>
<div class="box alt"> <div class="box alt">
<div class="row gtr-uniform"> <div class="row gtr-uniform">
<div class="col-12"><span class="image fit"><img src="images/pic04.jpg" alt="" /></span></div> <div class="col-12"><span class="image fit"><img src="assets/images/pic04.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic01.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic01.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic02.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic02.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic03.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic03.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic03.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic03.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic01.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic01.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic02.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic02.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic02.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic02.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic03.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic03.jpg" alt="" /></span></div>
<div class="col-4"><span class="image fit"><img src="images/pic01.jpg" alt="" /></span></div> <div class="col-4"><span class="image fit"><img src="assets/images/pic01.jpg" alt="" /></span></div>
</div> </div>
</div> </div>
<h3>Left &amp; Right</h3> <h3>Left &amp; Right</h3>
<p><span class="image left"><img src="images/pic05.jpg" alt="" /></span>Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.</p> <p><span class="image left"><img src="assets/images/pic05.jpg" alt="" /></span>Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.</p>
<p><span class="image right"><img src="images/pic06.jpg" alt="" /></span>Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.</p> <p><span class="image right"><img src="assets/images/pic06.jpg" alt="" /></span>Fringilla nisl. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Donec accumsan interdum nisi, quis tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent tincidunt felis sagittis eget. tempus euismod. Vestibulum ante ipsum primis in faucibus vestibulum. Blandit adipiscing eu felis iaculis volutpat ac adipiscing accumsan eu faucibus. Integer ac pellentesque praesent.</p>
</section> </section>
</div> </div>

View File

@ -33,7 +33,7 @@
<section id="main" class="wrapper"> <section id="main" class="wrapper">
<div class="inner"> <div class="inner">
<h1 class="major">A Generic Page</h1> <h1 class="major">A Generic Page</h1>
<span class="image fit"><img src="images/pic04.jpg" alt="" /></span> <span class="image fit"><img src="assets/images/pic04.jpg" alt="" /></span>
<p>Donec eget ex magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fergiat. Pellentesque in mi eu massa lacinia malesuada et a elit. Donec urna ex, lacinia in purus ac, pretium pulvinar mauris. Curabitur sapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit tristique.</p> <p>Donec eget ex magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fergiat. Pellentesque in mi eu massa lacinia malesuada et a elit. Donec urna ex, lacinia in purus ac, pretium pulvinar mauris. Curabitur sapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit tristique.</p>
<p>Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fersapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit tristique lorem ipsum dolor.</p> <p>Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque venenatis dolor imperdiet dolor mattis sagittis. Praesent rutrum sem diam, vitae egestas enim auctor sit amet. Pellentesque leo mauris, consectetur id ipsum sit amet, fersapien risus, commodo eget turpis at, elementum convallis elit. Pellentesque enim turpis, hendrerit tristique lorem ipsum dolor.</p>
</div> </div>

View File

@ -46,7 +46,7 @@
<!-- One --> <!-- One -->
<section id="one" class="wrapper style2 spotlights"> <section id="one" class="wrapper style2 spotlights">
<section> <section>
<a href="#" class="image"><img src="images/pic01.jpg" alt="" data-position="center center" /></a> <a href="#" class="image"><img src="assets/images/pic01.jpg" alt="" data-position="center center" /></a>
<div class="content"> <div class="content">
<div class="inner"> <div class="inner">
<h2>Sed ipsum dolor</h2> <h2>Sed ipsum dolor</h2>
@ -58,7 +58,7 @@
</div> </div>
</section> </section>
<section> <section>
<a href="#" class="image"><img src="images/pic02.jpg" alt="" data-position="top center" /></a> <a href="#" class="image"><img src="assets/images/pic02.jpg" alt="" data-position="top center" /></a>
<div class="content"> <div class="content">
<div class="inner"> <div class="inner">
<h2>Feugiat consequat</h2> <h2>Feugiat consequat</h2>
@ -70,7 +70,7 @@
</div> </div>
</section> </section>
<section> <section>
<a href="#" class="image"><img src="images/pic03.jpg" alt="" data-position="25% 25%" /></a> <a href="#" class="image"><img src="assets/images/pic03.jpg" alt="" data-position="25% 25%" /></a>
<div class="content"> <div class="content">
<div class="inner"> <div class="inner">
<h2>Ultricies aliquam</h2> <h2>Ultricies aliquam</h2>

View File

@ -1,10 +1,8 @@
package ru.mipt package ru.mipt
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.testing.testApplication import io.ktor.server.testing.testApplication
import ru.mipt.plugins.configureRouting
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -12,11 +10,11 @@ class ApplicationTest {
@Test @Test
fun testRoot() = testApplication { fun testRoot() = testApplication {
application { application {
configureRouting() magProgSite()
} }
client.get("/").apply { client.get("/magprog").apply {
assertEquals(HttpStatusCode.OK, status) assertEquals(HttpStatusCode.OK, status)
assertEquals("Hello World!", bodyAsText()) // assertEquals("Hello World!", bodyAsText())
} }
} }
} }