Alex Pogosyan

Dropbox's javascript question.

Tags: javascript

Dropbox has recently posted a job opening for a web developer. They've included pretty interesting javascript problem to solve before applying for it:

 
function countdown (num) {
    for (var i = 0; i <= num; i += 1) {
        setTimeout(function () {
            alert(num - i);
        }, i * 1000);
    }
}

The desired result is a countdown from 5 to 0 using alert messages. 
Explain why the code only alerts -1, 
then fix the code so it works as expected.
 
It doesn't work because setTimeout'ed functions are executed after the for loop has ended, and since there are six iterations, the value of i is eventually set to 6, just before setTimout'ed functions are executed. 
 
How to make it work? One solution is to use setInterval instead of setTimeout. Time intervals are no longer depend on the local variable i and we don't need the for loop at all:
 
	function countdown (num) {
    id = setInterval(function() {
        if (i > num) {
            clearInterval(id);
        } else {
            console.log(num - i);
            i += 1
        }
    }, 1000);
}

Another approach is to create anonymous function that calls setInterval and call it with the value of i on each iteration:


function countdown (num) {
    for (var i = 0; i <= num; i++) {
        (function (i) {
            setTimeout(function () {
                console.log(num - i);
            }, i*1000);
        })(i);
    }
}

Custom Django template tag for displaying random pictures.

Tags: django, python

Suppose you need to display some random picture in Django. You have a folder with some pictures in it and on each request you want to pick random one and put it in the template. This task is easily accomplished by writing custom template tag. What we want is a way to say which directory it should grab random pictures from (which must be under settings.MEDIA_ROOT, of course), and then render it as an absolute address so we can surround it with img tag. For example:

<img src="{% random_pic "my/pics" %}" />

Let's get started.

We need to create templatetags directory in our app's directory. Inside the templatetags directory we need to create emtpy __init__.py file, so Python will treat it as a package. After that we need to create a file where we will store the code for our template tag. The file name is important - we'll use it later in our template to load our tag. Make sure it doesn't clash with tag names in other apps. Let's call it random_pic.py.

To define a template tag we need to tell django how to compile it and how to render it.

Compiling.

When django encounters template tag it calls a corresponding function which takes two arguments: parser object and tag's contents. The function should parse the contents and then either raise TemplateSyntaxError exception, or return a Node instance where the rendering of the tag takes place.

Here's our compiling function:

import template

def random_pic(parser, token):
    try:
        tag_name, dir_name = token.split_contents() 
    except ValueError:
        raise template.TemplateSyntaxError, 
            "%r tag requires a single argument" % token.contents.split()[0]
    if not (dir_name[0] == dir_name[-1] and dir_name[0] in ('"', "'")):
        raise template.TemplateSyntaxError, 
            "%r tag's argument should be in quotes" % tag_name
    return RandomPicNode(dir_name[1:-1]) 

dir_name is an argument you supplied to random_pic tag, e.g "my/pics".

Rendering.

If no exception is raised, the instance of Node subclass is created where rendering takes place. Node class has render method which returns a regular string which is inserted in place of template tag.

class RandomPicNode(template.Node):
    def __init__(self, dir_name):
        self.dir_name = dir_name

    def filter(self, filelist):
        regex = re.compile(r'(\.jp[e]*g|\.png|\.gif)', re.I)
        return [pic for pic in filelist if re.search(regex, pic)]

    def render(self, context):
        try:
            pics = self.filter(os.listdir(os.path.join(settings.MEDIA_ROOT, self.dir_name)))
            filename = random.choice(pics)
        except: return ""
        return os.path.join(settings.MEDIA_URL, self.dir_name, filename)

We just get all the files in the dir_name directory, filter out files that are not pictures, pick random one and return absolute http path.

According to django documentation, Node subclasses should never raise exceptions. If any error occurs during rendering, it should be silenced and the return value should be empty string or the original template tag argument. That's the reason why all potentially dangerous operations are surrounded in the try...except block here.

We only need to register this tag before we can use it:

register = template.Library()
register.tag(current_time)

Now we can use it in our templates:

{% load random_pic %}

<div>Random picture:</div>
<img src="{% random_pic "my/pics" %}" />

Get the code here.