Skip to content

Working with Executable Scripts

Young Ji edited this page Oct 31, 2020 · 4 revisions

Executable scripts

The scripts can be executed in two different places:

  • The subject's browsers
  • Server

The scripts run on the server using Rhino Engine by Mozilla .

The scripts can be related to different entities:

  • Session

    • Session wide script override (executed on subject's browsers in all of the session's workspace pages)
    • Session condition script to start perpetual session (executed on server)
    • Script that runs before session starts (executed on server)
    • Script that runs after session is done (executed on server)
  • Task

    • Script to run before work
    • Script to run after work
    • Script to score

Session scripts

Session wide script

Session wide script is the only override script that runs on the subject's browser. All others run on the server. Session wide script is used to provide extensibility on the workspace pages. e.g., a researcher wants to change subjects' names and add a prefix or suffix to their display names to signal some individual characteristic throughout the session. Running a session wide script does not require any special methods to register users. The script is executed as is after POGS objects are loaded. All items related to the workspace can be retrieved by the global pogs object.

Script that runs before session starts & Script that runs after session is done

Both scripts run just like their names suggest. The main idea is to change some of the session variables. It was only used so far to update the final URL using a randomizer.

This is a boilerplate code:

//Variables injected in the script
var _sessionExecutionAttributes = JSON.parse(sessionExecutionAttributes);
var _teammates = JSON.parse(teammates);



var attributesToAddz = [{"attributeName": "SESSION_DONE_REDIRECT_URL",
    "stringValue":""}]

//Variables to save after script is executed.
sessionExecutionAttributesToAdd = JSON.stringify(attributesToAddz);

In the future the idea is to extend this to other session attributes, and even change the task order or schedule.

Session Condition script to start perpetual session

This condition script is used to start a session based in any condition. All the script needs to do is return true/false to trigger a session start and the selected subjects from the pool to begin a session.

The only variable that is injected is the list of subjects with their attributes.

//all checked in subjects
var subjectsList = JSON.parse(subjects);
for(var i=0; i < subjectsList.length; i ++) {

    for(var j=0 ; j < subjectsList[i].attributes.length; j ++){
        if(subjectsList[i].attributes[j].attributeName == "politicalOrientation") {
            if(subjectsList[i].attributes[j].stringValue == "democrat"){
               selectedDemocrats.push(subjectsList[i].externalId); 
            }
        }
    }
}

shouldStart = true;
subjectsToJoinSession = JSON.stringify(selectedSubjects);

The variable names MUST BE THE FOLLOWING:

  • shouldStart - true or false if the session should start.
  • subjectsToJoinSession - all selected subjects

Task scripts

All of the task scripts follow the same logic of variable injection and retrieval for saving. All task plugins can define their implementations for this plugins following the name convention:

  • taskBeforeWork.js
  • taskAfterWork.js
  • taskScore.js

But to increase flexibility the same scripts can be overridden by customized versions of the scripts.

E.g., The researcher wants to change the calculation of the score of the Sudoku game. Instead of having to make a new plugin, the researcher can create a taskScore in the platform and override the plugin configuration's default script.

Script to run before work

The ideia for this script is to make new attributes using information that is only available at runtime. Ex.: The researcher wants to randomize the order of the subjects and have a turn based approach to solving a problem.

var teammatez = JSON.parse(teammates);
var taskConfigAttr = JSON.parse(taskConfigurationAttributes);

var attributesToAddz = [{"attributeName": "colorHasSubjects", "stringValue":JSON.stringify(colorHasSubjects) },
        {"attributeName": "subjectsHasColumns", "stringValue":JSON.stringify(subjectsHasColumn)}]

completedTaskAttributesToAdd = JSON.stringify(attributesToAddz);

The complete list of injected variables is:

  • sessionId - The session database id
  • completedTaskId- The current completed task id Workspace flow and attributes
  • subject - The current subject object if running on solo mode
  • isSolotTask - If running in solo mode
  • teammates - The list of all teaamates of the current session. To know more about the attributes: Workspace flow and attributes
  • taskConfigurationAttributes - All the task configuration attributes
  • completedTaskAttributes - The current completed task attributes it is very unlikely that this will be filled when running in the before script. But expected to be filled on the after work script.

The complete list of variables that are processed to save is:

  • subjectAttributesToAdd - JSON object of the attributes to add to the subjects.
  • completedTaskAttributesToAdd - JSON object of the attributes to add to the completed task attributes.

Script to run after work

The idea for this script is to make new subject, or completed task attributes using information that is only available after the task execution. Ex.: The researcher wants to add to the subject's attributes his political orientation that was asked in a survey format.

var _teammates = JSON.parse(teammates);
var _subject = JSON.parse(subject);
var _isSoloTask = isSoloTask;
var _taskConfigurationAttributes = JSON.parse(taskConfigurationAttributes);
var _completedTaskAttributes = JSON.parse(completedTaskAttributes);

var politicalOrientation = "";
for(var i = 0 ; i <  _completedTaskAttributes.length; i ++) {
    if(_completedTaskAttributes[i].attributeName == "surveyAnswer0"){
        if( _completedTaskAttributes[i].stringValue == "Republican") {
            politicalOrientation = "republican";
        } else {
            politicalOrientation = "democrat";
        }

    }
}

//politicalOrientation

_subjectAttributesToAdd = [{
    "externalId": _subject.externalId,
    "attributes": [{
        "attributeName": "politicalOrientation",
        "stringValue": politicalOrientation
    }]
}];

subjectAttributesToAdd = JSON.stringify(_subjectAttributesToAdd);

This script goes through the survey's answers and looks for the "surveyAnswer0" to check if it was republican or democrat. And tags the subject by adding a subject attribute to him.

The list of variables is the same as the task before work.

Script to score

The idea is to have all answers and all task configurations and do the score calculation based on the desired algorithm. The following is the full script used to score a Sudoku game. It is very important to notice one thing in this script : how it handles empty cells. The code may assume that the user has answered all cells, but that may punish the score. In this case the comparison is only done on entries that the subjects have answered. Adding 1 if the answer was right, and 0 if it was wrong. If we had a penalty for wrong answers it would be good to differentiate empty from wrong answers.

var _teammates = JSON.parse(teammates);
var _subject = JSON.parse(subject);
var _isSoloTask = isSoloTask;
var _taskConfigurationAttributes = JSON.parse(taskConfigurationAttributes);
var _completedTaskAttributes = JSON.parse(completedTaskAttributes);


var answerSheet;

var RIGHT_ANSWER_REWARD = 1;
var WRONG_ANSWER_REWARD = 0;


for(var i=0 ; i < _taskConfigurationAttributes.length; i ++) {
    if(_taskConfigurationAttributes[i].attributeName == "answerSheet"){
        answerSheet = _taskConfigurationAttributes[i].stringValue.split(",");
        break;
    }
}

var _completedTaskScore = {
    "totalScore" : 0,
    "numberOfRightAnswers" : 0,
    "numberOfWrongAnswers" : 0,
    "numberOfEntries" : 0,
    "numberOfProcessedEntries" : 0,
    "scoringData" : ""
};

var answerKeyMap = [];


for(var k =0 ; k < answerSheet.length; k ++ ) {
    answerKeyMap[k] = "";
}

for(var i=0 ; i < _completedTaskAttributes.length; i ++) {
    if(_completedTaskAttributes[i].attributeName.indexOf("sudokuAnswer_") != -1){
        var index = parseInt(_completedTaskAttributes[i].attributeName.replace("sudokuAnswer_",""));
        var answer = _completedTaskAttributes[i].stringValue;
        answerKeyMap[index] = answer;
    }
}

for(var i=0 ;i < answerSheet.length; i++) {

    _completedTaskScore.numberOfEntries++;
    _completedTaskScore.numberOfProcessedEntries++;
    if (answerSheet[i] == answerKeyMap[i]) {
        _completedTaskScore.numberOfRightAnswers++;
        _completedTaskScore.totalScore += RIGHT_ANSWER_REWARD;
    } else {
        _completedTaskScore.numberOfWrongAnswers++;
        _completedTaskScore.totalScore += WRONG_ANSWER_REWARD;
    }
}


completedTaskScore = JSON.stringify(_completedTaskScore);

The injected variables are basically the same of the previous scripts, please go to their definitions in case you need clarification.

The output variable is the completedTaskScore. This variable will be saved in the database and it is not an array but only one object, Description of attributes of the completedTaskScore:

  • totalScore
  • numberOfRightAnswers
  • numberOfWrongAnswers
  • numberOfEntries - In the case of the sudoku game the amount of empty cells the users need to fill in.
  • numberOfProcessedEntries - The entries that were processed. This is used in string comparisons, sometimes the entries need manual validation.
  • scoringData - This is where any kind of data is stored if needed afterwards. The strings that need human evaluation are a good example of that.

Clone this wiki locally