// 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 hits resetAllHits(); // 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 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=0; j--) { retireHIT(currentHITs.splice(j, 1)); } }