Fully functional!
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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()
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
101
src/main/kotlin/ru/mipt/spc/magprog/DataSetSiteContext.kt
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
78
src/main/kotlin/ru/mipt/spc/magprog/DirectoryDataTree.kt
Normal 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
|
@ -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
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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()
|
||||||
}
|
}
|
Before Width: | Height: | Size: 4.2 MiB After Width: | Height: | Size: 4.2 MiB |
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 5.6 MiB After Width: | Height: | Size: 5.6 MiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 613 KiB After Width: | Height: | Size: 613 KiB |
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.8 MiB |
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 5.5 MiB After Width: | Height: | Size: 5.5 MiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
#### Организация
|
#### Организация
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
**Консультант от ФПМИ**
|
**Консультант от ФПМИ**
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
**Руководитель программы**
|
**Руководитель программы**
|
||||||
|
@ -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
|
||||||
---
|
---
|
||||||
**Заместитель руководителя**
|
**Заместитель руководителя**
|
||||||
|
@ -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 & Right</h3>
|
<h3>Left & 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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|