mirror of
https://github.com/ethauvin/kobalt-doc.git
synced 2025-04-25 03:57:11 -07:00
645 lines
20 KiB
HTML
645 lines
20 KiB
HTML
<html>
|
|
<head>
|
|
<title>
|
|
|
|
Kobalt, by Cedric Beust
|
|
|
|
</title>
|
|
|
|
<!-- Bootstrap core CSS -->
|
|
|
|
<link href="../bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
|
|
|
|
<!-- Optional Bootstrap Theme -->
|
|
|
|
<link href="data:text/css;charset=utf-8," data-href="../bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet" id="bs-theme-stylesheet">
|
|
|
|
|
|
<!--[if lt IE 9]><script src="../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
|
|
<!--
|
|
<script src="../bootstrap/assets/js/ie-emulation-modes-warning.js"></script>
|
|
-->
|
|
|
|
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
|
<!--[if lt IE 9]>
|
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
|
<![endif]-->
|
|
|
|
<!-- Favicons -->
|
|
<!--
|
|
<link rel="icon" href="/favicon.ico">
|
|
-->
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
|
|
<div class="container">
|
|
|
|
<!-- Static navbar -->
|
|
<nav class="navbar navbar-default">
|
|
<div class="container-fluid">
|
|
<div class="navbar-header">
|
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
|
<span class="sr-only">Toggle navigation</span>
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
</button>
|
|
<a class="navbar-brand">Kobalt</a>
|
|
</div>
|
|
<div id="navbar" class="navbar-collapse collapse">
|
|
<ul class="nav navbar-nav">
|
|
<li><a href="../home/index.html">Home</a></li>
|
|
<li class="active"><a href="../documentation/index.html">Documentation</a></li>
|
|
<li><a href="../plug-in/index.html">A plug-in in 10mn</a></li>
|
|
</ul>
|
|
</div><!--/.nav-collapse -->
|
|
</div><!--/.container-fluid -->
|
|
</nav>
|
|
|
|
<!-- Main component for a primary marketing message or call to action -->
|
|
<div class="jumbotron">
|
|
<h1>Kobalt</h1>
|
|
<p>A universal build system for the exigent developer.</p>
|
|
<!--
|
|
<p>
|
|
<a class="btn btn-lg btn-primary" href="../../components/#navbar" role="button">Download »</a>
|
|
</p>
|
|
-->
|
|
</div>
|
|
|
|
|
|
<div class="col-md-9">
|
|
|
|
<p>
|
|
Curious to see what a Kobalt build file looks like? Here is <a href="http://jcommander.org">JCommander's entire Kobalt build file</a>:
|
|
</p>
|
|
|
|
<pre>
|
|
import com.beust.kobalt.*
|
|
import com.beust.kobalt.plugin.java.*
|
|
import com.beust.kobalt.plugin.packaging.*
|
|
import com.beust.kobalt.plugin.publish.*
|
|
|
|
val jcommander = javaProject {
|
|
name = "jcommander"
|
|
group = "com.beust"
|
|
artifactId = name
|
|
version = "1.52"
|
|
|
|
dependenciesTest {
|
|
compile("org.testng:testng:6.9.5")
|
|
}
|
|
}
|
|
|
|
val a = assemble(jcommander) {
|
|
mavenJars {
|
|
}
|
|
}
|
|
|
|
val j = jcenter(jcommander) {
|
|
publish = false
|
|
}
|
|
</pre>
|
|
<h2 id="downloading">Downloading and installing Kobalt</h3>
|
|
|
|
<p>
|
|
<a href="https://github.com/cbeust/kobalt/releases/latest">Download the zip file</a> then unzip it in a location we'll call <code>KOBALT_HOME</code>:
|
|
</p>
|
|
|
|
<pre>
|
|
cd $KOBALT_HOME
|
|
unzip kobalt-xxx.zip
|
|
</pre>
|
|
|
|
<p>
|
|
Change to your project directory and call the <code>kobaltw</code> command with <code>--init</code>:
|
|
</p>
|
|
|
|
<pre>
|
|
cd ~/java/project
|
|
$KOBALT_HOME/kobaltw --init
|
|
</pre>
|
|
|
|
<p>
|
|
This command will do two things:
|
|
</p>
|
|
|
|
<ol>
|
|
<li>Create a default <code>Build.kt</code> file in your current directory based on what was found there.
|
|
<li>Install the Kobalt Wrapper in your current directory (script `kobaltw`) and in the <code>kobalt/</code> directory. From now on, you can just use <code>./kobaltw</code> to build and you can ignore <code>$KOBALT_HOME</code>.
|
|
</ol>
|
|
|
|
<p>
|
|
You can now attempt to build your project with Kobalt:
|
|
</p>
|
|
|
|
<pre>
|
|
./kobaltw assemble
|
|
</pre>
|
|
|
|
If your project follows a regular build structure (e.g. Maven's hierarchy), this should compile your file and create a .jar file. If not, you will have to make a few edits to your <code>Build.kt</code>.
|
|
|
|
As of this writing, Kobalt supports Java and Kotlin projects.
|
|
|
|
<h2 id="structure">Structure of a build file</h2>
|
|
|
|
<h3 id="general-concepts">General concepts</h3>
|
|
|
|
<p>
|
|
The build file is typically called <code>Built.kt</code> and it is a valid Kotlin file. Typically, it contains imports, the declaration of one or more projects and the declaration of additional configurations (e.g. packaging, publishing, etc...). Since it's a Kotlin file, it can also contain any class or function you need:
|
|
</p>
|
|
|
|
<pre>
|
|
import com.beust.kobalt.*
|
|
import com.beust.kobalt.plugin.kotlin.kotlinProject
|
|
|
|
val kobalt = kotlinProject {
|
|
name = "kobalt"
|
|
group = "com.beust"
|
|
artifactId = name
|
|
version = "0.62"
|
|
directory = homeDir("kotlin/kobalt")
|
|
}
|
|
</pre>
|
|
|
|
Here are a few noteworthy details about this small build file:
|
|
|
|
<ul>
|
|
<li>You have now declared a variable called <code>kobalt</code> which you can reuse (see below).
|
|
<li>You can specify the directory of the project, which means that one build file can be used to build multiple projects.
|
|
<li>The functions <code>kotlinProject</code> and <code>homeDir</code> are supplied by Kobalt and are sometimes referred to as "directives"
|
|
</ul>
|
|
|
|
<h3 id="directives">Directives</h3>
|
|
|
|
<p>
|
|
Now that we have declared a project, we can use it to configure additional steps of our build, such as the assembling it (creating jar and other files:
|
|
</p>
|
|
|
|
<pre>
|
|
import com.beust.kobalt.plugin.packaging.assemble
|
|
|
|
// ...
|
|
|
|
val packKobalt = assemble(kobalt) {
|
|
jar {
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
This is the simplest jar declaration you can have. You can trigger the creation of this jar file by invoking the task <code>"assemble"</code>. Note that we passed the <code>kobalt</code> variable to the <code>assemble</code> function, so we make it clear which project we are currently configuring for packaging. The <code>jar</code> directive accepts various settings, so let's be a bit more specific. And let's add a zip file too:
|
|
</p>
|
|
|
|
<pre>
|
|
val assembleKobalt = assemble(kobalt) {
|
|
jar {
|
|
fatJar = true
|
|
manifest {
|
|
attributes("Main-Class", "com.beust.kobalt.KobaltPackage")
|
|
}
|
|
}
|
|
zip {
|
|
include("kobaltw")
|
|
include(from("${kobalt.buildDirectory}/libs"),
|
|
to("kobalt/wrapper"),
|
|
"${kobalt.name}-${kobalt.version}.jar",
|
|
"${kobalt.name}-wrapper.jar")
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
Our jar file is now declared to be a "fat jar" (which means it will include all its dependencies) and we specified a <code>Main-Class</code> to the jar Manifest, which means we will be able to invoke it with <code>java -jar kobalt-0.61.jar</code>. If you don't like this name, you can override it with a <code>name = "myName.jar"</code> statement.
|
|
</p>
|
|
|
|
<p>
|
|
The zip directive follows a similar structure, although here we are specifying which file we want to include. For more details on the <code>packaging</code> plug-in, please see its documentation.
|
|
</p>
|
|
|
|
<h3>Dependencies</h3>
|
|
|
|
<p>
|
|
You can declare compile and test dependencies as follows:
|
|
</p>
|
|
|
|
<pre>
|
|
dependencies {
|
|
compile("com.beust:jcommander:1.48",
|
|
"com.beust:klaxon:0.14")
|
|
}
|
|
|
|
dependenciesTest {
|
|
compile("org.testng:testng:6.9.5")
|
|
}
|
|
</pre>
|
|
|
|
<h2 id="maven-repos">Maven repos</h2>
|
|
|
|
<p>
|
|
Kobalt already knows the location of the most popular Maven repos (Maven Central, JCenter, JBoss) but you can add repos with the <code>repos()</code> directive:
|
|
</p>
|
|
|
|
<pre>
|
|
val repos = repos("https://dl.bintray.com/cbeust/maven/")
|
|
</pre>
|
|
|
|
<h2 id="using-plug-ins">Using plug-ins</h2>
|
|
|
|
<p>
|
|
Kobalt comes with a few preconfigured plug-ins but you will want to include external ones as well, which can be downloaded either from a Maven repository (Sonatype, JCenter, ...) or from a local file.
|
|
</p>
|
|
|
|
<p>
|
|
First of all, let's take a quick look at the tasks available in the default distribution (your actual output might differ somewhat):
|
|
</p>
|
|
|
|
<pre>
|
|
$ ./kobaltw --tasks
|
|
===== java =====
|
|
compile Compile the project
|
|
compileTest Compile the tests
|
|
test Run the tests
|
|
clean Clean the project
|
|
|
|
===== publish =====
|
|
generatePom Generate the .pom file
|
|
uploadJcenter Upload the artifacts to JCenter
|
|
|
|
===== packaging =====
|
|
assemble Package the artifacts
|
|
</pre>
|
|
|
|
<p>
|
|
Let's modify our build to include a plug-in. We do this by adding a call to the <code>plugins</code> directive on top of the build file:
|
|
</p>
|
|
|
|
<pre>
|
|
val repos = repos("https://dl.bintray.com/cbeust/maven/")
|
|
val p = plugins("com.beust:kobalt-example-plugin:0.42")
|
|
</pre>
|
|
|
|
<p>
|
|
Now, run the <code>--tasks</code> command again:
|
|
</p>
|
|
|
|
<pre>
|
|
$ ./kobaltw --tasks
|
|
===== java =====
|
|
compile Compile the project
|
|
|
|
===== publish =====
|
|
generatePom Generate the .pom file
|
|
uploadJcenter Upload the artifacts to JCenter
|
|
|
|
===== kobalt-example-plugin =====
|
|
coverage Run coverage
|
|
|
|
===== packaging =====
|
|
assemble Package the artifacts
|
|
</pre>
|
|
|
|
Notice the new <code>"coverage"</code> task, provided by the plug-in <code>kobalt-example-plugin</code> that we just included. With the simple action of declaring the plug-in, it is now fully loaded and available right away. Of course, such plug-ins can allow or require additional configuration with their own directives. Please read the plug-in developer documentation for more details.
|
|
|
|
<h2 id="multiple-projects">Multiple projects</h2>
|
|
|
|
<p>
|
|
You can specify more than one project in a build file, simply by declaring them:
|
|
</p>
|
|
|
|
<pre>
|
|
val p1 = javaProject { ... }
|
|
val p2 = kotlinProject { ... }
|
|
</pre>
|
|
|
|
<p>
|
|
If some of your projects need to be built in a certain order, you can specify dependencies when you create your project. For example:
|
|
</p>
|
|
|
|
<pre>
|
|
val p2 = kotlinProject(p1) { ... }
|
|
</pre>
|
|
|
|
<p>
|
|
This declares that the Kotlin project <code>p2</code> depends on <code>p1</code>, which means that the project <code>p1</code> will be built first.
|
|
</p>
|
|
|
|
<p>
|
|
You can also run tasks for a specific project only as follows:
|
|
</p>
|
|
|
|
<pre>
|
|
./kobaltw p2:assemble
|
|
</pre>
|
|
|
|
This will run the <code>assemble</code> task only for the <code>p2</code>, instead of running it for all projects.
|
|
|
|
<h2 id="command-line">Command line</h2>
|
|
|
|
<p>
|
|
Here are the options that you can pass to <code>./kobaltw</code>:
|
|
</p>
|
|
|
|
<table style="font-size: 14px" class="table table-striped">
|
|
<colgroup>
|
|
<col span="1" style="width: 20%;">
|
|
<col span="1" style="width: 10%;">
|
|
<col span="1" style="width: 30%;">
|
|
<col span="1" style="width: 30%;">
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<td>Name</td>
|
|
<td>Type</td>
|
|
<td>Description</td>
|
|
<td>Details</td>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tr>
|
|
<td><code>--buildFile</code></td>
|
|
<td>File</td>
|
|
<td>Specify a build file.</td>
|
|
<td>Use this option if you are trying to build a project that's not in the current directory.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>--checkVersions</code></td>
|
|
<td>Boolean</td>
|
|
<td>Display all the new versions of your dependencies.</td>
|
|
<td>This option looks at all the dependencies found in your build file and then contacts all the Maven repositories in order to find out if any of these repos contains a newer version. If any are found, they are displayed:
|
|
<pre>
|
|
$ ./kobaltw --checkVersions
|
|
New versions found:
|
|
com.beust:klaxon:0.14
|
|
org.testng:testng:6.9.5
|
|
</pre>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>--init</code></td>
|
|
<td>Boolean</td>
|
|
<td>Initialize a project for Kobalt.</td>
|
|
<td>This option will create a build file in the current directory (unless one already exists) and will install the Kobalt wrapper.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>--log</code></td>
|
|
<td>Integer (0..3)</td>
|
|
<td>Specify the log level.</td>
|
|
<td>The default level is 1. Level 0 will quiet everything and 2 and 3 will display increasingly verbose output.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>--tasks</code></td>
|
|
<td>Boolean</td>
|
|
<td>List the tasks available.</td>
|
|
<td>Note that the available tasks will vary depending on which projects are in your build file.</td>
|
|
</tr>
|
|
</table>
|
|
|
|
|
|
<h2 id="publishing">Publishing</h2>
|
|
|
|
<p>
|
|
Kobalt supports JCenter natively so you can upload your project and make it available on JCenter very easily.
|
|
</p>
|
|
|
|
<p>
|
|
|
|
First of all, make sure you specified the group, artifactId and version of your project, as required by Maven:
|
|
</p>
|
|
|
|
<pre>
|
|
val kobalt = kotlinProject {
|
|
group = "com.beust"
|
|
artifactId = "kobalt"
|
|
version = "0.72"
|
|
</pre>
|
|
|
|
<p>
|
|
Next, create a file <code>local.properties</code> in the root directory of your project with the following keys:
|
|
</p>
|
|
|
|
<pre>
|
|
bintray.user=...
|
|
bintray.apikey=...
|
|
</pre>
|
|
|
|
<p>
|
|
The values for the <code>user</code> and <code>apikey</code> keys can be found in your bintray profile, as described <a href="https://bintray.com/docs/usermanual/interacting/interacting_editingyouruserprofile.html#anchorAPIKEY">here</a>. Note that you should <b>not</b> check this <code>local.properties</code> file into your source control (so add it to <code>.gitignore</code>). Next, make sure that your build creates a jar file (using the <code>packaging</code> directive, as explained above).
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
Now, all you need to do is to upload your package:
|
|
|
|
</p>
|
|
|
|
<pre>
|
|
./gradlew uploadJcenter
|
|
</pre>
|
|
|
|
<h2 id="writing-a-plug-in">Writing a plug-in</h2>
|
|
|
|
A good starting point to write a plug-in is the <a href="https://github.com/cbeust/kobalt-line-count">kobalt-line-count project</a>, which shows a minimalistic plug-in.
|
|
|
|
<h3 id="building">Building</h3>
|
|
|
|
You only need to do two things to build a Kobalt plug-in:
|
|
|
|
<h4>1. Add Kobalt as a dependency:</h4>
|
|
|
|
<pre>
|
|
dependencies {
|
|
compile("com.beust:kobalt:0.61")
|
|
}
|
|
</pre>
|
|
|
|
<h4>2. Declare the main class of your plug-in in the Jar file's manifest:</h4>
|
|
|
|
<pre>
|
|
val p = packaging(examplePlugin) {
|
|
jar {
|
|
manifest {
|
|
attributes("Kobalt-Plugin-Class", "com.beust.kobalt.example.ExamplePlugin")
|
|
}
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<h3 id="implementing">Implementing</h3>
|
|
|
|
A plug-in typically has three components:
|
|
|
|
<ul>
|
|
<li>Extending and implementing the methods of <code>BasePlugin</code>.
|
|
<li>Specifying one or more tasks.
|
|
<li>Specifying directives (functions that will be used from the build file).
|
|
</ul>
|
|
|
|
<h3 id="base-plugin">BasePlugin</h3>
|
|
|
|
<p>
|
|
The main class of your plugin extends <code>BasePlugin</code> and implements its <code>apply()</code> method and <code>name</code> variable:
|
|
</p>
|
|
|
|
<pre>
|
|
public class ExamplePlugin : BasePlugin() {
|
|
override val name = "kobalt-example-plugin"
|
|
|
|
override fun apply(project: Project, context: KobaltContext) {
|
|
println("Applying plugin ${name} with project ${project}")
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<h3 id="plugin-tasks">Plugin tasks</h3>
|
|
|
|
<p>
|
|
Next, you can declare tasks with the <code>@Task</code> annotation:
|
|
</p>
|
|
|
|
<pre>
|
|
@Task(name = "coverage", description = "Run coverage",
|
|
runAfter = arrayOf("compile"))
|
|
public fun coverage(project: Project): TaskResult {
|
|
println("Running the coverage on project ${project}")
|
|
return TaskResult()
|
|
}
|
|
</pre>
|
|
|
|
<ul>
|
|
<li>Tasks return a <code>TaskResult</code> object, which can be initialized with <code>false</code> if the task didn't succeed for some reason.
|
|
<li>The name of the task is the same name that can be passed to the <code>kobaltw</code> command (e.g. <code>"./kobaltw coverage"</code>)
|
|
<li>The description is what is displayed with <code>"./kobaltw --tasks"</code>
|
|
<li><code>runAfter</code> and <code>runBefore</code> let you specify the dependencies of your task. In this example plug-in, we want to calculate the coverage of the project so it makes sense to run after the <code>"compile"</code> task.
|
|
</ul>
|
|
|
|
<h3 id="plugin-directives">Directives</h3>
|
|
|
|
<p>
|
|
Finally, you need to define functions that can be used from the build file (directives). You are encouraged to use the <a href="https://confluence.jetbrains.com/display/Kotlin/Type-safe+Groovy-style+builders">Kotlin DSL approach</a> to expose these functions so that the build file syntax can remain consistent. Typically, these functions will update data that your tasks can then use to do their job.
|
|
</p>
|
|
|
|
<p>
|
|
|
|
These can be either straight functions or extension functions. For example, here is the <code>kotlinProject</code> directive:
|
|
|
|
<pre>
|
|
@Directive
|
|
public fun kotlinProject(init: KotlinProject.() -> Unit): KotlinProject {
|
|
val result = KotlinProject()
|
|
result.init()
|
|
return result
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
This function returns a <code>KotlinProject</code> and the user can then override variables or invoke methods from this class in their build file:
|
|
</p>
|
|
|
|
<pre>
|
|
val kobalt = kotlinProject {
|
|
name = "kobalt"
|
|
group = "com.beust"
|
|
...
|
|
</pre>
|
|
|
|
<p>
|
|
Using an extension function to define a directive allows you to add new functions to Kobalt classes. For example, currently, a project can have <code>"dependencies"</code> and <code>"dependenciesTest"</code>. For a coverage plug-in, we would want to add a <code>"dependenciesCoverage"</code> section, which can be easily done by defining an extension function on <code>Project</code>:
|
|
</p>
|
|
|
|
|
|
<pre>
|
|
@Directive
|
|
public fun Project.dependenciesCoverage(ini: Dependencies.() -> Unit) : Dependencies {
|
|
val result = Dependencies()
|
|
result.init()
|
|
return result
|
|
}
|
|
</pre>
|
|
|
|
<p>
|
|
And we can now use:
|
|
</p>
|
|
|
|
<pre>
|
|
val p = kotlinProject {
|
|
dependenciesCoverage("com.example:foo:0.1")
|
|
}
|
|
</pre>
|
|
|
|
<h2 id="sources">Sources and license</h2>
|
|
|
|
<p>
|
|
Kobalt is <a href="https://github.com/cbeust/kobalt/blob/master/LICENSE.txt">licensed under Apache 2.0</a> and is <a href="http://github.com/cbeust/kobalt">currently hosted on github.</a>
|
|
</p>
|
|
|
|
<h2 id="discuss">Discuss Kobalt</h2>
|
|
|
|
<p>
|
|
If you are interested in discussing Kobalt related topics with other fellow users or developers, you have several options:
|
|
</p>
|
|
|
|
<ul>
|
|
<li>Live discussions are happening on Kotlin's Slack Channel, managed by JetBrains. You can get an automated invitation <a href="http://kotlinslackin.herokuapp.com/">here</a> and then, just join the <code>#kobalt</code> channel.
|
|
</li>
|
|
<li><a href="https://groups.google.com/forum/#!forum/kobalt-users">Join <code>kobalt-users</code>, the mailing-list for Kobalt users.</a></li>
|
|
<li><a href="https://groups.google.com/forum/#!forum/kobalt-dev">Join <code>kobalt-dev</code>, the mailing-list for Kobalt developers</a>. This mailing-list is for people interested in writing code for Kobalt, either the core, or writing plug-ins, or just to follow various technical discussions about Kobalt's internals.</li>
|
|
</ul>
|
|
|
|
<p>
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- Table of contents -->
|
|
<div class="col-md-3">
|
|
<ul class="nav">
|
|
<li><a href="#downloading">Downloading and installing</a>
|
|
<li><a href="#structure">Structure of a build file</a>
|
|
<ul>
|
|
<li><a href="#general-concepts">General concepts</a>
|
|
<li><a href="#directives">Directives</a>
|
|
<li><a href="#dependencies">Dependencies</a>
|
|
</ul>
|
|
<li><a href="#maven-repos">Maven repos</a>
|
|
<li><a href="#using-plug-ins">Using plug-ins</a>
|
|
<li><a href="#publishing">Publishing</a>
|
|
<li><a href="#multiple-projects">Multiple projects</a>
|
|
<li><a href="#command-line">Command line arguments</a>
|
|
<li><a href="#writing-a-plug-in">Writing a plug-in</a>
|
|
<ul>
|
|
<li><a href="#building">Building</a>
|
|
<li><a href="#implemeting">Implementing</a>
|
|
<li><a href="#base-plugin"><code>BasePlugin</code></a>
|
|
<li><a href="#plugin-tasks">Plugin tasks</a>
|
|
<li><a href="#plugin-directives">Directives
|
|
</ul>
|
|
<li><a href="#sources">Sources</a>
|
|
<li><a href="#discuss">Discuss Kobalt</a>
|
|
</ul>
|
|
</div>
|
|
|
|
</div> <!-- /container -->
|
|
|
|
<!-- Bootstrap core JavaScript
|
|
================================================== -->
|
|
<!-- Placed at the end of the document so the pages load faster -->
|
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
|
<script src="../bootstrap/dist/js/bootstrap.min.js"></script>
|
|
<!--
|
|
<script src="../bootstrap/dist/js/docs.min.js"></script>
|
|
-->
|
|
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
|
<!--
|
|
<script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
|
|
-->
|
|
|
|
</body>
|