Jeremy

Forum Replies Created

Viewing 15 posts - 931 through 945 (of 1,522 total)
  • Author
    Posts
  • in reply to: Repeat sample trial with audio recording #6708
    Jeremy
    Keymaster

    Hi,

    This is a problem that has to do with how I coded the Controller element. Add this to your script, and replace .print().wait().remove() with simply .run() on your Controller element:

    PennController._AddStandardCommands( function(PennEngine) {
        this.actions = {
            run: async function(resolve){
                if (this.type != "Controller" || this.controller != "DashedSentence")
                    return resolve();
                this.done = false;
                await new Promise(r=>PennEngine.elements.standardCommands.actions.print.call(this,r));
                const oldCallback = this.finishedCallback;
                await new Promise(r=>this.finishedCallback=function(){
                    oldCallback.call(this);
                    this.jQueryContainer.detach();
                    r();
                });
                resolve();
            }
        }
    })

    You also want to change your trial’s code slightly:

    newTrial("practice-trial",
        newButton("launch-practice-trial", "Redo")
            .callback(
                ...PracticeTrial()
                ,
                getButton("proceed").print()
                ,
                getButton("launch-practice-trial").print()
            )
            .center()
            .click()
        ,
        newButton("proceed", "Proceed")
            .center()
            .wait()
    )

    Here’s a demo link: https://farm.pcibex.net/r/AjyfGD/

    Let me know if you have any questions

    Jeremy

    Jeremy
    Keymaster

    Hi,

    Here’s a live demo: https://farm.pcibex.net/r/EMYHvp/

    And here’s the code (you can edit it directly on the farm too):

    newTargetButton = (name,text) => newButton(name, (name||text))
        .callback(
            getButton(name)
                .disable()
                .css("color","red")
            ,
            getVar("targetsLeft")
                .set(v=>v-1)
                .test.is(0)
                .success( getButton("Next").click() )
            ,
            getText("counter")
                .text( getVar("targetsLeft") )
        )
        .selector("buttons")
        
    newFilerButton = (name,text) => newButton(name, (name||text))
        .callback( getButton(name).disable() )
        .selector("buttons")
    
    newTrial(
        newVar("targetsLeft", 3)
        ,
        newText("counter", '3')
            .before( newText("# targets left: ") )
            .print()
        ,
        newCanvas("container", 800,100)
        ,
        newSelector("buttons").disableClicks()
        ,
        newTargetButton("target1").print(   0,0,getCanvas("container")),
        newTargetButton("target2").print(200, 0,getCanvas("container")),
        newTargetButton("target3").print(400, 0,getCanvas("container"))
        ,
        newFilerButton("filler1").print(600, 0,getCanvas("container")),
        newFilerButton("filler2").print(  0,40,getCanvas("container")),
        newFilerButton("filler3").print(200,40,getCanvas("container")),
        newFilerButton("filler4").print(400,40,getCanvas("container")),
        newFilerButton("filler5").print(600,40,getCanvas("container")),
        newFilerButton("filler6").print(  0,80,getCanvas("container")),
        newFilerButton("filler7").print(200,80,getCanvas("container"))
        ,
        getCanvas("container").print()
        ,
        getSelector("buttons").shuffle()
        ,
        newButton("Next").wait()
    )

    Let me know if you have any questions

    Jeremy

    in reply to: access participants' browser info #6703
    Jeremy
    Keymaster

    Dear Aliona,

    Each submission in the results file starts with these lines:

    # Results on Friday February 26 2021 14:31:11 UTC
    # USER AGENT: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0

    As you can see, in this case, the submission came from a participant (me) who used Firefox. This is not 100% reliable, but there is no method that is 100% reliable when it comes to determining the browser’s identity

    Jeremy

    in reply to: Data repetition during collection #6701
    Jeremy
    Keymaster

    Thank you—so, the first event that gets logged in your trial (after its start) is indeed the keypress of the space bar that reveals the second word (ie. the keypress that “validates” the first word): if you subtract all the reading times from the bolded timestamp, you’ll get the timestamp corresponding to when the first word was revealed. Because the very first event that occurs in your trial is printing the all-blank sentence, you can subtract the trial’s start timestamp (which approximates when the all-blank sentence was printed to the page) from the first-word timestamp you just calculated, and you’ll get how long it took to your participant to reveal the first word by pressing the space bar.

    The last event in your trial is a keypress on F or J, which you log: if you subtract the bolded timestamp (which corresponds to the completion of the Controller element) from the keypress’s timestamp, you’ll get how it took for your participant to give an answer to the question

    Let me know if you have questions

    Jeremy

    in reply to: Data repetition during collection #6698
    Jeremy
    Keymaster

    Hi,

    Regarding your first question, it is a known bug: pressing the spacebar again during the same trial after the DashedSentence controller has completed will duplicate the logged lines. I am working on fixing this for the next release of PennController. In the meantime, the easiest way to avoid this is to move to the next trial immediately after the DashedSentence controller, but I realize this is not always possible.

    Regarding you second question: the bolded number is the timestamp corresponding to when the DashedSentence controller was completed. If you subtract all the reading times from it, you’ll get the timestamp corresponding to the when the first word was displayed (not to when the all-blank sentence itself was displayed). The delay between the display of the the all-blank sentence and when the first word was revealed might account for the mismatch you report, but I would need to see your code to tell for sure (you can use the demonstration link from your project’s Share action for that)

    Jeremy

    in reply to: Reading data into R Column Names #6695
    Jeremy
    Keymaster

    Hi,

    Remove these three lines from the definition of read.pcibex:

    if (index < length(cols)){
        cols <- c()
    }

    Jeremy

    in reply to: Cannot getVal correctly #6690
    Jeremy
    Keymaster

    Hi Rick,

    As far as I can tell, you don’t need a Var element to do what you’re after:

    subjID = String.fromCharCode(65+Math.floor(Math.random() * 26)) + Math.floor((Math.random() * 10000) + 1)
    
    Sequence ("experiment","bye")
    
    Header(
      // ...
    )
    .log("ParticipantID", subjID)
    
    // ... experiment
    
    newTrial("bye",
        defaultText
            .center()
            .print()
        ,
        newText("<p>Thank you for doing this study!!!</p>")
        ,
        newText("Your participant id number is:")
        ,
        newText(subjID)
        ,
        newButton("void")
            .wait()
    )
    .setOption("countsForProgressBar" , false)

    What you report is a known bug, I’ll work on fixing it for the next release (or the one after that)

    Jeremy

    Jeremy
    Keymaster

    I’m not sure why, but I realize that the once command there is superfluous, so maybe try removing it to see if that fixes the problem. Also try adding a 200ms Timer element (don’t forget to start and wait for it) before the closing parenthesis of the newTrial so as to give time to your trial to process the stopping of the MediaRecorder element

    Jeremy
    Keymaster

    Hi,

    The code you posted will not show any button, because there is no print command in the script after clear has been executed. Why don’t you remove the last wait command (on the MediaRecorder element) and create a “Save recording” button?

    newMediaRecorder("recorder", "audio")
      .log()
      .once()
      .record()
      // .wait()
    ,
    newButton("Save recording")
      .callback(getMediaRecorder("recorder").stop())
      .print()
      .wait()

    Jeremy

    in reply to: Audio stop/wait problems with new Farm #6672
    Jeremy
    Keymaster

    Hi,

    Feel free to share the demonstration link of your experiment with me, here or at support@pcibex.net, so I can take a look

    If you say that it was working on the old farm (that is, even using Chrome/Opera/Edge) then maybe what changed is that your project on the new farm uses a newer version of the PennController library. Maybe try downgrading to PennController 1.8 (remember to pause data collection when editing your project): https://github.com/PennController/penncontroller/tree/master/releases/1.8
    (download the js file and upload it to the Modules folder of your project)

    Jeremy

    in reply to: Randomize DashedSentence #6669
    Jeremy
    Keymaster

    Glad it ended up working! I don’t know what might have caused an issue with PennController 1.8, but it’s good to know that PennController 1.9 seems to have fixed it (whatever “it” is)

    Jeremy

    in reply to: Randomize DashedSentence #6666
    Jeremy
    Keymaster

    Hi,

    Your code works well for me. (Note that I replaced s: with q: in the Question controller, but that wouldn’t make the experiment crash anyway)

    If you are using a Sequence command, did you make sure to include the trials labeled "trials" in it?

    Jeremy

    in reply to: Some final issues before the experiment #6664
    Jeremy
    Keymaster

    Hi Danil

    2.

    I know the recordings of the trial before the last trial and the last trial are uploaded because I can see the lines

    1613560743,856aafdd008ea714bef357058d6b9c1c,PennController,1,0,sendAsync,NULL,PennController,UploadRecordings,_Trial_,Start,1613560695092,NULL
    1613560743,856aafdd008ea714bef357058d6b9c1c,PennController,1,0,sendAsync,NULL,PennController,UploadRecordings,_Trial_,End,1613560695095,NULL

    These lines simply report that the UploadRecordings trial was run, they do not report that any file was uploaded. The lines that report successful uploads are the ones you mention otherwise, which include the filename of the zip file that was uploaded, like this one:

    1613560743,856aafdd008ea714bef357058d6b9c1c,PennController,73,0,experiment,NULL,PennController,UploadRecordings,Filename,2b02bf46-7ba9-6d0a-4f64-ebf0ad7c8394.zip,1613560695207,filler2,APN,,карамфил,От градината бяха откъснати засадените от девойката,карамфил,A,STE-044_mono.wav,filler2_APN_карамфил__A,async

    It does not seem to be a problem of coding since the final uploading (which is asynchronous (the line used in the main file is indeed UploadRecordings(“sendAsync”, “noblock”)) and the next trial begins before the last upload has completed, which in turn explains why each .zip file points to the preceding trial) seems to happen after the execution of the final trial (as the second “sendAsync”) suggests.

    Precisely, this is why I suggested you make (at least the last of) your UploadRecordings trial synchronous, so that the final screen is only reached after upload has completed

    Contrary to your previous suggestion I cannot input this information with my materials during the experiment, since I do not have a direct control of my participants.

    Are you referring to this message? I’m not sure how it is relevant to the current point, which is about checking whether the (algorithmatically uniquely-named) zip files have been uploaded

    Contrary again to your previous suggestion, I wouldn’t want to reset the value of this counter file, since this file contains important information about the number of participants.

    Are you referring to my suggestion to use the SetCounter command to increase the value of the counter early in the experiment? Using that command would not reset the counter, it would simply change the default behavior of automatically increasing the counter at the end of experiment, and would increase it wherever you run the SetCounter trial instead (for example, at the very beginning of the experiment, if you make that SetCoutner trial the first one to run). If you want to test your experiment in a specific group without editing anything in your project, use the withsquare method described in the tutorial.

    Regarding adding participant-identifying info to the filenames of your audio recordings (ie not the uploaded zip files themselves, but the files they contain): for the reasons you describe, two or more participants could run the experiment with the same counter value, but generating another unique id, in addition to the MD5 hash that’s reported at the beginning of every line, and adding it at the end of every line is not terribly difficult. Just add this to your script:

    var id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c=>{
      const r = Math.random() * 16 | 0,v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16)];
    })
    Header(
      // void
    )
    .log("uniqueID", id)

    And then add +id to your MediaRecorder elements’ names, for example newMediaRecorder("test1_recording"+id, "audio") / getMediaRecorder("test1_recording"+id)

    3. The first thing you should do, assuming you are hosting your experiment on a secure domain (which is the case on the PCIbex Farm) is replace your line

    AddHost("http://sabotin.ung.si/~dk0035/")

    with

    AddHost("https://sabotin.ung.si/~dk0035/")

    In any case, your experiment seems to use many files, each between 250-800KB: I wouldn’t be surprised if the servers where you host your files just stopped serving some files after too many requests in a short time window. Which makes me reiterate my recommendation to consolidate them into one or a few zip files. You can easily generate unique filenames by prefixing the name of their current containing folder, eg: Fillers2_STE-001_mono.wav

    Regarding some of your participants taking your experiment again: this is something you should avoid, so I think you should rather spend time and efforts reducing the likelihood that they would have to take your experiment again. I don’t know how you will be recruiting your participants and what resources you have access to, but my policy with online experiments has been to pay each participant only once, so they had no incentive to take the experiment again after completing it once, and to pay them even if they couldn’t finish the experiment as long as they can prove that they tried (usually by describing the content of the experiment and/or sending a screenshot). In my opinion, the counter-based conditional system that you describe seems overly complicated, and ultimately not necessary once the initial problem has been addressed.

    Feel free to send me a link to your experiment here or by email at support@pcibex.net

    Jeremy

    in reply to: Response time on comprehension questions #6651
    Jeremy
    Keymaster

    Good morning,

    There sure are alternative/additional ways, but subtracting the two timestamps is probably the most accurate measure you can get: each timestamp reports when the event happened, to the millisecond (modulo browser lag). In your case, you know that the participant pressed a key almost exactly one second (1072ms) after the main Canvas element was displayed. Subtracting the timestamps is a simple operation in R (line 7).

    If you really need to report the RT at the end of every row, you can use a global Var element that you set to Date.now() when printing the Canvas and whose value you subtract to Date.now() after selection happened, and you can log it on your newTrial:

    Template("fullstim.csv",
        row => ["fullstim",
            "DashedSentence", {s: row.Sentence},
            "PennController", newTrial("experiment",
        defaultImage
            .size(500,350)
            ,
        newImage("male", row.MaleImageFile)
            ,  
        newImage("female", row.FemaleImageFile)
           ,
        newCanvas(1000,500)
            .add(   -50 , 0 , newCanvas("left" , 500, 500) )  
            .add( 475 , 0 , newCanvas("right", 500, 500) )  
            .print()
            .log()
            ,
        newVar("RT").global().set( v=>Date.now() )
            ,
        newCanvas(50,50)
            .add(180,-100, newText("(A)"))
            .add(700,-100, newText("(B)"))
            .print()
            ,
        
        getCanvas("left").add( 0 , 0 , getImage(row.LeftPicture))
        ,
        getCanvas("right").add( 0, 0 , getImage(row.RightPicture))
        ,
        newSelector()
            .disableClicks()
            .add( getImage(row.LeftPicture) , getImage(row.RightPicture) )
            .keys(          "A"    ,          "B"   )
            .log()
            .wait()
            .test.selected( getImage(row.Target) )
            .success( newText("Correct! Remember, <i> faire </i> plus the infinitive shows that the object performs the action. Otherwise, the subject performs the action.").css("font-size","1.5em").print() )
            .failure( newText("Incorrect! Remember, <i> faire </i> plus the infinitive shows that the object performs the action. Otherwise, the subject performs the action.").css("font-size", "1.5em").print() )
            ,
        getVar("RT").set( v=>Date.now()-v )
            ,
        newButton("Next").print().wait()
        )
        .log('Item', row.Sentence)
        .log('Group', row.Group)
        .log('RT', getVar("RT"))
    ])

    Jeremy

    in reply to: including attention checks and break #6646
    Jeremy
    Keymaster

    Hi,

    Simply replace randomize with seq and it should be enough

    Jeremy

Viewing 15 posts - 931 through 945 (of 1,522 total)