aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Formats/FormatDescriptor.kt11
-rw-r--r--src/Formats/HtmlFormatService.kt6
-rw-r--r--src/Formats/JekyllFormatService.kt4
-rw-r--r--src/Formats/KotlinWebsiteFormatService.kt5
-rw-r--r--src/Formats/MarkdownFormatService.kt4
-rw-r--r--src/Formats/StandardFormats.kt47
-rw-r--r--src/Formats/YamlOutlineService.kt3
-rw-r--r--src/Generation/FileGenerator.kt37
-rw-r--r--src/Generation/Generator.kt15
-rw-r--r--src/Locations/FoldersLocationService.kt5
-rw-r--r--src/Locations/LocationService.kt2
-rw-r--r--src/Locations/SingleFolderLocationService.kt6
-rw-r--r--src/Utilities/GuiceModule.kt58
-rw-r--r--src/Utilities/ServiceLocator.kt105
-rw-r--r--src/main.kt37
15 files changed, 295 insertions, 50 deletions
diff --git a/src/Formats/FormatDescriptor.kt b/src/Formats/FormatDescriptor.kt
new file mode 100644
index 00000000..beff730f
--- /dev/null
+++ b/src/Formats/FormatDescriptor.kt
@@ -0,0 +1,11 @@
+package org.jetbrains.dokka.Formats
+
+import org.jetbrains.dokka.FormatService
+import org.jetbrains.dokka.Generator
+import org.jetbrains.dokka.OutlineFormatService
+
+public interface FormatDescriptor {
+ val formatServiceClass: Class<out FormatService>?
+ val outlineServiceClass: Class<out OutlineFormatService>?
+ val generatorServiceClass: Class<out Generator>
+} \ No newline at end of file
diff --git a/src/Formats/HtmlFormatService.kt b/src/Formats/HtmlFormatService.kt
index 78d3cff2..5dcd432b 100644
--- a/src/Formats/HtmlFormatService.kt
+++ b/src/Formats/HtmlFormatService.kt
@@ -1,10 +1,12 @@
package org.jetbrains.dokka
+import com.google.inject.Inject
+import com.google.inject.name.Named
import java.io.File
-public open class HtmlFormatService(locationService: LocationService,
+public open class HtmlFormatService @Inject constructor(@Named("folders") locationService: LocationService,
signatureGenerator: LanguageService,
- val templateService: HtmlTemplateService = HtmlTemplateService.default())
+ val templateService: HtmlTemplateService)
: StructuredFormatService(locationService, signatureGenerator, "html"), OutlineFormatService {
override public fun formatText(text: String): String {
return text.htmlEscape()
diff --git a/src/Formats/JekyllFormatService.kt b/src/Formats/JekyllFormatService.kt
index e4c3ccd5..113f229f 100644
--- a/src/Formats/JekyllFormatService.kt
+++ b/src/Formats/JekyllFormatService.kt
@@ -1,6 +1,8 @@
package org.jetbrains.dokka
-public open class JekyllFormatService(locationService: LocationService,
+import com.google.inject.Inject
+
+public open class JekyllFormatService @Inject constructor(locationService: LocationService,
signatureGenerator: LanguageService)
: MarkdownFormatService(locationService, signatureGenerator) {
diff --git a/src/Formats/KotlinWebsiteFormatService.kt b/src/Formats/KotlinWebsiteFormatService.kt
index 21fc9dae..8fbebaae 100644
--- a/src/Formats/KotlinWebsiteFormatService.kt
+++ b/src/Formats/KotlinWebsiteFormatService.kt
@@ -1,8 +1,11 @@
package org.jetbrains.dokka
-public class KotlinWebsiteFormatService(locationService: LocationService,
+import com.google.inject.Inject
+
+public class KotlinWebsiteFormatService @Inject constructor(locationService: LocationService,
signatureGenerator: LanguageService)
: JekyllFormatService(locationService, signatureGenerator) {
+
override fun appendFrontMatter(nodes: Iterable<DocumentationNode>, to: StringBuilder) {
super.appendFrontMatter(nodes, to)
to.appendln("layout: api")
diff --git a/src/Formats/MarkdownFormatService.kt b/src/Formats/MarkdownFormatService.kt
index ba7d8f7b..29a9f5c4 100644
--- a/src/Formats/MarkdownFormatService.kt
+++ b/src/Formats/MarkdownFormatService.kt
@@ -1,7 +1,9 @@
package org.jetbrains.dokka
+import com.google.inject.Inject
-public open class MarkdownFormatService(locationService: LocationService,
+
+public open class MarkdownFormatService @Inject constructor(locationService: LocationService,
signatureGenerator: LanguageService)
: StructuredFormatService(locationService, signatureGenerator, "md") {
override public fun formatBreadcrumbs(items: Iterable<FormatLink>): String {
diff --git a/src/Formats/StandardFormats.kt b/src/Formats/StandardFormats.kt
new file mode 100644
index 00000000..1d5ffe13
--- /dev/null
+++ b/src/Formats/StandardFormats.kt
@@ -0,0 +1,47 @@
+package org.jetbrains.dokka.Formats
+
+import org.jetbrains.dokka.*
+
+class HtmlFormatDescriptor : FormatDescriptor {
+ override val formatServiceClass: Class<out FormatService>
+ get() = javaClass<HtmlFormatService>()
+
+ override val outlineServiceClass: Class<out OutlineFormatService>
+ get() = javaClass<HtmlFormatService>()
+
+ override val generatorServiceClass: Class<out Generator>
+ get() = javaClass<FileGenerator>()
+}
+
+class KotlinWebsiteFormatDescriptor : FormatDescriptor {
+ override val formatServiceClass: Class<out FormatService>
+ get() = javaClass<KotlinWebsiteFormatService>()
+
+ override val outlineServiceClass: Class<out OutlineFormatService>
+ get() = javaClass<YamlOutlineService>()
+
+ override val generatorServiceClass: Class<out Generator>
+ get() = javaClass<FileGenerator>()
+}
+
+class JekyllFormatDescriptor : FormatDescriptor {
+ override val formatServiceClass: Class<out FormatService>
+ get() = javaClass<JekyllFormatService>()
+
+ override val outlineServiceClass: Class<out OutlineFormatService>?
+ get() = null
+
+ override val generatorServiceClass: Class<out Generator>
+ get() = javaClass<FileGenerator>()
+}
+
+class MarkdownFormatDescriptor : FormatDescriptor {
+ override val formatServiceClass: Class<out FormatService>
+ get() = javaClass<MarkdownFormatService>()
+
+ override val outlineServiceClass: Class<out OutlineFormatService>?
+ get() = null
+
+ override val generatorServiceClass: Class<out Generator>
+ get() = javaClass<FileGenerator>()
+}
diff --git a/src/Formats/YamlOutlineService.kt b/src/Formats/YamlOutlineService.kt
index cdab4eeb..7968824c 100644
--- a/src/Formats/YamlOutlineService.kt
+++ b/src/Formats/YamlOutlineService.kt
@@ -1,8 +1,9 @@
package org.jetbrains.dokka
+import com.google.inject.Inject
import java.io.File
-class YamlOutlineService(val locationService: LocationService,
+class YamlOutlineService @Inject constructor(val locationService: LocationService,
val languageService: LanguageService) : OutlineFormatService {
override fun getOutlineFileName(location: Location): File = File("${location.path}.yml")
diff --git a/src/Generation/FileGenerator.kt b/src/Generation/FileGenerator.kt
index abe4257f..08a885ab 100644
--- a/src/Generation/FileGenerator.kt
+++ b/src/Generation/FileGenerator.kt
@@ -1,36 +1,41 @@
package org.jetbrains.dokka
+import com.google.inject.Inject
+import java.io.File
import java.io.FileOutputStream
+import java.io.IOException
import java.io.OutputStreamWriter
-public class FileGenerator(val signatureGenerator: LanguageService,
- val locationService: FileLocationService,
+public class FileGenerator @Inject constructor(val locationService: FileLocationService,
val formatService: FormatService,
- val outlineService: OutlineFormatService?) {
+ @Inject(optional = true) val outlineService: OutlineFormatService?) : Generator {
- public fun buildPage(node: DocumentationNode): Unit = buildPages(listOf(node))
- public fun buildOutline(node: DocumentationNode): Unit = buildOutlines(listOf(node))
+ override fun buildPages(nodes: Iterable<DocumentationNode>) {
+ val specificLocationService = locationService.withExtension(formatService.extension)
- public fun buildPages(nodes: Iterable<DocumentationNode>) {
- for ((location, items) in nodes.groupBy { locationService.location(it) }) {
+ for ((location, items) in nodes.groupBy { specificLocationService.location(it) }) {
val file = location.file
- file.getParentFile()?.mkdirs()
- FileOutputStream(file).use {
- OutputStreamWriter(it, Charsets.UTF_8).use {
- it.write(formatService.format(location, items))
+ file.parentFile?.mkdirsOrFail()
+ try {
+ FileOutputStream(file).use {
+ OutputStreamWriter(it, Charsets.UTF_8).use {
+ it.write(formatService.format(location, items))
+ }
}
+ } catch (e: Throwable) {
+ println(e)
}
buildPages(items.flatMap { it.members })
}
}
- public fun buildOutlines(nodes: Iterable<DocumentationNode>) {
+ override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
if (outlineService == null) {
return
}
for ((location, items) in nodes.groupBy { locationService.location(it) }) {
val file = outlineService.getOutlineFileName(location)
- file.getParentFile()?.mkdirs()
+ file.parentFile?.mkdirsOrFail()
FileOutputStream(file).use {
OutputStreamWriter(it, Charsets.UTF_8).use {
it.write(outlineService.formatOutline(location, items))
@@ -38,4 +43,10 @@ public class FileGenerator(val signatureGenerator: LanguageService,
}
}
}
+}
+
+private fun File.mkdirsOrFail() {
+ if (!mkdirs() && !exists()) {
+ throw IOException("Failed to create directory $this")
+ }
} \ No newline at end of file
diff --git a/src/Generation/Generator.kt b/src/Generation/Generator.kt
new file mode 100644
index 00000000..7dcabb0b
--- /dev/null
+++ b/src/Generation/Generator.kt
@@ -0,0 +1,15 @@
+package org.jetbrains.dokka
+
+public interface Generator {
+ fun buildPages(nodes: Iterable<DocumentationNode>)
+ fun buildOutlines(nodes: Iterable<DocumentationNode>)
+
+ final fun buildAll(nodes: Iterable<DocumentationNode>) {
+ buildPages(nodes)
+ buildOutlines(nodes)
+ }
+
+ final fun buildPage(node: DocumentationNode): Unit = buildPages(listOf(node))
+ final fun buildOutline(node: DocumentationNode): Unit = buildOutlines(listOf(node))
+ final fun buildAll(node: DocumentationNode): Unit = buildAll(listOf(node))
+}
diff --git a/src/Locations/FoldersLocationService.kt b/src/Locations/FoldersLocationService.kt
index e85c2c98..8a0cf6be 100644
--- a/src/Locations/FoldersLocationService.kt
+++ b/src/Locations/FoldersLocationService.kt
@@ -1,9 +1,12 @@
package org.jetbrains.dokka
+import com.google.inject.Inject
+import com.google.inject.name.Named
import java.io.File
public fun FoldersLocationService(root: String): FoldersLocationService = FoldersLocationService(File(root), "")
-public class FoldersLocationService(val root: File, val extension: String) : FileLocationService {
+public class FoldersLocationService @Inject constructor(@Named("outputDir") val root: File, val extension: String) : FileLocationService {
+
override fun withExtension(newExtension: String): FileLocationService {
return if (extension.isEmpty()) FoldersLocationService(root, newExtension) else this
}
diff --git a/src/Locations/LocationService.kt b/src/Locations/LocationService.kt
index 7d0b8b56..000b2c5e 100644
--- a/src/Locations/LocationService.kt
+++ b/src/Locations/LocationService.kt
@@ -55,6 +55,8 @@ public interface LocationService {
public interface FileLocationService: LocationService {
+ override fun withExtension(newExtension: String): FileLocationService = this
+
override fun location(node: DocumentationNode): FileLocation = location(node.path.map { it.name }, node.members.any())
override fun location(qualifiedName: List<String>, hasMembers: Boolean): FileLocation
}
diff --git a/src/Locations/SingleFolderLocationService.kt b/src/Locations/SingleFolderLocationService.kt
index c26d2b34..049636c0 100644
--- a/src/Locations/SingleFolderLocationService.kt
+++ b/src/Locations/SingleFolderLocationService.kt
@@ -1,10 +1,12 @@
package org.jetbrains.dokka
+import com.google.inject.Inject
+import com.google.inject.name.Named
import java.io.File
public fun SingleFolderLocationService(root: String): SingleFolderLocationService = SingleFolderLocationService(File(root), "")
-public class SingleFolderLocationService(val root: File, val extension: String) : FileLocationService {
- override fun withExtension(newExtension: String): LocationService =
+public class SingleFolderLocationService @Inject constructor(@Named("outputDir") val root: File, val extension: String) : FileLocationService {
+ override fun withExtension(newExtension: String): FileLocationService =
SingleFolderLocationService(root, newExtension)
override fun location(qualifiedName: List<String>, hasMembers: Boolean): FileLocation {
diff --git a/src/Utilities/GuiceModule.kt b/src/Utilities/GuiceModule.kt
new file mode 100644
index 00000000..4ce4863d
--- /dev/null
+++ b/src/Utilities/GuiceModule.kt
@@ -0,0 +1,58 @@
+package org.jetbrains.dokka.Utilities
+
+import com.google.inject.Binder
+import com.google.inject.Module
+import com.google.inject.Provider
+import com.google.inject.name.Names
+import org.jetbrains.dokka.*
+import org.jetbrains.dokka.Formats.FormatDescriptor
+import java.io.File
+
+class GuiceModule(val config: DokkaGenerator) : Module {
+ override fun configure(binder: Binder) {
+ binder.bind(javaClass<DokkaGenerator>()).toInstance(config)
+ binder.bind(javaClass<File>()).annotatedWith(Names.named("outputDir")).toInstance(File(config.outputDir))
+
+ binder.bindNameAnnotated<LocationService, SingleFolderLocationService>("singleFolder")
+ binder.bindNameAnnotated<FileLocationService, SingleFolderLocationService>("singleFolder")
+ binder.bindNameAnnotated<LocationService, FoldersLocationService>("folders")
+ binder.bindNameAnnotated<FileLocationService, FoldersLocationService>("folders")
+
+ // defaults
+ binder.bind(javaClass<LocationService>()).to(javaClass<FoldersLocationService>())
+ binder.bind(javaClass<FileLocationService>()).to(javaClass<FoldersLocationService>())
+ binder.bind(javaClass<LanguageService>()).to(javaClass<KotlinLanguageService>())
+
+ binder.bind(javaClass<HtmlTemplateService>()).toProvider(object : Provider<HtmlTemplateService> {
+ override fun get(): HtmlTemplateService = HtmlTemplateService.default("/dokka/styles/style.css")
+ })
+
+ binder.registerCategory<LanguageService>("language")
+ binder.registerCategory<OutlineFormatService>("outline")
+ binder.registerCategory<FormatService>("format")
+ binder.registerCategory<Generator>("generator")
+
+ val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", config.outputFormat, config)
+
+ descriptor.outlineServiceClass?.let { clazz ->
+ binder.bind(javaClass<OutlineFormatService>()).to(clazz)
+ }
+ descriptor.formatServiceClass?.let { clazz ->
+ binder.bind(javaClass<FormatService>()).to(clazz)
+ }
+ binder.bind(javaClass<Generator>()).to(descriptor.generatorServiceClass)
+ }
+
+}
+
+private inline fun <reified T> Binder.registerCategory(category: String) {
+ ServiceLocator.allServices(category).forEach {
+ @suppress("UNCHECKED_CAST")
+ bind(javaClass<T>()).annotatedWith(Names.named(it.name)).to(javaClass<T>().classLoader.loadClass(it.className) as Class<T>)
+ }
+}
+
+private inline fun <reified Base, reified T : Base> Binder.bindNameAnnotated(name: String) {
+ bind(javaClass<Base>()).annotatedWith(Names.named(name)).to(javaClass<T>())
+}
+
diff --git a/src/Utilities/ServiceLocator.kt b/src/Utilities/ServiceLocator.kt
new file mode 100644
index 00000000..e2ed0499
--- /dev/null
+++ b/src/Utilities/ServiceLocator.kt
@@ -0,0 +1,105 @@
+package org.jetbrains.dokka.Utilities
+
+import org.jetbrains.dokka.DokkaGenerator
+import java.io.File
+import java.util.Properties
+import java.util.jar.JarFile
+import java.util.zip.ZipEntry
+
+data class ServiceDescriptor(val name: String, val category: String, val description: String?, val className: String)
+
+class ServiceLookupException(message: String) : Exception(message)
+
+public object ServiceLocator {
+ public fun <T : Any> lookup(clazz: Class<T>, category: String, implementationName: String, conf: DokkaGenerator): T {
+ val descriptor = lookupDescriptor(category, implementationName)
+ val loadedClass = javaClass.classLoader.loadClass(descriptor.className)
+ val constructor = loadedClass.constructors
+ .filter { it.parameterTypes.isEmpty() || (it.parameterTypes.size() == 1 && conf.javaClass.isInstance(it.parameterTypes[0])) }
+ .sortDescendingBy { it.parameterTypes.size() }
+ .firstOrNull() ?: throw ServiceLookupException("Class ${descriptor.className} has no corresponding constructor")
+
+ val implementationRawType: Any = if (constructor.parameterTypes.isEmpty()) constructor.newInstance() else constructor.newInstance(constructor)
+
+ if (!clazz.isInstance(implementationRawType)) {
+ throw ServiceLookupException("Class ${descriptor.className} is not a subtype of ${clazz.name}")
+ }
+
+ @suppress("UNCHECKED_CAST")
+ return implementationRawType as T
+ }
+
+ public fun <T> lookupClass(clazz: Class<T>, category: String, implementationName: String): Class<T> = lookupDescriptor(category, implementationName).className.let { className ->
+ javaClass.classLoader.loadClass(className).let { loaded ->
+ if (!clazz.isAssignableFrom(loaded)) {
+ throw ServiceLookupException("Class $className is not a subtype of ${clazz.name}")
+ }
+
+ @suppress("UNCHECKED_CAST")
+ val casted = loaded as Class<T>
+
+ casted
+ }
+ }
+
+ private fun lookupDescriptor(category: String, implementationName: String): ServiceDescriptor {
+ val properties = javaClass.classLoader.getResourceAsStream("dokka/$category/$implementationName.properties")?.use { stream ->
+ Properties().let { properties ->
+ properties.load(stream)
+ properties
+ }
+ } ?: throw ServiceLookupException("No implementation with name $implementationName found in category $category")
+
+ val className = properties["class"]?.toString() ?: throw ServiceLookupException("Implementation $implementationName has no class configured")
+
+ return ServiceDescriptor(implementationName, category, properties["description"]?.toString(), className)
+ }
+
+ fun allServices(category: String): List<ServiceDescriptor> = javaClass.classLoader.getResourceAsStream("dokka/$category")?.use { stream ->
+ val entries = this.javaClass.classLoader.getResources("dokka/$category")?.toList() ?: emptyList()
+
+ entries.flatMap {
+ when (it.protocol) {
+ "file" -> File(it.file).listFiles()?.filter { it.extension == "properties" }?.map { lookupDescriptor(category, it.nameWithoutExtension) } ?: emptyList()
+ "jar" -> {
+ val file = JarFile(it.file.removePrefix("file:").substringBefore("!"))
+ try {
+ val jarPath = it.file.substringAfterLast("!").removePrefix("/")
+ file.entries()
+ .asSequence()
+ .filter { entry -> !entry.isDirectory && entry.path == jarPath && entry.extension == "properties" }
+ .map { entry ->
+ lookupDescriptor(category, entry.fileName.substringBeforeLast("."))
+ }.toList()
+ } finally {
+ file.close()
+ }
+ }
+ else -> emptyList<ServiceDescriptor>()
+ }
+ }
+ } ?: emptyList()
+}
+
+public inline fun <reified T : Any> ServiceLocator.lookup(category: String, implementationName: String, conf: DokkaGenerator): T = lookup(javaClass<T>(), category, implementationName, conf)
+public inline fun <reified T : Any> ServiceLocator.lookupClass(category: String, implementationName: String): Class<T> = lookupClass(javaClass<T>(), category, implementationName)
+public inline fun <reified T : Any> ServiceLocator.lookupOrNull(category: String, implementationName: String, conf: DokkaGenerator): T? = try {
+ lookup(javaClass<T>(), category, implementationName, conf)
+} catch (any: Throwable) {
+ null
+}
+
+fun main(args: Array<String>) {
+ ServiceLocator.allServices("format").forEach {
+ println(it)
+ }
+}
+
+private val ZipEntry.fileName: String
+ get() = name.substringAfterLast("/", name)
+
+private val ZipEntry.path: String
+ get() = name.substringBeforeLast("/", "").removePrefix("/")
+
+private val ZipEntry.extension: String?
+ get() = fileName.let { fn -> if ("." in fn) fn.substringAfterLast(".") else null }
diff --git a/src/main.kt b/src/main.kt
index 4a0c22f8..29a22672 100644
--- a/src/main.kt
+++ b/src/main.kt
@@ -1,5 +1,6 @@
package org.jetbrains.dokka
+import com.google.inject.Guice
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiFile
@@ -7,6 +8,7 @@ import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.sampullara.cli.Args
import com.sampullara.cli.Argument
+import org.jetbrains.dokka.Utilities.GuiceModule
import org.jetbrains.kotlin.cli.common.arguments.ValueDescription
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
@@ -17,6 +19,7 @@ import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
+import kotlin.util.measureTimeMillis
class DokkaArguments {
Argument(value = "src", description = "Source file or directory (allows many paths separated by the system path separator)")
@@ -141,8 +144,8 @@ class DokkaGenerator(val logger: DokkaLogger,
fun generate() {
val environment = createAnalysisEnvironment()
- logger.info("Module: ${moduleName}")
- logger.info("Output: ${File(outputDir).getAbsolutePath()}")
+ logger.info("Module: $moduleName")
+ logger.info("Output: ${File(outputDir).absolutePath}")
logger.info("Sources: ${environment.sources.join()}")
logger.info("Classpath: ${environment.classpath.joinToString()}")
@@ -155,34 +158,12 @@ class DokkaGenerator(val logger: DokkaLogger,
val timeAnalyse = System.currentTimeMillis() - startAnalyse
logger.info("done in ${timeAnalyse / 1000} secs")
- val startBuild = System.currentTimeMillis()
- val signatureGenerator = KotlinLanguageService()
- val locationService = FoldersLocationService(outputDir)
- val templateService = HtmlTemplateService.default("/dokka/styles/style.css")
-
- val (formatter, outlineFormatter) = when (outputFormat) {
- "html" -> {
- val htmlFormatService = HtmlFormatService(locationService, signatureGenerator, templateService)
- htmlFormatService to htmlFormatService
- }
- "markdown" -> MarkdownFormatService(locationService, signatureGenerator) to null
- "jekyll" -> JekyllFormatService(locationService.withExtension("html"), signatureGenerator) to null
- "kotlin-website" -> KotlinWebsiteFormatService(locationService.withExtension("html"), signatureGenerator) to
- YamlOutlineService(locationService, signatureGenerator)
- else -> {
- logger.error("Unrecognized output format ${outputFormat}")
- null to null
- }
+ val timeBuild = measureTimeMillis {
+ logger.info("Generating pages... ")
+ Guice.createInjector(GuiceModule(this)).getInstance(javaClass<Generator>()).buildAll(documentation)
}
- if (formatter == null) return
-
- val generator = FileGenerator(signatureGenerator, locationService.withExtension(formatter.extension),
- formatter, outlineFormatter)
- logger.info("Generating pages... ")
- generator.buildPage(documentation)
- generator.buildOutline(documentation)
- val timeBuild = System.currentTimeMillis() - startBuild
logger.info("done in ${timeBuild / 1000} secs")
+
Disposer.dispose(environment)
}