// URL containing the page you want turkers to work on.var getTask_url = "http://roc.cs.rochester.edu/donato/qturk/getTask.php";// Maximum number of seconds until retiring the HIT (seconds).var maxTimeTillDeath = 60*5;// Maximum time to complete one task in a HIT (seconds).var maxTimePerTask = 60;// Number of HITs that should always be posted.var steadyStateNum = 5;// Minimum time between adding HITs.// Number of seconds between deleting and readding HITs -// setting this too low can cause thrashing, where turkers// try to accept a HIT but quikturkit has already deleted it.var minTimeBetweenHITs = 15;// Number of HITs added at once.// Maximum number of HITs to add a one time.var numHITsAtOnce = 2;// The reward for each HIT.var reward = 0.01;// Number of assignments offered in each HIT posted.var assignments = 2;// Current number of active assignments.var activeAssignments = 0;//reset ALL current hitsresetAllHits();// The init function ...var TasksObj = initTasks(getTask_url);//// The main (infinite) loop.// Be careful, the only thing stopping you from losing a bundle is the// global safety values (money spent, number of HITs)//for(var i=0; true; i++) { print("\n\nITERATION " + i + " (" + currentHITs.length + " hits):"); //get the list of tasks to iterate over var text = getTasks(); var lines = text.split("\n"); //for each task //1. retire completed hits //2. find the youngest hit //3. count the number of active assignments for (line in lines) { data = line.split("%%n%%"); var id = data[0]; var current_users = data[1]; var desired_users = data[2]; if((i%10==0 && TasksObj[id].activeAssignments>0)) { // Reset activeAssignments for counting next. var activeAssignments = 0; var youngestHIT = 0; // // Review the current HITs to see how many have completed. // for(var j = TasksObj[id].currentHITs.length-1; j>=0; j--) { var hit = mturk.getHIT(TasksObj[id].currentHITs[j]); var secs = (time() - hit.creationTime) / 1000; if(secs < youngestHIT || youngestHIT == 0) { youngestHIT = secs; } // Count active assignments, delete finished HITs. if(hit.done || secs > maxTimeTillDeath) { // Remove this HIT from our list. retireHIT(TasksObj[id].currentHITs.splice(j, 1)); } else { print("Adding: " + (hit.maxAssignments - hit.assignments.length)); activeAssignments += (hit.maxAssignments - hit.assignments.length); } } print("active: " + activeAssignments + ", low: " + lowAnswer + "->" + numAnswersDesired + ", steady@: " + steadyStateNum); } } // // Add or delete HITs as needed. // var hitsToAdd = overShootMultiplier*(numAnswersDesired - lowAnswer) - activeAssignments; // How many tasks should new HITs have? // The default is 12, but this goes down to 5 or 2 based on how long until we expect to what answers. var tasksForNewHits = 12; if(diff<0) { tasksForNewHits = 2; } else if(diff < 4*60) { tasksForNewHits = 5; } // Adjust for HIT creation rate. if(time() - youngestHIT < minTimeBetweenHITs) { hitsToAdd = 0; } else if(hitsToAdd > numHITsAtOnce) { hitsToAdd = (hitsToAdd - numHITsAtOnce > numHITsAtOnce) ? (hitsToAdd-numHITsAtOnce) : numHITsAtOnce; } // print("ADD: " + hitsToAdd + ", DIFF: " + diff = ", low: " + lowAnswer + ", active: " + activeAssignments + ", add: " + hitsToAdd); // if(hitsToAdd > 0) { for(var j=0; j<hitsToAdd;) { var hits = createNewHIT(reward, assignments, numhits, tasksForNewHits); currentHITs = currentHITs.concat(hits); // Final number of jobs actually created. j+=numhits*assignments; print(currentHITs.length + " current HITs, " + hits.length + " new ones created."); } } else if(hitsToAdd < 0) { for(var j=hitsToAdd; j<0; j++) { if(currentHITs.length > 0) { print("retiring here"); retireHIT(currentHITs.splice(0, 1)); } } } else { // We're already in a good state, so do nothing. } // Store current currentHITs. database.query("currentHITs = " + json(currentHITs)); // Wait for a little bit before polling again. Packages.java.lang.Thread.currentThread().sleep(2000);}/* ********************* * Helper Functions ********************* */function createNewHIT(reward, assignments, numhits, tasks) { var hitsCreated = []; // Generate a random number 0-1000; salt = Math.floor(Math.random()*1001); if(typeof tasks == 'undefined') { tasks = 3; } var mytitle = title.replace(/%%n%%/g, tasks); var mydescription = description.replace(/%%n%%/g, tasks); var myurl = url.replace(/%%n%%/g, tasks); for(var i=0; i<numhits; i++) { // create a HIT on MTurk using the webpage var hitId = mturk.createHITRaw({ title : mytitle, desc : mydescription + " " + salt, url : myurl, height : 1200, reward : reward, assignmentDurationInSeconds: maxTimeTillDeath, maxAssignments: assignments }); hitsCreated.push(hitId); } return hitsCreated;}function getTasks() { var plainText = read(getTask_url); return plainText;}function initTasks(var str) { var plainText = read(str); var lines = plainText.split("\n"); obj = new Object(); for(line in lines) { data = lines.split("\t"); var id = data[0]; obj[id] =[] obj[id].title = data[1]; obj[id].desc = data[2]; obj[id].url = data[3]; obj[id].currentHITs = []; } return obj;}/** * Function for retiring a HIT. **/function retireHIT(hit) { mturk.approveAssignments(hit.assignments); mturk.deleteHITs([hit]);}function printHITs(hits) { foreach(hits, printHIT);}function printHIT(hit) { var h = mturk.getHIT(hit); var vals = [h.done, h.assignments.length]; print(vals.join(','));}function resetAllHits() { var currentHITs = database.query("return currentHITs;"); print("Old HITs: " + json(currentHITs)); // // Start things over before we get going by resetting all HITs. // for(var j=currentHITs.length-1; j>=0; j--) { retireHIT(currentHITs.splice(j, 1)); } }