 
     # **one off code for migrating to google cloud storage**
     # For each project modified recently, update it in google cloud storage
+    ###
+db = new (require("cassandra").Salvus)(keyspace:'salvus', hosts:['10.240.97.10'], username:'hub', password:require('fs').readFileSync('data/secrets/cassandra/hub').toString().trim(), cb:console.log)
+x={};s=require('bup_server').global_client(database:db, cb:(err,c)->console.log("err=",err);x.c=c;x.c.migrate_update_recent(query_limit:60000, test_limit:4, max_age_h:24, cb:(e)->console.log("DONE",e)))
+
+x={};s=require('bup_server').global_client(database:db, cb:(err,c)->console.log("err=",err);x.c=c;x.c.migrate_update_recent(max_age_h:1, cb:(e)->console.log("DONE",e)))
+    ###
     migrate_update_recent: (opts) =>
+        opts = defaults opts,
+            limit       : 10  # number to do at once in parallel
+            test_limit  : undefined # if given, only migrate first this many projects.
+            query_limit : undefined
+            max_age_h   : 24   # max age of projects to update, in hours
+            cb          : undefined
+        dbg = (m) => winston.debug("migrate_missing: #{m}")
+        projects = undefined
+        oldest   = (new Date() - 0) - opts.max_age_h*60*60*1000
+        errors = {}
+        async.series([
+            (cb) =>
+                dbg("getting overview of projects")
+                @overview_projects
+                    bad_servers  : ['0985aa3e-c5e9-400e-8faa-32e7d5399dab']
+                    limit        : opts.query_limit
+                    convert_time : false
+                    cb           : (err, x) =>
+                        if err
+                            cb(err)
+                        else
+                            dbg("got #{projects.length} projects")
+                            projects = (project for project in x when project.last_edited >= oldest)
+                            dbg("of these, #{projects.length} projects are at most #{opts.max_age_h} hours old")
+                            cb()
+            (cb) =>
+                if opts.test_limit
+                    projects = projects.slice(0, opts.test_limit)
+                dbg("#{projects.length} projects to be updaed")
+                i = 0
+                t = misc.walltime()
+                f = (project, cb) =>
+                    i += 1
+                    elapsed = misc.walltime() - t; avg = elapsed/i; remaining = (projects.length-i)*avg/60
+                    dbg("#{i}/#{projects.length}: time left = #{remaining}m")
+                    if not project.ssh?
+                        errors[project.project_id] = "project has no location WHAT THE HECK!"
+                        dbg(misc.to_json(errors))
+                        return
+                    try
+                        misc_node.execute_code
+                            command : '/home/salvus/salvus/salvus/scripts/gb_storage.py'
+                            args    : ['migrate_live', '--port=2222', project.ssh[-1].split(':')[0], project.project_id]
+                            timeout : 5000
+                            cb      : (err, output) =>
+                                dbg(misc.to_json(output))
+                                cb(err)
+                    catch err
+                        error = "Error running code! #{err}"
+                        errors[project.project_id] = error
+                        dbg(misc.to_json(errors))
+                        cb()
+                async.mapLimit(projects, opts.limit, f, cb)
+        ], (err) =>
+            dbg("DONE!, err=#{err}")
+            dbg("ERRORS: #{misc.to_json(errors)}")
+            opts.cb?(err)
+        )
 
 ###########################
 ## Client -- code below mainly sets up a connection to a given storage server

    ###
db = new (require("cassandra").Salvus)(keyspace:'salvus', hosts:['10.240.97.10'], username:'hub', password:require('fs').readFileSync('data/secrets/cassandra/hub').toString().trim(), cb:console.log)
x={};s=require('bup_server').global_client(database:db, cb:(err,c)->console.log("err=",err);x.c=c;x.c.migrate_missing(query_limit:20000, test_limit:4, cb:(e)->console.log("DONE",e)))

x={};s=require('bup_server').global_client(database:db, cb:(err,c)->console.log("err=",err);x.c=c;x.c.migrate_missing(test_limit:4, cb:(e)->console.log("DONE",e)))

x={};s=require('bup_server').global_client(database:db, cb:(err,c)->console.log("err=",err);x.c=c;x.c.migrate_missing(cb:(e)->console.log("DONE",e)))
    ###

                            else
                                return 0
                        projects = r  # to save memory (also why we process in place below)
                        if opts.convert_time
                            f = misc.date_to_snapshot_format
                        else
                            f = (x) -> x
                        for i in [0...projects.length]
                            x = projects[i]
                            projects[i] = {last_edited:f(x.last_edited), project_id:x.project_id, server_id:x.bup_location}
                        dbg("done processing projects (phase 1)")
                        cb()
            (cb) =>
