JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdn.jsdelivr.net/kefir/3.1.0/kefir.js"></script>
<p>This is a solution for challenge from "<a href="http://www.jayway.com/2014/09/16/comparing-core-async-and-rx-by-example/" target="_blank">Comparing Core Async and Rx by Example</a>"  blog post by Johan Haleby.</p>

<hr/>

<button id="a">A</button>
<button id="b">B</button>

<span id="status">

JavaScript

var SECRET = 'ABBABA';
var TIME_LIMIT = 5 * 1000;


// Base sources

var aClciks = Kefir.fromEvents(document.querySelector('#a'), 'click');
var bClciks = Kefir.fromEvents(document.querySelector('#b'), 'click');


// Compose base sources to create the desirable observables

var letters = Kefir.merge([
    aClciks.map(function() {return 'A'}),
    bClciks.map(function() {return 'B'})
]);

var withTime = letters.map(function(letter) {
    return {
        time: Date.now(),
        letter: letter
    };
});

var lastCombination = withTime
    .slidingWindow(SECRET.length)
    .map(function(comb) {
        return {
            timeSpend: comb[comb.length - 1].time - comb[0].time,
            letters: comb.map(function(x) {return x.letter}).join('')
        }
    });

var statusText = lastCombination.map(function(comb) {
    return comb.letters + ' (within ' + Math.ceil(comb.timeSpend / 1000) + ' sec.)';
});

var success = lastCombination.filter(function(comb) {
    return comb.timeSpend < TIME_LIMIT && comb.letters === SECRET;
});


// Side effects

var statusEl = document.querySelector('#status');
statusText.onValue(function(text) {
    statusEl.innerHTML = text;              
});

success.onValue(function() {
  alert('Combination unlocked!');
});