Jeremy

Forum Replies Created

Viewing 15 posts - 391 through 405 (of 1,522 total)
  • Author
    Posts
  • in reply to: MediaRecorder – filenames using ID #8268
    Jeremy
    Keymaster

    Hi Dod,

    PennController Var elements are not javascript variables (visit the link in my message above to read about differences between PennController and plain javascript)

    The keyword variable has no meaning in plain javascript, and PennController defines no global object with that name. You will sometimes see variable in the scope of Template in some people’s code, but in your case it looks like you are using row instead (as determined by row =>, which I assume comes with Template in your code)

    You could try that instead:

    const speakID = [...Array(4)].reduce(a=>a+alphanum.charAt(Math.floor(Math.random()*alphanum.length)),'')
    
    newTrial("speakID",
        newText("speakID", speakID).print()
        ,
        newButton().print().wait()   // to be deleted, just to double check that the code matches the audiofile
    )
    .log("speakID", speakID)
    
    // ...
    newMediaRecorder(row.itemID+"_"+row.modality+"_"+speakID, "audio")

    Jeremy

    in reply to: Variable fixation dot position #8267
    Jeremy
    Keymaster

    Hi Ana,

    Are you trying to align ... with the start of the SPR sentence? If so, since you use a mono-spaced font to display the SPR sentence, you can simply pass a string of the same length to the three-dot Text element and it will be the exact same size as the SPR sentence, so if you print it at the same coordinates, they will be perfectly aligned. The trick is to make that string start with ... and render all remaining (dummy) characters invisible, eg:

    // dots 1_1
    newText("start1_1", "...<span style='visibility: hidden;'>"+
                        [...new Array(variable.context.length-3)].map(v=>'_').join('')+"</span>")
        .css({"font-size":"23px","font-family":"courier"})
        .print("center at 50%", "middle at 50%")
    ,
    // Keep the dots in place for about a second 
    newTimer("start1_1_timer", 1000).start().wait()
    ,
    // Remove the dots
    getText("start1_1").remove()
    ,
    // context sentence
    newText ("read_ctxt","Lies bitte den ersten Satz und drücke die Leertaste um fortzufahren")
        .css({"font-size":"15px","font-family":"times new roman"})
        .center()
        .color("red")
        .print("center at 50%", "middle at 46%")
    ,
    // context sentence in SPR
    ...cumulative_ctxt(variable.context, "remove")
    ,
    getText("read_ctxt").remove()

    Jeremy

    in reply to: Block n of n? #8263
    Jeremy
    Keymaster

    Hi Simone,

    Your code seems perfectly fine to me (assuming you have 9 blocks of 108 test trials—if you have 9 blocks of 12 trials, you need to write sepWithN("break", randomize("test"), 12)). You could write your “break” trial like this, for example:

    newTrial("break", 
        newVar("block_n", 0).global().set(v=>v+1)
        ,
        newVar("text").set(getVar("block_n")).set(v=>"You've just finished block "+v+" of 9")
        ,
        newText("prompt", "").text(getVar("text")).print()
        ,
        newButton("Next").print().wait()
    )

    Jeremy

    in reply to: Bidirectional self-paced reading #8262
    Jeremy
    Keymaster

    Hi Jun,

    You’ll have to edit DashedSentence.js in the Modules folder and replace the conditional on "self-paced reading" toward the top with a simple if (this.mode == "self-paced reading") this.sprResults = [];. Then replace the safeBind piece of code further down with this:

    this.safeBind($(document), 'keydown', function(e) {
      var time = new Date().getTime();
      var code = e.keyCode;
    
      if (code == 37 || code == 39) {
          var word = t.currentWord;
          if (word > 0 && word <= t.stoppingPoint)
              t.sprResults.push([time,t.previousTime,word]);
          t.previousTime = time;
    
          if (code == 37){
              if (code != t.lastKey) t.currentWord--;
              if (t.currentWord < t.stoppingPoint)
                  t.blankWord(t.currentWord);
              if (t.currentWord - 1 >= 0)
                  t.showWord(t.currentWord - 1);
              t.currentWord--;
              if (t.currentWord<0) t.currentWord = 0;
          }
          else if (code == 39){
              if (t.currentWord>0 && code != t.lastKey) t.currentWord++;
              if (t.currentWord - 1 >= 0)
                  t.blankWord(t.currentWord - 1);
              if (t.currentWord < t.stoppingPoint)
                  t.showWord(t.currentWord);
              t.currentWord++;
              if (t.currentWord > t.stoppingPoint) {
                  t.processSprResults();
                  t.finishedCallback(t.resultsLines);
              }
          }
          t.lastKey = code;
          return false;
          // ***
      }
      else {
          return true;
      }
    });

    And the processSprResults piece of code toward the end of the script with this:

    processSprResults: function () {
        for (var i = 0; i < this.sprResults.length; ++i) {
            var n = this.sprResults[i][2];
            this.resultsLines.push([
                ["Word number", n],
                ["Word", csv_url_encode(this.words[n-1]||"")],
                ["Reading time", this.sprResults[i][0] - this.sprResults[i][1]],
                ["Newline?", (! this.display == "in place") &&
                              boolToInt(((n+1) < this.wordOSpans.length) &&
                              (this.wordOSpans[n].offset().top != this.wordOSpans[n+1].offset().top))],
                ["Sentence (or sentence MD5)", this.sentenceDesc]
            ]);
        }
    }

    Jeremy

    in reply to: MouseTracker element: Dynamic starting procedure #8261
    Jeremy
    Keymaster

    Hi Judith,

    Apologies for the late reply. You can pass a function to the callback command of the MouseTracker element that takes the x,y coordinates as arguments—you can then use the Y coordinate to either check that the cursor moved upwards by N pixels, or that it is above a certain line. Here is a simple trial illustrating how to update a Text element once the mouse has moved at least 50px north after clicking:

    newTrial(
        newButton("Start").print().wait().remove()
        ,
        newVar("start_y", undefined)
        ,
        newText("prompt", "Hello _____").print()
        ,
        newMouseTracker("mouse")
            .callback( async (x,y) => {
                if (getVar("start_y").value === "stop") return;
                else if (getVar("start_y").value === undefined) 
                    await getVar("start_y").set(y)._runPromises();
                else if (getVar("start_y").value - y > 50) {
                    await getVar("start_y").set("stop")._runPromises();
                    await getText("prompt").text("Hello World")._runPromises();
                }
            })
            .start()
        ,
        newButton("Finish").print().wait()
        ,
        getMouseTracker("mouse").stop()
    )

    Jeremy

    in reply to: MediaRecorder's Ajax post failed;Could not GET #8260
    Jeremy
    Keymaster

    Hi,

    Apologies for the late reply. Do you mind sharing the link to your experiment and API gateway URL with me, here or at support@pcibex.net so I can proceed to some tests for troubleshooting? Thank you

    EDIT: after an email exchange, it was determined that this was a case of Cross-Origin Resource Sharing (CORS) misconfiguration on the API gateway’s side that comes with the default configuration. It was fixed by opening the API gateway in the AWS console, visiting the CORS tab, and then clicking the “Clear” button: after that, the API allows the Lambda function to return the headers, including the CORS-relevant ones

    Jeremy

    • This reply was modified 3 years, 2 months ago by Jeremy. Reason: problem solved
    in reply to: unable to make the stimuli font bigger #8257
    Jeremy
    Keymaster

    Hi Loid,

    My apologies for the late reply. You can make a font bigger by setting the CSS rule font-size that targets the relevant HTML nodes

    Assuming you are using the native-IBEX AcceptabilityJudgment controller, which is composed of the FlashSentence controller to render the s parameter and the Question controller to render q and as, you can edit the file FlashSentence.css in your project’s Aesthetics folder to modify the font size of the s parameter by adding:

    p.FlashSentence {
        font-size: 3em;
    }

    To change the font size of the q and as parameters, you can edit the file Question.css and add:

    p.question-text {
        font-size: 4em;
    }
    li.normal-answer {
        font-size: 2em;
    }

    Note that those changes will affect any other item using the FlashSentence and/or the Question controller

    Jeremy

    in reply to: Unable to randomize fillers and experimental items #8256
    Jeremy
    Keymaster

    Hi Yasmin,

    My apologies for the late reply. What is the error you encounter when trying to use read.pcibex? That function should output a table whose columns are named after the comments lines

    1.655924e+12 is a visual representation of a number composed of 13 digits used by whatever software you are using to view it, but the internal representation of the number is effectively between 1655924000000 and 1655924999999 (depending on how the software decided to truncate/round the number in its exponent representation)

    Jeremy

    in reply to: suddenly: conditional never 'success' #8255
    Jeremy
    Keymaster

    Hello Daniela,

    My apologies for the late reply. As far as I can tell, you don’t need to use any Var element in your code. You could do something like this instead:

    // Top of your script
    const YES_KEY = 'F', NO_KEY = 'J';
    
    // inside your trial
    newKey("rating", "FJ")
      .callback( getTimer("time_out1").stop() )
      .log("all")  
    ,
    getTimer("time_out1").wait() // I added this here as it seems to make sense given the callback above
    ,
    getKey("rating")
      .test.pressed( variable.match=='yes' ? YES_KEY : NO_KEY )
      .success(
        newText ("match_text", variable.prac_correct)  // print the CORRECT feedback response for this trial
          .css({"font-size":"20px","font-family":"times new roman"})
          .print("20vw","40vh")
      )
      .failure(
        newText ("mismatch_text", variable.prac_incorrect)  // print INCORRECT feedback
          .css({"font-size":"20px","font-family":"times new roman"})
          .color("red")
          .print("20vw","40vh")
      )
    ,
    newText("spacebar", "Press the spacebar to continue.")
      .css({"font-size":"15px","font-family":"times new roman"})
      .italic()
      .center()
      .color("red")
      .print("20vw","50vh")
    ,
    newKey("feedback", " ").wait()

    Remember that you can always share your project’s demonstration link as a way to share your code and make troubleshooting easier

    Jeremy

    in reply to: server setup queries/issues #8242
    Jeremy
    Keymaster

    You don’t need to run server_conf.py: server.py has this line execfile(SERVER_CONF_PY_FILE, CFG) which takes care of running server_conf.py itself

    All you need to do, when things are configured properly, is visit the URL that points to server.py (eg. https://my.domain.xyz/myxp/server.py?withsquare=0) or to experiment.html (eg. https://my.domain.xyz/myxp/experiment.html) — experiment.html itself invokes server.py on several occasions, effectively executing it

    To reiterate my point, when running the experiment as a CGI application, you don’t need to run anything yourself: your webserver (if configured properly) will take care of running the script itself upon request (ie by visiting the experiment’s URL). Also, you don’t need to update the PORT variable in server_conf.py, since you are not running your experiment in stand-alone (toy) mode, as per the comments above the PORT line: # The port the server will run on if running in stand-alone mode.

    The “site can’t be reached” error is most likely unrelated to IBEX, but rather to some other configuration on the webserver or domain end, for example. Are you able to visit other resources served by your webserver? I’m afraid I can’t really help with that

    EDIT: it just occurred to me that Chrome does say “This site can’t be reached” if you try to visit localhost:3000 without spinning up server.py in stand-alone (toy) mode. Do you mean to run your experiment in stand-alone (toy) mode on your machine? If so, you do need to run server.py, but make sure the SERVER_MODE variable in server_conf.py is set to "toy" (and make sure you visit the same port that you set in server_conf.py, which is 3000 by default)

    Jeremy

    • This reply was modified 3 years, 2 months ago by Jeremy.
    Jeremy
    Keymaster

    Hi,

    You need to include the category information in the trials’ labels, otherwise the various sequence functions will have no way of knowing which trial is from which category, and therefore you’ll have no hope of constraining their distribution

    I wrote a function called randomizeNoMoreThan that does what you want. Once you’ve added a .js file defining the function to your project’s Modules folder, you can proceed to the following modifications:

    • replace newTrial("experimental_items" with newTrial("experimental_items_"+row.Kategorie
    • replace critical = randomize("experimental_items"); with critical = randomizeNoMoreThan(startsWith("experimental_items"), 3);
    • replace all three occurrences of rshuffle(pick(critical, 61)) with pick(critical, 61)

    Since pick selects consecutive trials from a set (ie. the next 61 trials it picks follow the previous 61 trials it picked in the set stored in the critical variable) and since the set stored in critical has been randomized using randomizedNoMoreThan, you should get the desired behavior

    Jeremy

    in reply to: server setup queries/issues #8237
    Jeremy
    Keymaster

    Hi,

    You will get this error if you set SERVER_MODE to "cgi" in server_conf.py but not actually run the experiment as CGI (which would involve visiting the URL of your experiment on a web server under, say, Apache) but instead run it in stand-alone mode using python server.py. If you run your experiment on your machine (and not on a web server) then you are running it in “toy” mode, so set SERVER_MODE to "toy"

    Jeremy

    in reply to: recording audio production #8235
    Jeremy
    Keymaster

    Hi,

    You cannot do that, because there is one recording per MediaRecorder element, and elements are created before the sequence of trials is run, they cannot be created on the fly

    My suggestion is you give unique labels to your recording trials and use jump to run them again if needed, eg:

    Template( row => 
      newTrial( "recorder-"+row.item ,
        newMediaRecorder("mediarecorder-"+row.item, "audio").print().wait().log()
        ,
        // Jump to this trial (= recorder-ITEM#)
        newButton("Again").print().callback( jump("recorder-"+row.item) , getButton("Next").click() )
        ,
        newButton("Next").print().wait()
      )
      .log("item#", row.item)
    )

    Jeremy

    Jeremy
    Keymaster

    Hi Eva,

    Target the label nodes (clickable) instead of the parent .option nodes:

    .PennController-Scale .option label {
       margin: 0em 1em; 
       font-size: 24px;
    }

    Jeremy

    Jeremy
    Keymaster

    Hi,

    You can add CSS rules to Aesthetics/global_main.css to control the visual rendering of your Scale element. See this post

    Jeremy

Viewing 15 posts - 391 through 405 (of 1,522 total)