diff --git a/build.gradle.kts b/build.gradle.kts index 3e30285f..dcf9eb7d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("ru.mipt.npm.gradle.project") kotlin("jvm") apply false + kotlin("js") apply false kotlin("jupyter.api") apply false } @@ -20,7 +21,7 @@ allprojects { } group = "space.kscience" - version = "0.2.0-dev-9" + version = "0.2.0-dev-13" } subprojects { diff --git a/demo/gdml/build.gradle.kts b/demo/gdml/build.gradle.kts index e4fef51e..ae64890e 100644 --- a/demo/gdml/build.gradle.kts +++ b/demo/gdml/build.gradle.kts @@ -2,7 +2,8 @@ import ru.mipt.npm.gradle.DependencyConfiguration import ru.mipt.npm.gradle.FXModule plugins { - id("ru.mipt.npm.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") application } diff --git a/demo/gdml/src/jsMain/kotlin/drop/FileDrop.kt b/demo/gdml/src/jsMain/kotlin/drop/FileDrop.kt index 2799eead..a52343b0 100644 --- a/demo/gdml/src/jsMain/kotlin/drop/FileDrop.kt +++ b/demo/gdml/src/jsMain/kotlin/drop/FileDrop.kt @@ -5,7 +5,9 @@ package drop import org.w3c.dom.DragEvent import org.w3c.files.FileList -import react.* +import react.Component +import react.RProps +import react.RState external enum class DropEffects { copy, diff --git a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlJsDemoApp.kt b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlJsDemoApp.kt index 31f4645b..f1cbec0d 100644 --- a/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlJsDemoApp.kt +++ b/demo/gdml/src/jsMain/kotlin/space/kscience/visionforge/gdml/demo/GdmlJsDemoApp.kt @@ -22,6 +22,7 @@ private class GDMLDemoApp : Application { val context = Global.context("demo") .apply{ plugins.fetch(ThreePlugin) } + render(element) { child(GDMLApp) { val vision = GdmlShowcase.cubes.toVision() @@ -32,7 +33,6 @@ private class GDMLDemoApp : Application { } } } - } } diff --git a/demo/muon-monitor/build.gradle.kts b/demo/muon-monitor/build.gradle.kts index 72e086b0..209685b9 100644 --- a/demo/muon-monitor/build.gradle.kts +++ b/demo/muon-monitor/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME - plugins { id("ru.mipt.npm.gradle.mpp") application @@ -7,7 +5,7 @@ plugins { group = "ru.mipt.npm" -val ktorVersion: String = ru.mipt.npm.gradle.KScienceVersions.ktorVersion +val ktorVersion: String = ru.mipt.npm.gradle.KScienceVersions.ktorVersion kscience { useSerialization() @@ -15,20 +13,18 @@ kscience { } kotlin { + jvm { + withJava() + } + afterEvaluate { val jsBrowserDistribution by tasks.getting - jvm { - withJava() - compilations[MAIN_COMPILATION_NAME]?.apply { - tasks.getByName(processResourcesTaskName) { - dependsOn(jsBrowserDistribution) - afterEvaluate { - from(jsBrowserDistribution) - } - } + tasks.getByName("jvmProcessResources") { + dependsOn(jsBrowserDistribution) + afterEvaluate { + from(jsBrowserDistribution) } - } } @@ -61,13 +57,13 @@ application { mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt") } -distributions { - main { - contents { - from("$buildDir/libs") { - rename("${rootProject.name}-jvm", rootProject.name) - into("lib") - } - } - } -} \ No newline at end of file +//distributions { +// main { +// contents { +// from("$buildDir/libs") { +// rename("${rootProject.name}-jvm", rootProject.name) +// into("lib") +// } +// } +// } +//} \ No newline at end of file diff --git a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/server/MMServer.kt b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/server/MMServer.kt index aa9dbbb2..9e4ff43c 100644 --- a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/server/MMServer.kt +++ b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/server/MMServer.kt @@ -1,10 +1,6 @@ package ru.mipt.npm.muon.monitor.server -import space.kscience.dataforge.context.Context -import space.kscience.dataforge.context.Global -import space.kscience.dataforge.misc.DFExperimental -import space.kscience.visionforge.solid.Solids import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -28,6 +24,10 @@ import org.apache.commons.math3.random.JDKRandomGenerator import ru.mipt.npm.muon.monitor.Model import ru.mipt.npm.muon.monitor.sim.Cos2TrackGenerator import ru.mipt.npm.muon.monitor.sim.simulateOne +import space.kscience.dataforge.context.Context +import space.kscience.dataforge.context.Global +import space.kscience.dataforge.misc.DFExperimental +import space.kscience.visionforge.solid.Solids import java.awt.Desktop import java.io.File import java.net.URI diff --git a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt index ca82dc87..de704441 100644 --- a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt +++ b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/line.kt @@ -1,11 +1,11 @@ package ru.mipt.npm.muon.monitor.sim -import space.kscience.visionforge.solid.Point3D import org.apache.commons.math3.geometry.euclidean.threed.Line import org.apache.commons.math3.geometry.euclidean.threed.Plane import org.apache.commons.math3.geometry.euclidean.threed.Vector3D import ru.mipt.npm.muon.monitor.Monitor.CENTRAL_LAYER_Z import ru.mipt.npm.muon.monitor.Monitor.GEOMETRY_TOLERANCE +import space.kscience.visionforge.solid.Point3D /** * Created by darksnake on 11-May-16. diff --git a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt index 01ff5d3b..a4e83c8b 100644 --- a/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt +++ b/demo/muon-monitor/src/jvmMain/kotlin/ru/mipt/npm/muon/monitor/sim/monitor.kt @@ -7,7 +7,6 @@ import ru.mipt.npm.muon.monitor.Event import ru.mipt.npm.muon.monitor.Monitor import ru.mipt.npm.muon.monitor.SC1 import ru.mipt.npm.muon.monitor.readResource -import java.util.* // minimal track length in detector diff --git a/demo/muon-monitor/src/jvmTest/kotlin/ru/mipt/npm/muon/monitor/GeometryTest.kt b/demo/muon-monitor/src/jvmTest/kotlin/ru/mipt/npm/muon/monitor/GeometryTest.kt index 6e1ec106..6221c529 100644 --- a/demo/muon-monitor/src/jvmTest/kotlin/ru/mipt/npm/muon/monitor/GeometryTest.kt +++ b/demo/muon-monitor/src/jvmTest/kotlin/ru/mipt/npm/muon/monitor/GeometryTest.kt @@ -1,6 +1,7 @@ package ru.mipt.npm.muon.monitor -import kotlin.test.* +import kotlin.test.Test +import kotlin.test.assertTrue class GeometryTest { diff --git a/demo/playground/src/jvmMain/kotlin/serverExtensions.kt b/demo/playground/src/jvmMain/kotlin/serverExtensions.kt index 285a14a2..da4d6cde 100644 --- a/demo/playground/src/jvmMain/kotlin/serverExtensions.kt +++ b/demo/playground/src/jvmMain/kotlin/serverExtensions.kt @@ -27,7 +27,7 @@ public fun VisionForge.makeVisionFile( show: Boolean = true, ): Unit { val actualPath = page(title, content = content).makeFile(path) { actualPath -> - mapOf("threeJs" to scriptHeader("js/visionforge-playground.js", actualPath, resourceLocation)) + mapOf("threeJs" to scriptHeader("js/visionforge-playground.js", resourceLocation, actualPath)) } if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI()) } diff --git a/jupyter/visionforge-gdml-jupyter/build.gradle.kts b/jupyter/visionforge-gdml-jupyter/build.gradle.kts index cc1988dc..86847c2c 100644 --- a/jupyter/visionforge-gdml-jupyter/build.gradle.kts +++ b/jupyter/visionforge-gdml-jupyter/build.gradle.kts @@ -1,16 +1,54 @@ plugins { - id("ru.mipt.npm.gradle.jvm") + id("ru.mipt.npm.gradle.mpp") kotlin("jupyter.api") } description = "Jupyter api artifact for GDML rendering" -dependencies { - implementation(project(":visionforge-gdml")) - implementation(project(":visionforge-threejs:visionforge-threejs-server")) +kotlin{ + explicitApi = null + js{ + browser { + webpackTask { + this.outputFileName = "js/gdml-jupyter.js" + } + } + binaries.executable() + } + + afterEvaluate { + val jsBrowserDistribution by tasks.getting + + tasks.getByName("jvmProcessResources") { + dependsOn(jsBrowserDistribution) + afterEvaluate { + from(jsBrowserDistribution) + } + } + } + + sourceSets{ + commonMain { + dependencies { + api(project(":visionforge-solid")) + } + } + jvmMain{ + dependencies { + implementation(project(":visionforge-gdml")) + implementation(kotlin("script-runtime")) + } + } + jsMain { + dependencies { + api(project(":visionforge-threejs")) + implementation(project(":ui:bootstrap")) + } + } + + } } readme{ maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -} - +} \ No newline at end of file diff --git a/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/ThreeWithControls.kt b/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/ThreeWithControls.kt new file mode 100644 index 00000000..bad07723 --- /dev/null +++ b/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/ThreeWithControls.kt @@ -0,0 +1,49 @@ +package space.kscience.visionforge.gdml.jupyter + +import org.w3c.dom.Element +import react.child +import space.kscience.dataforge.context.AbstractPlugin +import space.kscience.dataforge.context.Context +import space.kscience.dataforge.context.PluginFactory +import space.kscience.dataforge.context.PluginTag +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.asName +import space.kscience.visionforge.ElementVisionRenderer +import space.kscience.visionforge.Vision +import space.kscience.visionforge.solid.Solid +import space.kscience.visionforge.solid.three.ThreePlugin +import kotlin.reflect.KClass + +class ThreeWithControls : AbstractPlugin(), ElementVisionRenderer { + val three by require(ThreePlugin) + + override val tag: PluginTag get() = Companion.tag + + override fun rateVision(vision: Vision): Int = + if (vision is Solid) ElementVisionRenderer.DEFAULT_RATING * 2 else ElementVisionRenderer.ZERO_RATING + + override fun render(element: Element, vision: Vision, meta: Meta) { + react.dom.render(element) { + child(GdmlView) { + attrs { + this.context = this@ThreeWithControls.context + this.rootVision = vision + } + } + } + } + + override fun content(target: String): Map { + return when (target) { + ElementVisionRenderer.TYPE -> mapOf("three.withControls".asName() to this) + else -> super.content(target) + } + } + + companion object : PluginFactory { + override val tag: PluginTag = PluginTag("vision.threejs.withControls", PluginTag.DATAFORGE_GROUP) + override val type: KClass = ThreeWithControls::class + override fun invoke(meta: Meta, context: Context): ThreeWithControls = ThreeWithControls() + } +} \ No newline at end of file diff --git a/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/gdmlJupyter.kt b/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/gdmlJupyter.kt new file mode 100644 index 00000000..57bdb872 --- /dev/null +++ b/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/gdmlJupyter.kt @@ -0,0 +1,32 @@ +package space.kscience.visionforge.gdml.jupyter + +import kotlinx.browser.window +import kotlinx.css.ListStyleType +import kotlinx.css.listStyleType +import space.kscience.dataforge.misc.DFExperimental +import space.kscience.visionforge.VisionForge +import space.kscience.visionforge.bootstrap.useBootstrap +import space.kscience.visionforge.plugins +import styled.injectGlobal + +@DFExperimental +fun main(): Unit = VisionForge.run { + useBootstrap() + injectGlobal { + rule("ul.nav") { + listStyleType = ListStyleType.none + } + + rule(".treeStyles-tree") { + listStyleType = ListStyleType.none + } + + rule("ol.breadcrumb") { + listStyleType = ListStyleType.none + } + } + console.info("Starting VisionForge context") + plugins.fetch(ThreeWithControls) + window.asDynamic()["VisionForge"] = VisionForge + renderVisionsInWindow() +} \ No newline at end of file diff --git a/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/threeViewer.kt b/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/threeViewer.kt new file mode 100644 index 00000000..d7818254 --- /dev/null +++ b/jupyter/visionforge-gdml-jupyter/src/jsMain/kotlin/threeViewer.kt @@ -0,0 +1,83 @@ +package space.kscience.visionforge.gdml.jupyter + +import kotlinx.css.* +import react.RProps +import react.child +import react.dom.h1 +import react.functionalComponent +import react.useState +import space.kscience.dataforge.context.Context +import space.kscience.dataforge.names.Name +import space.kscience.visionforge.Vision +import space.kscience.visionforge.bootstrap.gridRow +import space.kscience.visionforge.bootstrap.nameCrumbs +import space.kscience.visionforge.bootstrap.threeControls +import space.kscience.visionforge.react.ThreeCanvasComponent +import space.kscience.visionforge.react.flexColumn +import space.kscience.visionforge.solid.Solid +import space.kscience.visionforge.solid.specifications.Canvas3DOptions +import space.kscience.visionforge.solid.three.ThreeCanvas +import styled.css +import styled.styledDiv + +external interface GdmlViewProps : RProps { + var context: Context + var rootVision: Vision? + var selected: Name? +} + +@JsExport +val GdmlView = functionalComponent("GdmlView") { props -> + var selected by useState { props.selected } + var canvas: ThreeCanvas? by useState { null } + var vision: Vision? by useState { props.rootVision } + + val onSelect: (Name?) -> Unit = { + selected = it + } + + gridRow { + flexColumn { + css { + +"col-lg-9" + height = 100.vh + } + styledDiv { + css { + +"mx-auto" + +"page-header" + } + h1 { +"GDML/JSON loader demo" } + } + nameCrumbs(selected, "World", onSelect) + //canvas + + child(ThreeCanvasComponent) { + attrs { + this.context = props.context + this.obj = vision as? Solid + this.selected = selected + this.options = Canvas3DOptions.invoke { + this.onSelect = onSelect + } + this.canvasCallback = { + canvas = it + } + } + } + + } + flexColumn { + css { + +"col-lg-3" + padding(top = 4.px) + //border(1.px, BorderStyle.solid, Color.lightGray) + height = 100.vh + overflowY = Overflow.auto + } + canvas?.let { + threeControls(it, selected, onSelect) + } + } + } +} \ No newline at end of file diff --git a/jupyter/visionforge-gdml-jupyter/src/main/kotlin/GdmlForJupyter.kt b/jupyter/visionforge-gdml-jupyter/src/jvmMain/kotlin/GdmlForJupyter.kt similarity index 86% rename from jupyter/visionforge-gdml-jupyter/src/main/kotlin/GdmlForJupyter.kt rename to jupyter/visionforge-gdml-jupyter/src/jvmMain/kotlin/GdmlForJupyter.kt index 16b7c9f9..0161d621 100644 --- a/jupyter/visionforge-gdml-jupyter/src/main/kotlin/GdmlForJupyter.kt +++ b/jupyter/visionforge-gdml-jupyter/src/jvmMain/kotlin/GdmlForJupyter.kt @@ -7,7 +7,8 @@ import kotlinx.html.stream.createHTML import kotlinx.html.unsafe import org.jetbrains.kotlinx.jupyter.api.HTML import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary -import org.jetbrains.kotlinx.jupyter.api.libraries.* +import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration +import org.jetbrains.kotlinx.jupyter.api.libraries.resources import space.kscience.dataforge.misc.DFExperimental import space.kscience.gdml.Gdml import space.kscience.visionforge.Vision @@ -25,11 +26,6 @@ import space.kscience.visionforge.visionManager @DFExperimental internal class GdmlForJupyter : JupyterIntegration() { - private val jsBundle = ResourceFallbacksBundle(listOf( - ResourceLocation("js/visionforge-three.js", ResourcePathType.CLASSPATH_PATH)) - ) - private val jsResource = LibraryResource(name = "visionforge-three", type = ResourceType.JS, bundles = listOf(jsBundle)) - private var counter = 0 private fun produceHtmlVisionString(fragment: HtmlVisionFragment) = createHTML().div { @@ -45,7 +41,15 @@ internal class GdmlForJupyter : JupyterIntegration() { } override fun Builder.onLoaded() { - resource(jsResource) + + resources { + js("three"){ + classPath("js/gdml-jupyter.js") + } +// css("override") { +// classPath("css/jupyter-override.css") +// } + } onLoaded { VisionForge.plugins.fetch(Solids) diff --git a/settings.gradle.kts b/settings.gradle.kts index d8a039bc..9654d977 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,9 @@ pluginManagement { val kotlinVersion = "1.4.31" - val toolsVersion = "0.9.1" + val toolsVersion = "0.9.2" repositories { + mavenLocal() maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() @@ -15,7 +16,7 @@ pluginManagement { id("ru.mipt.npm.gradle.js") version toolsVersion id("ru.mipt.npm.gradle.publish") version toolsVersion kotlin("jvm") version kotlinVersion - kotlin("jupyter.api") version "0.8.3.236" + kotlin("jupyter.api") version "0.8.3.279" kotlin("js") version kotlinVersion kotlin("multiplatform") version kotlinVersion } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionFragment.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionFragment.kt index b57db4a5..4597a955 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionFragment.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/html/HtmlVisionFragment.kt @@ -2,11 +2,14 @@ package space.kscience.visionforge.html import kotlinx.html.FlowContent import kotlinx.html.TagConsumer +import kotlinx.html.stream.createHTML import space.kscience.dataforge.misc.DFExperimental import space.kscience.visionforge.VisionForge public typealias HtmlFragment = TagConsumer<*>.() -> Unit +public fun HtmlFragment.render(): String = createHTML().apply(this).finalize() + public fun TagConsumer<*>.fragment(fragment: HtmlFragment) { fragment() } diff --git a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/visionForgeJs.kt b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/visionForgeJs.kt index 28e2ef66..e605b4d1 100644 --- a/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/visionForgeJs.kt +++ b/visionforge-core/src/jsMain/kotlin/space/kscience/visionforge/visionForgeJs.kt @@ -19,6 +19,7 @@ private fun whenDocumentLoaded(block: Document.() -> Unit): Unit { @JsExport @DFExperimental +@JsName("VisionForge") public actual object VisionForge { /** * Render all visions in this [window] using current global state of [VisionForge] diff --git a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt index 6bf8be49..56b2e17b 100644 --- a/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt +++ b/visionforge-core/src/jvmMain/kotlin/space/kscience/visionforge/html/headers.kt @@ -89,7 +89,7 @@ internal fun embedScriptHeader(resource: String): HtmlFragment = { script { type = "text/javascript" unsafe { - val bytes = VisionManager::class.java.getResourceAsStream("/$resource").readAllBytes() + val bytes = VisionManager::class.java.getResourceAsStream("/$resource")!!.readAllBytes() +bytes.toString(Charsets.UTF_8) } } @@ -113,8 +113,8 @@ internal fun fileCssHeader( @DFExperimental public fun scriptHeader( scriptResource: String, - htmlPath: Path?, resourceLocation: ResourceLocation, + htmlPath: Path? = null, ): HtmlFragment { val targetPath = when (resourceLocation) { ResourceLocation.LOCAL -> checkOrStoreFile( diff --git a/visionforge-plotly/src/jvmMain/kotlin/space/kscience/visionforge/plotly/plotlyHeaders.kt b/visionforge-plotly/src/jvmMain/kotlin/space/kscience/visionforge/plotly/plotlyHeaders.kt index fe966172..a09909c7 100644 --- a/visionforge-plotly/src/jvmMain/kotlin/space/kscience/visionforge/plotly/plotlyHeaders.kt +++ b/visionforge-plotly/src/jvmMain/kotlin/space/kscience/visionforge/plotly/plotlyHeaders.kt @@ -17,8 +17,8 @@ internal val plotlyScriptLocation = "js/visionforge-three.js" public fun plotlyHeader(location: ResourceLocation, filePath: Path? = null): HtmlFragment = { scriptHeader( plotlyScriptLocation, - filePath, - resourceLocation = location + resourceLocation = location, + htmlPath = filePath ).invoke(this) script { type = "text/javascript" diff --git a/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/server/serverExtensions.kt b/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/server/serverExtensions.kt index fd9b1636..9bd6e6b9 100644 --- a/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/server/serverExtensions.kt +++ b/visionforge-threejs/visionforge-threejs-server/src/jvmMain/kotlin/space/kscience/visionforge/three/server/serverExtensions.kt @@ -24,7 +24,7 @@ public fun VisionForge.makeThreeJsFile( show: Boolean = true, ): Unit { val actualPath = page(title, content = content).makeFile(path) { actualPath -> - mapOf("threeJs" to scriptHeader("js/visionforge-three.js", actualPath, resourceLocation)) + mapOf("threeJs" to scriptHeader("js/visionforge-three.js", resourceLocation, actualPath)) } if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI()) }