                 if err
                     cb(err)
                 else
-                    delay = 100
-                    @info = misc.from_json(output.stdout)
-                    {base, pid, port} = @info
-                    wait_for_url_to_work
-                        url : base
-                        cb  : (err) => cb(err, base)
+                    info = misc.from_json(output.stdout)
+                    @url = info.base; @pid = info.pid; @port = info.port
+                    get_with_retry
+                        url : @url
+                        cb  : cb
+
+
+    notebooks: (cb) =>  # cb(err, [{kernel_id:?, name:?, notebook_id:?}, ...]  # kernel_id is null if not running
+        get_with_retry
+            url : @url + 'notebooks'
+            cb  : (err, data) =>
+                if not err
+                    cb(false, misc.from_json(data))
+                else
+                    cb(err)
 
     stop_server: (cb) =>
-        if not @info?.pid?
+        if not @pid?
             cb?(); return
         salvus_client.exec
             project_id : @project_id

                console.log(err, output)
                cb?(err)

wait_for_url_to_work = (opts) ->
    opts = defaults opts,
        url           : required
        initial_delay : 100
        max_delay     : 15000     # once delay hits this, give up
        factor        : 1.2       # for exponential backoff
        cb            : required  # cb(err)
    delay = opts.initial_delay
    f = () =>
        if delay >= opts.max_delay  # too many attempts
            opts.cb("unable to connect to remote server")
            return
        $.get(opts.url, (data) ->
            console.log(data.slice(0,100))
            if 'ECONNREFUSED' in data or '404: Not Found' in data
                delay *= opts.factor
                setTimeout(f, delay)
            else
                opts.cb(false)
        ).fail(() ->
            delay *= 1.2
            setTimeout(f, delay)

# IPython Support
#**************************************************

ipython_notebook_server = (opts) ->
    opts = defaults opts,
        project_id : required
        path       : required   # directory from which the files are served
        cb         : required   # cb(err, server)

    I = new IPythonNotebookServer(opts.project_id, opts.path)
    I.start_server (err, base) =>
        opts.cb(err, I)

class IPythonNotebookServer  # call ipython_notebook_server above
    constructor: (@project_id, @path) ->

    start_server: (cb) =>
        salvus_client.exec
            project_id : @project_id
            path       : @path
