Duolingo lessons to go

If you are using Duolingo and are nearing the end of the tree, you might be anxious to know how many lessons are left till you can claim your tree is all golden. Here’s a small Javascript snippet that allows to get that from the main language page on the site:

var lessons = $('.lessons-left:not(:empty)').map(function() {
    return this.innerHTML

var listToInt = function(list) {
    return _.map(list, function(e) {
        return parseInt(e)

var expanded = _.map(lessons, function(e) {
    var list = e.split('/')
    return listToInt(list)

var done = _.collect(expanded, _.head)
var total = _.collect(expanded, _.last)

var sum = function(list) {
    return _.reduce(list, function(a, b) { 
        return a + b
    }, 0)

console.log("lessons to go:", sum(total) - sum(done))

Here’s how it can be used:

  • Open Chrome Developer Tools window by pressing F12
  • Go to Sources tab
  • Go to Snippets sub-tab
  • On the left, right-click and select New to create a new snippet. Name it whatever you like, I named it “Duolingo – lessons to go”
  • Put the above code in the snippet source tab that opens
  • Run it by pressing Ctrl + Enter or by clicking on a play icon in the top right of the Developer Tools window

It should print your tree leftover in the console. Now let’s get that number down to 0!

Testing Ajax on jsFiddle with jQuery

jsFiddle is a wonderful site. Just got to love the idea and the implementation. It has so much that’s invaluable for quick testing. Recently, I discovered that you can actually test Ajax calls on jsFiddle. They call it “Echo” requests, as they do exactly that – they echo back whatever you send. You can read more about this in jsFiddle documentation.

What’s nice about this is that you write both the client and the “server” – it’s really strong to call echo server a server, but I digress – on the same page, you see the whole code here and it’s great for quick tests for situations such as “why is this 20+-page web site not working after adding these 5 lines of straightforward code?” which usually end in banging the head against the wall and then realizing that you misplaced a comma, added one parentheses too many, mispelled that 15-character identifier or something frustrating along these lines. So you fire a browser (that is, a new tab, as you always have your browser open, don’t you), write a quick jsFiddle and you get the “doh!” moment relatively quickly.

Here’s how one could write a simple Fibonnaci number “generator” that uses jsFiddle’s echo:

  • HTML
<button id="next-fib">Next Fibonnaci</button>
<ul id="fibs">

We just created a button and a list of fibs. The button will launch an Ajax call when clicked, see Javascript below.

  • CSS
#fibs {
  list-style-type: none; 
#fibs li {
  float: left;
  padding-left: 10px;

Some basic styling for nicer number placement.

  • Javascript:
function make_next_fib() {
  var all_lis = $('#fibs > li');
  var last_two_lis = all_lis.slice(all_lis.length - 2);
  var last_two_fibs = last_two_lis.map(function() {
    return parseInt($(this).text());

  var sum = last_two_fibs[0] + last_two_fibs[1];
  var json = $.toJSON({ next_fib: sum });
    url: '/echo/json/',
    dataType: 'json',
    type: 'POST',
    data: {
      json: json,
    success: function(data) {
      var li = $('<li>').text(data.next_fib);

$('#next-fib').click(function() {

Javascript is pretty self-explanatory. make_next_fib is the meat. It will:

  • Find all li elements within parent fibs
  • Select the last two (as Fibonnaci numbers are made by summing the last two)
  • Map the li into actual numbers
  • Get the sum of these numbers – this is what we are going to send via jsFiddle echo service
  • Make the Ajax call
  • In success, just append a new li to #fibs

A few things about the Ajax call itself:

  • The call has to target a specific URL made available by jsFiddle. These are provided in the documentation. We use json one, so the url is /echo/json/
  • It needs to be a POST to send the data and we set dataType to json, as we are sending and receiving the json
  • The json is actually sent as a string. In order to convert, a plugin can be used – such as jquery-json. This needs to be added to your jsFiddle. Use Add Resources (which changes to Manage Resources when you add some) on the left to point to the minified version (currently version 2.3)

The click event handler at the end is there to enable all this to happen when the button is clicked.

That’s it! Here’s a working jsFiddle:

After clicking a few times, you should see something like this in the result part:

CouchDB and Kanso

To see how CouchDB and Kanso work together, I’m going to build a very simple application that allows you to list and show capitals of countries in the world.

For the impatient

If you just want to play or first see the app and then determine whether it’s worth reading at all, you can find the code at GitHub.


You can read about installing CouchDB here, for Ubuntu:

The important thing is that you need CouchDB 1.1+, as that’s what Kanso requires. You can use the following ppa for that:

like this:

$ sudo apt-add-repository ppa:kmpm/ppa
$ sudo apt-get update
$ sudo apt-get install couchdb

You should verify you have CouchDB 1.1+ now:

$ curl http://localhost:5984/

Installing Kanso is outlined in Kanso tutorial, but basically boils down to:

  • Installing node.js
  • Installing node.js package manager npm
  • Installing Kanso with sudo npm install -g kanso.

For Ubuntu, you can follow the following to-the-point tutorial by Kip Lawrence for node.js and npm:

If you want to use ppas, you can check this:

I used the last method, like this:

$ sudo apt-add-repository ppa:mdz/locker
$ sudo apt-get update
$ sudo apt-get install nodejs npm
$ sudo npm install -g kanso

and a quick check that everything is in place:

$ node -v
$ npm -v
$ kanso -v

Getting started with the application

To start a new Kanso application:

$ kanso create country-capitals
OK: /home/icyrock.com/web/couchdb/kanso/country-capitals

If you list the files:

$ find -type f

you will see there are several important folder and files. Most of these are outlined in the Kanso tutorial, here are my comments on this:

  • You can see that jQuery version is 1.5.2 and minified. Current jQuery is 1.6.2, so this is a bit outdated and if you run into some problems where you actually need to debug, you’d probably want to substitute a non-minified version. Obviously, Kanso was designed for “ready to push to prod” kind of attitude, so this is expected
  • You already have some basic templates there – edit these to suit your needs
  • There are a lot of .js files in lib folder – this is the logic piece that should be edited by the application creator to describe what the app should actually do
  • There are a lot of CommonJS modules included – if on Ubuntu and installed as I did, take a look at /usr/lib/node_modules/kanso, especially commonjs/kanso subfolder


As my data source, I used list of national capitals from Wikipedia. Kanso supports data transformations and uploads just as we need. Here’s what we are going to do:

  • For starters, I put the list from Wikipedia into a CSV file. Note the csv will have three columns: the expected two are country and capital, but the third one is a requirement of Kanso type system that will assign the type to a document. We’ll see this later, but for now just remember the type is countryCapital
  • Kanso can transform CSV into JSON with kanso transform
  • After that, we will use kanso transform add-ids to populate the IDs for each of the documents, to prevent duplication from multiple pushes
  • The next step is to create the database – curl will be just enough
  • We’ll then use kanso pushdata to push the data into CouchDB

So, do the following within your app’s root folder:

$ mkdir data
$ cd data
$ wget <file>
$ kanso transform csv country-list.csv country-list.json
$ kanso transform add-ids country-list.json country-list-with-ids.json
$ curl -X PUT http://localhost:5984/country-capitals
$ kanso pushdata http://localhost:5984/country-capitals country-list-with-ids.json

If you glance your local Futon, specifically country-capitals database, you should see all the data in there. Awesome, let’s go to the application.

Basic test

Let’s push this to our local CouchDB and test whether it works:

$ kanso push http://localhost:5984/country-capitals
OK: http://localhost:5984/country-capitals/_design/country-capitals/_rewrite

The url after OK is where you should point your browser after the above.

If during running the above you get the message such as:

{"error":"os_process_error","reason":"OS process timed out."}

then check that you have CouchDB 1.1+. Otherwise, you should get a greeting and a confirmation you are running a Kanso-powered app.

After confirming Kanso works as expected, let’s build our app.


Kanso has a notion of types which allow for a simple mapping from CouchDB database objects to plain Javascript objects. We have only one database, country-capitals, and the objects in it have country and capital fields, both strings. Here’s how we’d map this with Kanso’s types:

var Type = require('kanso/types').Type,
    fields = require('kanso/fields');

exports.countryCapital = new Type('countryCapital', {
    fields: {
        country: fields.string(),
        capital: fields.string(),

Let’s run through the above quickly. The first part requires the necessary CommonJS modules from Kanso – Type and fields. These are used later to define the document contents. Now we use exports to export a newly defined type – country-capitals, that references CouchDB documents in country-capitals database. Each of these have two string fields, country and capital.

The above and all code related to defining types goes to lib/types.js file. Let’s put it there, push the app again, then push the admin app like this:

$ kanso pushadmin http://localhost:5984/country-capitals
OK: http://localhost:5984/country-capitals/_design/admin/_rewrite/

and go to the above URL. You should see the admin interface which allows you to drill down to actual CountryCapitals instances. You should see all the instances we put previously.


Views are used by CouchDB to do transformation of data, mainly to do searches and display. Views transform all documents into a list of (key, value) pairs that should suit your particular needs in solving a problem. They are indexed, the index is created on the first view use and will be updated quickly on document insert/update/delete operations. One important thing is that they are static, i.e. you cannot pass any dynamic parameters into the view. That’s why they are easy to index. The only thing that’s dynamic is the keyset restriction you can optionally add. This can greatly reduce the number of documents returned. To compare with SQL – they are a pandan of SQL views, but it’s important to realize they are not similar to SQL queries.

In our case, we’ll make two views. The first one will transform key all country/capital pairs by their first letter. Here are a few random rows from country-capitals database:

"Marshall Islands","Majuro","countryCapital"

which our view will transform into:

{key:"a", country:"Aruba",            capital:"Oranjestad"}
{key:"c", country:"Comoros",          capital:"Moroni"}
{key:"m", country:"Marshall Islands", capital:"Majuro"}
{key:"m", country:"Myanmar",          capital:"Naypyidaw"}

The other way is symmetric one, but for the capitals – here’s the other view for the above data:

{key:"m", country:"Comoros",          capital:"Moroni"}
{key:"m", country:"Marshall Islands", capital:"Majuro"}
{key:"n", country:"Myanmar",          capital:"Naypyidaw"}
{key:"o", country:"Aruba",            capital:"Oranjestad"}

The code for these two should go into lib/views.js file and would be:

exports.countriesByFirstLetter = {
    map: function(doc) {
        if(doc.type = 'countryCapital') {
            emit(doc.country.charAt(0).toLowerCase(), {
                country: doc.country,
                capital: doc.capital

exports.capitalsByFirstLetter = {
    map: function(doc) {
        if(doc.type = 'countryCapital') {
            emit(doc.capital.charAt(0).toLowerCase(), {
                country: doc.country,
                capital: doc.capital

You can now kanso push http://localhost:5984/country-capitals and go to:

to see these.

Templates and rewrite rules

Kanso supports Dust templates directly. We’ll need to make a template to show the results – here’s what we’ll use (this is in templates/ccindex.htm):

<h1>Country/capital index</h1>
Countries by first letter:
<ul id="countriesByFirstLetter">
    <a href="{baseURL}/countriesByFirstLetter?key=&quot;{letter}&quot;">{display}</a>

Capitals by first letter:
<ul id="capitalsByFirstLetter">
    <a href="{baseURL}/capitalsByFirstLetter?key=&quot;{letter}&quot;">{display}</a>


<table id="results">

Here are a few comments about the above:

  • base_template attribute in kanso.json file in your application root defines which is the base template. By default it’s base.html and all other templates are embedded into it by supplying content attribute. It also has title attribute that you can use to set the title of the current page. I added the CSS (base.css), so the file looks like:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
    <link rel="stylesheet" href="static/css/base.css" />
    <div id="content">
    <script src="{baseURL}/static/js/jquery-1.5.2.min.js"></script>
    <script src="{baseURL}/static/js/json2.js"></script>
    <script src="{baseURL}/kanso.js"></script>

Note that CSS is references as static/css/base.css – this is done by the rewrite rules, that’s discussed after this

  • The above template uses {#list} and {/list} to iterate over the array named list – this is used for letters and rows above. When doing this, everything in between can use the objects in the array directly. For example, the following:
    <a href="{baseURL}/countriesByFirstLetter?key=&quot;{letter}&quot;">{display}</a>

will take the current letter (from letters array) and, from the object representing the letter, extract two properties – letter and display. – Similar to the above example, there are some “global” variables, such as {baseURL}, which denotes the base of the design document rewrite root

Let’s add a bit of CSS to the above just to be nice (this is not functionally required) – this goes to static/css/base.css:

#countriesByFirstLetter li,
#capitalsByFirstLetter li {
  display: inline;

#countriesByFirstLetter li a,
#capitalsByFirstLetter li a {
  text-decoration: none;
  display: inline-block;
  width: 1em;
  height: 1em;
  padding: .2em;
  background: #ffee50;
  border: 1px solid #009999;
  color: black;

#results {
  border-collapse: collapse;
#results td,
#results th {
  background: #ffcc30;
  border: 1px solid #009999;
  padding: 0em 1em 0em .3em;
  width: 60em;
#results td {
  background: #ffee50;

Templates are internal Kanso’s thing and without it they are not useful. To make use of them, you make either list or show functions – these are regular CouchDB show/list functions, but are extended by Kanso to do client-side rendering if possible (== Javascript enabled). Let’s make a list function for our case – these go into lib/lists.js:

exports.ccindex = function (head, req) {
    start({code: 200, headers: {'Content-Type': 'text/html'}});

    var row, rows = [];
    while(row = getRow()) {

    var letters = [];
    _.each("abcdefghijlkmnopqrstuvwxyz", function(e) {
            letter: e,
            display: e.toUpperCase(),
    var content = templates.render('ccindex.htm', req, {
        letters: letters,
        rows: rows,
    return {title: 'Country/capital index', content: content};

Here’s a commentary about the above code:

  • The above exports a function called ccindex that is stored as a list function. This is exported as a regular CouchDB list function, so you can call it with e.g.:
$ curl http://localhost:5984/country-capitals/_design/country-capitals/_list/ccindex/countriesByFirstLetter?key=%22a%22

to get a list of countries whose name starts with letter a. Note that you will not be able to run within browser if Javascript is enabled, as Kanso interferes with this. The result will be a HTML document that renders ccindex.htm template

  • getRows function will get all the rows from the specified view. List functions always take a view – if you look at the above URL, it has _list/ccindex/countriesByFirstLetter. This means “use ccindex list function to display the results of the countriesByFirstLetter view”. Thus, getRows in this case would be the rows returned by countriesByFirstLetter view.

  • Variable letters is just a dummy letter holder – this could have been done to actually go through the keys and extract only the ones present. This variable is used in the template to populate the filter sections.

The last part we need to do is rewrites. These are used to tell CouchDB what to actually do. Here’s our rewrite:

module.exports = [
    {from: '/static/*', to: 'static/*'},
//    {from: '/', to: '_show/welcome'},
    {from: '/', to: '_list/ccindex/countriesByFirstLetter', query: {key: ''}},
    {from: '/countriesByFirstLetter', to: '_list/ccindex/countriesByFirstLetter'},
    {from: '/capitalsByFirstLetter', to: '_list/ccindex/capitalsByFirstLetter'},
    {from: '*', to: '_show/not_found'}

The above says:

  • You can see that there’s a mention of static. This is used to reference our static/css/base.css file
  • I commented out the default root that GTE’s to _show/welcome and instead remapped this to actually call the ccindex list function with a countriesByFirstLetter view. As I supplied key that has a value of an empty string (”), nothing will match, so we will get no results. This is just for defaulting purposes – I could very well have done something else, e.g. default to letter a
  • There are two more redirects to our two views through ccindex list


I put a small script called recreate.sh that you can always use to scratch everything, upload the data and the application that you currently have. This might help you in the beginning if you get stuck and don’t know whether the issue is with the app itself or some file that you left dangling somewhere.


After all this, you should be able to go to

and see our small app. Again, the code is here. All is left is to relax