Global commands

Used outside of a trial.


table of contents


AddHost

syntax

AddHost()

description

You can use AddHost to spare you from specifying a URL when you create an element with newAudio, newVideo or newImage. The URL must end with /.

example

click to expand

@
$AddHost("https://files.lab.florianschwarz.net/test/");
$AddHost("http://spellout.net/ibexfarm/static/images/");
@
@newTrial(
@    newImage("ibex", "ibex.jpg")
@        .print()
@    ,
@    newImage("wait", "https://openclipart.org/image/300px/svg_to_png/23920/Anonymous-Sandglass.png")
@        .print()
@    ,
@    newAudio("sentence", "test.mp3")
@        .play()
@        .wait()
@);
  • The trial shows two images and plays one audio file. PennController will first try send a request for the file https://files.lab.florianschwarz.net/test/ibex.png and another one for the file http://spellout.net/ibexfarm/static/images/ibex.png. The same is true for the audio file: PennController will first send a request for the file https://files.lab.florianschwarz.net/test/test.mp3 and another one for the file http://spellout.net/ibexfarm/static/images/test.mp3. PennController uses the resource from the first successfully resolving request: in this example, assuming there is a file named ibex.png at http://spellout.net/ibexfarm/static/images/ and a file named test.mp3 at https://files.lab.florianschwarz.net/test/ (and only there), those are the resources that PennController will use (it may still trigger warnings in the console for the unsuccessful requests). PennController will only look for the wait image at https://openclipart.org/image/300px/svg_to_png/23920/Anonymous-Sandglass.png, since a full URL is provided there.

↑ back to top

AddTable

syntax

AddTable()

description

You can use this command to manually define a table to use with Template. You normally do not need to use this command since, as of PennController beta 0.4, you can directly upload your CSV file under Resources / chunk_includes.

example

click to expand


@
$AddTable( "myTable",  // Name of the table
$    "Type,Sentence\n"+           // Column names (mind the \n)
$    "practice,Hello world!\n"+   // First row (mind the \n)
$    "test,Bye world!"            // Second row
$);
@
@Template( "myTable" , row => 
@    newTrial(
@        newText("type", row.Type)
@            .print()
@        ,
@        newButton("sentence", row.Sentence)
@            .print()
@            .wait()
@    )
@);
↑ back to top

CheckPreloaded

syntax

CheckPreloaded()

description

PennController always starts the preloading of every image, audio and video resource used in your experiment as soon as the experiment starts running and, by default, it will wait before running a trial that all the resources it uses are preloaded. Since this could result in undesirable random breaks in the flow of your experiment, you can control when PennController should check that the resources used by (subsets of) your trials are preloaded before proceeding by using CheckPreloaded.

example

click to expand

@
$CheckPreloaded("audio", "video");
@
@newTrial( "audio" ,
@    newAudio("audio file", "test.mp3")
@        .print()
@        .play()
@        .wait()
@);
@
@newTrial( "video" ,
@    newVideo("video file", "skate.mp4")
@        .print()
@        .play()
@        .wait()
@);
@
$CheckPreloaded();
@
@newTrial( "filler" ,
@    newImage("image", "square.png")
@        .print()
@    ,
@    newKey("fj", "FJ")
@        .wait()
@);
@
@newTrial( "test" ,
@    newImage("image", "triangle.png")
@        .print()
@    ,
@    newKey("fj", "FJ")
@        .wait()
@);
  • Will make sure that test.mp3 and skate.mp4 are fully preloaded before running the very first PennController trial, labeled audio. After the PennController trial labeled video has ended, will make sure that all image, audio and video resources ever used in the experiment are preloaded before running the trial labeled filler (which practically means it will check that square.png and triangle.png are preloaded, since the first preloader made sure the audio and video resources were already preloaded).
↑ back to top

Debug

syntax

Debug()

description

Runs your experiment in Debug mode.

example

click to expand

$PennController.Debug()
@
@PennController(
@    newButton("hello", "Hello world")
@        .print()
@        .wait()
@)
@
@PennController.AddTable( "Words" ,
@    "item,Word\n"  +
@       "1,Hello\n" +
@       "2,World"
@)
@
@PennController.Template( "Words" ,
@    row => PennController(
@        newButton(row.Word)
@            .print()
@            .wait()
@    )
@)
↑ back to top

DebugOff

syntax

DebugOff()

description

Tells your experiment to not run in Debug mode. This will close the popin window at the bottom-right corner of your experiment, no longer providing you with debugging tools and helpful feedback. You should only use this command when you are ready to collect data.

example

click to expand

$PennController.DebugOff()
@
@PennController(
@    newButton("hello", "Hello world")
@        .print()
@        .wait()
@)
@
@PennController.AddTable( "Words" ,
@    "item,Word\n"  +
@       "1,Hello\n" +
@       "2,World"
@)
@
@PennController.Template( "Words" ,
@    row => PennController(
@        newButton(row.Word)
@            .print()
@            .wait()
@    )
@)
↑ back to top

DownloadRecordingButton

syntax

DownloadRecordingButton()

description

Generates a <button> that, when clicked, proposes to download a ZIP archive containing all the media recordings collected during the experiment.

example

click to expand

@InitiateRecorder("https://myserver/uploadVoices/saveRecordings.php")
@
@newTrial( "record" ,
@    newMediaRecorder("recorder")
@        .print()
@        .wait()
@)
@
@SendResults()
@
@newTrial(
@    newFunction("check upload", ()=>PennController.uploadRecordingsError)
@        .test.is()
@        .success(
@            newText("confirmation", "The recordings were sent to the server. ")
@                .print()
@        )
@        .failure(
@            newText("error", "There was a problem sending the recordings to the server. ") 
@                .color("red")
@                .print()
@        )
@    ,
$    newText("download", DownloadRecordingButton("Click here to download an archive of your recordings.") )
@        .print()
@    ,
@    newTimer("inifinite", 0)
@        .wait()
@)
  • Invites the participant to make a video recording and sends the results to the server. In this case, we specified a dummy URL, so uploading the recordings will fail, and PennController.uploadRecordingsError will accordingly be defined. The last screen will inform the participant of the error (since PennController.uploadRecordingsError is not void/undefined) and will show a button to download an archive of the recordings.
↑ back to top

EyeTrackerURL

syntax

EyeTrackerURL()

description

Tells the script where to send the data collected via the EyeTracker elements.

example

click to expand

@EyeTrackerURL("www.dummypage.com") 
@newTrial( newButton("Start").print().wait(newEyeTracker().test.ready()) )
@
@newTrial(
@    newEyeTracker("tracker")
@        .calibrate(70)
@        .train(true)
@    ,
@    newButton("Click here first").print("20vw","40vh").wait().remove(), 
@    newButton("Now Click here").print("60vw","40vh").wait().remove()
@    ,
@    newText("Left").css("padding","20vw").print("20vw", "40vh"),
@    newText("Right").css("padding","20vw").print("60vw", "40vh")
@    ,
@    getEyeTracker("tracker")
@        .stopTraining()
$        .add( getText("Left") , getText("Right") )
@    ,
@    newSelector().add( getText("Left") , getText("Right") ).wait()
@)
  • Collected data will be sent at the URL in the example.

  • Will add Left and Right as tracked elements.

↑ back to top


GetTable().filter

syntax

GetTable().filter()

description

Returns a filtered version of the table, containing only rows whose specified column’s value is a match.

example

click to expand

@
@Template( 
@    GetTable( "spreadsheet.csv" )
$        .filter( row => row.Item > 0 )      // 'Item' should be greater than 0, and
$        .filter( "ButtonText" , /second/ )  // 'ButtonText' should contain 'second'
@    ,
@    row => newTrial( "button trial" ,
@        newButton("test button", row.ButtonText)
@            .print()
@            .wait()
@    )
@    .log( "Item" , row.Item       )
@    .log( "Text" , row.ButtonText )
@);
  • Generates only one trial from a subset of the table spreadsheet.csv: first we only consider rows where the value in the Item column is a number greater than 0 (this is practically ineffective, for both rows in spreadsheet.csv already satisfy this condition) and we further consider only rows among those rows where the value of the ButtonText column is a text containing the string second (only the second row satisfies this condition).
↑ back to top

GetTable().setGroupColumn

syntax

GetTable().setGroupColumn()

description

Tells which column in the table assigns each row to a given group of participants, i.e. which subset of rows PennController will keep for each group of participants listed in the column.

example

click to expand


@
@SetCounter();
@
@AddTable( "test_table" , 
@    "Spelling,Text\n"+
@    "Normal,Hello\n"+
@    "Reversed,olleH\n"+
@    "Normal,World\n"+
@    "Reversed,dlroW"
@);
@
@Template( 
@    GetTable( "test_table" ) 
$            .setGroupColumn( "Spelling" )
@    ,
@    row => newTrial( "button trial" ,
@        newButton("the button", row.Text )
@            .print()
@            .wait()
@    )
@    .log( "Group" , row.Spelling )
@    .log( "Text"  , row.Text     )
@);
  • Creates a 2x4 table called test_table with column names Spelling and Text (manual creation for purpose of illustration—you would normally upload a CSV file to chunk_includes). Uses the column Spelling from this table to identify which rows go with which groups of participants.

  • Every other time the experiment is run, participants will see trials generated either from the two rows where Spelling is Normal or from the two rows where Spelling is Reversed.

  • The very first line runs a trial incrementing Ibex’s internal counter at the beginning of the experiment, which determines which group is run, so you can cycle through the rows if you re-run the experiment.

↑ back to top

GetTable

syntax

GetTable()

description

Refers to a table, where tablename can be the filename of a CSV file you uploaded to Resources (chunk_includes) or the name of a table that was created with AddTable.

example

click to expand

@
$Template( GetTable( "spreadsheet.csv" ) , row =>
@    newTrial( "button trial" , 
@        newButton("test button", row.ButtonText)
@            .print()
@            .wait()
@    )
@    .log( "Group" , row.Item )
@    .log( "Text"  , row.ButtonText )
@);
  • Generate two trials from the table spreadsheet.csv which contains two rows and the columns Item and ButtonText.
↑ back to top

GetURLParameter

syntax

GetURLParameter()

description

Retrieves the value of a parameter that was passed after ? in the URL. This is particularly useful if you pass a uniquely identifying code to the URL when you recruit your participants, like http://spellout.net/ibexexps/PennController/Demo/experiment.html?id=abcdefgh

example

click to expand


@
@newTrial( "my trial" ,
@    newButton("helloworld", "Hello world!")
@        .log()
@        .print()
@        .wait()
@)
$.log( "ID" , GetURLParameter( "id" ) );
  • Will add a column to each result line logged by my trial reporting the value that was passed after id= in the URL.
↑ back to top

syntax

Header()

description

Will evaluate and run sequenceOfCommands at the beginning of each trial created with PennController.

example

click to expand

@
$Header(
$    defaultText
$        .print()
$)
@
@newTrial(
@    newText("test sentence", "The cat is chasing the mouse")
@    ,
@    newText("instructions", "How natural is this sentence?")
@    ,
@    newScale("natural", 5)
@        .slider()
@        .before( newText("left", "Unnatural") )
@        .after(  newText("right", "Natural")  )
@        .print()
@        .wait()
@)
@
@newTrial(
@    newText("test sentence", "The mouse is being chased by the cat")
@    ,
@    newText("instructions", "How natural is this sentence?")
@    ,
@    newScale("natural", 5)
@        .slider()
@        .before( newText("left", "Unnatural") )
@        .after(  newText("right", "Natural")  )
@        .print()
@        .wait()
@)
  • Though no print command explicitly appears in the trials themselves, the Text elements will be printed onto the page because the header defines print as a default command for all Text elements.

↑ back to top

InitiateRecorder

syntax

InitiateRecorder()

description

Use this to specify the URL of the PHP file to upload the audio recordings collected during the experiment.

example

click to expand

@
@Sequence("first_trial", "second-trial")
@
$InitiateRecorder(
$    "https://myserver/uploadVoices/saveRecordings.php"
$    ,
$    "This experiment collects audio recordings. **Once you grant it access to your recording device, you will be notified of whether you are being recorded by a label at the top of the page**"
$)
$.label("first-trial")
@
@newTrial( "second-trial" ,
@    newMediaRecorder("recorder", "audio")
@        .print()
@        .wait()
@)
  • Adds a page asking for the participant’s authorization to use their recording device, using a custom text message.
↑ back to top

PreloadZip

syntax

PreloadZip()

description

Instead of fetching audio and images from a distant URL for every single one of your PennController trials using one, you can choose to store them in ZIP archives that you upload on your server. Use PreloadZip to tell where to look the ZIP archives up.

example

click to expand
  • Click here for a detailed guide.
↑ back to top

ResetPrefix

syntax

ResetPrefix()

description

By default, all the commands to create and refer back to elements in a PennController trial should be preceded by a prefix (PennController.Elements. as of beta 0.3). It is standard practice that every command added by a javascript module (which is what PennController is) uses a specific prefix (in this case, PennController). This is to avoid inadvertently overwriting (or being overwritten by) commands of the same names defined somewhere else, outside of the module. For instance, it could be that you or another module defined a function getImage which, say, takes a filename and adds it at the end of a certain URL (this would be useful if you defined many items using built-in Ibex controllers that contain images and you do not want to type the host URL each time).

example

click to expand

@
@PennController.newTrial(
$    PennController.Elements.defaultImage
@        .size(80, 80)
@    ,
$    PennController.Elements.newText("helloworld", "Hello world!")
@        .print()
@    ,
$    PennController.Elements.newCanvas("geometry", 200, 100)
$        .add(  10, 10, PennController.Elements.newImage("left image", "triangle.png") )
$        .add( 110, 10, PennController.Elements.newImage("right image", "square.png") )
@        .print()
@    ,
$    PennController.Elements.newSelector("shapes")
$        .add( PennController.Elements.getImage("left image") , PennController.Elements.getImage("right image") )
@        .print()
@        .wait()
@);
  • Long, painful and a little messy, right?

  • Now if you already have a getImage function defined somewhere else and you do not want to rename it, but you do not want PennController to erase it either, you can choose to reset the prefix to make everything shorter while keeping your own getImage function. For instance, you can choose to use the prefix E for Element (assuming no script defined a global object named E otherwise):


@
+PennController.ResetPrefix("E");
@
@E.newTrial(
$    E.defaultImage
@        .size(80, 80)
@    ,
$    E.newText("helloworld", "Hello world!")
@        .print()
@    ,
$    E.newCanvas("geometry", 200, 100)
$        .add(  10, 10, E.newImage("left image", "triangle.png") )
$        .add( 110, 10, E.newImage("right image", "square.png") )
@        .print()
@    ,
$    E.newSelector("shapes")
$        .add( E.getImage("left image") , E.getImage("right image") )
@        .print()
@        .wait()
@);
  • This is already much better. But to the extent that PennController’s element commands have names that are not used by default Ibex projects, you may want to straight out drop the prefix using PennController.ResetPrefix( null ), which is what is assumed throughout this documentation (no longer assuming the pre-existence of a getImage function in your project).
↑ back to top

SendResults

syntax

SendResults()

description

Since PennController 1.7, SendResults can be used in three different environments:

example

click to expand

$Sequence( "hello" , "world" , SendResults() , "bye" )
@
@newTrial( "hello" ,
@    newButton("Hello")
@        .log()
@        .print()
@        .wait()
@)
@newTrial( "world" ,
@    newButton("Send  quit now")
@        .callback( 
@            getButton("World")
@                .remove()
@            ,
@            SendResults()
@        )
@        .print( 10 , 10 )
@    ,
@    newButton("World")
@        .log()
@        .print()
@        .wait()
@)
@
@newTrial( "bye" ,
@    newText("thanks", "Thank your for participating in this experiment.")
@        .print()
@    ,
@    newText("link", "Click here to confirm your participation.")
@        .print()
@    ,
@    newTimer("forever", 1)
@        .wait()            // Timer never started: will wait forever
@)
@.setOption("countsForProgressBar",false)
  • Through the Try-it interface, the Send quit now button will crash because the experiment is not run globally but instead from within the test page.
↑ back to top

Sequence

syntax

Sequence()

description

Determines the order in which your trials will be run. Use your trials’ labels to manipulate the running order.

example

click to expand

$Sequence( "hello" , randomize("world") )
@
@newTrial( "world" ,
@    newButton("world", "Earth")
@        .print()
@        .wait()
@)
@newTrial( "world" ,
@    newButton("world", "Moon")
@        .print()
@        .wait()
@)
@newTrial( "world" ,
@    newButton("world", "Mars")
@        .print()
@        .wait()
@)
@
@newTrial( "hello" ,
@    newButton("world", "Hello...")
@        .print()
@        .wait()
@)
  • Will run the trial labeled hello first, even though it is defined below the world ones, and then will run all three trials labeled world in a random order.
↑ back to top

SetCounter

syntax

SetCounter()

description

Creates an item that will set Ibex’s internal counter when it is run.

example

click to expand

@AddTable( "myTable" , 
@  "Group,Button\n"+
@  "A,Hello\n"+
@  "B,World"
@);
@
@Sequence("counter", "trial");
@
$SetCounter("counter", "inc", 1);
@
@Template( "myTable" , row => 
@  newTrial( "trial" ,
@    newButton( "greetings" , row.Button )
@        .print()
@        .wait()
@  )
@);
  • Increments the counter as soon as the experiment starts running. Since we use a table defining two groups (A and B) the button will read Hello or World every other time the experiment is run (try running it multiple times without clicking the button).
↑ back to top

Template

syntax

Template()

description

Generates trials from a table. See this page to learn how to use it. You can have as many Template as you want (which is helpful if you use different trial templates).

example

click to expand

@AddTable( "mytable" ,
@    "Type,Sentence,TargetPicture,CompetitorPicture\n"+
@    "Test,This is a square,square.png,triangle.png\n"+
@    "Filler,This is a triangle,triangle.png,pear.png"
@);
@
$Template( "mytable" , row => 
$   newTrial( row.Type ,
@        newText("sentence", row.Sentence)
@            .print()
@        ,
@        newSelector("choice")
@        ,
@        defaultImage
@            .size(200,200)
@            .selector("choice")
@        ,
@        newCanvas( "images", 500, 200 )
@            .add(   0, 0, newImage("target", row.TargetPicture)     ) 
@            .add( 300, 0, newImage("target", row.CompetitorPicture) ) 
@            .print()
@        ,
@        getSelector("choice")
@            .shuffle()
@            .wait()
@    )
@);
  • Generates trials labeled according to the Type column of the table, showing a sentence whose text is retrieved from the Sentence column of the table, and two pictures side by side retrieved from the TargetPicture and CompetitorPicture columns.

@AddTable( "mytable" ,
@    "Type,Sentence\n"+
@    "Filler,The cat that is chasing the mouse runs fast\n"+
@    "Test,The mouse that the cat is chasing runs fast"
@);
@
@Template( "mytable" , row => 
@    [
@        "DashedSentence", {s: row.Sentence},
$        "PennController", newTrial(
$            newText("question", "How natural did you find this sentence?")
@                .print()
@            ,
@            newScale("natural", 7)
@                .before( newText("left", "Completely unnatural") )
@                .after( newText("right", "Completely natural") )
@                .print()
@                .wait()
@        )
@    ]
@);
  • Generates two-screen trials, the first screen using the native Ibex DashedSentence with the value from the Sentence column passed as its s parameter, the second screen using PennController to show a naturalness scale.
↑ back to top

UploadRecordings

syntax

UploadRecordings()

description

Creates a trial which, when executed, will send the recordings collected so far via the MediaRecorder element to the URL provided to InitiateRecorder.

example

click to expand

@Sequence( 
@  "intro" 
@  ,
@  sepWith("sendAsync", "recordTrial") 
$)
@
@InitiateRecorder("https://my.server/path/to/uploadScript.php")
@  .label("intro")
@
$UploadRecordings("sendAsync", "noblock")
@
@newTrial("recordTrial", 
@  newText("Please act out happiness").print()
@  ,
@  newMediaRecorder("happiness").print().log().wait()
@)
@
@newTrial("recordTrial", 
@  newText("Please act out sadness").print()
@  ,
@  newMediaRecorder("happiness").print().log().wait()
@)
  • Will start sending each video sample to the server immediately after it is recorded.
↑ back to top

newTrial().label

syntax

newTrial().label()

description

This is another way to assign a label to a PennController trial so you can refer to it in Sequence. It is most useful called on CheckPreloaded or InitiateRecorder since those commands do not take labels as arguments.

example

click to expand


@
$Sequence( "practice" , "preload-exp" , rshuffle("filler","test") )
@
@CheckPreloaded( 
@  "filler"
@  ,
@  "test"
$).label( "preload-exp" )
  • Creates a trial labeled preload-exp checking that all the resources used in the PennController trials labeled filler or test are preloaded, and refers to its label in Sequence so it will be run before the filler and test trials, but after the practice trials.
↑ back to top

newTrial().log

syntax

newTrial().log()

description

You can use the .log method to add columns to every line corresponding to this trial that is logged in the results file. You can add as many .log as you want.

example

click to expand


@
@newTrial(
@    newButton("helloworld", "Hello world!")
@        .log()
@        .print()
@        .wait()
@)
$.log("Trial type", "One-Button")
$.log("Text on button", "Hello world!");
  • Will add One-Button and Hello world! to the end of every line saved to the results file for this trial.

↑ back to top

newTrial().noFooter

syntax

newTrial().noFooter()

description

Will not run the footer sequence at the end of the trial.

example

click to expand


@Footer(
@    newButton("validate", "Got it!")
@        .print()
@        .wait()
@);
@
@newTrial( "with footer" ,
@    newScale("score", 5)
@        .before( newText("left","Score:") )
@        .print()
@        .wait()
@);
@  
@newTrial( "without footer" ,
@    newScale("score", 5)
@        .before( newText("left","Score:") )
@        .print()
@        .wait()
@)
$.noFooter();
  • The first trial (labeled with footer) will show a radio-button scale on the screen and reveal a button reading Got it! to be clicked when a radio button is selected. The second trial (labeled without footer) will end right after a radio button is selected.

↑ back to top

newTrial().noHeader

syntax

newTrial().noHeader()

description

Will not run the header sequence at the beginning of the trial. Note that this also concerns default commands defined in the header: those will not be run in trials where you use noHeader.

example

click to expand


@Header(
@    defaultButton
@        .print()
@        .wait()
@    ,
@    newText("please", "Please give a score")
@        .print()
@)
@
@newTrial( "twoClicks" ,
@    newScale("score", 5)
@        .print()
@    ,
@    newButton("validate", "Validate")
@        .wait( getScale("score").test.selected() )
@)
@
@newTrial( "oneClick" ,
@    newScale("score", 5)
@        .print()
@    ,
@    newButton("validate", "Validate")
@        .print()
@        .wait( getScale("score").test.selected() )
@)
$.noHeader()
  • The first trial (labeled twoClicks) will show a text at the top of the page, then a radio-button scale and a button. Because the header already contains a wait command, two clicks will be necessary to validate the button (the second one having to happen after a radio-button is selected). On the contrary, the second trial (labeled oneClick) which uses noHeader, will show no text at the top of the page and will only require one click on the button to validate it (assuming a radio-button is selected), because it will only evaluate and execute one wait command.

↑ back to top

newTrial().setOption

syntax

newTrial().setOption()

description

Lets you modify a parameter of the controller, as you would for any other controller in Ibex.

example

click to expand

@
@newTrial(
@    newScale("Score", 8)
@        .slider()
@        .print()
@        .wait()
@)
$.setOption("countsForProgressBar", false);
  • This trial will not count for the progress bar at the top of the Ibex experiment page (see the Ibex documentation manual).
↑ back to top

newTrial

syntax

newTrial()

description

The newTrial command (formerly PennController) creates a new PennController trial. You can use it in three environments: on its own to create a trial (since version 1.0), within Template to generate trials from a spreadsheet, or within the definition of the Ibex variable items to create single elements (deprecated since PennController 1.0).

example

click to expand

@
$newTrial(
@    newButton("helloworld", "Hello world!")
@        .print()
@        .wait()
@);
@
@Template( row => 
$    newTrial( row.Type ,
@        newButton("button", row.ButtonText)
@            .print()
@            .wait()
@    )
@);
  • Creates one trial labeled unlabeled with a single button on the screen reading Hello world!, and generate one-button trials from a spreadsheet, assigning the text from its Type cells as their label and the text from its ButtonText cells as the button’s text (see Template).
↑ back to top