Merge remote-tracking branch 'origin/master' into develop
diff --git a/README.md b/README.md
index 25137f1..428551f 100644
--- a/README.md
+++ b/README.md
@@ -2,46 +2,50 @@
 
 Library support for Kotlin coroutines. This is a companion version for Kotlin 1.1.0 release. 
 
-## Modules and features
+## Modules
 
-* [kotlinx-coroutines-core](kotlinx-coroutines-core) module with core primitives to work with coroutines. 
-  * This module's functionality is covered by the [guide to kotlinx.coroutines](coroutines-guide.md). 
-* [kotlinx-coroutines-jdk8](kotlinx-coroutines-jdk8) module with additional libraries for JDK8 (or Android API level 24).
-* [kotlinx-coroutines-nio](kotlinx-coroutines-nio) module with extensions for asynchronous IO on JDK7+.
-* [kotlinx-coroutines-swing](kotlinx-coroutines-swing) module with `Swing` context for Swing UI applications.
-* [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx) module with `JavaFx` context for JavaFX UI applications.
-* [kotlinx-coroutines-reactive](kotlinx-coroutines-reactive) module with utilities for [Reactive Streams](http://www.reactive-streams.org)
-* [kotlinx-coroutines-rx1](kotlinx-coroutines-rx1) module with utilities for [RxJava 1.x](https://github.com/ReactiveX/RxJava/tree/1.x)
-* [kotlinx-coroutines-rx2](kotlinx-coroutines-rx2) module with utilities for [RxJava 2.x](https://github.com/ReactiveX/RxJava)
+Basic modules:
+
+* [kotlinx-coroutines-core](kotlinx-coroutines-core) -- core primitives to work with coroutines. 
+* [kotlinx-coroutines-jdk8](kotlinx-coroutines-jdk8) -- additional libraries for JDK8 (or Android API level 24).
+* [kotlinx-coroutines-nio](kotlinx-coroutines-nio) -- extensions for asynchronous IO on JDK7+.
+
+Modules that provide builders and iteration support for various reactive streams libraries:
+
+* [kotlinx-coroutines-reactive](reactive/kotlinx-coroutines-reactive) -- utilities for [Reactive Streams](http://www.reactive-streams.org)
+* [kotlinx-coroutines-rx1](reactive/kotlinx-coroutines-rx1) -- utilities for [RxJava 1.x](https://github.com/ReactiveX/RxJava/tree/1.x)
+* [kotlinx-coroutines-rx2](reactive/kotlinx-coroutines-rx2) -- utilities for [RxJava 2.x](https://github.com/ReactiveX/RxJava)
+
+Modules that provide coroutine dispatchers for various single-threaded UI libraries:
+
+* [kotlinx-coroutines-android](ui/kotlinx-coroutines-android) -- `UI` context for Android applications.
+* [kotlinx-coroutines-javafx](ui/kotlinx-coroutines-javafx) -- `JavaFx` context for JavaFX UI applications.
+* [kotlinx-coroutines-swing](ui/kotlinx-coroutines-swing) -- `Swing` context for Swing UI applications.
  
-## References and documentation
+## Documentation
 
-* [Guide to kotlinx.coroutines by example](coroutines-guide.md) 
+* [Guide to kotlinx.coroutines by example](coroutines-guide.md) (**read it first**)
+* [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
 * [Change log for kotlinx.coroutines](CHANGES.md)
 * [Coroutines design document (KEEP)](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md)
+* [Full kotlinx.coroutines API reference](http://kotlin.github.io/kotlinx.coroutines)
  
 ## Using in your projects
 
 > Note that these libraries are experimental and are subject to change.
 
-The libraries are published to [kotlin-eap-1.1](https://bintray.com/kotlin/kotlin-eap-1.1/kotlinx.coroutines) bintray repository.
-
+The libraries are available via [JCenter](https://bintray.com/bintray/jcenter).
 These libraries require kotlin compiler version to be at least `1.1.0` and 
 require kotlin runtime of the same version as a dependency.
 
 ### Maven
 
-Add the bintray repository to `<repositories>` section (and also add `pluginRepository` to `<pluginRepositories>`,
-if you're willing to get `kotlin-maven-plugin` from there):
+Add Bintray JCenter repository to `<repositories>` section:
 
 ```xml
 <repository>
-    <snapshots>
-        <enabled>false</enabled>
-    </snapshots>
-    <id>dl</id>
-    <name>bintray</name>
-    <url>http://dl.bintray.com/kotlin/kotlin-eap-1.1</url>
+    <id>central</id>
+    <url>http://jcenter.bintray.com</url>
 </repository>
 ```
 
@@ -65,13 +69,11 @@
 
 ### Gradle
 
-Add the bintray repository (and also add it to `buildScript` section, if you're willing to get `kotlin-gradle-plugin` from there):
+Add Bintray JCenter repository:
 
 ```groovy
 repositories {
-    maven {
-        url "http://dl.bintray.com/kotlin/kotlin-eap-1.1"
-    }
+    jcenter()
 }
 ```
 
diff --git a/coroutines-guide.md b/coroutines-guide.md
index edb6374..6a16d6f 100644
--- a/coroutines-guide.md
+++ b/coroutines-guide.md
@@ -102,6 +102,7 @@
   * [Selecting to send](#selecting-to-send)
   * [Selecting deferred values](#selecting-deferred-values)
   * [Switch over a channel of deferred values](#switch-over-a-channel-of-deferred-values)
+* [Further reading](#further-reading)
 
 <!--- END_TOC -->
 
@@ -795,7 +796,7 @@
     val jobs = arrayListOf<Job>()
     jobs += launch(Unconfined) { // not confined -- will work with main thread
         println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
-        delay(1000)
+        delay(500)
         println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}")
     }
     jobs += launch(context) { // context of the parent, runBlocking coroutine
@@ -807,7 +808,7 @@
 }
 ```
 
-> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-contest-02.kt)
+> You can get full code [here](kotlinx-coroutines-core/src/test/kotlin/guide/example-context-02.kt)
 
 Produces the output: 
  
@@ -2150,6 +2151,12 @@
 
 <!--- TEST -->
 
+## Further reading
+
+* [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
+* [Coroutines design document (KEEP)](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md)
+* [Full kotlinx.coroutines API reference](http://kotlin.github.io/kotlinx.coroutines)
+
 <!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core -->
 <!--- DOCS_ROOT kotlinx-coroutines-core/target/dokka/kotlinx-coroutines-core -->
 <!--- INDEX kotlinx.coroutines.experimental -->
diff --git a/knit/src/Knit.kt b/knit/src/Knit.kt
index 67bd4c5..9552355 100644
--- a/knit/src/Knit.kt
+++ b/knit/src/Knit.kt
@@ -67,7 +67,7 @@
     val test = arrayListOf<String>()
     var testOut: PrintWriter? = null
     var lastPgk: String? = null
-    val files = mutableSetOf<String>()
+    val files = mutableSetOf<File>()
     val allApiRefs = arrayListOf<ApiRef>()
     val remainingApiRefNames = mutableSetOf<String>()
     var siteRoot: String? = null
@@ -190,8 +190,9 @@
             }
             knitRegex?.find(inLine)?.let { knitMatch ->
                 val fileName = knitMatch.groups[1]!!.value
-                require(files.add(fileName)) { "Duplicate file name: $fileName"}
-                println("Knitting $fileName ...")
+                val file = File(markdownFile.parentFile, fileName)
+                require(files.add(file)) { "Duplicate file: $file"}
+                println("Knitting $file ...")
                 val outLines = arrayListOf<String>()
                 for (include in includes) {
                     val includeMatch = include.regex.matchEntire(fileName) ?: continue
@@ -204,7 +205,6 @@
                 }
                 outLines += code
                 code.clear()
-                val file = File(fileName)
                 val oldLines = try { file.readLines() } catch (e: IOException) { emptyList<String>() }
                 if (outLines != oldLines) writeLines(file, outLines)
             }
@@ -401,7 +401,6 @@
     namePrefix: String = ""
 ): Map<String, String> {
     val fileName = docsRoot + "/" + path + INDEX_MD
-    println("Reading index from $fileName")
     val visited = mutableSetOf<String>()
     val map = HashMap<String,String>()
     File(fileName).withLineNumberReader<LineNumberReader>(::LineNumberReader) {
@@ -431,7 +430,12 @@
     remainingApiRefNames: MutableSet<String>
 ): List<String> {
     val key = ApiIndexKey(docsRoot, pkg)
-    val map = apiIndexCache.getOrPut(key, { loadApiIndex(docsRoot, pkg, pkg) })
+    val map = apiIndexCache.getOrPut(key, {
+        print("Parsing API docs at $docsRoot: ")
+        val result = loadApiIndex(docsRoot, pkg, pkg)
+        println("${result.size} definitions")
+        result
+    })
     val indexList = arrayListOf<String>()
     val it = remainingApiRefNames.iterator()
     while (it.hasNext()) {
diff --git a/kotlinx-coroutines-core/README.md b/kotlinx-coroutines-core/README.md
index 8ba91dc..efc003b 100644
--- a/kotlinx-coroutines-core/README.md
+++ b/kotlinx-coroutines-core/README.md
@@ -19,7 +19,7 @@
 | [CommonPool]                | Confines coroutine execution to a shared pool of threads
 | [newSingleThreadContext]    | Create new single-threaded coroutine context
 | [newFixedThreadPoolContext] | Creates new thread pool of a fixed size 
-| [Executor.toCoroutineDispatcher][java.util.concurrent.Executor.toCoroutineDispatcher] | Extension to convert any executor
+| [Executor.asCoroutineDispatcher][java.util.concurrent.Executor.asCoroutineDispatcher] | Extension to convert any executor
 | [Unconfined]                | Does not confine coroutine execution in any way
 
 Synchronization primitives for coroutines:
@@ -86,7 +86,7 @@
 [CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html
 [newSingleThreadContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-single-thread-context.html
 [newFixedThreadPoolContext]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/new-fixed-thread-pool-context.html
-[java.util.concurrent.Executor.toCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/java.util.concurrent.-executor/to-coroutine-dispatcher.html
+[java.util.concurrent.Executor.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/java.util.concurrent.-executor/as-coroutine-dispatcher.html
 [Unconfined]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-unconfined/index.html
 [delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html
 [yield]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/yield.html
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt
index 4db38bb..833824e 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Builders.kt
@@ -18,6 +18,8 @@
 
 import java.util.concurrent.locks.LockSupport
 import kotlin.coroutines.experimental.*
+import kotlin.coroutines.experimental.intrinsics.startCoroutineUninterceptedOrReturn
+import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn
 
 // --------------- basic coroutine builders ---------------
 
@@ -58,10 +60,28 @@
  * different thread inside the block, and back when it completes.
  * The specified [context] is added onto the current coroutine context for the execution of the block.
  */
-public suspend fun <T> run(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T =
-    suspendCoroutine { cont ->
-        // new don't invoke `newCoroutineContext`, but consider this being the same coroutine in the new context
-        InnerCoroutine(cont.context + context, cont).also { block.startCoroutine(it, it) }
+public suspend fun <T> run(context: CoroutineContext, block: suspend () -> T): T =
+    suspendCoroutineOrReturn sc@ { cont ->
+        val oldContext = cont.context
+        // fast path #1 if there is no change in the actual context:
+        if (context === oldContext || context is CoroutineContext.Element && oldContext[context.key] === context)
+            return@sc block.startCoroutineUninterceptedOrReturn(cont)
+        // compute new context
+        val newContext = oldContext + context
+        // fast path #2 if the result is actually the same
+        if (newContext === oldContext)
+            return@sc block.startCoroutineUninterceptedOrReturn(cont)
+        // fast path #3 if the new dispatcher is the same as the old one
+        if (newContext[ContinuationInterceptor] === oldContext[ContinuationInterceptor]) {
+            val newContinuation = RunContinuationDirect(newContext, cont)
+            return@sc block.startCoroutineUninterceptedOrReturn(newContinuation)
+        }
+        // slowest path otherwise -- use new interceptor, sync to its result via a
+        // full-blown instance of CancellableContinuation
+        val newContinuation = RunContinuationCoroutine(newContext, cont)
+        newContinuation.initCancellability()
+        block.startCoroutine(newContinuation)
+        newContinuation.getResult()
     }
 
 /**
@@ -81,11 +101,11 @@
 @Throws(InterruptedException::class)
 public fun <T> runBlocking(context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T): T {
     val currentThread = Thread.currentThread()
-    val privateEventLoop = if (context[ContinuationInterceptor] == null) EventLoopImpl(currentThread) else null
-    val newContext = newCoroutineContext(context + (privateEventLoop ?: EmptyCoroutineContext))
-    val coroutine = BlockingCoroutine<T>(newContext, currentThread, privateEventLoop != null)
+    val eventLoop = if (context[ContinuationInterceptor] == null) EventLoopImpl(currentThread) else null
+    val newContext = newCoroutineContext(context + (eventLoop ?: EmptyCoroutineContext))
+    val coroutine = BlockingCoroutine<T>(newContext, currentThread, privateEventLoop = eventLoop != null)
     coroutine.initParentJob(context[Job])
-    privateEventLoop?.initParentJob(coroutine)
+    eventLoop?.initParentJob(coroutine)
     block.startCoroutine(coroutine, coroutine)
     return coroutine.joinBlocking()
 }
@@ -104,27 +124,34 @@
 
 private class LazyStandaloneCoroutine(
     parentContext: CoroutineContext,
-    val block: suspend CoroutineScope.() -> Unit
+    private val block: suspend CoroutineScope.() -> Unit
 ) : StandaloneCoroutine(parentContext, active = false) {
     override fun onStart() {
         block.startCoroutine(this, this)
     }
 }
 
-private class InnerCoroutine<in T>(
+private class RunContinuationDirect<in T>(
     override val context: CoroutineContext,
     continuation: Continuation<T>
-) : Continuation<T> by continuation, CoroutineScope {
-    override val isActive: Boolean = context[Job]?.isActive ?: true
-}
+) : Continuation<T> by continuation
+
+private class RunContinuationCoroutine<in T>(
+    override val parentContext: CoroutineContext,
+    continuation: Continuation<T>
+) : CancellableContinuationImpl<T>(continuation, active = true)
 
 private class BlockingCoroutine<T>(
     override val parentContext: CoroutineContext,
-    val blockedThread: Thread,
-    val hasPrivateEventLoop: Boolean
+    private val blockedThread: Thread,
+    private val privateEventLoop: Boolean
 ) : AbstractCoroutine<T>(active = true) {
     val eventLoop: EventLoop? = parentContext[ContinuationInterceptor] as? EventLoop
 
+    init {
+        if (privateEventLoop) require(eventLoop is EventLoopImpl)
+    }
+
     override fun afterCompletion(state: Any?, mode: Int) {
         if (Thread.currentThread() != blockedThread)
             LockSupport.unpark(blockedThread)
@@ -132,15 +159,15 @@
 
     @Suppress("UNCHECKED_CAST")
     fun joinBlocking(): T {
-        while (isActive) {
+        while (true) {
             if (Thread.interrupted()) throw InterruptedException().also { cancel(it) }
-            if (eventLoop == null || !eventLoop.processNextEvent())
-                LockSupport.park(this)
+            val parkNanos = eventLoop?.processNextEvent() ?: Long.MAX_VALUE
+            // note: process next even may look unpark flag, so check !isActive before parking
+            if (!isActive) break
+            LockSupport.parkNanos(this, parkNanos)
         }
-        // process remaining events (that could have been added after last processNextEvent and before cancel
-        if (hasPrivateEventLoop) {
-            while (eventLoop!!.processNextEvent()) { /* just spin */ }
-        }
+        // process queued events (that could have been added after last processNextEvent and before cancel
+        if (privateEventLoop) (eventLoop as EventLoopImpl).shutdown()
         // now return result
         val state = this.state
         (state as? CompletedExceptionally)?.let { throw it.exception }
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CancellableContinuation.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CancellableContinuation.kt
index 0d92c15..569ed0f 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CancellableContinuation.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CancellableContinuation.kt
@@ -179,7 +179,7 @@
     }
 
     override fun initCancellability() {
-        initParentJob(delegate.context[Job])
+        initParentJob(parentContext[Job])
     }
 
     @PublishedApi
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt
index ac7e1c4..19a23d6 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CoroutineDispatcher.kt
@@ -34,7 +34,7 @@
  *   a common pool of shared background threads.
  *   This is an appropriate choice for compute-intensive coroutines that consume a lot of CPU resources.
  * * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext].
- * * An arbitrary [Executor][java.util.concurrent.Executor] can be converted to dispatcher with [toCoroutineDispatcher] extension function.
+ * * An arbitrary [Executor][java.util.concurrent.Executor] can be converted to dispatcher with [asCoroutineDispatcher] extension function.
  *
  * This class ensures that debugging facilities in [newCoroutineContext] function work properly.
  */
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt
index 91dad91..2e69343 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Deferred.kt
@@ -155,7 +155,7 @@
 
     @Suppress("UNCHECKED_CAST")
     private suspend fun awaitSuspend(): T = suspendCancellableCoroutine { cont ->
-        cont.unregisterOnCompletion(invokeOnCompletion {
+        cont.disposeOnCompletion(invokeOnCompletion {
             val state = this.state
             check(state !is Incomplete)
             if (state is CompletedExceptionally)
@@ -183,7 +183,7 @@
             }
             if (startInternal(state) == 0) {
                 // slow-path -- register waiter for completion
-                select.unregisterOnCompletion(invokeOnCompletion(SelectAwaitOnCompletion(this, select, block)))
+                select.disposeOnSelect(invokeOnCompletion(SelectAwaitOnCompletion(this, select, block)))
                 return
             }
         }
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Delay.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Delay.kt
index 24c0aa3..e6daa03 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Delay.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Delay.kt
@@ -16,12 +16,16 @@
 
 package kotlinx.coroutines.experimental
 
+import java.util.concurrent.Future
 import java.util.concurrent.TimeUnit
 import kotlin.coroutines.experimental.ContinuationInterceptor
 
 /**
  * This dispatcher _feature_ is implemented by [CoroutineDispatcher] implementations that natively support
- * non-blocking [delay] function.
+ * scheduled execution of tasks.
+ *
+ * Implementation of this interface affects operation of
+ * [delay][kotlinx.coroutines.experimental.delay] and [withTimeout] functions.
  */
 public interface Delay {
     /**
@@ -52,6 +56,16 @@
      * ```
      */
     fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>)
+
+    /**
+     * Schedules invocation of a specified [block] after a specified delay [time].
+     * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] of this invocation
+     * request if it is not needed anymore.
+     *
+     * This implementation uses a built-in single-threaded scheduled executor service.
+     */
+    fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle =
+        DisposableFutureHandle(scheduledExecutor.schedule(block, time, unit))
 }
 
 /**
@@ -60,18 +74,26 @@
  * If the [Job] of the current coroutine is completed while this suspending function is suspended, this function
  * immediately resumes with [CancellationException].
  *
- * This function delegates to [Delay] implementation of the context [CoroutineDispatcher] if possible,
- * otherwise it resumes using a built-in single-threaded scheduled executor service.
+ * This function delegates to [Delay.scheduleResumeAfterDelay] if the context [CoroutineDispatcher]
+ * implements [Delay] interface, otherwise it resumes using a built-in single-threaded scheduled executor service.
  */
 suspend fun delay(time: Long, unit: TimeUnit = TimeUnit.MILLISECONDS) {
     require(time >= 0) { "Delay time $time cannot be negative" }
     if (time <= 0) return // don't delay
     return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
-        (cont.context[ContinuationInterceptor] as? Delay)?.apply {
-            scheduleResumeAfterDelay(time, unit, cont)
-            return@sc
-        }
-        val timeout = scheduledExecutor.schedule(ResumeRunnable(cont), time, unit)
-        cont.cancelFutureOnCompletion(timeout)
+        val delay = cont.context[ContinuationInterceptor] as? Delay
+        if (delay != null)
+            delay.scheduleResumeAfterDelay(time, unit, cont) else
+            cont.cancelFutureOnCompletion(scheduledExecutor.schedule(ResumeRunnable(cont), time, unit))
     }
 }
+
+/**
+ * An implementation of [DisposableHandle] that cancels the specified future on dispose.
+ */
+public class DisposableFutureHandle(private val future: Future<*>) : DisposableHandle {
+    override fun dispose() {
+        future.cancel(false)
+    }
+    override fun toString(): String = "DisposableFutureHandle[$future]"
+}
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt
index 041aa9c..632978a 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt
@@ -18,20 +18,29 @@
 
 import kotlinx.coroutines.experimental.internal.LockFreeLinkedListHead
 import kotlinx.coroutines.experimental.internal.LockFreeLinkedListNode
+import java.util.concurrent.ConcurrentSkipListMap
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicLong
 import java.util.concurrent.locks.LockSupport
 import kotlin.coroutines.experimental.CoroutineContext
 
 /**
  * Implemented by [CoroutineDispatcher] implementations that have event loop inside and can
- * be asked to process next event from their event queue. It is used by [runBlocking] to
+ * be asked to process next event from their event queue.
+ *
+ * It may optionally implement [Delay] interface and support time-scheduled tasks. It is used by [runBlocking] to
  * continue processing events when invoked from the event dispatch thread.
  */
 public interface EventLoop {
     /**
-     * Processes next event in this event loop and returns `true` or returns `false` if there are
-     * no events to process or when invoked from the wrong thread.
+     * Processes next event in this event loop.
+     *
+     * The result of this function is to be interpreted like this:
+     * * `<= 0` -- there are potentially more events for immediate processing;
+     * * `> 0` -- a number of nanoseconds to wait for next scheduled event;
+     * * [Long.MAX_VALUE] -- no more events, or was invoked from the wrong thread.
      */
-    public fun processNextEvent(): Boolean
+    public fun processNextEvent(): Long
 
     public companion object Factory {
         /**
@@ -43,7 +52,7 @@
          * ```
          * while (needsToBeRunning) {
          *     if (Thread.interrupted()) break // or handle somehow
-         *     if (!eventLoop.processNextEvent()) LockSupport.park() // event loop will unpark
+         *     LockSupport.parkNanos(eventLoop.processNextEvent()) // event loop will unpark
          * }
          * ```
          */
@@ -55,10 +64,12 @@
 }
 
 internal class EventLoopImpl(
-    val thread: Thread
-) : CoroutineDispatcher(), EventLoop {
-    val queue = LockFreeLinkedListHead()
-    var parentJob: Job? = null
+    private val thread: Thread
+) : CoroutineDispatcher(), EventLoop, Delay {
+    private val queue = LockFreeLinkedListHead()
+    private val delayed = ConcurrentSkipListMap<DelayedTask, DelayedTask>()
+    private val nextSequence = AtomicLong()
+    private var parentJob: Job? = null
 
     fun initParentJob(coroutine: Job) {
         require(this.parentJob == null)
@@ -66,37 +77,127 @@
     }
 
     override fun dispatch(context: CoroutineContext, block: Runnable) {
-        schedule(Dispatch(block))
-    }
-
-    fun schedule(node: Node): Boolean {
-        val added = if (parentJob == null) {
-            queue.addLast(node)
-            true
-        } else
-            queue.addLastIf(node) { !parentJob!!.isCompleted }
-        if (added) {
-            if (Thread.currentThread() !== thread)
-                LockSupport.unpark(thread)
+        if (scheduleQueued(QueuedRunnableTask(block))) {
+            unpark()
         } else {
-            node.run()
+            block.run()
         }
-        return added
     }
 
-    override fun processNextEvent(): Boolean {
-        if (Thread.currentThread() !== thread) return false
-        (queue.removeFirstOrNull() as? Runnable)?.apply {
-            run()
+    override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
+        if (scheduleDelayed(DelayedResumeTask(time, unit, continuation))) {
+            // todo: we should unpark only when this delayed task became first in the queue
+            unpark()
+        } else {
+            scheduledExecutor.schedule(ResumeRunnable(continuation), time, unit)
+        }
+    }
+
+    override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle =
+        DelayedRunnableTask(time, unit, block).also { scheduleDelayed(it) }
+
+    override fun processNextEvent(): Long {
+        if (Thread.currentThread() !== thread) return Long.MAX_VALUE
+        // queue all delayed tasks that are due to be executed
+        while (true) {
+            val delayedTask = delayed.firstEntry()?.key ?: break
+            val now = System.nanoTime()
+            if (delayedTask.nanoTime - now > 0) break
+            if (!scheduleQueued(delayedTask)) break
+            delayed.remove(delayedTask)
+        }
+        // then process one event from queue
+        (queue.removeFirstOrNull() as? QueuedTask)?.let { queuedTask ->
+            queuedTask()
+        }
+        if (!queue.isEmpty) return 0
+        val nextDelayedTask = delayed.firstEntry()?.key ?: return Long.MAX_VALUE
+        return nextDelayedTask.nanoTime - System.nanoTime()
+    }
+
+    fun shutdown() {
+        // complete processing of all queued tasks
+        while (true) {
+            val queuedTask = (queue.removeFirstOrNull() ?: break) as QueuedTask
+            queuedTask()
+        }
+        // cancel all delayed tasks
+        while (true) {
+            val delayedTask = delayed.pollFirstEntry()?.key ?: break
+            delayedTask.cancel()
+        }
+    }
+
+    override fun toString(): String = "EventLoopImpl@${Integer.toHexString(System.identityHashCode(this))}"
+
+    private fun scheduleQueued(queuedTask: QueuedTask): Boolean {
+        if (parentJob == null) {
+            queue.addLast(queuedTask)
             return true
         }
+        return queue.addLastIf(queuedTask, { !parentJob!!.isCompleted })
+    }
+
+    private fun scheduleDelayed(delayedTask: DelayedTask): Boolean {
+        delayed.put(delayedTask, delayedTask)
+        if (parentJob?.isActive != false) return true
+        delayedTask.dispose()
         return false
     }
 
-    abstract class Node : LockFreeLinkedListNode(), Runnable
+    private fun unpark() {
+        if (Thread.currentThread() !== thread)
+            LockSupport.unpark(thread)
+    }
 
-    class Dispatch(block: Runnable) : Node(), Runnable by block
+    private abstract class QueuedTask : LockFreeLinkedListNode(), () -> Unit
 
-    override fun toString(): String = "EventLoopImpl@${Integer.toHexString(System.identityHashCode(this))}"
+    private class QueuedRunnableTask(
+        private val block: Runnable
+    ) : QueuedTask() {
+        override fun invoke() { block.run() }
+    }
+
+    private abstract inner class DelayedTask(
+        time: Long, timeUnit: TimeUnit
+    ) : QueuedTask(), Comparable<DelayedTask>, DisposableHandle {
+        @JvmField val nanoTime: Long = System.nanoTime() + timeUnit.toNanos(time)
+        @JvmField val sequence: Long = nextSequence.getAndIncrement()
+
+        override fun compareTo(other: DelayedTask): Int {
+            val dTime = nanoTime - other.nanoTime
+            if (dTime > 0) return 1
+            if (dTime < 0) return -1
+            val dSequence = sequence - other.sequence
+            return if (dSequence > 0) 1 else if (dSequence < 0) -1 else 0
+        }
+
+        override final fun dispose() {
+            delayed.remove(this)
+            cancel()
+        }
+
+        open fun cancel() {}
+    }
+
+    private inner class DelayedResumeTask(
+        time: Long, timeUnit: TimeUnit,
+        private val cont: CancellableContinuation<Unit>
+    ) : DelayedTask(time, timeUnit) {
+        override fun invoke() {
+            with(cont) { resumeUndispatched(Unit) }
+        }
+        override fun cancel() {
+            if (!cont.isActive) return
+            val remaining = nanoTime - System.nanoTime()
+            scheduledExecutor.schedule(ResumeRunnable(cont), remaining, TimeUnit.NANOSECONDS)
+        }
+    }
+
+    private inner class DelayedRunnableTask(
+        time: Long, timeUnit: TimeUnit,
+        private val block: Runnable
+    ) : DelayedTask(time, timeUnit) {
+        override fun invoke() { block.run() }
+    }
 }
-
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Executors.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Executors.kt
index f0be651..072bcce 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Executors.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Executors.kt
@@ -24,11 +24,22 @@
 
 /**
  * Converts an instance of [Executor] to an implementation of [CoroutineDispatcher].
+ * @suppress **Deprecated**: Renamed to [asCoroutineDispatcher].
  */
+@Deprecated("Renamed to `asCoroutineDispatcher`",
+    replaceWith = ReplaceWith("asCoroutineDispatcher()"))
 public fun Executor.toCoroutineDispatcher(): CoroutineDispatcher =
     ExecutorCoroutineDispatcher(this)
 
-internal open class ExecutorCoroutineDispatcher(val executor: Executor) : CoroutineDispatcher(), Delay {
+/**
+ * Converts an instance of [Executor] to an implementation of [CoroutineDispatcher].
+ */
+public fun Executor.asCoroutineDispatcher(): CoroutineDispatcher =
+    ExecutorCoroutineDispatcher(this)
+
+internal open class ExecutorCoroutineDispatcher(
+    private val executor: Executor
+) : CoroutineDispatcher(), Delay {
     override fun dispatch(context: CoroutineContext, block: Runnable) = executor.execute(block)
 
     override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
@@ -37,20 +48,29 @@
             scheduledExecutor.schedule(ResumeRunnable(continuation), time, unit)
         continuation.cancelFutureOnCompletion(timeout)
     }
+
+    override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle {
+        val timeout = if (executor is ScheduledExecutorService)
+            executor.schedule(block, time, unit) else
+            scheduledExecutor.schedule(block, time, unit)
+        return DisposableFutureHandle(timeout)
+    }
 }
 
 // --- reusing these classes in other places ---
 
 internal class ResumeUndispatchedRunnable(
-    val dispatcher: CoroutineDispatcher,
-    val continuation: CancellableContinuation<Unit>
+    private val dispatcher: CoroutineDispatcher,
+    private val continuation: CancellableContinuation<Unit>
 ) : Runnable {
     override fun run() {
         with(continuation) { dispatcher.resumeUndispatched(Unit) }
     }
 }
 
-internal class ResumeRunnable(val continuation: Continuation<Unit>) : Runnable {
+internal class ResumeRunnable(
+    private val continuation: Continuation<Unit>
+) : Runnable {
     override fun run() {
         continuation.resume(Unit)
     }
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Job.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Job.kt
index 18cba3a..503f9a7 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Job.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Job.kt
@@ -102,18 +102,14 @@
      * Registers handler that is **synchronously** invoked on completion of this job.
      * When job is already complete, then the handler is immediately invoked
      * with a cancellation cause or `null`. Otherwise, handler will be invoked once when this
-     * job is complete. Note, that [cancellation][cancel] is also a form of completion).
+     * job is complete. Note, that [cancellation][cancel] is also a form of completion.
      *
-     * The resulting [Registration] can be used to [Registration.unregister] if this
-     * registration is no longer needed. There is no need to unregister after completion.
+     * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] the
+     * registration of this handler and release its memory if its invocation is no longer needed.
+     * There is no need to dispose the handler after completion of this job. The reference to
+     * all the handlers are released when this job completes.
      */
-    public fun invokeOnCompletion(handler: CompletionHandler): Registration
-
-    /**
-     * @suppress **Deprecated**: Renamed to `invokeOnCompletion`
-     */
-    @Deprecated(message = "Renamed to `invokeOnCompletion`", replaceWith = ReplaceWith("invokeOnCompletion(handler)"))
-    public fun onCompletion(handler: CompletionHandler): Registration
+    public fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
 
     /**
      * Suspends coroutine until this job is complete. This invocation resumes normally (without exception)
@@ -161,16 +157,41 @@
     /**
      * Registration object for [invokeOnCompletion]. It can be used to [unregister] if needed.
      * There is no need to unregister after completion.
+     * @suppress **Deprecated**: Replace with `DisposableHandle`
      */
+    @Deprecated(message = "Replace with `DisposableHandle`",
+        replaceWith = ReplaceWith("DisposableHandle"))
     public interface Registration {
         /**
          * Unregisters completion handler.
+         * @suppress **Deprecated**: Replace with `dispose`
          */
+        @Deprecated(message = "Replace with `dispose`",
+            replaceWith = ReplaceWith("dispose()"))
         public fun unregister()
     }
 }
 
 /**
+ * A handle to an allocated object that can be disposed to make it eligible for garbage collection.
+ */
+public interface DisposableHandle : Job.Registration {
+    /**
+     * Disposes the corresponding object, making it eligible for garbage collection.
+     * Repeated invocation of this function has no effect.
+     */
+    public fun dispose()
+
+    /**
+     * Unregisters completion handler.
+     * @suppress **Deprecated**: Replace with `dispose`
+     */
+    @Deprecated(message = "Replace with `dispose`",
+        replaceWith = ReplaceWith("dispose()"))
+    public override fun unregister() = dispose()
+}
+
+/**
  * Handler for [Job.invokeOnCompletion].
  */
 public typealias CompletionHandler = (Throwable?) -> Unit
@@ -187,9 +208,23 @@
  * ```
  * invokeOnCompletion { registration.unregister() }
  * ```
+ * @suppress: **Deprecated**: Renamed to `disposeOnCompletion`.
  */
-public fun Job.unregisterOnCompletion(registration: Job.Registration): Job.Registration =
-    invokeOnCompletion(UnregisterOnCompletion(this, registration))
+@Deprecated(message = "Renamed to `disposeOnCompletion`",
+    replaceWith = ReplaceWith("disposeOnCompletion(registration)"))
+public fun Job.unregisterOnCompletion(registration: DisposableHandle): DisposableHandle =
+    invokeOnCompletion(DisposeOnCompletion(this, registration))
+
+/**
+ * Disposes a specified [handle] when this job is complete.
+ *
+ * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
+ * ```
+ * invokeOnCompletion { handle.dispose() }
+ * ```
+ */
+public fun Job.disposeOnCompletion(handle: DisposableHandle): DisposableHandle =
+    invokeOnCompletion(DisposeOnCompletion(this, handle))
 
 /**
  * Cancels a specified [future] when this job is complete.
@@ -199,7 +234,7 @@
  * invokeOnCompletion { future.cancel(false) }
  * ```
  */
-public fun Job.cancelFutureOnCompletion(future: Future<*>): Job.Registration =
+public fun Job.cancelFutureOnCompletion(future: Future<*>): DisposableHandle =
     invokeOnCompletion(CancelFutureOnCompletion(this, future))
 
 /**
@@ -212,12 +247,19 @@
 /**
  * No-op implementation of [Job.Registration].
  */
-public object EmptyRegistration : Job.Registration {
-    /** Does not do anything. */
-    override fun unregister() {}
+@Deprecated(message = "Replace with `NonDisposableHandle`",
+    replaceWith = ReplaceWith("NonDisposableHandle"))
+typealias EmptyRegistration = NonDisposableHandle
 
-    /** Returns "EmptyRegistration" string. */
-    override fun toString(): String = "EmptyRegistration"
+/**
+ * No-op implementation of [DisposableHandle].
+ */
+public object NonDisposableHandle : DisposableHandle {
+    /** Does not do anything. */
+    override fun dispose() {}
+
+    /** Returns "NonDisposableHandle" string. */
+    override fun toString(): String = "NonDisposableHandle"
 }
 
 // --------------- utility classes to simplify job implementation
@@ -280,7 +322,7 @@
     private var _state: Any? = if (active) EmptyActive else EmptyNew // shared objects while we have no listeners
 
     @Volatile
-    private var registration: Job.Registration? = null
+    private var parentHandle: DisposableHandle? = null
 
     protected companion object {
         @JvmStatic
@@ -298,16 +340,16 @@
      * It shall be invoked at most once after construction after all other initialization.
      */
     public fun initParentJob(parent: Job?) {
-        check(registration == null)
+        check(parentHandle == null)
         if (parent == null) {
-            registration = EmptyRegistration
+            parentHandle = NonDisposableHandle
             return
         }
         // directly pass HandlerNode to parent scope to optimize one closure object (see makeNode)
         val newRegistration = parent.invokeOnCompletion(ParentOnCompletion(parent, this))
-        registration = newRegistration
+        parentHandle = newRegistration
         // now check our state _after_ registering (see updateState order of actions)
-        if (isCompleted) newRegistration.unregister()
+        if (isCompleted) newRegistration.dispose()
     }
 
     internal open fun onParentCompletion(cause: Throwable?) {
@@ -326,23 +368,29 @@
     }
 
     /**
-     * Tries to update current [state] of this job.
+     * Updates current [state] of this job.
      */
-    internal fun updateState(expect: Any, update: Any?, mode: Int): Boolean {
+    protected fun updateState(expect: Any, update: Any?, mode: Int): Boolean {
         if (!tryUpdateState(expect, update)) return false
         completeUpdateState(expect, update, mode)
         return true
     }
 
-    internal fun tryUpdateState(expect: Any, update: Any?): Boolean  {
+    /**
+     * Tries to initiate update of the current [state] of this job.
+     */
+    protected fun tryUpdateState(expect: Any, update: Any?): Boolean  {
         require(expect is Incomplete && update !is Incomplete) // only incomplete -> completed transition is allowed
         if (!STATE.compareAndSet(this, expect, update)) return false
         // Unregister from parent job
-        registration?.unregister() // volatile read registration _after_ state was updated
+        parentHandle?.dispose() // volatile read parentHandle _after_ state was updated
         return true // continues in completeUpdateState
     }
 
-    internal fun completeUpdateState(expect: Any, update: Any?, mode: Int) {
+    /**
+     * Completes update of the current [state] of this job.
+     */
+    protected fun completeUpdateState(expect: Any, update: Any?, mode: Int) {
         // Invoke completion handlers
         val cause = (update as? CompletedExceptionally)?.cause
         var completionException: Throwable? = null
@@ -515,9 +563,7 @@
         }
     }
 
-    override fun onCompletion(handler: CompletionHandler): Job.Registration = invokeOnCompletion(handler)
-
-    final override fun invokeOnCompletion(handler: CompletionHandler): Job.Registration {
+    final override fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle {
         var nodeCache: JobNode<*>? = null
         while (true) { // lock-free loop on state
             val state = this.state
@@ -545,7 +591,7 @@
                 }
                 else -> { // is inactive
                     handler((state as? CompletedExceptionally)?.exception)
-                    return EmptyRegistration
+                    return NonDisposableHandle
                 }
             }
         }
@@ -560,7 +606,7 @@
     }
 
     private suspend fun joinSuspend() = suspendCancellableCoroutine<Unit> { cont ->
-        cont.unregisterOnCompletion(invokeOnCompletion(ResumeOnCompletion(this, cont)))
+        cont.disposeOnCompletion(invokeOnCompletion(ResumeOnCompletion(this, cont)))
     }
 
     override fun <R> registerSelectJoin(select: SelectInstance<R>, block: suspend () -> R) {
@@ -576,7 +622,7 @@
             }
             if (startInternal(state) == 0) {
                 // slow-path -- register waiter for completion
-                select.unregisterOnCompletion(invokeOnCompletion(SelectJoinOnCompletion(this, select, block)))
+                select.disposeOnSelect(invokeOnCompletion(SelectJoinOnCompletion(this, select, block)))
                 return
             }
         }
@@ -731,12 +777,12 @@
 
 internal abstract class JobNode<out J : Job>(
     @JvmField val job: J
-) : LockFreeLinkedListNode(), Job.Registration, CompletionHandler, JobSupport.Incomplete {
+) : LockFreeLinkedListNode(), DisposableHandle, CompletionHandler, JobSupport.Incomplete {
     final override val isActive: Boolean get() = true
     final override val idempotentStart: Any? get() = null
     // if unregister is called on this instance, then Job was an instance of JobSupport that added this node it itself
     // directly without wrapping
-    final override fun unregister() = (job as JobSupport).removeNode(this)
+    final override fun dispose() = (job as JobSupport).removeNode(this)
     override abstract fun invoke(reason: Throwable?)
 }
 
@@ -756,12 +802,12 @@
     override fun toString() = "ResumeOnCompletion[$continuation]"
 }
 
-internal class UnregisterOnCompletion(
+internal class DisposeOnCompletion(
     job: Job,
-    @JvmField val registration: Job.Registration
+    @JvmField val handle: DisposableHandle
 ) : JobNode<Job>(job) {
-    override fun invoke(reason: Throwable?) = registration.unregister()
-    override fun toString(): String = "UnregisterOnCompletion[$registration]"
+    override fun invoke(reason: Throwable?) = handle.dispose()
+    override fun toString(): String = "DisposeOnCompletion[$handle]"
 }
 
 private class ParentOnCompletion(
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/NonCancellable.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/NonCancellable.kt
index 69f68db..801d741 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/NonCancellable.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/NonCancellable.kt
@@ -57,10 +57,8 @@
     /** Always throws [IllegalStateException]. */
     override fun getCompletionException(): CancellationException = throw IllegalStateException("This job is always active")
 
-    override fun onCompletion(handler: CompletionHandler): Job.Registration = invokeOnCompletion(handler)
-
-    /** Always returns [EmptyRegistration]. */
-    override fun invokeOnCompletion(handler: CompletionHandler): Job.Registration = EmptyRegistration
+    /** Always returns [NonDisposableHandle]. */
+    override fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle = NonDisposableHandle
 
     /** Always returns `false`. */
     override fun cancel(cause: Throwable?): Boolean = false
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt
index d447ad5..7e47932 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt
@@ -16,10 +16,13 @@
 
 package kotlinx.coroutines.experimental
 
+import kotlinx.coroutines.experimental.intrinsics.startUndispatchedCoroutine
 import java.util.concurrent.ScheduledExecutorService
 import java.util.concurrent.ScheduledThreadPoolExecutor
 import java.util.concurrent.TimeUnit
-import kotlin.coroutines.experimental.startCoroutine
+import kotlin.coroutines.experimental.Continuation
+import kotlin.coroutines.experimental.ContinuationInterceptor
+import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn
 
 private val KEEP_ALIVE = java.lang.Long.getLong("kotlinx.coroutines.ScheduledExecutor.keepAlive", 1000L)
 
@@ -62,18 +65,32 @@
 /**
  * Runs a given suspending block of code inside a coroutine with a specified timeout and throws
  * [CancellationException] if timeout was exceeded.
+ *
+ * This function delegates to [Delay.invokeOnTimeout] if the context [CoroutineDispatcher]
+ * implements [Delay] interface, otherwise it tracks time using a built-in single-threaded scheduled executor service.
  */
-suspend fun <T> withTimeout(time: Long, unit: TimeUnit = TimeUnit.MILLISECONDS, block: suspend () -> T): T {
+public suspend fun <T> withTimeout(time: Long, unit: TimeUnit = TimeUnit.MILLISECONDS, block: suspend () -> T): T {
     require(time >= 0) { "Timeout time $time cannot be negative" }
     if (time <= 0L) throw CancellationException("Timed out immediately")
-    return suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
+    return suspendCoroutineOrReturn sc@ { delegate: Continuation<T> ->
         // schedule cancellation of this continuation on time
-        val timeout = scheduledExecutor.schedule({
-            // create an exception with a specific text
-            cont.cancel(CancellationException("Timed out waiting for $time $unit"))
-        }, time, unit)
-        cont.cancelFutureOnCompletion(timeout)
-        // restart block in a separate coroutine using cancellable context of this continuation,
-        block.startCoroutine(cont)
+        val cont = TimeoutContinuation(time, unit, delegate)
+        val delay = cont.context[ContinuationInterceptor] as? Delay
+        if (delay != null)
+            cont.disposeOnCompletion(delay.invokeOnTimeout(time, unit, cont)) else
+            cont.cancelFutureOnCompletion(scheduledExecutor.schedule(cont, time, unit))
+        // restart block using cancellable context of this continuation,
+        // however start it as undispatched coroutine, because we are already in the proper context
+        block.startUndispatchedCoroutine(cont)
+        cont.getResult()
     }
 }
+
+private class TimeoutContinuation<T>(
+    private val time: Long,
+    private val unit: TimeUnit,
+    delegate: Continuation<T>
+) : CancellableContinuationImpl<T>(delegate, active = true), Runnable {
+    override fun defaultResumeMode(): Int = MODE_DIRECT
+    override fun run() { cancel(CancellationException("Timed out waiting for $time $unit")) }
+}
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/ThreadPoolDispatcher.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/ThreadPoolDispatcher.kt
index 4cb12a7..c3df491 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/ThreadPoolDispatcher.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/ThreadPoolDispatcher.kt
@@ -72,4 +72,7 @@
         val timeout = executor.schedule(ResumeUndispatchedRunnable(this, continuation), time, unit)
         continuation.cancelFutureOnCompletion(timeout)
     }
+
+    override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle =
+        DisposableFutureHandle(executor.schedule(block, time, unit))
 }
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/AbstractChannel.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/AbstractChannel.kt
index 7fe9e6b..1cfe134 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/AbstractChannel.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/AbstractChannel.kt
@@ -146,9 +146,22 @@
     /**
      * @suppress **This is unstable API and it is subject to change.**
      */
+    protected fun sendConflated(element: E): Boolean {
+        val node = SendBuffered(element)
+        if (!queue.addLastIfPrev(node, { it !is ReceiveOrClosed<*> })) return false
+        // remove previous SendBuffered
+        val prev = node.prev
+        if (prev is SendBuffered<*>)
+            prev.remove()
+        return true
+    }
+
+    /**
+     * @suppress **This is unstable API and it is subject to change.**
+     */
     protected fun describeSendBuffered(element: E): AddLastDesc<*> = SendBufferedDesc(queue, element)
 
-    private class SendBufferedDesc<E>(
+    private open class SendBufferedDesc<out E>(
         queue: LockFreeLinkedListHead,
         element: E
     ) : AddLastDesc<SendBuffered<E>>(queue, SendBuffered(element)) {
@@ -158,6 +171,23 @@
         }
     }
 
+    /**
+     * @suppress **This is unstable API and it is subject to change.**
+     */
+    protected fun describeSendConflated(element: E): AddLastDesc<*> = SendConflatedDesc(queue, element)
+
+    private class SendConflatedDesc<out E>(
+        queue: LockFreeLinkedListHead,
+        element: E
+    ) : SendBufferedDesc<E>(queue, element) {
+        override fun finishOnSuccess(affected: LockFreeLinkedListNode, next: LockFreeLinkedListNode) {
+            super.finishOnSuccess(affected, next)
+            // remove previous SendBuffered
+            if (affected is SendBuffered<*>)
+                affected.remove()
+        }
+    }
+
     // ------ SendChannel ------
 
     public final override val isClosedForSend: Boolean get() = closedForSend != null
@@ -289,7 +319,7 @@
         override fun finishOnSuccess(affected: LockFreeLinkedListNode, next: LockFreeLinkedListNode) {
             super.finishOnSuccess(affected, next)
             // we can actually remove on select start, but this is also Ok (it'll get removed if discovered there)
-            node.removeOnSelectCompletion()
+            node.disposeOnSelect()
         }
     }
 
@@ -694,7 +724,7 @@
         override val pollResult: Any?,
         @JvmField val select: SelectInstance<R>,
         @JvmField val block: suspend () -> R
-    ) : LockFreeLinkedListNode(), Send, CompletionHandler {
+    ) : LockFreeLinkedListNode(), Send, DisposableHandle {
         override fun tryResumeSend(idempotent: Any?): Any? =
             if (select.trySelect(idempotent)) SELECT_STARTED else null
 
@@ -703,11 +733,11 @@
             block.startCoroutine(select.completion)
         }
 
-        fun removeOnSelectCompletion() {
-            select.invokeOnCompletion(this)
+        fun disposeOnSelect() {
+            select.disposeOnSelect(this)
         }
 
-        override fun invoke(cause: Throwable?) {
+        override fun dispose() {
             remove()
         }
 
@@ -820,7 +850,7 @@
         @JvmField val select: SelectInstance<R>,
         @JvmField val block: suspend (E?) -> R,
         @JvmField val nullOnClose: Boolean
-    ) : Receive<E>(), CompletionHandler {
+    ) : Receive<E>(), DisposableHandle {
         override fun tryResumeReceive(value: E, idempotent: Any?): Any?  =
             if (select.trySelect(idempotent)) (value ?: NULL_VALUE) else null
 
@@ -839,9 +869,11 @@
             }
         }
 
-        fun removeOnSelectCompletion() { select.invokeOnCompletion(this) }
+        fun removeOnSelectCompletion() {
+            select.disposeOnSelect(this)
+        }
 
-        override fun invoke(cause: Throwable?) { // invoked on select completion
+        override fun dispose() { // invoked on select completion
             if (remove())
                 onCancelledReceive() // notify cancellation of receive
         }
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Channel.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Channel.kt
index a07ba0c..7c661c6 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Channel.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Channel.kt
@@ -224,23 +224,31 @@
      */
     public companion object Factory {
         /**
-         * Requests channel with unlimited capacity buffer in [Channel()][invoke] factory function.
+         * Requests channel with unlimited capacity buffer in [Channel()][invoke] factory function --
+         * the [LinkedListChannel] gets created.
          */
         public const val UNLIMITED = Int.MAX_VALUE
 
         /**
+         * Requests conflated channel in [Channel()][invoke] factory function --
+         * the [ConflatedChannel] gets created.
+         */
+        public const val CONFLATED = -1
+
+        /**
          * Creates a channel with specified buffer capacity (or without a buffer by default).
          *
          * The resulting channel type depends on the specified [capacity] parameter:
          * * when `capacity` is 0 -- creates [RendezvousChannel];
          * * when `capacity` is [UNLIMITED] -- creates [LinkedListChannel];
+         * * when `capacity` is [CONFLATED] -- creates [ConflatedChannel];
          * * otherwise -- creates [ArrayChannel].
          */
         public operator fun <E> invoke(capacity: Int = 0): Channel<E> {
-            check(capacity >= 0) { "Channel capacity cannot be negative, but $capacity was specified" }
             return when (capacity) {
                 0 -> RendezvousChannel()
                 UNLIMITED -> LinkedListChannel()
+                CONFLATED -> ConflatedChannel()
                 else -> ArrayChannel(capacity)
             }
         }
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/ConflatedChannel.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/ConflatedChannel.kt
new file mode 100644
index 0000000..4d12000
--- /dev/null
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/ConflatedChannel.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.coroutines.experimental.channels
+
+import kotlinx.coroutines.experimental.ALREADY_SELECTED
+import kotlinx.coroutines.experimental.selects.SelectInstance
+
+/**
+ * Channel that buffers at most one element and conflates all subsequent `send` and `offer` invocations,
+ * so that the receiver always gets the most recently sent element.
+ * Back-to-send sent elements are _conflated_ -- only the the most recently sent element is received,
+ * while previously sent elements **are lost**.
+ * Sender to this channel never suspends and [offer] always returns `true`.
+ *
+ * This implementation is fully lock-free.
+ */
+public open class ConflatedChannel<E> : AbstractChannel<E>() {
+    protected final override val isBufferAlwaysEmpty: Boolean get() = true
+    protected final override val isBufferEmpty: Boolean get() = true
+    protected final override val isBufferAlwaysFull: Boolean get() = false
+    protected final override val isBufferFull: Boolean get() = false
+
+    // result is always `OFFER_SUCCESS | Closed`
+    protected override fun offerInternal(element: E): Any {
+        while (true) {
+            val result = super.offerInternal(element)
+            when {
+                result === OFFER_SUCCESS -> return OFFER_SUCCESS
+                result === OFFER_FAILED -> { // try to buffer
+                    if (sendConflated(element))
+                        return OFFER_SUCCESS
+                }
+                result is Closed<*> -> return result
+                else -> error("Invalid offerInternal result $result")
+            }
+        }
+    }
+
+    // result is always `ALREADY_SELECTED | OFFER_SUCCESS | Closed`.
+    protected override fun offerSelectInternal(element: E, select: SelectInstance<*>): Any {
+        while (true) {
+            val result = if (hasReceiveOrClosed)
+                super.offerSelectInternal(element, select) else
+                (select.performAtomicTrySelect(describeSendConflated(element)) ?: OFFER_SUCCESS)
+            when {
+                result === ALREADY_SELECTED -> return ALREADY_SELECTED
+                result === OFFER_SUCCESS -> return OFFER_SUCCESS
+                result === OFFER_FAILED -> {} // retry
+                result is Closed<*> -> return result
+                else -> error("Invalid result $result")
+            }
+        }
+    }
+}
+
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/Atomic.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/Atomic.kt
index a258d92..75cd679 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/Atomic.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/Atomic.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package kotlinx.coroutines.experimental.internal
 
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/LockFreeLinkedList.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/LockFreeLinkedList.kt
index b434602..30fbe1c 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/LockFreeLinkedList.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/internal/LockFreeLinkedList.kt
@@ -68,9 +68,9 @@
 @Suppress("LeakingThis")
 public open class LockFreeLinkedListNode {
     @Volatile
-    private var _next: Any = this // DoubleLinkedNode | Removed | OpDescriptor
+    private var _next: Any = this // Node | Removed | OpDescriptor
     @Volatile
-    private var _prev: Any = this // DoubleLinkedNode | Removed
+    private var _prev: Any = this // Node | Removed
     @Volatile
     private var _removedRef: Removed? = null // lazily cached removed ref to this
 
@@ -114,7 +114,7 @@
 
     public val isRemoved: Boolean get() = next is Removed
 
-    // LINEARIZABLE.
+    // LINEARIZABLE. Returns Node | Removed
     public val next: Any get() {
         while (true) { // operation helper loop on _next
             val next = this._next
@@ -123,10 +123,12 @@
         }
     }
 
-    // LINEARIZABLE. Note: use it on sentinel (never removed) node only
-    public val prev: Node get() {
-        while (true) {
-            val prev = this._prev as Node // this sentinel node is never removed
+    // LINEARIZABLE. Returns Node | Removed
+    public val prev: Any get() {
+        while (true) { // insert helper loop on _prev
+            val prev = this._prev
+            if (prev is Removed) return prev
+            prev as Node // otherwise, it can be only node otherwise
             if (prev.next === this) return prev
             helpInsert(prev, null)
         }
@@ -155,7 +157,7 @@
      */
     public fun addLast(node: Node) {
         while (true) { // lock-free loop on prev.next
-            val prev = prev
+            val prev = prev as Node // sentinel node is never removed, so prev is always defined
             if (prev.addNext(node, this)) return
         }
     }
@@ -168,7 +170,7 @@
     public inline fun addLastIf(node: Node, crossinline condition: () -> Boolean): Boolean {
         val condAdd = makeCondAddOp(node, condition)
         while (true) { // lock-free loop on prev.next
-            val prev = prev
+            val prev = prev as Node // sentinel node is never removed, so prev is always defined
             when (prev.tryCondAddNext(node, this, condAdd)) {
                 SUCCESS -> return true
                 FAILURE -> return false
@@ -178,7 +180,7 @@
 
     public inline fun addLastIfPrev(node: Node, predicate: (Node) -> Boolean): Boolean {
         while (true) { // lock-free loop on prev.next
-            val prev = prev
+            val prev = prev as Node // sentinel node is never removed, so prev is always defined
             if (!predicate(prev)) return false
             if (prev.addNext(node, this)) return true
         }
@@ -191,7 +193,7 @@
     ): Boolean {
         val condAdd = makeCondAddOp(node, condition)
         while (true) { // lock-free loop on prev.next
-            val prev = prev
+            val prev = prev as Node // sentinel node is never removed, so prev is always defined
             if (!predicate(prev)) return false
             when (prev.tryCondAddNext(node, this, condAdd)) {
                 SUCCESS -> return true
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/intrinsics/Undispatched.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/intrinsics/Undispatched.kt
index 9947590..43419fb 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/intrinsics/Undispatched.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/intrinsics/Undispatched.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package kotlinx.coroutines.experimental.intrinsics
 
 import kotlin.coroutines.experimental.Continuation
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/selects/Select.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/selects/Select.kt
index 1c7041f..815d7d9 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/selects/Select.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/selects/Select.kt
@@ -114,11 +114,10 @@
 
     public fun resumeSelectWithException(exception: Throwable, mode: Int)
 
-    public fun invokeOnCompletion(handler: CompletionHandler): Job.Registration
-
-    public fun unregisterOnCompletion(registration: Job.Registration)
-
-    public fun removeOnCompletion(node: LockFreeLinkedListNode)
+    // This function is actually implemented to dispose the handle only when the whole
+    // select expression complete. It is later than it could be, but if resource will get released anyway
+    // :todo: Invoke this function on select really
+    public fun disposeOnSelect(handle: DisposableHandle)
 }
 
 /**
@@ -241,19 +240,7 @@
         registerSelectLock(this@SelectBuilderImpl, owner, block)
     }
 
-    override fun unregisterOnCompletion(registration: Job.Registration) {
-        invokeOnCompletion(UnregisterOnCompletion(this, registration))
+    override fun disposeOnSelect(handle: DisposableHandle) {
+        invokeOnCompletion(DisposeOnCompletion(this, handle))
     }
-
-    override fun removeOnCompletion(node: LockFreeLinkedListNode) {
-        invokeOnCompletion(RemoveOnCompletion(this, node))
-    }
-}
-
-private class RemoveOnCompletion(
-    select: SelectBuilderImpl<*>,
-    @JvmField val node: LockFreeLinkedListNode
-) : JobNode<SelectBuilderImpl<*>>(select) {
-    override fun invoke(reason: Throwable?) { node.remove() }
-    override fun toString(): String = "RemoveOnCompletion[$node]"
 }
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/sync/Mutex.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/sync/Mutex.kt
index 26c1a5b..66d32b1 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/sync/Mutex.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/sync/Mutex.kt
@@ -232,7 +232,7 @@
                     val failure = select.performAtomicIfNotSelected(enqueueOp)
                     when {
                         failure == null -> { // successfully enqueued
-                            select.removeOnCompletion(enqueueOp.node)
+                            select.disposeOnSelect(enqueueOp.node)
                             return
                         }
                         failure === ALREADY_SELECTED -> return // already selected -- bail out
@@ -345,7 +345,8 @@
 
     private abstract class LockWaiter(
         @JvmField val owner: Any?
-    ) : LockFreeLinkedListNode() {
+    ) : LockFreeLinkedListNode(), DisposableHandle {
+        final override fun dispose() { remove() }
         abstract fun tryResumeLockWaiter(): Any?
         abstract fun completeResumeLockWaiter(token: Any)
     }
diff --git a/kotlinx-coroutines-core/src/test/kotlin/guide/example-contest-02.kt b/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-02.kt
similarity index 96%
rename from kotlinx-coroutines-core/src/test/kotlin/guide/example-contest-02.kt
rename to kotlinx-coroutines-core/src/test/kotlin/guide/example-context-02.kt
index 5d20be9..6a40e9b 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/guide/example-contest-02.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/guide/example-context-02.kt
@@ -15,7 +15,7 @@
  */
 
 // This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
-package guide.contest.example02
+package guide.context.example02
 
 import kotlinx.coroutines.experimental.*
 
@@ -23,7 +23,7 @@
     val jobs = arrayListOf<Job>()
     jobs += launch(Unconfined) { // not confined -- will work with main thread
         println(" 'Unconfined': I'm working in thread ${Thread.currentThread().name}")
-        delay(1000)
+        delay(500)
         println(" 'Unconfined': After delay in thread ${Thread.currentThread().name}")
     }
     jobs += launch(context) { // context of the parent, runBlocking coroutine
diff --git a/kotlinx-coroutines-core/src/test/kotlin/guide/test/GuideTest.kt b/kotlinx-coroutines-core/src/test/kotlin/guide/test/GuideTest.kt
index 3563934..58a4e43 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/guide/test/GuideTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/guide/test/GuideTest.kt
@@ -167,8 +167,8 @@
     }
 
     @Test
-    fun testGuideContestExample02() {
-        test { guide.contest.example02.main(emptyArray()) }.verifyLinesStart(
+    fun testGuideContextExample02() {
+        test { guide.context.example02.main(emptyArray()) }.verifyLinesStart(
             " 'Unconfined': I'm working in thread main",
             "    'context': I'm working in thread main",
             " 'Unconfined': After delay in thread kotlinx.coroutines.ScheduledExecutor",
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/CancellableContinuationImplTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/CancellableContinuationImplTest.kt
index 7c5afee..5139c9b 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/CancellableContinuationImplTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/CancellableContinuationImplTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package kotlinx.coroutines.experimental
 
 import org.junit.Test
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/ExecutorsTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/ExecutorsTest.kt
index 2d175ae..e802c4e 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/ExecutorsTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/ExecutorsTest.kt
@@ -78,7 +78,7 @@
     @Test
     fun testToExecutor() {
         val executor = Executors.newSingleThreadExecutor { r -> Thread(r, "TestExecutor") }
-        runBlocking(executor.toCoroutineDispatcher()) {
+        runBlocking(executor.asCoroutineDispatcher()) {
             checkThreadName("TestExecutor")
         }
         executor.shutdown()
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/LaunchLazyTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/LaunchLazyTest.kt
index 09d80b8..a24678b 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/LaunchLazyTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/LaunchLazyTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package kotlinx.coroutines.experimental
 
 import org.junit.Test
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/RunTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/RunTest.kt
new file mode 100644
index 0000000..5b13391
--- /dev/null
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/RunTest.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.coroutines.experimental
+
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.core.IsEqual
+import org.junit.Test
+
+class RunTest : TestBase() {
+    @Test
+    fun testSameContextNoSuspend() = runBlocking<Unit> {
+        expect(1)
+        launch(context) { // make sure there is not early dispatch here
+            finish(5)
+        }
+        expect(2)
+        val result = run(context) { // same context!
+            expect(3) // still here
+            "OK"
+        }
+        assertThat(result, IsEqual("OK"))
+        expect(4)
+    }
+
+    @Test
+    fun testSameContextWithSuspend() = runBlocking<Unit> {
+        expect(1)
+        launch(context) { // make sure there is not early dispatch here
+            expect(4)
+        }
+        expect(2)
+        val result = run(context) { // same context!
+            expect(3) // still here
+            yield() // now yields to launch!
+            expect(5)
+            "OK"
+        }
+        assertThat(result, IsEqual("OK"))
+        finish(6)
+    }
+
+    @Test
+    fun testCancelWithJobNoSuspend() = runBlocking<Unit> {
+        expect(1)
+        launch(context) { // make sure there is not early dispatch to here
+            finish(6)
+        }
+        expect(2)
+        val job = Job()
+        val result = run(context + job) { // same context + new job
+            expect(3) // still here
+            job.cancel() // cancel out job!
+            try {
+                yield() // shall throw CancellationException
+                expectUnreached()
+            } catch (e: CancellationException) {
+                expect(4)
+            }
+            "OK"
+        }
+        assertThat(result, IsEqual("OK"))
+        expect(5)
+    }
+
+    @Test
+    fun testCancelWithJobWithSuspend() = runBlocking<Unit> {
+        expect(1)
+        launch(context) { // make sure there is not early dispatch to here
+            expect(4)
+        }
+        expect(2)
+        val job = Job()
+        val result = run(context + job) { // same context + new job
+            expect(3) // still here
+            yield() // now yields to launch!
+            expect(5)
+            job.cancel() // cancel out job!
+            try {
+                yield() // shall throw CancellationExpcetion
+                expectUnreached()
+            } catch (e: CancellationException) {
+                expect(6)
+            }
+            "OK"
+        }
+        assertThat(result, IsEqual("OK"))
+        finish(7)
+    }
+
+    @Test
+    fun testCommonPoolNoSuspend() = runBlocking<Unit> {
+        expect(1)
+        val result = run(CommonPool) {
+            expect(2)
+            "OK"
+        }
+        assertThat(result, IsEqual("OK"))
+        finish(3)
+    }
+
+    @Test
+    fun testCommonPoolWithSuspend() = runBlocking<Unit> {
+        expect(1)
+        val result = run(CommonPool) {
+            expect(2)
+            delay(100)
+            expect(3)
+            "OK"
+        }
+        assertThat(result, IsEqual("OK"))
+        finish(4)
+    }
+}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/TestBase.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/TestBase.kt
index 0454fc3..712498b 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/TestBase.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/TestBase.kt
@@ -23,7 +23,7 @@
 
 open class TestBase {
     val isStressTest = System.getProperty("stressTest") != null
-    val stressTestMultiplier = if (isStressTest) 10 else 1
+    val stressTestMultiplier = if (isStressTest) 30 else 1
 
     var actionIndex = AtomicInteger()
     var finished = AtomicBoolean()
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/WithTimeoutTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/WithTimeoutTest.kt
new file mode 100644
index 0000000..fde334b
--- /dev/null
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/WithTimeoutTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.coroutines.experimental
+
+import org.junit.Test
+
+class WithTimeoutTest : TestBase() {
+    /**
+     * Tests property dispatching of `withTimeout` blocks
+     */
+    @Test
+    fun testDispatch() = runBlocking {
+        expect(1)
+        launch(context) {
+            expect(4)
+            yield() // back to main
+            expect(7)
+        }
+        expect(2)
+        // test that it does not yield to the above job when started
+        withTimeout(1000) {
+            expect(3)
+            yield() // yield only now
+            expect(5)
+        }
+        expect(6)
+        yield() // back to launch
+        finish(8)
+    }
+
+    /**
+     * Tests that a 100% CPU-consuming loop will react on timeout if it has yields.
+     */
+    @Test(expected = CancellationException::class)
+    fun testYieldBlockingWithTimeout() = runBlocking {
+        withTimeout(100) {
+            while (true) {
+                yield()
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelAtomicCancelStressTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelAtomicCancelStressTest.kt
index e5657ea..93df270 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelAtomicCancelStressTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelAtomicCancelStressTest.kt
@@ -98,9 +98,11 @@
         println("          Missed $missedCnt ints")
         println("      Duplicated $dupCnt ints")
         failed.get()?.let { throw it }
-        assertEquals(0, missedCnt)
         assertEquals(0, dupCnt)
-        assertEquals(lastSent, lastReceived)
+        if (kind != TestChannelKind.CONFLATED) {
+            assertEquals(0, missedCnt)
+            assertEquals(lastSent, lastReceived)
+        }
     }
 
     fun launchSender() {
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelSendReceiveStressTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelSendReceiveStressTest.kt
index 44bfe1d..e2ca9c0 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelSendReceiveStressTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ChannelSendReceiveStressTest.kt
@@ -81,6 +81,14 @@
                 sendersCompleted.incrementAndGet()
             }
         }
+        // print progress
+        val progressJob = launch(context) {
+            var seconds = 0
+            while (true) {
+                delay(1000)
+                println("${++seconds}: Sent ${sentTotal.get()}, received ${receivedTotal.get()}")
+            }
+        }
         try {
             withTimeout(timeLimit) {
                 senders.forEach { it.join() }
@@ -90,6 +98,7 @@
         } catch (e: CancellationException) {
             println("!!! Test timed out $e")
         }
+        progressJob.cancel()
         println("Tested $kind with nSenders=$nSenders, nReceivers=$nReceivers")
         println("Completed successfully ${sendersCompleted.get()} sender coroutines")
         println("Completed successfully ${receiversCompleted.get()} receiver coroutines")
@@ -103,7 +112,7 @@
         assertEquals(nReceivers, receiversCompleted.get())
         assertEquals(0, dupes.get())
         assertEquals(nEvents, sentTotal.get())
-        assertEquals(nEvents, receivedTotal.get())
+        if (kind != TestChannelKind.CONFLATED) assertEquals(nEvents, receivedTotal.get())
         repeat(nReceivers) { receiveIndex ->
             assertTrue("Each receiver should have received something", receivedBy[receiveIndex] > 0)
         }
@@ -111,8 +120,10 @@
 
     private suspend fun doSent() {
         sentTotal.incrementAndGet()
-        while (sentTotal.get() > receivedTotal.get() + maxBuffer)
-            yield() // throttle fast senders to prevent OOM with LinkedListChannel
+        if (kind != TestChannelKind.CONFLATED) {
+            while (sentTotal.get() > receivedTotal.get() + maxBuffer)
+                yield() // throttle fast senders to prevent OOM with LinkedListChannel
+        }
     }
 
     private suspend fun doSend(senderIndex: Int) {
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ConflatedChannelTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ConflatedChannelTest.kt
new file mode 100644
index 0000000..6f67df9
--- /dev/null
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ConflatedChannelTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.coroutines.experimental.channels
+
+import kotlinx.coroutines.experimental.TestBase
+import kotlinx.coroutines.experimental.launch
+import kotlinx.coroutines.experimental.runBlocking
+import kotlinx.coroutines.experimental.yield
+import org.hamcrest.core.IsEqual
+import org.hamcrest.core.IsNull
+import org.junit.Assert.assertThat
+import org.junit.Test
+
+class ConflatedChannelTest : TestBase() {
+    @Test
+    fun testBasicConflationOfferPoll() {
+        val q = ConflatedChannel<Int>()
+        assertThat(q.poll(), IsNull())
+        assertThat(q.offer(1), IsEqual(true))
+        assertThat(q.offer(2), IsEqual(true))
+        assertThat(q.offer(3), IsEqual(true))
+        assertThat(q.poll(), IsEqual(3))
+        assertThat(q.poll(), IsNull())
+    }
+
+    @Test
+    fun testConflationSendReceive() = runBlocking<Unit> {
+        val q = ConflatedChannel<Int>()
+        expect(1)
+        launch(context) { // receiver coroutine
+            expect(4)
+            assertThat(q.receive(), IsEqual(2))
+            expect(5)
+            assertThat(q.receive(), IsEqual(3)) // this receive suspends
+            expect(8)
+            assertThat(q.receive(), IsEqual(6)) // last conflated value
+            expect(9)
+        }
+        expect(2)
+        q.send(1)
+        q.send(2) // shall conflate
+        expect(3)
+        yield() // to receiver
+        expect(6)
+        q.send(3) // send to the waiting receiver
+        q.send(4) // buffer
+        q.send(5) // conflate
+        q.send(6) // conflate again
+        expect(7)
+        yield() // to receiver
+        finish(10)
+    }
+}
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/SimpleSendReceiveTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/SimpleSendReceiveTest.kt
index 400ace3..5021cbc 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/SimpleSendReceiveTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/SimpleSendReceiveTest.kt
@@ -19,10 +19,12 @@
 import kotlinx.coroutines.experimental.CommonPool
 import kotlinx.coroutines.experimental.launch
 import kotlinx.coroutines.experimental.runBlocking
+import org.hamcrest.core.IsEqual
+import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import org.junit.Assert.*
 
 @RunWith(Parameterized::class)
 class SimpleSendReceiveTest(
@@ -47,10 +49,17 @@
             repeat(n) { channel.send(it) }
             channel.close()
         }
-        var received = 0
+        var expected = 0
         for (x in channel) {
-            assertEquals(received++, x)
+            if (kind != TestChannelKind.CONFLATED) {
+                assertThat(x, IsEqual(expected++))
+            } else {
+                assertTrue(x >= expected)
+                expected = x + 1
+            }
         }
-        assertEquals(n, received)
+        if (kind != TestChannelKind.CONFLATED) {
+            assertThat(expected, IsEqual(n))
+        }
     }
 }
\ No newline at end of file
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/TestChannelKind.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/TestChannelKind.kt
index 3aeeada..2a12b03 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/TestChannelKind.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/TestChannelKind.kt
@@ -32,6 +32,10 @@
     LINKED_LIST {
         override fun create(): Channel<Int> = LinkedListChannel<Int>()
         override fun toString(): String = "LinkedListChannel"
+    },
+    CONFLATED {
+        override fun create(): Channel<Int> = ConflatedChannel<Int>()
+        override fun toString(): String = "ConflatedChannel"
     }
     ;
 
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/selects/SelectDeferredTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/selects/SelectDeferredTest.kt
index 0e65408..cf34b4e 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/selects/SelectDeferredTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/selects/SelectDeferredTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package kotlinx.coroutines.experimental.selects
 
 import kotlinx.coroutines.experimental.*
diff --git a/kotlinx-coroutines-javafx/README.md b/kotlinx-coroutines-javafx/README.md
deleted file mode 100644
index df8a3b7..0000000
--- a/kotlinx-coroutines-javafx/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Module kotlinx-coroutines-javafx
-
-Provides `JavaFx` context for JavaFX UI applications.
-
-# Package kotlinx.coroutines.experimental.javafx
-
-Provides `JavaFx` context for JavaFX UI applications.
diff --git a/kotlinx-coroutines-jdk8/README.md b/kotlinx-coroutines-jdk8/README.md
index f70af09..988459a 100644
--- a/kotlinx-coroutines-jdk8/README.md
+++ b/kotlinx-coroutines-jdk8/README.md
@@ -13,7 +13,7 @@
 | **Name** | **Description**
 | -------- | ---------------
 | [CompletableFuture.await][java.util.concurrent.CompletableFuture.await] | Awaits for completion of the future
-| [Deferred.toCompletableFuture][kotlinx.coroutines.experimental.Deferred.toCompletableFuture] | Converts a deferred value to the future
+| [Deferred.asCompletableFuture][kotlinx.coroutines.experimental.Deferred.asCompletableFuture] | Converts a deferred value to the future
 
 # Package kotlinx.coroutines.experimental.future
 
@@ -29,5 +29,5 @@
 [future]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.experimental.future/future.html
 [java.util.concurrent.CompletableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.experimental.future/java.util.concurrent.-completable-future/index.html
 [java.util.concurrent.CompletableFuture.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.experimental.future/java.util.concurrent.-completable-future/await.html
-[kotlinx.coroutines.experimental.Deferred.toCompletableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.experimental.future/kotlinx.coroutines.experimental.-deferred/to-completable-future.html
+[kotlinx.coroutines.experimental.Deferred.asCompletableFuture]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-jdk8/kotlinx.coroutines.experimental.future/kotlinx.coroutines.experimental.-deferred/as-completable-future.html
 <!--- END -->
diff --git a/kotlinx-coroutines-jdk8/src/main/kotlin/kotlinx/coroutines/experimental/future/Future.kt b/kotlinx-coroutines-jdk8/src/main/kotlin/kotlinx/coroutines/experimental/future/Future.kt
index 7717baa..d95a456 100644
--- a/kotlinx-coroutines-jdk8/src/main/kotlin/kotlinx/coroutines/experimental/future/Future.kt
+++ b/kotlinx-coroutines-jdk8/src/main/kotlin/kotlinx/coroutines/experimental/future/Future.kt
@@ -44,11 +44,21 @@
     return future
 }
 
+
+/**
+ * Converts this deferred value to the instance of [CompletableFuture].
+ * The deferred value is cancelled when the resulting future is cancelled or otherwise completed.
+ * @suppress: **Deprecated**: Renamed to [asCompletableFuture]
+ */
+@Deprecated("Renamed to `asCompletableFuture`",
+    replaceWith = ReplaceWith("asCompletableFuture()"))
+public fun <T> Deferred<T>.toCompletableFuture(): CompletableFuture<T> = asCompletableFuture()
+
 /**
  * Converts this deferred value to the instance of [CompletableFuture].
  * The deferred value is cancelled when the resulting future is cancelled or otherwise completed.
  */
-public fun <T> Deferred<T>.toCompletableFuture(): CompletableFuture<T> {
+public fun <T> Deferred<T>.asCompletableFuture(): CompletableFuture<T> {
     val future = CompletableFuture<T>()
     future.whenComplete { _, exception -> cancel(exception) }
     invokeOnCompletion {
diff --git a/kotlinx-coroutines-jdk8/src/test/kotlin/examples/ToFuture-example.kt b/kotlinx-coroutines-jdk8/src/test/kotlin/examples/ToFuture-example.kt
index aa70ab0..974e1d0 100644
--- a/kotlinx-coroutines-jdk8/src/test/kotlin/examples/ToFuture-example.kt
+++ b/kotlinx-coroutines-jdk8/src/test/kotlin/examples/ToFuture-example.kt
@@ -19,7 +19,7 @@
 import kotlinx.coroutines.experimental.CommonPool
 import kotlinx.coroutines.experimental.async
 import kotlinx.coroutines.experimental.delay
-import kotlinx.coroutines.experimental.future.toCompletableFuture
+import kotlinx.coroutines.experimental.future.asCompletableFuture
 import java.util.concurrent.TimeUnit
 
 fun main(args: Array<String>)  {
@@ -30,6 +30,6 @@
         log("Done...")
         42
     }
-    val future = deferred.toCompletableFuture()
+    val future = deferred.asCompletableFuture()
     log("Got ${future.get()}")
 }
\ No newline at end of file
diff --git a/kotlinx-coroutines-jdk8/src/test/kotlin/kotlinx/coroutines/experimental/future/FutureTest.kt b/kotlinx-coroutines-jdk8/src/test/kotlin/kotlinx/coroutines/experimental/future/FutureTest.kt
index a7b66d0..ee2c059 100644
--- a/kotlinx-coroutines-jdk8/src/test/kotlin/kotlinx/coroutines/experimental/future/FutureTest.kt
+++ b/kotlinx-coroutines-jdk8/src/test/kotlin/kotlinx/coroutines/experimental/future/FutureTest.kt
@@ -60,8 +60,6 @@
                 e.message!!
             } + "K"
         }
-
-        assertFalse(future.isDone)
         assertEquals("OK", future.get())
     }
 
diff --git a/kotlinx-coroutines-swing/README.md b/kotlinx-coroutines-swing/README.md
deleted file mode 100644
index 1f47a64..0000000
--- a/kotlinx-coroutines-swing/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Module kotlinx-coroutines-swing
-
-Provides `Swing` context for Swing UI applications.
-
-# Package kotlinx.coroutines.experimental.swing
-
-Provides `Swing` context for Swing UI applications.
diff --git a/pom.xml b/pom.xml
index d2b4bd4..27acd22 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,14 +97,15 @@
 
     <modules>
         <module>kotlinx-coroutines-core</module>
-        <module>kotlinx-coroutines-swing</module>
-        <module>kotlinx-coroutines-javafx</module>
         <module>kotlinx-coroutines-jdk8</module>
         <module>kotlinx-coroutines-nio</module>
-        <module>kotlinx-coroutines-reactive</module>
-        <module>kotlinx-coroutines-rx1</module>
-        <module>kotlinx-coroutines-rx2</module>
-        <module>kotlinx-coroutines-rx-example</module>
+        <module>reactive/kotlinx-coroutines-reactive</module>
+        <module>reactive/kotlinx-coroutines-rx1</module>
+        <module>reactive/kotlinx-coroutines-rx2</module>
+        <module>reactive/kotlinx-coroutines-rx-example</module>
+        <module>ui/kotlinx-coroutines-swing</module>
+        <module>ui/kotlinx-coroutines-javafx</module>
+        <module>ui/kotlinx-coroutines-android</module>
         <module>site</module>
     </modules>
 
diff --git a/reactive/README.md b/reactive/README.md
new file mode 100644
index 0000000..8506b33
--- /dev/null
+++ b/reactive/README.md
@@ -0,0 +1,9 @@
+# Coroutines for reactive streams
+
+This directory contains modules with utilities for various reactive stream libraries:
+
+## Modules
+
+* [kotlinx-coroutines-reactive](kotlinx-coroutines-reactive) -- utilities for [Reactive Streams](http://www.reactive-streams.org)
+* [kotlinx-coroutines-rx1](kotlinx-coroutines-rx1) -- utilities for [RxJava 1.x](https://github.com/ReactiveX/RxJava/tree/1.x)
+* [kotlinx-coroutines-rx2](kotlinx-coroutines-rx2) -- utilities for [RxJava 2.x](https://github.com/ReactiveX/RxJava)
diff --git a/kotlinx-coroutines-reactive/README.md b/reactive/kotlinx-coroutines-reactive/README.md
similarity index 90%
rename from kotlinx-coroutines-reactive/README.md
rename to reactive/kotlinx-coroutines-reactive/README.md
index 54b3728..2c30254 100644
--- a/kotlinx-coroutines-reactive/README.md
+++ b/reactive/kotlinx-coroutines-reactive/README.md
@@ -22,7 +22,7 @@
 
 | **Name** | **Description**
 | -------- | ---------------
-| [ReceiveChannel.toPublisher][kotlinx.coroutines.experimental.channels.ReceiveChannel.toPublisher] | Converts streaming channel to hot publisher
+| [ReceiveChannel.asPublisher][kotlinx.coroutines.experimental.channels.ReceiveChannel.asPublisher] | Converts streaming channel to hot publisher
 
 <!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core -->
 <!--- DOCS_ROOT kotlinx-coroutines-core/target/dokka/kotlinx-coroutines-core -->
@@ -32,14 +32,14 @@
 [ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/index.html
 [ChannelIterator]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel-iterator/index.html
 <!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive -->
-<!--- DOCS_ROOT kotlinx-coroutines-reactive/target/dokka/kotlinx-coroutines-reactive -->
+<!--- DOCS_ROOT reactive/kotlinx-coroutines-reactive/target/dokka/kotlinx-coroutines-reactive -->
 <!--- INDEX kotlinx.coroutines.experimental.reactive -->
 [publish]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.experimental.reactive/publish.html
 [org.reactivestreams.Publisher.awaitFirst]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.experimental.reactive/org.reactivestreams.-publisher/await-first.html
 [org.reactivestreams.Publisher.awaitSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.experimental.reactive/org.reactivestreams.-publisher/await-single.html
 [org.reactivestreams.Publisher.open]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.experimental.reactive/org.reactivestreams.-publisher/open.html
 [org.reactivestreams.Publisher.iterator]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.experimental.reactive/org.reactivestreams.-publisher/iterator.html
-[kotlinx.coroutines.experimental.channels.ReceiveChannel.toPublisher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.experimental.reactive/kotlinx.coroutines.experimental.channels.-receive-channel/to-publisher.html
+[kotlinx.coroutines.experimental.channels.ReceiveChannel.asPublisher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-reactive/kotlinx.coroutines.experimental.reactive/kotlinx.coroutines.experimental.channels.-receive-channel/as-publisher.html
 <!--- END -->
 
 # Package kotlinx.coroutines.experimental.reactive
diff --git a/kotlinx-coroutines-reactive/pom.xml b/reactive/kotlinx-coroutines-reactive/pom.xml
similarity index 97%
rename from kotlinx-coroutines-reactive/pom.xml
rename to reactive/kotlinx-coroutines-reactive/pom.xml
index 2984076..aa56696 100644
--- a/kotlinx-coroutines-reactive/pom.xml
+++ b/reactive/kotlinx-coroutines-reactive/pom.xml
@@ -23,6 +23,7 @@
         <groupId>org.jetbrains.kotlinx</groupId>
         <artifactId>kotlinx-coroutines</artifactId>
         <version>0.12</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
     <artifactId>kotlinx-coroutines-reactive</artifactId>
diff --git a/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Await.kt b/reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Await.kt
similarity index 100%
rename from kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Await.kt
rename to reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Await.kt
diff --git a/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Channel.kt b/reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Channel.kt
similarity index 100%
rename from kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Channel.kt
rename to reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Channel.kt
diff --git a/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Convert.kt b/reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Convert.kt
similarity index 80%
rename from kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Convert.kt
rename to reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Convert.kt
index 1a290c7..1dbec54 100644
--- a/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Convert.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Convert.kt
@@ -28,7 +28,14 @@
  *
  * @param context -- the coroutine context from which the resulting observable is going to be signalled
  */
-public fun <T> ReceiveChannel<T>.toPublisher(context: CoroutineContext): Publisher<T> = publish(context) {
-    for (t in this@toPublisher)
+public fun <T> ReceiveChannel<T>.asPublisher(context: CoroutineContext): Publisher<T> = publish(context) {
+    for (t in this@asPublisher)
         send(t)
 }
+
+/**
+ * @suppress **Deprecated**: Renamed to [asPublisher]
+ */
+@Deprecated(message = "Renamed to `asPublisher`",
+    replaceWith = ReplaceWith("asPublisher(context)"))
+public fun <T> ReceiveChannel<T>.toPublisher(context: CoroutineContext): Publisher<T> = asPublisher(context)
\ No newline at end of file
diff --git a/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Publish.kt b/reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Publish.kt
similarity index 100%
rename from kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Publish.kt
rename to reactive/kotlinx-coroutines-reactive/src/main/kotlin/kotlinx/coroutines/experimental/reactive/Publish.kt
diff --git a/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/IntegrationTest.kt b/reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/IntegrationTest.kt
similarity index 97%
rename from kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/IntegrationTest.kt
rename to reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/IntegrationTest.kt
index 7c95386..a794864 100644
--- a/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/IntegrationTest.kt
+++ b/reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/IntegrationTest.kt
@@ -87,7 +87,7 @@
         }
         checkNumbers(n, pub)
         val channel = pub.open()
-        checkNumbers(n, channel.toPublisher(ctx(context)))
+        checkNumbers(n, channel.asPublisher(ctx(context)))
         channel.close()
     }
 
diff --git a/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublishTest.kt b/reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublishTest.kt
similarity index 100%
rename from kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublishTest.kt
rename to reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublishTest.kt
diff --git a/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherBackpressureTest.kt b/reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherBackpressureTest.kt
similarity index 100%
rename from kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherBackpressureTest.kt
rename to reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherBackpressureTest.kt
diff --git a/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherMultiTest.kt b/reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherMultiTest.kt
similarity index 100%
rename from kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherMultiTest.kt
rename to reactive/kotlinx-coroutines-reactive/src/test/kotlin/kotlinx/coroutines/experimental/reactive/PublisherMultiTest.kt
diff --git a/kotlinx-coroutines-rx-example/pom.xml b/reactive/kotlinx-coroutines-rx-example/pom.xml
similarity index 97%
rename from kotlinx-coroutines-rx-example/pom.xml
rename to reactive/kotlinx-coroutines-rx-example/pom.xml
index 9873efb..0da3d69 100644
--- a/kotlinx-coroutines-rx-example/pom.xml
+++ b/reactive/kotlinx-coroutines-rx-example/pom.xml
@@ -23,6 +23,7 @@
         <groupId>org.jetbrains.kotlinx</groupId>
         <artifactId>kotlinx-coroutines</artifactId>
         <version>0.12</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
     <artifactId>kotlinx-coroutines-rx-example</artifactId>
diff --git a/kotlinx-coroutines-rx-example/src/main/kotlin/main.kt b/reactive/kotlinx-coroutines-rx-example/src/main/kotlin/main.kt
similarity index 100%
rename from kotlinx-coroutines-rx-example/src/main/kotlin/main.kt
rename to reactive/kotlinx-coroutines-rx-example/src/main/kotlin/main.kt
diff --git a/kotlinx-coroutines-rx1/README.md b/reactive/kotlinx-coroutines-rx1/README.md
similarity index 82%
rename from kotlinx-coroutines-rx1/README.md
rename to reactive/kotlinx-coroutines-rx1/README.md
index 5d8c819..3b23c07 100644
--- a/kotlinx-coroutines-rx1/README.md
+++ b/reactive/kotlinx-coroutines-rx1/README.md
@@ -14,7 +14,6 @@
 
 | **Name** | **Description**
 | -------- | ---------------
-| [Completable.await][rx.Completable.await] | Awaits for completion of the completable value 
 | [Single.await][rx.Single.await] | Awaits for completion of the single value and returns it 
 | [Observable.awaitFirst][rx.Observable.awaitFirst] | Returns the first value from the given observable
 | [Observable.awaitLast][rx.Observable.awaitFirst] | Returns the last value from the given observable
@@ -26,9 +25,9 @@
 
 | **Name** | **Description**
 | -------- | ---------------
-| [Job.toCompletable][kotlinx.coroutines.experimental.Job.toCompletable] | Converts job to hot completable
-| [Deferred.toSingle][kotlinx.coroutines.experimental.Deferred.toSingle] | Converts deferred value to hot single
-| [ReceiveChannel.toObservable][kotlinx.coroutines.experimental.channels.ReceiveChannel.toObservable] | Converts streaming channel to hot observable
+| [Job.asCompletable][kotlinx.coroutines.experimental.Job.asCompletable] | Converts job to hot completable
+| [Deferred.asSingle][kotlinx.coroutines.experimental.Deferred.asSingle] | Converts deferred value to hot single
+| [ReceiveChannel.asObservable][kotlinx.coroutines.experimental.channels.ReceiveChannel.asObservable] | Converts streaming channel to hot observable
 
 <!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core -->
 <!--- DOCS_ROOT kotlinx-coroutines-core/target/dokka/kotlinx-coroutines-core -->
@@ -39,20 +38,19 @@
 [ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/index.html
 [ChannelIterator]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel-iterator/index.html
 <!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1 -->
-<!--- DOCS_ROOT kotlinx-coroutines-rx1/target/dokka/kotlinx-coroutines-rx1 -->
+<!--- DOCS_ROOT reactive/kotlinx-coroutines-rx1/target/dokka/kotlinx-coroutines-rx1 -->
 <!--- INDEX kotlinx.coroutines.experimental.rx1 -->
 [rxCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx-completable.html
 [rxSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx-single.html
 [rxObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx-observable.html
-[rx.Completable.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx.-completable/await.html
 [rx.Single.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx.-single/await.html
 [rx.Observable.awaitFirst]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx.-observable/await-first.html
 [rx.Observable.awaitSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx.-observable/await-single.html
 [rx.Observable.open]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx.-observable/open.html
 [rx.Observable.iterator]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/rx.-observable/iterator.html
-[kotlinx.coroutines.experimental.Job.toCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/kotlinx.coroutines.experimental.-job/to-completable.html
-[kotlinx.coroutines.experimental.Deferred.toSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/kotlinx.coroutines.experimental.-deferred/to-single.html
-[kotlinx.coroutines.experimental.channels.ReceiveChannel.toObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/kotlinx.coroutines.experimental.channels.-receive-channel/to-observable.html
+[kotlinx.coroutines.experimental.Job.asCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/kotlinx.coroutines.experimental.-job/as-completable.html
+[kotlinx.coroutines.experimental.Deferred.asSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/kotlinx.coroutines.experimental.-deferred/as-single.html
+[kotlinx.coroutines.experimental.channels.ReceiveChannel.asObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx1/kotlinx.coroutines.experimental.rx1/kotlinx.coroutines.experimental.channels.-receive-channel/as-observable.html
 <!--- END -->
 
 # Package kotlinx.coroutines.experimental.rx1
diff --git a/kotlinx-coroutines-rx1/pom.xml b/reactive/kotlinx-coroutines-rx1/pom.xml
similarity index 97%
rename from kotlinx-coroutines-rx1/pom.xml
rename to reactive/kotlinx-coroutines-rx1/pom.xml
index 64c708a..547cca0 100644
--- a/kotlinx-coroutines-rx1/pom.xml
+++ b/reactive/kotlinx-coroutines-rx1/pom.xml
@@ -23,6 +23,7 @@
         <groupId>org.jetbrains.kotlinx</groupId>
         <artifactId>kotlinx-coroutines</artifactId>
         <version>0.12</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
     <artifactId>kotlinx-coroutines-rx1</artifactId>
diff --git a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxAwait.kt b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxAwait.kt
similarity index 82%
rename from kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxAwait.kt
rename to reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxAwait.kt
index 6c5e1dc..f5ea2e6 100644
--- a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxAwait.kt
+++ b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxAwait.kt
@@ -22,24 +22,6 @@
 import kotlinx.coroutines.experimental.suspendCancellableCoroutine
 import rx.*
 
-// ------------------------ Completable ------------------------
-
-/**
- * Awaits for completion of the completable value without blocking a thread and
- * returns or throws the corresponding exception if this completable had produced error.
- *
- * This suspending function is cancellable.
- * If the [Job] of the current coroutine is completed while this suspending function is waiting, this function
- * immediately resumes with [CancellationException].
- */
-public suspend fun Completable.await(): Unit = suspendCancellableCoroutine { cont ->
-    subscribe(object : CompletableSubscriber {
-        override fun onSubscribe(sub: Subscription) { cont.unsubscribeOnCompletion(sub) }
-        override fun onCompleted() { cont.resume(Unit) }
-        override fun onError(error: Throwable) { cont.resumeWithException(error) }
-    })
-}
-
 // ------------------------ Single ------------------------
 
 /**
diff --git a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxChannel.kt b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxChannel.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxChannel.kt
rename to reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxChannel.kt
diff --git a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxCompletable.kt b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxCompletable.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxCompletable.kt
rename to reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxCompletable.kt
diff --git a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxConvert.kt b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxConvert.kt
similarity index 73%
rename from kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxConvert.kt
rename to reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxConvert.kt
index 4d3f6f4..e068680 100644
--- a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxConvert.kt
+++ b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxConvert.kt
@@ -31,8 +31,8 @@
  *
  * @param context -- the coroutine context from which the resulting completable is going to be signalled
  */
-public fun Job.toCompletable(context: CoroutineContext): Completable = rxCompletable(context) {
-    this@toCompletable.join()
+public fun Job.asCompletable(context: CoroutineContext): Completable = rxCompletable(context) {
+    this@asCompletable.join()
 }
 
 /**
@@ -44,8 +44,8 @@
  *
  * @param context -- the coroutine context from which the resulting single is going to be signalled
  */
-public fun <T> Deferred<T>.toSingle(context: CoroutineContext): Single<T> = rxSingle<T>(context) {
-    this@toSingle.await()
+public fun <T> Deferred<T>.asSingle(context: CoroutineContext): Single<T> = rxSingle<T>(context) {
+    this@asSingle.await()
 }
 
 /**
@@ -56,7 +56,28 @@
  *
  * @param context -- the coroutine context from which the resulting observable is going to be signalled
  */
-public fun <T> ReceiveChannel<T>.toObservable(context: CoroutineContext): Observable<T> = rxObservable(context) {
-    for (t in this@toObservable)
+public fun <T> ReceiveChannel<T>.asObservable(context: CoroutineContext): Observable<T> = rxObservable(context) {
+    for (t in this@asObservable)
         send(t)
 }
+
+/**
+ * @suppress **Deprecated**: Renamed to [asCompletable]
+ */
+@Deprecated(message = "Renamed to `asCompletable`",
+    replaceWith = ReplaceWith("asCompletable(context)"))
+public fun Job.toCompletable(context: CoroutineContext): Completable = asCompletable(context)
+
+/**
+ * @suppress **Deprecated**: Renamed to [asSingle]
+ */
+@Deprecated(message = "Renamed to `asSingle`",
+    replaceWith = ReplaceWith("asSingle(context)"))
+public fun <T> Deferred<T>.toSingle(context: CoroutineContext): Single<T> = asSingle(context)
+
+/**
+ * @suppress **Deprecated**: Renamed to [asObservable]
+ */
+@Deprecated(message = "Renamed to `asObservable`",
+    replaceWith = ReplaceWith("asObservable(context)"))
+public fun <T> ReceiveChannel<T>.toObservable(context: CoroutineContext): Observable<T> = asObservable(context)
diff --git a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxObservable.kt b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxObservable.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxObservable.kt
rename to reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxObservable.kt
diff --git a/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxSingle.kt b/reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxSingle.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxSingle.kt
rename to reactive/kotlinx-coroutines-rx1/src/main/kotlin/kotlinx/coroutines/experimental/rx1/RxSingle.kt
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/Check.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/Check.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/Check.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/Check.kt
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/CompletableTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/CompletableTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/CompletableTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/CompletableTest.kt
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ConvertTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ConvertTest.kt
similarity index 87%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ConvertTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ConvertTest.kt
index 9f2bae1..32ea56f 100644
--- a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ConvertTest.kt
+++ b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ConvertTest.kt
@@ -20,9 +20,8 @@
 import kotlinx.coroutines.experimental.channels.produce
 import org.hamcrest.core.IsEqual
 import org.hamcrest.core.IsInstanceOf
-import org.junit.Assert.*
+import org.junit.Assert.assertThat
 import org.junit.Test
-import java.io.IOException
 
 class ConvertTest : TestBase() {
     class TestException(s: String): RuntimeException(s)
@@ -33,7 +32,7 @@
         val job = launch(context) {
             expect(3)
         }
-        val completable = job.toCompletable(context)
+        val completable = job.asCompletable(context)
         completable.subscribe {
             expect(4)
         }
@@ -49,7 +48,7 @@
             expect(3)
             throw RuntimeException("OK")
         }
-        val completable = job.toCompletable(context)
+        val completable = job.asCompletable(context)
         completable.subscribe {
             expect(4)
         }
@@ -64,11 +63,11 @@
             delay(50)
             "OK"
         }
-        val single1 = d.toSingle(Unconfined)
+        val single1 = d.asSingle(Unconfined)
         checkSingleValue(single1) {
             assertThat(it, IsEqual("OK"))
         }
-        val single2 = d.toSingle(Unconfined)
+        val single2 = d.asSingle(Unconfined)
         checkSingleValue(single2) {
             assertThat(it, IsEqual("OK"))
         }
@@ -80,12 +79,12 @@
             delay(50)
             throw TestException("OK")
         }
-        val single1 = d.toSingle(Unconfined)
+        val single1 = d.asSingle(Unconfined)
         checkErroneous(single1) {
             assertThat(it, IsInstanceOf(TestException::class.java))
             assertThat(it.message, IsEqual("OK"))
         }
-        val single2 = d.toSingle(Unconfined)
+        val single2 = d.asSingle(Unconfined)
         checkErroneous(single2) {
             assertThat(it, IsInstanceOf(TestException::class.java))
             assertThat(it.message, IsEqual("OK"))
@@ -100,7 +99,7 @@
             delay(50)
             send("K")
         }
-        val observable = c.toObservable(Unconfined)
+        val observable = c.asObservable(Unconfined)
         checkSingleValue(observable.reduce { t1, t2 -> t1 + t2 }) {
             assertThat(it, IsEqual("OK"))
         }
@@ -114,7 +113,7 @@
             delay(50)
             throw TestException("K")
         }
-        val observable = c.toObservable(Unconfined)
+        val observable = c.asObservable(Unconfined)
         val single = rxSingle(Unconfined) {
             var result = ""
             try {
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/IntegrationTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/IntegrationTest.kt
similarity index 97%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/IntegrationTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/IntegrationTest.kt
index 7472ab8..09c000f 100644
--- a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/IntegrationTest.kt
+++ b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/IntegrationTest.kt
@@ -87,7 +87,7 @@
         }
         checkNumbers(n, observable)
         val channel = observable.open()
-        checkNumbers(n, channel.toObservable(ctx(context)))
+        checkNumbers(n, channel.asObservable(ctx(context)))
         channel.close()
     }
 
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableBackpressureTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableBackpressureTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableBackpressureTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableBackpressureTest.kt
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableMultiTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableMultiTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableMultiTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableMultiTest.kt
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableSingleTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableSingleTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableSingleTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableSingleTest.kt
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/ObservableTest.kt
diff --git a/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/SingleTest.kt b/reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/SingleTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/SingleTest.kt
rename to reactive/kotlinx-coroutines-rx1/src/test/kotlin/kotlinx/coroutines/experimental/rx1/SingleTest.kt
diff --git a/kotlinx-coroutines-rx2/README.md b/reactive/kotlinx-coroutines-rx2/README.md
similarity index 81%
rename from kotlinx-coroutines-rx2/README.md
rename to reactive/kotlinx-coroutines-rx2/README.md
index 0322a4a..b448ee1 100644
--- a/kotlinx-coroutines-rx2/README.md
+++ b/reactive/kotlinx-coroutines-rx2/README.md
@@ -30,20 +30,22 @@
 
 | **Name** | **Description**
 | -------- | ---------------
-| [Job.toCompletable][kotlinx.coroutines.experimental.Job.toCompletable] | Converts job to hot completable
-| [Deferred.toSingle][kotlinx.coroutines.experimental.Deferred.toSingle] | Converts deferred value to hot single
-| [ReceiveChannel.toObservable][kotlinx.coroutines.experimental.channels.ReceiveChannel.toObservable] | Converts streaming channel to hot observable
+| [Job.asCompletable][kotlinx.coroutines.experimental.Job.asCompletable] | Converts job to hot completable
+| [Deferred.asSingle][kotlinx.coroutines.experimental.Deferred.asSingle] | Converts deferred value to hot single
+| [ReceiveChannel.asObservable][kotlinx.coroutines.experimental.channels.ReceiveChannel.asObservable] | Converts streaming channel to hot observable
+| [Scheduler.asCoroutineDispatcher][io.reactivex.Scheduler.asCoroutineDispatcher] | Converts scheduler to [CoroutineDispatcher]
 
 <!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core -->
 <!--- DOCS_ROOT kotlinx-coroutines-core/target/dokka/kotlinx-coroutines-core -->
 <!--- INDEX kotlinx.coroutines.experimental -->
 [CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-scope/index.html
+[CoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-coroutine-dispatcher/index.html
 <!--- INDEX kotlinx.coroutines.experimental.channels -->
 [ProducerScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-producer-scope/index.html
 [ReceiveChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-receive-channel/index.html
 [ChannelIterator]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel-iterator/index.html
 <!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2 -->
-<!--- DOCS_ROOT kotlinx-coroutines-rx2/target/dokka/kotlinx-coroutines-rx2 -->
+<!--- DOCS_ROOT reactive/kotlinx-coroutines-rx2/target/dokka/kotlinx-coroutines-rx2 -->
 <!--- INDEX kotlinx.coroutines.experimental.rx2 -->
 [rxCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/rx-completable.html
 [rxSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/rx-single.html
@@ -54,9 +56,10 @@
 [io.reactivex.ObservableSource.awaitSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/io.reactivex.-observable-source/await-single.html
 [io.reactivex.ObservableSource.open]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/io.reactivex.-observable-source/open.html
 [io.reactivex.ObservableSource.iterator]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/io.reactivex.-observable-source/iterator.html
-[kotlinx.coroutines.experimental.Job.toCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/kotlinx.coroutines.experimental.-job/to-completable.html
-[kotlinx.coroutines.experimental.Deferred.toSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/kotlinx.coroutines.experimental.-deferred/to-single.html
-[kotlinx.coroutines.experimental.channels.ReceiveChannel.toObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/kotlinx.coroutines.experimental.channels.-receive-channel/to-observable.html
+[kotlinx.coroutines.experimental.Job.asCompletable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/kotlinx.coroutines.experimental.-job/as-completable.html
+[kotlinx.coroutines.experimental.Deferred.asSingle]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/kotlinx.coroutines.experimental.-deferred/as-single.html
+[kotlinx.coroutines.experimental.channels.ReceiveChannel.asObservable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/kotlinx.coroutines.experimental.channels.-receive-channel/as-observable.html
+[io.reactivex.Scheduler.asCoroutineDispatcher]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-rx2/kotlinx.coroutines.experimental.rx2/io.reactivex.-scheduler/as-coroutine-dispatcher.html
 <!--- END -->
 
 # Package kotlinx.coroutines.experimental.rx2
diff --git a/kotlinx-coroutines-rx2/pom.xml b/reactive/kotlinx-coroutines-rx2/pom.xml
similarity index 97%
rename from kotlinx-coroutines-rx2/pom.xml
rename to reactive/kotlinx-coroutines-rx2/pom.xml
index 4dc61b4..fa4794f 100644
--- a/kotlinx-coroutines-rx2/pom.xml
+++ b/reactive/kotlinx-coroutines-rx2/pom.xml
@@ -23,6 +23,7 @@
         <groupId>org.jetbrains.kotlinx</groupId>
         <artifactId>kotlinx-coroutines</artifactId>
         <version>0.12</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
     <artifactId>kotlinx-coroutines-rx2</artifactId>
diff --git a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxAwait.kt b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxAwait.kt
similarity index 97%
rename from kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxAwait.kt
rename to reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxAwait.kt
index 680f48c..fac3bfe 100644
--- a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxAwait.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxAwait.kt
@@ -36,7 +36,7 @@
     subscribe(object : CompletableObserver {
         override fun onSubscribe(d: Disposable) { cont.disposeOnCompletion(d) }
         override fun onComplete() { cont.resume(Unit) }
-        override fun onError(e: Throwable) { cont.tryResumeWithException(e) }
+        override fun onError(e: Throwable) { cont.resumeWithException(e) }
     })
 }
 
@@ -92,7 +92,7 @@
 
 // ------------------------ private ------------------------
 
-private fun CancellableContinuation<*>.disposeOnCompletion(d: Disposable) =
+internal fun CancellableContinuation<*>.disposeOnCompletion(d: Disposable) =
     invokeOnCompletion { d.dispose() }
 
 private enum class Mode(val s: String) {
diff --git a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxChannel.kt b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxChannel.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxChannel.kt
rename to reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxChannel.kt
diff --git a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxCompletable.kt b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxCompletable.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxCompletable.kt
rename to reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxCompletable.kt
diff --git a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxConvert.kt b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxConvert.kt
similarity index 74%
rename from kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxConvert.kt
rename to reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxConvert.kt
index ad97366..ffc9404 100644
--- a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxConvert.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxConvert.kt
@@ -36,8 +36,8 @@
  *
  * @param context -- the coroutine context from which the resulting completable is going to be signalled
  */
-public fun Job.toCompletable(context: CoroutineContext): Completable = rxCompletable(context) {
-    this@toCompletable.join()
+public fun Job.asCompletable(context: CoroutineContext): Completable = rxCompletable(context) {
+    this@asCompletable.join()
 }
 
 /**
@@ -49,8 +49,8 @@
  *
  * @param context -- the coroutine context from which the resulting single is going to be signalled
  */
-public fun <T> Deferred<T>.toSingle(context: CoroutineContext): Single<T> = rxSingle<T>(context) {
-    this@toSingle.await()
+public fun <T> Deferred<T>.asSingle(context: CoroutineContext): Single<T> = rxSingle<T>(context) {
+    this@asSingle.await()
 }
 
 /**
@@ -61,7 +61,28 @@
  *
  * @param context -- the coroutine context from which the resulting observable is going to be signalled
  */
-public fun <T> ReceiveChannel<T>.toObservable(context: CoroutineContext): Observable<T> = rxObservable(context) {
-    for (t in this@toObservable)
+public fun <T> ReceiveChannel<T>.asObservable(context: CoroutineContext): Observable<T> = rxObservable(context) {
+    for (t in this@asObservable)
         send(t)
 }
+
+/**
+ * @suppress **Deprecated**: Renamed to [asCompletable]
+ */
+@Deprecated(message = "Renamed to `asCompletable`",
+    replaceWith = ReplaceWith("asCompletable(context)"))
+public fun Job.toCompletable(context: CoroutineContext): Completable = asCompletable(context)
+
+/**
+ * @suppress **Deprecated**: Renamed to [asSingle]
+ */
+@Deprecated(message = "Renamed to `asSingle`",
+    replaceWith = ReplaceWith("asSingle(context)"))
+public fun <T> Deferred<T>.toSingle(context: CoroutineContext): Single<T> = asSingle(context)
+
+/**
+ * @suppress **Deprecated**: Renamed to [asObservable]
+ */
+@Deprecated(message = "Renamed to `asObservable`",
+    replaceWith = ReplaceWith("asObservable(context)"))
+public fun <T> ReceiveChannel<T>.toObservable(context: CoroutineContext): Observable<T> = asObservable(context)
diff --git a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxObservable.kt b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxObservable.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxObservable.kt
rename to reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxObservable.kt
diff --git a/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxScheduler.kt b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxScheduler.kt
new file mode 100644
index 0000000..cb43b24
--- /dev/null
+++ b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxScheduler.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.coroutines.experimental.rx2
+
+import io.reactivex.Scheduler
+import kotlinx.coroutines.experimental.CancellableContinuation
+import kotlinx.coroutines.experimental.CoroutineDispatcher
+import kotlinx.coroutines.experimental.Delay
+import kotlinx.coroutines.experimental.DisposableHandle
+import java.util.concurrent.TimeUnit
+import kotlin.coroutines.experimental.CoroutineContext
+
+/**
+ * Converts an instance of [Scheduler] to an implementation of [CoroutineDispatcher]
+ * and provides native [delay][Delay.delay] support.
+ */
+public fun Scheduler.asCoroutineDispatcher() = SchedulerCoroutineDispatcher(this)
+
+/**
+ * Implements [CoroutineDispatcher] on top of an arbitrary [Scheduler].
+ * @param scheduler a scheduler.
+ */
+public class SchedulerCoroutineDispatcher(private val scheduler: Scheduler) : CoroutineDispatcher(), Delay {
+    override fun dispatch(context: CoroutineContext, block: Runnable) {
+        scheduler.scheduleDirect(block)
+    }
+
+    override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
+        val disposable = scheduler.scheduleDirect({
+            with(continuation) { resumeUndispatched(Unit) }
+        }, time, unit)
+        continuation.disposeOnCompletion(disposable)
+    }
+
+    override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle {
+        val disposable = scheduler.scheduleDirect(block, time, unit)
+        return object : DisposableHandle {
+            override fun dispose() {
+                disposable.dispose()
+            }
+        }
+    }
+
+    override fun toString(): String = scheduler.toString()
+}
diff --git a/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxSingle.kt b/reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxSingle.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxSingle.kt
rename to reactive/kotlinx-coroutines-rx2/src/main/kotlin/kotlinx/coroutines/experimental/rx2/RxSingle.kt
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/Check.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/Check.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/Check.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/Check.kt
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/CompletableTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/CompletableTest.kt
similarity index 77%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/CompletableTest.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/CompletableTest.kt
index 4859276..a85af96 100644
--- a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/CompletableTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/CompletableTest.kt
@@ -16,7 +16,6 @@
 
 package kotlinx.coroutines.experimental.rx2
 
-import kotlinx.coroutines.experimental.CancellationException
 import kotlinx.coroutines.experimental.TestBase
 import kotlinx.coroutines.experimental.runBlocking
 import kotlinx.coroutines.experimental.yield
@@ -83,4 +82,32 @@
         yield()
         finish(6)
     }
+
+    @Test
+    fun testAwaitSuccess() = runBlocking<Unit> {
+        expect(1)
+        val completable = rxCompletable(context) {
+            expect(3)
+        }
+        expect(2)
+        completable.await() // shall launch coroutine
+        finish(4)
+    }
+
+    @Test
+    fun testAwaitFailure() = runBlocking<Unit> {
+        expect(1)
+        val completable = rxCompletable(context) {
+            expect(3)
+            throw RuntimeException("OK")
+        }
+        expect(2)
+        try {
+            completable.await() // shall launch coroutine and throw exception
+            expectUnreached()
+        } catch (e: RuntimeException) {
+            finish(4)
+            assertThat(e.message, IsEqual("OK"))
+        }
+    }
 }
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ConvertTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ConvertTest.kt
similarity index 88%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ConvertTest.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ConvertTest.kt
index c716a0c..7afe7c1 100644
--- a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ConvertTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ConvertTest.kt
@@ -30,7 +30,7 @@
         val job = launch(context) {
             expect(3)
         }
-        val completable = job.toCompletable(context)
+        val completable = job.asCompletable(context)
         completable.subscribe {
             expect(4)
         }
@@ -46,7 +46,7 @@
             expect(3)
             throw RuntimeException("OK")
         }
-        val completable = job.toCompletable(context)
+        val completable = job.asCompletable(context)
         completable.subscribe {
             expect(4)
         }
@@ -61,11 +61,11 @@
             delay(50)
             "OK"
         }
-        val single1 = d.toSingle(Unconfined)
+        val single1 = d.asSingle(Unconfined)
         checkSingleValue(single1) {
             assertEquals("OK", it)
         }
-        val single2 = d.toSingle(Unconfined)
+        val single2 = d.asSingle(Unconfined)
         checkSingleValue(single2) {
             assertEquals("OK", it)
         }
@@ -77,11 +77,11 @@
             delay(50)
             throw TestException("OK")
         }
-        val single1 = d.toSingle(Unconfined)
+        val single1 = d.asSingle(Unconfined)
         checkErroneous(single1) {
             check(it is TestException && it.message == "OK") { "$it" }
         }
-        val single2 = d.toSingle(Unconfined)
+        val single2 = d.asSingle(Unconfined)
         checkErroneous(single2) {
             check(it is TestException && it.message == "OK") { "$it" }
         }
@@ -95,7 +95,7 @@
             delay(50)
             send("K")
         }
-        val observable = c.toObservable(Unconfined)
+        val observable = c.asObservable(Unconfined)
         checkSingleValue(observable.reduce { t1, t2 -> t1 + t2 }.toSingle()) {
             assertEquals("OK", it)
         }
@@ -109,7 +109,7 @@
             delay(50)
             throw TestException("K")
         }
-        val observable = c.toObservable(Unconfined)
+        val observable = c.asObservable(Unconfined)
         val single = rxSingle(Unconfined) {
             var result = ""
             try {
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/IntegrationTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/IntegrationTest.kt
similarity index 97%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/IntegrationTest.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/IntegrationTest.kt
index 6b2fda7..28626c9 100644
--- a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/IntegrationTest.kt
+++ b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/IntegrationTest.kt
@@ -86,7 +86,7 @@
         }
         checkNumbers(n, observable)
         val channel = observable.open()
-        checkNumbers(n, channel.toObservable(ctx(context)))
+        checkNumbers(n, channel.asObservable(ctx(context)))
         channel.close()
     }
 
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableMultiTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableMultiTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableMultiTest.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableMultiTest.kt
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableSingleTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableSingleTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableSingleTest.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableSingleTest.kt
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableTest.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/ObservableTest.kt
diff --git a/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/SchedulerTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/SchedulerTest.kt
new file mode 100644
index 0000000..24a6ee8
--- /dev/null
+++ b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/SchedulerTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.coroutines.experimental.rx2
+
+import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.experimental.*
+import org.hamcrest.core.IsEqual
+import org.hamcrest.core.IsNot
+import org.junit.Assert.assertThat
+import org.junit.Test
+
+class SchedulerTest : TestBase() {
+    @Test
+    fun testIoScheduler(): Unit = runBlocking {
+        expect(1)
+        val mainThread = Thread.currentThread()
+        run(Schedulers.io().asCoroutineDispatcher()) {
+            val t1 = Thread.currentThread()
+            println(t1)
+            assertThat(t1, IsNot(IsEqual(mainThread)))
+            expect(2)
+            delay(100)
+            val t2 = Thread.currentThread()
+            println(t2)
+            assertThat(t2, IsNot(IsEqual(mainThread)))
+            expect(3)
+        }
+        finish(4)
+    }
+}
\ No newline at end of file
diff --git a/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/SingleTest.kt b/reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/SingleTest.kt
similarity index 100%
rename from kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/SingleTest.kt
rename to reactive/kotlinx-coroutines-rx2/src/test/kotlin/kotlinx/coroutines/experimental/rx2/SingleTest.kt
diff --git a/site/build.xml b/site/build.xml
index e7614e0..d31a34e 100644
--- a/site/build.xml
+++ b/site/build.xml
@@ -1,3 +1,19 @@
+<!--
+  ~ Copyright 2016-2017 JetBrains s.r.o.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
 <project name="site" default="site">
     <target name="site">
         <copy todir="target">
@@ -5,11 +21,12 @@
             <fileset dir="../kotlinx-coroutines-core/target/dokka" includes="**/*.md"/>
             <fileset dir="../kotlinx-coroutines-jdk8/target/dokka" includes="**/*.md"/>
             <fileset dir="../kotlinx-coroutines-nio/target/dokka" includes="**/*.md"/>
-            <fileset dir="../kotlinx-coroutines-swing/target/dokka" includes="**/*.md"/>
-            <fileset dir="../kotlinx-coroutines-javafx/target/dokka" includes="**/*.md"/>
-            <fileset dir="../kotlinx-coroutines-reactive/target/dokka" includes="**/*.md"/>
-            <fileset dir="../kotlinx-coroutines-rx1/target/dokka" includes="**/*.md"/>
-            <fileset dir="../kotlinx-coroutines-rx2/target/dokka" includes="**/*.md"/>
+            <fileset dir="../reactive/kotlinx-coroutines-reactive/target/dokka" includes="**/*.md"/>
+            <fileset dir="../reactive/kotlinx-coroutines-rx1/target/dokka" includes="**/*.md"/>
+            <fileset dir="../reactive/kotlinx-coroutines-rx2/target/dokka" includes="**/*.md"/>
+            <fileset dir="../ui/kotlinx-coroutines-android/target/dokka" includes="**/*.md"/>
+            <fileset dir="../ui/kotlinx-coroutines-javafx/target/dokka" includes="**/*.md"/>
+            <fileset dir="../ui/kotlinx-coroutines-swing/target/dokka" includes="**/*.md"/>
         </copy>
         <antcall target="jekyll"/>
     </target>
diff --git a/ui/README.md b/ui/README.md
new file mode 100644
index 0000000..3c57817
--- /dev/null
+++ b/ui/README.md
@@ -0,0 +1,9 @@
+# Coroutines for UI
+
+This directory contains modules for coroutine programming with various single-threaded UI libraries:
+
+## Modules
+
+* [kotlinx-coroutines-android](kotlinx-coroutines-android) -- `UI` context for Android applications.
+* [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx) -- `JavaFx` context for JavaFX UI applications.
+* [kotlinx-coroutines-swing](kotlinx-coroutines-swing) -- `Swing` context for Swing UI applications.
diff --git a/ui/coroutines-guide-ui.md b/ui/coroutines-guide-ui.md
new file mode 100644
index 0000000..40e44aa
--- /dev/null
+++ b/ui/coroutines-guide-ui.md
@@ -0,0 +1,647 @@
+<!--- INCLUDE .*/example-ui-([a-z]+)-([0-9]+)\.kt 
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.$$1.example$$2
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+-->
+<!--- KNIT     kotlinx-coroutines-javafx/src/test/kotlin/guide/.*\.kt -->
+
+# Guide to UI programming with coroutines
+
+This guide assumes familiarity with basic coroutine concepts that are 
+covered in [Guide to kotlinx.coroutines](../coroutines-guide.md) and gives specific 
+examples on how to use coroutines in UI applications. 
+
+All UI application libraries have one thing in common. They have the single thread where all state of the UI 
+is confined, and all updates to the UI has to happen in this particular thread. With respect to coroutines, 
+it means that you need an appropriate _coroutine dispatcher context_ that confines the coroutine 
+execution to this UI thread. 
+
+In particular, `kotlinx.coroutines` has three modules that provide coroutine context for 
+different UI application libraries:
+ 
+* [kotlinx-coroutines-android](kotlinx-coroutines-android) -- `UI` context for Android applications.
+* [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx) -- `JavaFx` context for JavaFX UI applications.
+* [kotlinx-coroutines-swing](kotlinx-coroutines-swing) -- `Swing` context for Swing UI applications.
+
+This guide covers all UI libraries simultaneously, because each of these modules consists of just one
+object definition that is couple of pages long. You can use any of them as an example to write the corresponding
+context object for your favourite UI library, even if it is not included out of the box here.
+
+## Table of contents
+
+<!--- TOC -->
+
+* [Setup](#setup)
+  * [JavaFx](#javafx)
+  * [Android](#android)
+* [Basic UI coroutines](#basic-ui-coroutines)
+  * [Launch UI coroutine](#launch-ui-coroutine)
+  * [Cancel UI coroutine](#cancel-ui-coroutine)
+* [Using actors within UI context](#using-actors-within-ui-context)
+  * [Extensions for coroutines](#extensions-for-coroutines)
+  * [At most one concurrent job](#at-most-one-concurrent-job)
+  * [Event conflation](#event-conflation)
+* [Blocking operations](#blocking-operations)
+  * [The problem of UI freezes](#the-problem-of-ui-freezes)
+  * [Blocking operations](#blocking-operations)
+* [Lifecycle](#lifecycle)
+  * [Using coroutine parent-child hierarchy](#using-coroutine-parent-child-hierarchy)
+
+<!--- END_TOC -->
+
+## Setup
+
+The runnable examples in this guide are be presented for JavaFx. The advantage is that all the examples can 
+be directly started on any OS without the need for emulators or anything like that and they are fully self-contained
+(all code is in one file). 
+There are separate notes on what changes need to be made (if any) to reproduce them on Android. 
+
+### JavaFx
+
+The basic example application for JavaFx consists of a window with a text label named `hello` that initially
+contains "Hello World!" string and a pinkish circle in the bottom-right corner named `fab` (floating action button).
+
+![UI example for JavaFx](ui-example-javafx.png)
+
+The `start` function of JavaFX application invokes `setup` function, passing it reference to `hello` and `fab`
+nodes. That is where various code is placed in the rest of this guide:
+
+```kotlin
+fun setup(hello: Text, fab: Circle) {
+    // placeholder
+}
+```
+
+> You can get full code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-01.kt)
+
+You can clone [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) project from GitHub onto your 
+workstation and open the project in IDE. All the examples from this guide are in the test folder of 
+[`ui/kotlinx-coroutines-javafx`](kotlinx-coroutines-javafx) module. 
+This way you'll be able to run and see how each example works and to 
+experiment with them by making changes.
+
+### Android
+
+Follow the guide on [Getting Started With Android and Kotlin](https://kotlinlang.org/docs/tutorials/kotlin-android.html)
+to create Kotlin project in Android Studio. You are also encouraged to add 
+[Kotlin Android Extensions](https://kotlinlang.org/docs/tutorials/android-plugin.html)
+to you application.
+
+In Android Studio 2.3 you'll get an application that looks similarly to the one shown below:
+
+![UI example for Android](ui-example-android.png)
+
+Go the `context_main.xml` of your application and assign an ID of "hello" to the text view with "Hello World!" string,
+so that it is available in your application as `hello` with Kotlin Android extensions. The pinkish floating
+action button is already named `fab` in the project template that gets created.
+
+In the `MainActivity.kt` of you application remove the block `fab.setOnClickListener { ... }` and instead
+add `setup(hello, fab)` invocation as the last line of `onCreate` function.
+Create a placeholder `setup` function at the end of the file. 
+That is where various code is placed in the rest of this guide:
+
+```kotlin
+fun setup(hello: TextView, fab: FloatingActionButton) {
+    // placeholder
+}
+```
+
+<!--- CLEAR -->
+
+Add dependencies on `kotlinx-coroutines-android` module to the `dependencies { ... }` section of
+`app/build.gradle` file:
+
+```groovy
+compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.12"
+```
+
+Coroutines are experimental feature in Kotlin.
+You need to enable coroutines in Kotlin compiler by adding the following line to `gradle.properties` file:
+ 
+```properties
+kotlin.coroutines=enable
+```
+
+You can clone [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) project from GitHub onto your 
+workstation. The resulting template project for Android resides in 
+[`ui/kotlinx-coroutines-android/example-app`](kotlinx-coroutines-android/example-app) directory. 
+You can load it in Android Studio to follow this guide on Android.
+
+## Basic UI coroutines
+
+This section shows basic usage of coroutines in UI applications.
+
+### Launch UI coroutine
+
+The `kotlinx-coroutines-javafx` module contains [JavaFx] context that dispatches coroutine execution to
+the JavaFx application thread. We import it as `UI` to make all the presented examples 
+easily portable to Android:
+ 
+```kotlin
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+```
+ 
+<!--- CLEAR -->
+
+Coroutines confined to UI thread can freely update anything in UI and suspend without blocking the UI thread.
+For example, we can perform animations by coding them in imperative style. The following code updates the
+text with a 10 to 1 countdown twice a second, using [launch] coroutine builder:
+
+```kotlin
+fun setup(hello: Text, fab: Circle) {
+    launch(UI) { // launch coroutine in UI context
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+}
+```
+
+> You can get full code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-02.kt)
+
+So, what happens here? Because we are launching coroutine in UI context, we can freely update UI from 
+inside this coroutine and invoke _suspending functions_ like [delay] at the same time. UI is not frozen
+while `delay` waits, because it does not block the UI thread -- it just suspends the coroutine.
+
+> The corresponding code for Android application is the same. 
+  You just need to copy the body of `setup` function into the corresponding function of Android project. 
+
+### Cancel UI coroutine
+
+We can keep a reference to the [Job] object that `launch` function returns and use it to cancel
+coroutine when want to stop it. Let us cancel the coroutine when pinkish circle is clicked:
+
+```kotlin
+fun setup(hello: Text, fab: Circle) {
+    val job = launch(UI) { // launch coroutine in UI context
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+    fab.onMouseClicked = EventHandler { job.cancel() } // cancel coroutine on click
+}
+```
+
+> You can get full code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-03.kt)
+
+Now, if the circle is clicked while countdown is still running, the countdown stops. 
+Note, that [Job.cancel] is completely thread-safe and non-blocking. It just signals the coroutine to cancel 
+its job, without waiting for it to actually terminate. It can be invoked from anywhere.
+Invoking it on a coroutine that was already cancelled or has completed does nothing. 
+
+> The corresponding line for Android is shown below: 
+
+```kotlin
+fab.setOnClickListener { job.cancel() }  // cancel coroutine on click
+```
+
+<!--- CLEAR -->
+
+## Using actors within UI context
+
+In this section we show how UI applications can use actors within their UI context make sure that 
+there is no unbounded growth in the number of launched coroutines.
+
+### Extensions for coroutines
+
+Our goal is to write an extension _coroutine builder_ function named `onClick`, 
+so that we can perform countdown animation every time when the circle is clicked with this simple code:
+
+```kotlin
+fun setup(hello: Text, fab: Circle) {
+    fab.onClick { // start coroutine when the circle is clicked
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+}
+```
+
+<!--- INCLUDE .*/example-ui-actor-([0-9]+).kt -->
+
+Our first implementation for `onClick` just launches a new coroutine on each mouse event and
+passes the corresponding mouse event into the block (just in case we need it):
+
+```kotlin
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    onMouseClicked = EventHandler { event ->
+        launch(UI) {
+            block(event)
+        }
+    }
+}
+```  
+
+> You can get full code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-01.kt)
+
+Note, that each time the circle is clicked, it starts a new coroutine and they all compete to 
+update the text. Try it. It does not look very good. We'll fix it later.
+
+> On Android, the corresponding extension can be written for `View` class, so that the code
+  in `setup` function that is shown above can be used without changes. There is no `MouseEvent`
+  on Android, so it is omitted.
+
+```kotlin
+fun View.onClick(block: suspend () -> Unit) {
+    setOnClickListener { 
+        launch(UI) {
+            block()
+        }
+    }
+}
+```
+
+<!--- CLEAR -->
+
+### At most one concurrent job
+
+We can cancel an active job before starting a new one to ensure that at most one coroutine is animating 
+the countdown. However, it is generally not the best idea. The [cancel][Job.cancel] function serves only as a signal
+to abort coroutine. Cancellation is cooperative and coroutine may, at the moment, be doing something non-cancellable
+or otherwise ignore a cancellation signal. A better solution is to use an [actor] for tasks that should
+not be performed concurrently. Let us change `onClick` extension implementation:
+  
+```kotlin
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    // launch one actor to handle all events on this node
+    val eventActor = actor<MouseEvent>(UI) {
+        for (event in channel) block(event) // pass event to block
+    }
+    // install a listener to offer events to this actor
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
+```  
+
+> You can get full code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-02.kt)
+  
+The key idea that underlies an integration of an actor coroutine and a regular event handler is that 
+there is an [offer][SendChannel.offer] function on [SendChannel] that does not wait. It sends an element to the actor immediately,
+if it is possible, or discards an element otherwise. An `offser` actually returns a `Boolean` result which we ignore here.
+
+Try clicking repeatedly on a circle in this version of the code. The clicks are just ignored while the countdown 
+animation is running. This happens because the actor is busy with an animation and does not receive from its channel.
+By default, an actor's mailbox is backed by [RendezvousChannel], whose `offer` operation succeeds only when 
+the `receive` is active. 
+
+> On Android, there is no `MouseEvent`, so we just send a `Unit` to the actor as a signal. 
+  The corresponding extension for `View` class looks like this:
+
+```kotlin
+fun View.onClick(block: suspend () -> Unit) {
+    // launch one actor
+    val eventActor = actor<Unit>(UI) {
+        for (event in channel) block()
+    }
+    // install a listener to activate this actor
+    setOnClickListener { 
+        eventActor.offer(Unit)
+    }
+}
+```
+
+<!--- CLEAR -->
+
+
+### Event conflation
+ 
+Sometimes it is more appropriate to process the most recent event, instead of just ignoring events while we were busy
+processing the previous one.  The [actor] coroutine builder accepts an optional `capacity` parameter that 
+controls the implementation of the channel that this actor is using for its mailbox. The description of all 
+the available choices is given in documentation of the [Channel()][Channel.invoke] factory function. 
+
+Let us change to the code to use [ConflatedChannel] by passing [Channel.CONFLATED] capacity value. The 
+change is only to the line that creates an actor:
+
+```kotlin
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    // launch one actor to handle all events on this node
+    val eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) { // <--- Changed here
+        for (event in channel) block(event) // pass event to block
+    }
+    // install a listener to offer events to this actor
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
+```  
+
+> You can get full JavaFx code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-03.kt).
+  On Android you need to update `val eventActor = ...` line from the previous example. 
+
+Now, if a circle is clicked while the animation is running, it restarts animation after the end of it. Just once. 
+Repeated clicks while the animation is running are _conflated_ and only the most recent event gets to be 
+processed. 
+
+This is also a desired behaviour for UI applications that have to react to incoming high-frequency
+event streams by updating their UI based on the most recently received update. A coroutine that is using
+[ConflatedChannel] avoids delays that are usually introduced by buffering of events.
+
+You can experiment with `capacity` parameter in the above line to see how it affects the behaviour of the code.
+Setting `capacity = Channel.UNLIMITED` creates a coroutine with [LinkedListChannel] mailbox that buffers all 
+events. In this case, the animation runs as many times and the circle is clicked.
+
+## Blocking operations
+
+This section explains patterns on using UI coroutines with thread-blocking operations.
+
+### The problem of UI freezes 
+
+It would have been great if all APIs out there were written as suspending functions that never block an 
+execution thread. However, it is quite often not the case. Sometimes you need to do a CPU-consuming computation
+or just need to invoke some 3rd party APIs for network access, for example, that blocks the invoker thread. 
+You can cannot do that from the UI thread nor from them UI-confined coroutine directly, because that would
+block the UI thread and cause the freeze up of the UI.
+
+<!--- INCLUDE .*/example-ui-blocking-([0-9]+).kt
+
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    val eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) {
+        for (event in channel) block(event) // pass event to block
+    }
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
+-->
+
+The following example illustrates the problem. We are going to use `onClick` extension with UI-confined
+event-conflating actor from the last section to process the last click in the UI thread. 
+For this example, we are going to 
+perform naive computation of [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number):
+ 
+```kotlin
+fun fib(x: Int): Int =
+    if (x <= 1) 1 else fib(x - 1) + fib(x - 2)
+``` 
+ 
+We'll be computing larger and larger Fibonacci number each time the circle is clicked. 
+To make the UI freeze more obvious, there is also a fast counting animation that is always running 
+and is constantly updating the text in the UI context:
+
+```kotlin
+fun setup(hello: Text, fab: Circle) {
+    var result = "none" // the last result
+    // counting animation 
+    launch(UI) {
+        var counter = 0
+        while (true) {
+            hello.text = "${++counter}: $result"
+            delay(100) // update the text every 100ms
+        }
+    }
+    // compute next fibonacci number of each click
+    var x = 1
+    fab.onClick {
+        result = "fib($x) = ${fib(x)}"
+        x++
+    }
+}
+```
+ 
+> You can get full JavaFx code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-01.kt).
+  You can just copy the `fib` function and the body of the `setup` function to your Android project.
+ 
+Try clicking on the circle in this example. After around 30-40th click our naive computation is going to become
+quite slow and you would immediately see how the UI thread freezes, because the animation stops running 
+during UI freeze.
+
+### Blocking operations
+
+The fix for the blocking operations on the UI thread is quite straightforward with coroutines. We'll 
+convert our "blocking" `fib` function to a non-blocking suspending function that runs the computation in 
+the background thread by using [run] function to change its execution context to [CommonPool] of background
+threads. Notice, that `fib` function is now marked with `suspend` modifier. It does not block the coroutine that
+it is invoked from anymore, but suspends its execution when the computation in background thread is working:
+
+<!--- INCLUDE .*/example-ui-blocking-0[23].kt
+
+fun setup(hello: Text, fab: Circle) {
+    var result = "none" // the last result
+    // counting animation 
+    launch(UI) {
+        var counter = 0
+        while (true) {
+            hello.text = "${++counter}: $result"
+            delay(100) // update the text every 100ms
+        }
+    }
+    // compute next fibonacci number of each click
+    var x = 1
+    fab.onClick {
+        result = "fib($x) = ${fib(x)}"
+        x++
+    }
+}
+-->
+
+```kotlin
+suspend fun fib(x: Int): Int = run(CommonPool) {
+    if (x <= 1) 1 else fib(x - 1) + fib(x - 2)
+}
+```
+
+> You can get full code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-02.kt).
+
+You can run this code and verify that UI is not frozen while large Fibonacci numbers are being computed. 
+However, this code computes `fib` somewhat slower, because every recursive call to `fib` goes via `run`. This is 
+not a big problem in practice, because `run` is smart enough to check that the coroutine is already running
+in the required context and avoids overhead of dispatching coroutine to a different thread again. It is an 
+overhead nonetheless, which is visible on this primitive code that does nothing else of use, but only adds integers 
+in between  invocations to `run`. For some more substantial code, the overhead of an extra `run` invocation is 
+not going to be significant.
+
+Still, this particular `fib` implementation can be made to run as fast as before, but in the background thread, by renaming
+the original `fib` function to `fibBlocking` and defining `fib` with `run` wrapper on top of `fibBlocking`:
+
+```kotlin
+suspend fun fib(x: Int): Int = run(CommonPool) {
+    fibBlocking(x)
+}
+
+fun fibBlocking(x: Int): Int = 
+    if (x <= 1) 1 else fibBlocking(x - 1) + fibBlocking(x - 2)
+```
+
+> You can get full code [here](kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-03.kt).
+
+You can now enjoy full-speed naive Fibonacci computation without blocking UI thread. All we need is `run(CommonPool)`.
+
+Note, that because the `fib` function is invoked from a single actor in our code, there is at most one concurrent 
+computation of it at any given time, so this code has a natural limit on the resource utilization. 
+It can saturate at most on CPU core at any given time.
+  
+## Lifecycle
+
+This section outlines an approach to life-cycle management with coroutines. 
+ 
+### Using coroutine parent-child hierarchy
+
+A typical UI application has a number of elements with a lifecycle. Windows, UI controls, activities, views, fragments
+and other visual elements are created and destroyed. A long-running coroutine, performing some IO or a background 
+computation, can retain reference to the corresponding UI elements for longer than it is needed, preventing garbage 
+collection of the whole trees of UI objects that were already destroyed and will not be displayed anymore.
+
+The natural solution to this problem is to associate a [Job] object with each UI object that has a lifecycle and create
+all the coroutines in the context of this job.
+
+For example, in Android application an `Activity` is initially _created_ and is _destroyed_ when it is no longer 
+needed and when its memory must be released. A natural solution is to attach an 
+instance of `Job` to an instance of `Activity`. We can create a mini-framework for that, 
+by defining the following `JobHolder` interface:
+
+```kotlin
+interface JobHolder {
+    val job: Job
+}
+```
+
+Now, an activity that is associated with a job needs to implement this `JobHolder` interface and define
+its `onDestroy` function to cancel the corresponding job:
+
+```kotlin
+class MainActivity : AppCompatActivity(), JobHolder {
+    override val job: Job = Job() // an instance of Job for this activity
+
+    override fun onDestroy() {
+        super.onDestroy()
+        job.cancel() // cancel the job when activity is destroyed
+    }
+ 
+    // the rest of code
+}
+```
+
+We also need a convenient way to retrieve a job for any view in the application. This is straightforward, because
+an activity is a context of the views in it, so we can define the following `View.contextJob` extension property:
+
+```kotlin
+val View.contextJob: Job
+    get() = (context as? JobHolder)?.job ?: NonCancellable
+```
+
+Here we use [NonCancellable] implementation of the `Job` as a null-object for the case where our `contextJob`
+extension property is invoked in a context that does not have an attached job.
+
+As convenience of having a `contextJob` available is that we can simply use it to start all the coroutines
+without having to worry about explicitly maintaining a list of the coroutines we had started. 
+All the life-cycle management will be taken care of by the mechanics of parent-child relations between jobs.
+ 
+For example, `View.onClick` extension from the previous section can now be defined using `contextJob`:
+ 
+```kotlin
+fun View.onClick(block: suspend () -> Unit) {
+    // launch one actor as a paren of the context job
+    val eventActor = actor<Unit>(contextJob + UI, capacity = Channel.CONFLATED) {
+        for (event in channel) block()
+    }
+    // install a listener to activate this actor
+    setOnClickListener {
+        eventActor.offer(Unit)
+    }
+}
+```
+
+Notice `contextJob + UI` expression that is used to start an actor in the above code. It defines a coroutine context
+for our new actor that includes the job and UI dispatcher. The coroutine that is started by this 
+`actor(contextJob + UI)` expression is going to become a child of the job of the corresponding context. When the 
+activity is destroyed and its job is cancelled, all its children coroutines are cancelled. 
+
+Parent-child relation between jobs forms a hierarchy. A coroutine that performs some background job on behalf of
+the view and in its context can create further children coroutines. The whole tree of coroutines gets cancelled
+when the parent job is cancelled. An example of that is shown in 
+["Children of a coroutine"](../coroutines-guide.md#children-of-a-coroutine) section of the guide to coroutines.
+  
+<!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core -->
+<!--- DOCS_ROOT kotlinx-coroutines-core/target/dokka/kotlinx-coroutines-core -->
+<!--- INDEX kotlinx.coroutines.experimental -->
+[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/launch.html
+[delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/delay.html
+[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/index.html
+[Job.cancel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-job/cancel.html
+[run]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/run.html
+[CommonPool]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-common-pool/index.html
+[NonCancellable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-non-cancellable/index.html
+<!--- INDEX kotlinx.coroutines.experimental.channels -->
+[actor]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/actor.html
+[SendChannel.offer]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/offer.html
+[SendChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-send-channel/index.html
+[RendezvousChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-rendezvous-channel/index.html
+[Channel.invoke]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/invoke.html
+[ConflatedChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-conflated-channel/index.html
+[Channel.CONFLATED]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-channel/-c-o-n-f-l-a-t-e-d.html
+[LinkedListChannel]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental.channels/-linked-list-channel/index.html
+<!--- SITE_ROOT https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-javafx -->
+<!--- DOCS_ROOT ui/kotlinx-coroutines-javafx/target/dokka/kotlinx-coroutines-javafx -->
+<!--- INDEX kotlinx.coroutines.experimental.javafx -->
+[JavaFx]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-javafx/kotlinx.coroutines.experimental.javafx/-java-fx/index.html
+<!--- DOCS_ROOT ui/kotlinx-coroutines-android/target/dokka/kotlinx-coroutines-android -->
+<!--- INDEX kotlinx.coroutines.experimental.android -->
+<!--- END -->
diff --git a/ui/kotlinx-coroutines-android/README.md b/ui/kotlinx-coroutines-android/README.md
new file mode 100644
index 0000000..8bbbdc7
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/README.md
@@ -0,0 +1,10 @@
+# Module kotlinx-coroutines-android
+
+Provides `UI` context for Android applications.
+
+Read [Guide to UI programming with coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md)
+for tutorial on this module.
+
+# Package kotlinx.coroutines.experimental.android
+
+Provides `UI` context for Android applications.
diff --git a/ui/kotlinx-coroutines-android/example-app/.gitignore b/ui/kotlinx-coroutines-android/example-app/.gitignore
new file mode 100644
index 0000000..03d649e
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/.gitignore
@@ -0,0 +1,7 @@
+local.properties
+.gradle
+.idea
+build
+example-app.iml
+app/build
+app/app.iml
diff --git a/ui/kotlinx-coroutines-android/example-app/app/build.gradle b/ui/kotlinx-coroutines-android/example-app/app/build.gradle
new file mode 100644
index 0000000..62dfdb4
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/build.gradle
@@ -0,0 +1,46 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+    compileSdkVersion 25
+    buildToolsVersion "25.0.2"
+    defaultConfig {
+        applicationId "com.example.app"
+        minSdkVersion 9
+        targetSdkVersion 25
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+repositories {
+    mavenLocal()
+    mavenCentral()
+}
+
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    compile 'com.android.support:appcompat-v7:25.2.0'
+    compile 'com.android.support.constraint:constraint-layout:1.0.1'
+    compile 'com.android.support:design:25.2.0'
+    testCompile 'junit:junit:4.12'
+    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+    compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.12"
+}
+
+kotlin {
+    experimental {
+        coroutines "enable"
+    }
+}
diff --git a/ui/kotlinx-coroutines-android/example-app/app/proguard-rules.pro b/ui/kotlinx-coroutines-android/example-app/app/proguard-rules.pro
new file mode 100644
index 0000000..a74eede
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in C:\Users\roman\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/AndroidManifest.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a04a27e
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.app">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name"
+            android:theme="@style/AppTheme.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt b/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt
new file mode 100644
index 0000000..9f04427
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt
@@ -0,0 +1,38 @@
+package com.example.app
+
+import android.os.Bundle
+import android.support.design.widget.FloatingActionButton
+import android.support.v7.app.AppCompatActivity
+import android.view.Menu
+import android.view.MenuItem
+import android.widget.TextView
+import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.android.synthetic.main.content_main.*
+
+class MainActivity : AppCompatActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_main)
+        setSupportActionBar(toolbar)
+        setup(hello, fab)
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        menuInflater.inflate(R.menu.menu_main, menu)
+        return true
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        val id = item.itemId
+        if (id == R.id.action_settings) return true
+        return super.onOptionsItemSelected(item)
+    }
+}
+
+fun setup(hello: TextView, fab: FloatingActionButton) {
+    // placeholder
+}
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..13d3225
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.app.MainActivity">
+
+    <android.support.design.widget.AppBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:theme="@style/AppTheme.AppBarOverlay">
+
+        <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize"
+            android:background="?attr/colorPrimary"
+            app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+    </android.support.design.widget.AppBarLayout>
+
+    <include layout="@layout/content_main" />
+
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/fab"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|end"
+        android:layout_margin="@dimen/fab_margin"
+        app:srcCompat="@android:drawable/ic_dialog_email" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml
new file mode 100644
index 0000000..110dc67
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    app:layout_behavior="@string/appbar_scrolling_view_behavior"
+    tools:context="com.example.app.MainActivity"
+    tools:showIn="@layout/activity_main">
+
+    <TextView
+        android:id="@+id/hello"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Hello World!"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/menu/menu_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 0000000..c4ad098
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context="com.example.app.MainActivity">
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:title="@string/action_settings"
+        app:showAsAction="never" />
+</menu>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/colors.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/dimens.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..59a0b0c
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/dimens.xml
@@ -0,0 +1,3 @@
+<resources>
+    <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/strings.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..a94b2df
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+    <string name="app_name">ExampleApp</string>
+    <string name="action_settings">Settings</string>
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/styles.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..d4ea9ae
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/ui/kotlinx-coroutines-android/example-app/build.gradle b/ui/kotlinx-coroutines-android/example-app/build.gradle
new file mode 100644
index 0000000..32e160d
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    ext.kotlin_version = '1.1.0'
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:2.3.0'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        jcenter()
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle.properties b/ui/kotlinx-coroutines-android/example-app/gradle.properties
new file mode 100644
index 0000000..b5b22e0
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradle.properties
@@ -0,0 +1,19 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+kotlin.coroutines=enable
\ No newline at end of file
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.jar b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..9a778d6
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Dec 28 10:00:20 PST 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/ui/kotlinx-coroutines-android/example-app/gradlew b/ui/kotlinx-coroutines-android/example-app/gradlew
new file mode 100644
index 0000000..9d82f78
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/ui/kotlinx-coroutines-android/example-app/gradlew.bat b/ui/kotlinx-coroutines-android/example-app/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/kotlinx-coroutines-android/example-app/settings.gradle b/ui/kotlinx-coroutines-android/example-app/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/example-app/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/kotlinx-coroutines-rx1/pom.xml b/ui/kotlinx-coroutines-android/pom.xml
similarity index 88%
copy from kotlinx-coroutines-rx1/pom.xml
copy to ui/kotlinx-coroutines-android/pom.xml
index 64c708a..ad7513a 100644
--- a/kotlinx-coroutines-rx1/pom.xml
+++ b/ui/kotlinx-coroutines-android/pom.xml
@@ -23,9 +23,10 @@
         <groupId>org.jetbrains.kotlinx</groupId>
         <artifactId>kotlinx-coroutines</artifactId>
         <version>0.12</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
-    <artifactId>kotlinx-coroutines-rx1</artifactId>
+    <artifactId>kotlinx-coroutines-android</artifactId>
     <packaging>jar</packaging>
 
     <build>
@@ -35,11 +36,6 @@
 
     <dependencies>
         <dependency>
-            <groupId>io.reactivex</groupId>
-            <artifactId>rxjava</artifactId>
-            <version>1.2.6</version>
-        </dependency>
-        <dependency>
             <groupId>org.jetbrains.kotlinx</groupId>
             <artifactId>kotlinx-coroutines-core</artifactId>
             <version>${project.version}</version>
@@ -52,6 +48,11 @@
             <classifier>tests</classifier>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.google.android</groupId>
+            <artifactId>android</artifactId>
+            <version>2.3.1</version>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/ui/kotlinx-coroutines-android/src/main/kotlin/kotlinx/coroutines/experimental/android/HandlerContext.kt b/ui/kotlinx-coroutines-android/src/main/kotlin/kotlinx/coroutines/experimental/android/HandlerContext.kt
new file mode 100644
index 0000000..de02f8d
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/src/main/kotlin/kotlinx/coroutines/experimental/android/HandlerContext.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.coroutines.experimental.android
+
+import android.os.Handler
+import android.os.Looper
+import kotlinx.coroutines.experimental.CancellableContinuation
+import kotlinx.coroutines.experimental.CoroutineDispatcher
+import kotlinx.coroutines.experimental.Delay
+import kotlinx.coroutines.experimental.DisposableHandle
+import java.util.concurrent.TimeUnit
+import kotlin.coroutines.experimental.CoroutineContext
+
+/**
+ * Dispatches execution onto Android main UI thread and provides native [delay][Delay.delay] support.
+ */
+val UI = HandlerContext(Handler(Looper.getMainLooper()), "UI")
+
+/**
+ * Represents an arbitrary [Handler] as a implementation of [CoroutineDispatcher].
+ */
+fun Handler.asCoroutineDispatcher() = HandlerContext(this)
+
+/**
+ * Implements [CoroutineDispatcher] on top of an arbitrary Android [Handler].
+ * @param handler a handler.
+ * @param name an optional name for debugging.
+ */
+public class HandlerContext(
+    private val handler: Handler,
+    private val name: String? = null
+) : CoroutineDispatcher(), Delay {
+    override fun dispatch(context: CoroutineContext, block: Runnable) {
+        handler.post(block)
+    }
+
+    override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
+        handler.postDelayed({
+            with(continuation) { resumeUndispatched(Unit) }
+        }, unit.toMillis(time))
+    }
+
+    override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle {
+        handler.postDelayed(block, unit.toMillis(time))
+        return object : DisposableHandle {
+            override fun dispose() {
+                handler.removeCallbacks(block)
+            }
+        }
+    }
+
+    override fun toString() = name ?: handler.toString()
+}
diff --git a/ui/kotlinx-coroutines-javafx/README.md b/ui/kotlinx-coroutines-javafx/README.md
new file mode 100644
index 0000000..1dba74e
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/README.md
@@ -0,0 +1,10 @@
+# Module kotlinx-coroutines-javafx
+
+Provides `JavaFx` context for JavaFX UI applications.
+
+Read [Guide to UI programming with coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md)
+for tutorial on this module.
+
+# Package kotlinx.coroutines.experimental.javafx
+
+Provides `JavaFx` context for JavaFX UI applications.
diff --git a/kotlinx-coroutines-javafx/pom.xml b/ui/kotlinx-coroutines-javafx/pom.xml
similarity index 96%
rename from kotlinx-coroutines-javafx/pom.xml
rename to ui/kotlinx-coroutines-javafx/pom.xml
index 38f66ed..b361bff 100644
--- a/kotlinx-coroutines-javafx/pom.xml
+++ b/ui/kotlinx-coroutines-javafx/pom.xml
@@ -23,6 +23,7 @@
         <groupId>org.jetbrains.kotlinx</groupId>
         <artifactId>kotlinx-coroutines</artifactId>
         <version>0.12</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
     <artifactId>kotlinx-coroutines-javafx</artifactId>
diff --git a/kotlinx-coroutines-javafx/src/main/kotlin/kotlinx/coroutines/experimental/javafx/JavaFx.kt b/ui/kotlinx-coroutines-javafx/src/main/kotlin/kotlinx/coroutines/experimental/javafx/JavaFx.kt
similarity index 80%
rename from kotlinx-coroutines-javafx/src/main/kotlin/kotlinx/coroutines/experimental/javafx/JavaFx.kt
rename to ui/kotlinx-coroutines-javafx/src/main/kotlin/kotlinx/coroutines/experimental/javafx/JavaFx.kt
index ce21513..b1587c5 100644
--- a/kotlinx-coroutines-javafx/src/main/kotlin/kotlinx/coroutines/experimental/javafx/JavaFx.kt
+++ b/ui/kotlinx-coroutines-javafx/src/main/kotlin/kotlinx/coroutines/experimental/javafx/JavaFx.kt
@@ -50,14 +50,26 @@
     }
 
     override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
-        val handler = EventHandler<ActionEvent> {
+        val timeline = schedule(time, unit, EventHandler<ActionEvent> {
             with(continuation) { resumeUndispatched(Unit) }
-        }
-        val timeline = Timeline(KeyFrame(Duration.millis(unit.toMillis(time).toDouble()), handler))
-        timeline.play()
+        })
         continuation.invokeOnCompletion { timeline.stop() }
     }
 
+    override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle {
+        val timeline = schedule(time, unit, EventHandler<ActionEvent> {
+            block.run()
+        })
+        return object : DisposableHandle {
+            override fun dispose() {
+                timeline.stop()
+            }
+        }
+    }
+
+    private fun schedule(time: Long, unit: TimeUnit, handler: EventHandler<ActionEvent>): Timeline =
+        Timeline(KeyFrame(Duration.millis(unit.toMillis(time).toDouble()), handler)).apply { play() }
+
     private class PulseTimer : AnimationTimer() {
         val next = CopyOnWriteArrayList<CancellableContinuation<Long>>()
 
diff --git a/kotlinx-coroutines-javafx/src/test/kotlin/examples/FxExampleApp.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/examples/FxExampleApp.kt
similarity index 96%
rename from kotlinx-coroutines-javafx/src/test/kotlin/examples/FxExampleApp.kt
rename to ui/kotlinx-coroutines-javafx/src/test/kotlin/examples/FxExampleApp.kt
index d861c8c..8db651f 100644
--- a/kotlinx-coroutines-javafx/src/test/kotlin/examples/FxExampleApp.kt
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/examples/FxExampleApp.kt
@@ -59,10 +59,10 @@
 
     val scene = Scene(root, 600.0, 400.0)
 
-    override fun start(primaryStage: Stage) {
-        primaryStage.title = "Hello world!"
-        primaryStage.scene = scene
-        primaryStage.show()
+    override fun start(stage: Stage) {
+        stage.title = "Hello world!"
+        stage.scene = scene
+        stage.show()
     }
 
     val random = Random()
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-01.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-01.kt
new file mode 100644
index 0000000..58255ac
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-01.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.actor.example01
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    fab.onClick { // start coroutine when the circle is clicked
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+}
+
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    onMouseClicked = EventHandler { event ->
+        launch(UI) {
+            block(event)
+        }
+    }
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-02.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-02.kt
new file mode 100644
index 0000000..906b57a
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-02.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.actor.example02
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    fab.onClick { // start coroutine when the circle is clicked
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+}
+
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    // launch one actor to handle all events on this node
+    val eventActor = actor<MouseEvent>(UI) {
+        for (event in channel) block(event) // pass event to block
+    }
+    // install a listener to offer events to this actor
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-03.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-03.kt
new file mode 100644
index 0000000..7ef31f2
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-actor-03.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.actor.example03
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    fab.onClick { // start coroutine when the circle is clicked
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+}
+
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    // launch one actor to handle all events on this node
+    val eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) { // <--- Changed here
+        for (event in channel) block(event) // pass event to block
+    }
+    // install a listener to offer events to this actor
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-01.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-01.kt
new file mode 100644
index 0000000..9072ff9
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-01.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.basic.example01
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    // placeholder
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-02.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-02.kt
new file mode 100644
index 0000000..63952cf
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-02.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.basic.example02
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    launch(UI) { // launch coroutine in UI context
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-03.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-03.kt
new file mode 100644
index 0000000..725b298
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-basic-03.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.basic.example03
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    val job = launch(UI) { // launch coroutine in UI context
+        for (i in 10 downTo 1) { // countdown from 10 to 1 
+            hello.text = "Countdown $i ..." // update text
+            delay(500) // wait half a second
+        }
+        hello.text = "Done!"
+    }
+    fab.onMouseClicked = EventHandler { job.cancel() } // cancel coroutine on click
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-01.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-01.kt
new file mode 100644
index 0000000..3ceaecb
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-01.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.blocking.example01
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    val eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) {
+        for (event in channel) block(event) // pass event to block
+    }
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
+
+fun fib(x: Int): Int =
+    if (x <= 1) 1 else fib(x - 1) + fib(x - 2)
+
+fun setup(hello: Text, fab: Circle) {
+    var result = "none" // the last result
+    // counting animation 
+    launch(UI) {
+        var counter = 0
+        while (true) {
+            hello.text = "${++counter}: $result"
+            delay(100) // update the text every 100ms
+        }
+    }
+    // compute next fibonacci number of each click
+    var x = 1
+    fab.onClick {
+        result = "fib($x) = ${fib(x)}"
+        x++
+    }
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-02.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-02.kt
new file mode 100644
index 0000000..ac24f0a
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-02.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.blocking.example02
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    val eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) {
+        for (event in channel) block(event) // pass event to block
+    }
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    var result = "none" // the last result
+    // counting animation 
+    launch(UI) {
+        var counter = 0
+        while (true) {
+            hello.text = "${++counter}: $result"
+            delay(100) // update the text every 100ms
+        }
+    }
+    // compute next fibonacci number of each click
+    var x = 1
+    fab.onClick {
+        result = "fib($x) = ${fib(x)}"
+        x++
+    }
+}
+
+suspend fun fib(x: Int): Int = run(CommonPool) {
+    if (x <= 1) 1 else fib(x - 1) + fib(x - 2)
+}
diff --git a/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-03.kt b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-03.kt
new file mode 100644
index 0000000..de041ee
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/src/test/kotlin/guide/example-ui-blocking-03.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file was automatically generated from coroutines-guide-ui.md by Knit tool. Do not edit.
+package guide.ui.blocking.example03
+
+import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.*
+import kotlinx.coroutines.experimental.javafx.JavaFx as UI
+import javafx.application.Application
+import javafx.event.EventHandler
+import javafx.geometry.*
+import javafx.scene.*
+import javafx.scene.input.MouseEvent
+import javafx.scene.layout.StackPane
+import javafx.scene.paint.Color
+import javafx.scene.shape.Circle
+import javafx.scene.text.Text
+import javafx.stage.Stage
+
+fun main(args: Array<String>) {
+    Application.launch(ExampleApp::class.java, *args)
+}
+
+class ExampleApp : Application() {
+    val hello = Text("Hello World!").apply {
+        fill = Color.valueOf("#C0C0C0")
+    }
+
+    val fab = Circle(20.0, Color.valueOf("#FF4081"))
+
+    val root = StackPane().apply {
+        children += hello
+        children += fab
+        StackPane.setAlignment(hello, Pos.CENTER)
+        StackPane.setAlignment(fab, Pos.BOTTOM_RIGHT)
+        StackPane.setMargin(fab, Insets(15.0))
+    }
+
+    val scene = Scene(root, 240.0, 380.0).apply {
+        fill = Color.valueOf("#303030")
+    }
+
+    override fun start(stage: Stage) {
+        stage.title = "Example"
+        stage.scene = scene
+        stage.show()
+        setup(hello, fab)
+    }
+}
+
+fun Node.onClick(block: suspend (MouseEvent) -> Unit) {
+    val eventActor = actor<MouseEvent>(UI, capacity = Channel.CONFLATED) {
+        for (event in channel) block(event) // pass event to block
+    }
+    onMouseClicked = EventHandler { event ->
+        eventActor.offer(event)
+    }
+}
+
+fun setup(hello: Text, fab: Circle) {
+    var result = "none" // the last result
+    // counting animation 
+    launch(UI) {
+        var counter = 0
+        while (true) {
+            hello.text = "${++counter}: $result"
+            delay(100) // update the text every 100ms
+        }
+    }
+    // compute next fibonacci number of each click
+    var x = 1
+    fab.onClick {
+        result = "fib($x) = ${fib(x)}"
+        x++
+    }
+}
+
+suspend fun fib(x: Int): Int = run(CommonPool) {
+    fibBlocking(x)
+}
+
+fun fibBlocking(x: Int): Int = 
+    if (x <= 1) 1 else fibBlocking(x - 1) + fibBlocking(x - 2)
diff --git a/ui/kotlinx-coroutines-swing/README.md b/ui/kotlinx-coroutines-swing/README.md
new file mode 100644
index 0000000..a035928
--- /dev/null
+++ b/ui/kotlinx-coroutines-swing/README.md
@@ -0,0 +1,10 @@
+# Module kotlinx-coroutines-swing
+
+Provides `Swing` context for Swing UI applications.
+
+Read [Guide to UI programming with coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md)
+for tutorial on this module.
+
+# Package kotlinx.coroutines.experimental.swing
+
+Provides `Swing` context for Swing UI applications.
diff --git a/kotlinx-coroutines-swing/pom.xml b/ui/kotlinx-coroutines-swing/pom.xml
similarity index 97%
rename from kotlinx-coroutines-swing/pom.xml
rename to ui/kotlinx-coroutines-swing/pom.xml
index 3822ee3..ce5bba6 100644
--- a/kotlinx-coroutines-swing/pom.xml
+++ b/ui/kotlinx-coroutines-swing/pom.xml
@@ -23,6 +23,7 @@
         <groupId>org.jetbrains.kotlinx</groupId>
         <artifactId>kotlinx-coroutines</artifactId>
         <version>0.12</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
     <artifactId>kotlinx-coroutines-swing</artifactId>
diff --git a/kotlinx-coroutines-swing/src/main/kotlin/kotlinx/coroutines/experimental/swing/Swing.kt b/ui/kotlinx-coroutines-swing/src/main/kotlin/kotlinx/coroutines/experimental/swing/Swing.kt
similarity index 72%
rename from kotlinx-coroutines-swing/src/main/kotlin/kotlinx/coroutines/experimental/swing/Swing.kt
rename to ui/kotlinx-coroutines-swing/src/main/kotlin/kotlinx/coroutines/experimental/swing/Swing.kt
index 08cb0da..44695c6 100644
--- a/kotlinx-coroutines-swing/src/main/kotlin/kotlinx/coroutines/experimental/swing/Swing.kt
+++ b/ui/kotlinx-coroutines-swing/src/main/kotlin/kotlinx/coroutines/experimental/swing/Swing.kt
@@ -19,6 +19,7 @@
 import kotlinx.coroutines.experimental.CancellableContinuation
 import kotlinx.coroutines.experimental.CoroutineDispatcher
 import kotlinx.coroutines.experimental.Delay
+import kotlinx.coroutines.experimental.DisposableHandle
 import kotlinx.coroutines.experimental.swing.Swing.delay
 import java.awt.event.ActionListener
 import java.util.concurrent.TimeUnit
@@ -33,16 +34,28 @@
     override fun dispatch(context: CoroutineContext, block: Runnable) = SwingUtilities.invokeLater(block)
 
     override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) {
-        val timerTime = unit.toMillis(time).coerceAtMost(Int.MAX_VALUE.toLong()).toInt()
-        val action = ActionListener {
+        val timer = schedule(time, unit, ActionListener {
             with(continuation) { resumeUndispatched(Unit) }
+        })
+        continuation.invokeOnCompletion { timer.stop() }
+    }
+
+    override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle {
+        val timer = schedule(time, unit, ActionListener {
+            block.run()
+        })
+        return object : DisposableHandle {
+            override fun dispose() {
+                timer.stop()
+            }
         }
-        val timer = Timer(timerTime, action).apply {
+    }
+
+    private fun schedule(time: Long, unit: TimeUnit, action: ActionListener): Timer =
+        Timer(unit.toMillis(time).coerceAtMost(Int.MAX_VALUE.toLong()).toInt(), action).apply {
             isRepeats = false
             start()
         }
-        continuation.invokeOnCompletion { timer.stop() }
-    }
 
     override fun toString() = "Swing"
 }
diff --git a/kotlinx-coroutines-swing/src/test/kotlin/examples/SwingExampleApp.kt b/ui/kotlinx-coroutines-swing/src/test/kotlin/examples/SwingExampleApp.kt
similarity index 100%
rename from kotlinx-coroutines-swing/src/test/kotlin/examples/SwingExampleApp.kt
rename to ui/kotlinx-coroutines-swing/src/test/kotlin/examples/SwingExampleApp.kt
diff --git a/kotlinx-coroutines-swing/src/test/kotlin/examples/swing-example.kt b/ui/kotlinx-coroutines-swing/src/test/kotlin/examples/swing-example.kt
similarity index 100%
rename from kotlinx-coroutines-swing/src/test/kotlin/examples/swing-example.kt
rename to ui/kotlinx-coroutines-swing/src/test/kotlin/examples/swing-example.kt
diff --git a/kotlinx-coroutines-swing/src/test/kotlin/kotlinx/coroutines/experimental/swing/SwingTest.kt b/ui/kotlinx-coroutines-swing/src/test/kotlin/kotlinx/coroutines/experimental/swing/SwingTest.kt
similarity index 100%
rename from kotlinx-coroutines-swing/src/test/kotlin/kotlinx/coroutines/experimental/swing/SwingTest.kt
rename to ui/kotlinx-coroutines-swing/src/test/kotlin/kotlinx/coroutines/experimental/swing/SwingTest.kt
diff --git a/ui/ui-example-android.png b/ui/ui-example-android.png
new file mode 100644
index 0000000..78ed5af
--- /dev/null
+++ b/ui/ui-example-android.png
Binary files differ
diff --git a/ui/ui-example-javafx.png b/ui/ui-example-javafx.png
new file mode 100644
index 0000000..60ded70
--- /dev/null
+++ b/ui/ui-example-javafx.png
Binary files differ