/********************** * Sopajsshuffle Test * **********************/ import { core, data, sound, util, visual, hardware } from './lib/psychojs-2022.2.0.js'; const { PsychoJS } = core; const { TrialHandler, MultiStairHandler } = data; const { Scheduler } = util; //some handy aliases as in the psychopy scripts; const { abs, sin, cos, PI: pi, sqrt } = Math; const { round } = util; // store info about the experiment session: let expName = 'SopaJsShuffle'; // from the Builder filename that created this script let expInfo = { 'participant': '', 'session': '001', 'age': '', 'gender': '', }; // Start code blocks for 'Before Experiment' // init psychoJS: const psychoJS = new PsychoJS({ debug: true }); // open window: psychoJS.openWindow({ fullscr: true, color: new util.Color([0,0,0]), units: 'height', waitBlanking: true }); // schedule the experiment: psychoJS.schedule(psychoJS.gui.DlgFromDict({ dictionary: expInfo, title: expName })); const flowScheduler = new Scheduler(psychoJS); const dialogCancelScheduler = new Scheduler(psychoJS); psychoJS.scheduleCondition(function() { return (psychoJS.gui.dialogComponent.button === 'OK'); }, flowScheduler, dialogCancelScheduler); // flowScheduler gets run if the participants presses OK flowScheduler.add(updateInfo); // add timeStamp flowScheduler.add(experimentInit); const trials_2LoopScheduler = new Scheduler(psychoJS); flowScheduler.add(trials_2LoopBegin(trials_2LoopScheduler)); flowScheduler.add(trials_2LoopScheduler); flowScheduler.add(trials_2LoopEnd); const trialsLoopScheduler = new Scheduler(psychoJS); flowScheduler.add(trialsLoopBegin(trialsLoopScheduler)); flowScheduler.add(trialsLoopScheduler); flowScheduler.add(trialsLoopEnd); flowScheduler.add(ByeByeRoutineBegin()); flowScheduler.add(ByeByeRoutineEachFrame()); flowScheduler.add(ByeByeRoutineEnd()); flowScheduler.add(quitPsychoJS, '', true); // quit if user presses Cancel in dialog box: dialogCancelScheduler.add(quitPsychoJS, '', false); psychoJS.start({ expName: expName, expInfo: expInfo, resources: [ {'name': 'Instructions/Slide10.JPG', 'path': 'Instructions/Slide10.JPG'}, {'name': 'Instructions/Slide8.JPG', 'path': 'Instructions/Slide8.JPG'}, {'name': 'Instructions/Slide2.JPG', 'path': 'Instructions/Slide2.JPG'}, {'name': 'Instructions/Slide13.JPG', 'path': 'Instructions/Slide13.JPG'}, {'name': 'Instructions/Slide7.JPG', 'path': 'Instructions/Slide7.JPG'}, {'name': 'Instructions/Slide3.JPG', 'path': 'Instructions/Slide3.JPG'}, {'name': 'Instructions/Slide1.JPG', 'path': 'Instructions/Slide1.JPG'}, {'name': 'Instructions/Slide4.JPG', 'path': 'Instructions/Slide4.JPG'}, {'name': 'Instructions/Slide11.JPG', 'path': 'Instructions/Slide11.JPG'}, {'name': 'Instructions/Slide5.JPG', 'path': 'Instructions/Slide5.JPG'}, {'name': 'Instructions/Slide12.JPG', 'path': 'Instructions/Slide12.JPG'}, {'name': 'Instructions/Slide9.JPG', 'path': 'Instructions/Slide9.JPG'}, {'name': 'Instructions/Slide6.JPG', 'path': 'Instructions/Slide6.JPG'}, {'name': 'Instructions/Slide14.JPG', 'path': 'Instructions/Slide14.JPG'} ] }); psychoJS.experimentLogger.setLevel(core.Logger.ServerLevel.EXP); var currentLoop; var frameDur; async function updateInfo() { currentLoop = psychoJS.experiment; // right now there are no loops expInfo['date'] = util.MonotonicClock.getDateStr(); // add a simple timestamp expInfo['expName'] = expName; expInfo['psychopyVersion'] = '2022.2.0'; expInfo['OS'] = window.navigator.platform; psychoJS.experiment.dataFileName = (("." + "/") + `data/${expInfo["participant"]}_${expName}_${expInfo["date"]}`); // store frame rate of monitor if we can measure it successfully expInfo['frameRate'] = psychoJS.window.getActualFrameRate(); if (typeof expInfo['frameRate'] !== 'undefined') frameDur = 1.0 / Math.round(expInfo['frameRate']); else frameDur = 1.0 / 60.0; // couldn't get a reliable measure so guess // add info from the URL: util.addInfoFromUrl(expInfo); psychoJS.setRedirectUrls('https://docs.google.com/forms/d/e/1FAIpQLSfAlCul5jYBqk4v9qshnfPq-6QiziEsC6daEuxpY43A7_ZcFQ/viewform?usp=sf_link', ''); return Scheduler.Event.NEXT; } var instructClock; var instructionImage; var key_resp_6; var slideN; var maxslideN; var minslideN; var trialClock; var image; var key_resp; var text; var numimg; var letter1; var letter2; var letter3; var letter4; var imagearray; var distortion; var stims; var repeats; var ISI; var blankClock; var text_2; var BreakClock; var key_resp_5; var text_4; var ByeByeClock; var text_3; var key_resp_4; var globalClock; var routineTimer; async function experimentInit() { // Initialize components for Routine "instruct" instructClock = new util.Clock(); instructionImage = new visual.ImageStim({ win : psychoJS.window, name : 'instructionImage', units : 'pix', image : undefined, mask : undefined, ori : 0.0, pos : [0, 0], size : [1600, 1067], color : new util.Color([1,1,1]), opacity : undefined, flipHoriz : false, flipVert : false, texRes : 128.0, interpolate : true, depth : 0.0 }); key_resp_6 = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true}); // Run 'Begin Experiment' code from code_2 slideN = 1; maxslideN = 14; minslideN = 1; // Initialize components for Routine "trial" trialClock = new util.Clock(); image = new visual.ImageStim({ win : psychoJS.window, name : 'image', units : 'pix', image : undefined, mask : undefined, ori : 0.0, pos : [0, 0], size : [1600, 1067], color : new util.Color([1,1,1]), opacity : undefined, flipHoriz : false, flipVert : false, texRes : 128.0, interpolate : true, depth : 0.0 }); key_resp = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true}); text = new visual.TextStim({ win: psychoJS.window, name: 'text', text: '1: Bad 2: Poor 3: Fair 4: Good 5: Excellent', font: 'Open Sans', units: undefined, pos: [0, (- 0.46)], height: 0.04, wrapWidth: undefined, ori: 0.0, languageStyle: 'LTR', color: new util.Color('white'), opacity: undefined, depth: -2.0 }); // Run 'Begin Experiment' code from code_3 // function for shuffling function shuffle(array) { var copy = [], n = array.length, i; // While there remain elements to shuffle… while (n) { // Pick a remaining element… i = Math.floor(Math.random() * array.length); // If not already shuffled, move it to the new array. if (i in array) { copy.push(array[i]); delete array[i]; n--; } } return copy; } // function for generating a sequence function range(start, end) { return Array(end - start + 1).fill().map((_, idx) => start + idx) } numimg = 32; letter1 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter2 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter3 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter4 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter1 = shuffle(letter1); letter2 = shuffle(letter2); letter3 = shuffle(letter3); letter4 = shuffle(letter4); // generate image array imagearray = range(1, numimg) imagearray = shuffle(imagearray); distortion = letter1.concat(letter2).concat(letter3).concat(letter4) // merge both arrays element by element to get the final stim array stims = [imagearray , distortion ].reduce((a, b) => a.map((v, i) => v + b[i])) // shuffle stims = shuffle(stims) // function for shuffling function shuffle(array) { var copy = [], n = array.length, i; // While there remain elements to shuffle… while (n) { // Pick a remaining element… i = Math.floor(Math.random() * array.length); // If not already shuffled, move it to the new array. if (i in array) { copy.push(array[i]); delete array[i]; n--; } } return copy; } // function for generating a sequence function range(start, end) { return Array(end - start + 1).fill().map((_, idx) => start + idx) } numimg = 192; repeats = 8 letter1 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter2 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter3 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter4 = new Array(numimg / 16).fill([".jpg", "_06_03.jpg", "_07_03.jpg", "_08_03.jpg"]).flat(); letter1 = shuffle(letter1); letter2 = shuffle(letter2); letter3 = shuffle(letter3); letter4 = shuffle(letter4); // generate image array imagearray = range(1, numimg) imagearray = shuffle(imagearray); distortion = letter1.concat(letter2).concat(letter3).concat(letter4) // merge both arrays element by element to get the final stim array stims = [imagearray , distortion ].reduce((a, b) => a.map((v, i) => v + b[i])) // shuffle stims = shuffle(stims) // Add elements to test correlation stims = stims.concat(stims.slice(0, repeats)) stims = shuffle(stims) ISI = new core.MinimalStim({ name: "ISI", win: psychoJS.window, autoDraw: false, autoLog: true, }); // Initialize components for Routine "blank" blankClock = new util.Clock(); text_2 = new visual.TextStim({ win: psychoJS.window, name: 'text_2', text: '', font: 'Open Sans', units: undefined, pos: [0, 0], height: 0.1, wrapWidth: undefined, ori: 0.0, languageStyle: 'LTR', color: new util.Color('white'), opacity: undefined, depth: 0.0 }); // Initialize components for Routine "Break" BreakClock = new util.Clock(); key_resp_5 = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true}); text_4 = new visual.TextStim({ win: psychoJS.window, name: 'text_4', text: 'Break. Rest your eyes, if necessary.\n\nPress space to continue.', font: 'Open Sans', units: undefined, pos: [0, 0], height: 0.05, wrapWidth: undefined, ori: 0.0, languageStyle: 'LTR', color: new util.Color('white'), opacity: undefined, depth: -1.0 }); // Initialize components for Routine "ByeBye" ByeByeClock = new util.Clock(); text_3 = new visual.TextStim({ win: psychoJS.window, name: 'text_3', text: 'Thank you for participating.\nPress space and wait for a confirmation that all is saved correctly.\n\nA survey should open briefly. If not, please find the link in the prolific description.\n\nAfter the survey, you will receive your completion code.', font: 'Open Sans', units: undefined, pos: [0, 0], height: 0.05, wrapWidth: undefined, ori: 0.0, languageStyle: 'LTR', color: new util.Color('white'), opacity: undefined, depth: 0.0 }); key_resp_4 = new core.Keyboard({psychoJS: psychoJS, clock: new util.Clock(), waitForStart: true}); // Create some handy timers globalClock = new util.Clock(); // to track the time since experiment started routineTimer = new util.CountdownTimer(); // to track time remaining of each (non-slip) routine return Scheduler.Event.NEXT; } var trials_2; function trials_2LoopBegin(trials_2LoopScheduler, snapshot) { return async function() { TrialHandler.fromSnapshot(snapshot); // update internal variables (.thisN etc) of the loop // set up handler to look after randomisation of conditions etc trials_2 = new TrialHandler({ psychoJS: psychoJS, nReps: 500, method: TrialHandler.Method.RANDOM, extraInfo: expInfo, originPath: undefined, trialList: undefined, seed: undefined, name: 'trials_2' }); psychoJS.experiment.addLoop(trials_2); // add the loop to the experiment currentLoop = trials_2; // we're now the current loop // Schedule all the trials in the trialList: for (const thisTrial_2 of trials_2) { snapshot = trials_2.getSnapshot(); trials_2LoopScheduler.add(importConditions(snapshot)); trials_2LoopScheduler.add(instructRoutineBegin(snapshot)); trials_2LoopScheduler.add(instructRoutineEachFrame()); trials_2LoopScheduler.add(instructRoutineEnd(snapshot)); trials_2LoopScheduler.add(trials_2LoopEndIteration(trials_2LoopScheduler, snapshot)); } return Scheduler.Event.NEXT; } } async function trials_2LoopEnd() { // terminate loop psychoJS.experiment.removeLoop(trials_2); // update the current loop from the ExperimentHandler if (psychoJS.experiment._unfinishedLoops.length>0) currentLoop = psychoJS.experiment._unfinishedLoops.at(-1); else currentLoop = psychoJS.experiment; // so we use addData from the experiment return Scheduler.Event.NEXT; } function trials_2LoopEndIteration(scheduler, snapshot) { // ------Prepare for next entry------ return async function () { if (typeof snapshot !== 'undefined') { // ------Check if user ended loop early------ if (snapshot.finished) { // Check for and save orphaned data if (psychoJS.experiment.isEntryEmpty()) { psychoJS.experiment.nextEntry(snapshot); } scheduler.stop(); } else { psychoJS.experiment.nextEntry(snapshot); } return Scheduler.Event.NEXT; } }; } var trials; function trialsLoopBegin(trialsLoopScheduler, snapshot) { return async function() { TrialHandler.fromSnapshot(snapshot); // update internal variables (.thisN etc) of the loop // set up handler to look after randomisation of conditions etc trials = new TrialHandler({ psychoJS: psychoJS, nReps: 200, method: TrialHandler.Method.RANDOM, extraInfo: expInfo, originPath: undefined, trialList: undefined, seed: undefined, name: 'trials' }); psychoJS.experiment.addLoop(trials); // add the loop to the experiment currentLoop = trials; // we're now the current loop // Schedule all the trials in the trialList: for (const thisTrial of trials) { snapshot = trials.getSnapshot(); trialsLoopScheduler.add(importConditions(snapshot)); trialsLoopScheduler.add(trialRoutineBegin(snapshot)); trialsLoopScheduler.add(trialRoutineEachFrame()); trialsLoopScheduler.add(trialRoutineEnd(snapshot)); trialsLoopScheduler.add(blankRoutineBegin(snapshot)); trialsLoopScheduler.add(blankRoutineEachFrame()); trialsLoopScheduler.add(blankRoutineEnd(snapshot)); trialsLoopScheduler.add(BreakRoutineBegin(snapshot)); trialsLoopScheduler.add(BreakRoutineEachFrame()); trialsLoopScheduler.add(BreakRoutineEnd(snapshot)); trialsLoopScheduler.add(trialsLoopEndIteration(trialsLoopScheduler, snapshot)); } return Scheduler.Event.NEXT; } } async function trialsLoopEnd() { // terminate loop psychoJS.experiment.removeLoop(trials); // update the current loop from the ExperimentHandler if (psychoJS.experiment._unfinishedLoops.length>0) currentLoop = psychoJS.experiment._unfinishedLoops.at(-1); else currentLoop = psychoJS.experiment; // so we use addData from the experiment return Scheduler.Event.NEXT; } function trialsLoopEndIteration(scheduler, snapshot) { // ------Prepare for next entry------ return async function () { if (typeof snapshot !== 'undefined') { // ------Check if user ended loop early------ if (snapshot.finished) { // Check for and save orphaned data if (psychoJS.experiment.isEntryEmpty()) { psychoJS.experiment.nextEntry(snapshot); } scheduler.stop(); } else { psychoJS.experiment.nextEntry(snapshot); } return Scheduler.Event.NEXT; } }; } var t; var frameN; var continueRoutine; var _key_resp_6_allKeys; var instructComponents; function instructRoutineBegin(snapshot) { return async function () { TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date //--- Prepare to start Routine 'instruct' --- t = 0; instructClock.reset(); // clock frameN = -1; continueRoutine = true; // until we're told otherwise // update component parameters for each repeat instructionImage.setImage((("Instructions/Slide" + slideN.toString()) + ".JPG")); key_resp_6.keys = undefined; key_resp_6.rt = undefined; _key_resp_6_allKeys = []; // keep track of which components have finished instructComponents = []; instructComponents.push(instructionImage); instructComponents.push(key_resp_6); for (const thisComponent of instructComponents) if ('status' in thisComponent) thisComponent.status = PsychoJS.Status.NOT_STARTED; return Scheduler.Event.NEXT; } } function instructRoutineEachFrame() { return async function () { //--- Loop for each frame of Routine 'instruct' --- // get current time t = instructClock.getTime(); frameN = frameN + 1;// number of completed frames (so 0 is the first frame) // update/draw components on each frame // *instructionImage* updates if (t >= 0.0 && instructionImage.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later instructionImage.tStart = t; // (not accounting for frame time here) instructionImage.frameNStart = frameN; // exact frame index instructionImage.setAutoDraw(true); } // *key_resp_6* updates if (t >= 0.0 && key_resp_6.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later key_resp_6.tStart = t; // (not accounting for frame time here) key_resp_6.frameNStart = frameN; // exact frame index // keyboard checking is just starting psychoJS.window.callOnFlip(function() { key_resp_6.clock.reset(); }); // t=0 on next screen flip psychoJS.window.callOnFlip(function() { key_resp_6.start(); }); // start on screen flip psychoJS.window.callOnFlip(function() { key_resp_6.clearEvents(); }); } if (key_resp_6.status === PsychoJS.Status.STARTED) { let theseKeys = key_resp_6.getKeys({keyList: ['left', 'right', 'space'], waitRelease: false}); _key_resp_6_allKeys = _key_resp_6_allKeys.concat(theseKeys); if (_key_resp_6_allKeys.length > 0) { key_resp_6.keys = _key_resp_6_allKeys[_key_resp_6_allKeys.length - 1].name; // just the last key pressed key_resp_6.rt = _key_resp_6_allKeys[_key_resp_6_allKeys.length - 1].rt; // a response ends the routine continueRoutine = false; } } // check for quit (typically the Esc key) if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) { return quitPsychoJS('The [Escape] key was pressed. Goodbye!', false); } // check if the Routine should terminate if (!continueRoutine) { // a component has requested a forced-end of Routine return Scheduler.Event.NEXT; } continueRoutine = false; // reverts to True if at least one component still running for (const thisComponent of instructComponents) if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) { continueRoutine = true; break; } // refresh the screen if continuing if (continueRoutine) { return Scheduler.Event.FLIP_REPEAT; } else { return Scheduler.Event.NEXT; } }; } function instructRoutineEnd(snapshot) { return async function () { //--- Ending Routine 'instruct' --- for (const thisComponent of instructComponents) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } } key_resp_6.stop(); // Run 'End Routine' code from code_2 if ((key_resp_6.keys === "left")) { slideN -= 1; } else { if ((key_resp_6.keys === "right")) { slideN += 1; } else { if ((key_resp_6.keys === "space")) { if ((slideN === maxslideN)) { trials_2.finished = true; } } } } if ((slideN > maxslideN)) { slideN = maxslideN; } if ((slideN < minslideN)) { slideN = minslideN; } // the Routine "instruct" was not non-slip safe, so reset the non-slip timer routineTimer.reset(); // Routines running outside a loop should always advance the datafile row if (currentLoop === psychoJS.experiment) { psychoJS.experiment.nextEntry(snapshot); } return Scheduler.Event.NEXT; } } var _key_resp_allKeys; var trialComponents; function trialRoutineBegin(snapshot) { return async function () { TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date //--- Prepare to start Routine 'trial' --- t = 0; trialClock.reset(); // clock frameN = -1; continueRoutine = true; // until we're told otherwise // update component parameters for each repeat key_resp.keys = undefined; key_resp.rt = undefined; _key_resp_allKeys = []; // keep track of which components have finished trialComponents = []; trialComponents.push(image); trialComponents.push(key_resp); trialComponents.push(text); trialComponents.push(ISI); for (const thisComponent of trialComponents) if ('status' in thisComponent) thisComponent.status = PsychoJS.Status.NOT_STARTED; return Scheduler.Event.NEXT; } } var frameRemains; function trialRoutineEachFrame() { return async function () { //--- Loop for each frame of Routine 'trial' --- // get current time t = trialClock.getTime(); frameN = frameN + 1;// number of completed frames (so 0 is the first frame) // update/draw components on each frame // *image* updates if (t >= 0.2 && image.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later image.tStart = t; // (not accounting for frame time here) image.frameNStart = frameN; // exact frame index image.setAutoDraw(true); } // *key_resp* updates if (t >= 0.2 && key_resp.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later key_resp.tStart = t; // (not accounting for frame time here) key_resp.frameNStart = frameN; // exact frame index // keyboard checking is just starting psychoJS.window.callOnFlip(function() { key_resp.clock.reset(); }); // t=0 on next screen flip psychoJS.window.callOnFlip(function() { key_resp.start(); }); // start on screen flip psychoJS.window.callOnFlip(function() { key_resp.clearEvents(); }); } if (key_resp.status === PsychoJS.Status.STARTED) { let theseKeys = key_resp.getKeys({keyList: ['1', '2', '3', '4', '5'], waitRelease: false}); _key_resp_allKeys = _key_resp_allKeys.concat(theseKeys); if (_key_resp_allKeys.length > 0) { key_resp.keys = _key_resp_allKeys[_key_resp_allKeys.length - 1].name; // just the last key pressed key_resp.rt = _key_resp_allKeys[_key_resp_allKeys.length - 1].rt; // a response ends the routine continueRoutine = false; } } // *text* updates if (t >= 0.2 && text.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later text.tStart = t; // (not accounting for frame time here) text.frameNStart = frameN; // exact frame index text.setAutoDraw(true); } if (t >= 0 && ISI.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later ISI.tStart = t; // (not accounting for frame time here) ISI.frameNStart = frameN; // exact frame index // Updating other components during *ISI* console.log('register and start downloading resources specified by component image'); await psychoJS.serverManager.prepareResources(("images/" + stims[trials.thisN].toString())); image.status = PsychoJS.Status.STARTED; image.setImage(("images/" + stims[trials.thisN].toString())) // Component updates done } frameRemains = 0 + 0.2 - psychoJS.window.monitorFramePeriod * 0.75; // most of one frame period left if (ISI.status === PsychoJS.Status.STARTED && t >= frameRemains) { if (psychoJS.serverManager.getResourceStatus(("images/" + stims[trials.thisN].toString())) === core.ServerManager.ResourceStatus.DOWNLOADED) { console.log('finished downloading resources specified by component ISI'); } else { console.log('resource specified in ISI took longer than expected to download'); await waitForResources(resources = ("images/" + stims[trials.thisN].toString())) } } // check for quit (typically the Esc key) if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) { return quitPsychoJS('The [Escape] key was pressed. Goodbye!', false); } // check if the Routine should terminate if (!continueRoutine) { // a component has requested a forced-end of Routine return Scheduler.Event.NEXT; } continueRoutine = false; // reverts to True if at least one component still running for (const thisComponent of trialComponents) if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) { continueRoutine = true; break; } // refresh the screen if continuing if (continueRoutine) { return Scheduler.Event.FLIP_REPEAT; } else { return Scheduler.Event.NEXT; } }; } function trialRoutineEnd(snapshot) { return async function () { //--- Ending Routine 'trial' --- for (const thisComponent of trialComponents) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } } // update the trial handler if (currentLoop instanceof MultiStairHandler) { currentLoop.addResponse(key_resp.corr, level); } psychoJS.experiment.addData('key_resp.keys', key_resp.keys); if (typeof key_resp.keys !== 'undefined') { // we had a response psychoJS.experiment.addData('key_resp.rt', key_resp.rt); routineTimer.reset(); } key_resp.stop(); // Run 'End Routine' code from code_save psychoJS.experiment.addData("imageshown", stims[trials.thisN].toString()); // the Routine "trial" was not non-slip safe, so reset the non-slip timer routineTimer.reset(); // Routines running outside a loop should always advance the datafile row if (currentLoop === psychoJS.experiment) { psychoJS.experiment.nextEntry(snapshot); } return Scheduler.Event.NEXT; } } var blankComponents; function blankRoutineBegin(snapshot) { return async function () { TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date //--- Prepare to start Routine 'blank' --- t = 0; blankClock.reset(); // clock frameN = -1; continueRoutine = true; // until we're told otherwise routineTimer.add(0.200000); // update component parameters for each repeat // keep track of which components have finished blankComponents = []; blankComponents.push(text_2); for (const thisComponent of blankComponents) if ('status' in thisComponent) thisComponent.status = PsychoJS.Status.NOT_STARTED; return Scheduler.Event.NEXT; } } function blankRoutineEachFrame() { return async function () { //--- Loop for each frame of Routine 'blank' --- // get current time t = blankClock.getTime(); frameN = frameN + 1;// number of completed frames (so 0 is the first frame) // update/draw components on each frame // *text_2* updates if (t >= 0.0 && text_2.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later text_2.tStart = t; // (not accounting for frame time here) text_2.frameNStart = frameN; // exact frame index text_2.setAutoDraw(true); } frameRemains = 0.0 + 0.2 - psychoJS.window.monitorFramePeriod * 0.75; // most of one frame period left if (text_2.status === PsychoJS.Status.STARTED && t >= frameRemains) { text_2.setAutoDraw(false); } // check for quit (typically the Esc key) if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) { return quitPsychoJS('The [Escape] key was pressed. Goodbye!', false); } // check if the Routine should terminate if (!continueRoutine) { // a component has requested a forced-end of Routine return Scheduler.Event.NEXT; } continueRoutine = false; // reverts to True if at least one component still running for (const thisComponent of blankComponents) if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) { continueRoutine = true; break; } // refresh the screen if continuing if (continueRoutine && routineTimer.getTime() > 0) { return Scheduler.Event.FLIP_REPEAT; } else { return Scheduler.Event.NEXT; } }; } function blankRoutineEnd(snapshot) { return async function () { //--- Ending Routine 'blank' --- for (const thisComponent of blankComponents) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } } // Routines running outside a loop should always advance the datafile row if (currentLoop === psychoJS.experiment) { psychoJS.experiment.nextEntry(snapshot); } return Scheduler.Event.NEXT; } } var _key_resp_5_allKeys; var BreakComponents; function BreakRoutineBegin(snapshot) { return async function () { TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date //--- Prepare to start Routine 'Break' --- t = 0; BreakClock.reset(); // clock frameN = -1; continueRoutine = true; // until we're told otherwise // update component parameters for each repeat key_resp_5.keys = undefined; key_resp_5.rt = undefined; _key_resp_5_allKeys = []; // Run 'Begin Routine' code from code if ((((trials.thisRepN % 24) !== 0) || (trials.thisRepN === 0))) { continueRoutine = false; } // keep track of which components have finished BreakComponents = []; BreakComponents.push(key_resp_5); BreakComponents.push(text_4); for (const thisComponent of BreakComponents) if ('status' in thisComponent) thisComponent.status = PsychoJS.Status.NOT_STARTED; return Scheduler.Event.NEXT; } } function BreakRoutineEachFrame() { return async function () { //--- Loop for each frame of Routine 'Break' --- // get current time t = BreakClock.getTime(); frameN = frameN + 1;// number of completed frames (so 0 is the first frame) // update/draw components on each frame // *key_resp_5* updates if (t >= 0.0 && key_resp_5.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later key_resp_5.tStart = t; // (not accounting for frame time here) key_resp_5.frameNStart = frameN; // exact frame index // keyboard checking is just starting psychoJS.window.callOnFlip(function() { key_resp_5.clock.reset(); }); // t=0 on next screen flip psychoJS.window.callOnFlip(function() { key_resp_5.start(); }); // start on screen flip psychoJS.window.callOnFlip(function() { key_resp_5.clearEvents(); }); } if (key_resp_5.status === PsychoJS.Status.STARTED) { let theseKeys = key_resp_5.getKeys({keyList: ['space'], waitRelease: false}); _key_resp_5_allKeys = _key_resp_5_allKeys.concat(theseKeys); if (_key_resp_5_allKeys.length > 0) { key_resp_5.keys = _key_resp_5_allKeys[_key_resp_5_allKeys.length - 1].name; // just the last key pressed key_resp_5.rt = _key_resp_5_allKeys[_key_resp_5_allKeys.length - 1].rt; // a response ends the routine continueRoutine = false; } } // *text_4* updates if (t >= 0.0 && text_4.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later text_4.tStart = t; // (not accounting for frame time here) text_4.frameNStart = frameN; // exact frame index text_4.setAutoDraw(true); } // check for quit (typically the Esc key) if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) { return quitPsychoJS('The [Escape] key was pressed. Goodbye!', false); } // check if the Routine should terminate if (!continueRoutine) { // a component has requested a forced-end of Routine return Scheduler.Event.NEXT; } continueRoutine = false; // reverts to True if at least one component still running for (const thisComponent of BreakComponents) if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) { continueRoutine = true; break; } // refresh the screen if continuing if (continueRoutine) { return Scheduler.Event.FLIP_REPEAT; } else { return Scheduler.Event.NEXT; } }; } function BreakRoutineEnd(snapshot) { return async function () { //--- Ending Routine 'Break' --- for (const thisComponent of BreakComponents) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } } key_resp_5.stop(); // the Routine "Break" was not non-slip safe, so reset the non-slip timer routineTimer.reset(); // Routines running outside a loop should always advance the datafile row if (currentLoop === psychoJS.experiment) { psychoJS.experiment.nextEntry(snapshot); } return Scheduler.Event.NEXT; } } var _key_resp_4_allKeys; var ByeByeComponents; function ByeByeRoutineBegin(snapshot) { return async function () { TrialHandler.fromSnapshot(snapshot); // ensure that .thisN vals are up to date //--- Prepare to start Routine 'ByeBye' --- t = 0; ByeByeClock.reset(); // clock frameN = -1; continueRoutine = true; // until we're told otherwise // update component parameters for each repeat key_resp_4.keys = undefined; key_resp_4.rt = undefined; _key_resp_4_allKeys = []; // keep track of which components have finished ByeByeComponents = []; ByeByeComponents.push(text_3); ByeByeComponents.push(key_resp_4); for (const thisComponent of ByeByeComponents) if ('status' in thisComponent) thisComponent.status = PsychoJS.Status.NOT_STARTED; return Scheduler.Event.NEXT; } } function ByeByeRoutineEachFrame() { return async function () { //--- Loop for each frame of Routine 'ByeBye' --- // get current time t = ByeByeClock.getTime(); frameN = frameN + 1;// number of completed frames (so 0 is the first frame) // update/draw components on each frame // *text_3* updates if (t >= 0.0 && text_3.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later text_3.tStart = t; // (not accounting for frame time here) text_3.frameNStart = frameN; // exact frame index text_3.setAutoDraw(true); } // *key_resp_4* updates if (t >= 0.0 && key_resp_4.status === PsychoJS.Status.NOT_STARTED) { // keep track of start time/frame for later key_resp_4.tStart = t; // (not accounting for frame time here) key_resp_4.frameNStart = frameN; // exact frame index // keyboard checking is just starting psychoJS.window.callOnFlip(function() { key_resp_4.clock.reset(); }); // t=0 on next screen flip psychoJS.window.callOnFlip(function() { key_resp_4.start(); }); // start on screen flip psychoJS.window.callOnFlip(function() { key_resp_4.clearEvents(); }); } if (key_resp_4.status === PsychoJS.Status.STARTED) { let theseKeys = key_resp_4.getKeys({keyList: ['space'], waitRelease: false}); _key_resp_4_allKeys = _key_resp_4_allKeys.concat(theseKeys); if (_key_resp_4_allKeys.length > 0) { key_resp_4.keys = _key_resp_4_allKeys[_key_resp_4_allKeys.length - 1].name; // just the last key pressed key_resp_4.rt = _key_resp_4_allKeys[_key_resp_4_allKeys.length - 1].rt; // a response ends the routine continueRoutine = false; } } // check for quit (typically the Esc key) if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) { return quitPsychoJS('The [Escape] key was pressed. Goodbye!', false); } // check if the Routine should terminate if (!continueRoutine) { // a component has requested a forced-end of Routine return Scheduler.Event.NEXT; } continueRoutine = false; // reverts to True if at least one component still running for (const thisComponent of ByeByeComponents) if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) { continueRoutine = true; break; } // refresh the screen if continuing if (continueRoutine) { return Scheduler.Event.FLIP_REPEAT; } else { return Scheduler.Event.NEXT; } }; } function ByeByeRoutineEnd(snapshot) { return async function () { //--- Ending Routine 'ByeBye' --- for (const thisComponent of ByeByeComponents) { if (typeof thisComponent.setAutoDraw === 'function') { thisComponent.setAutoDraw(false); } } key_resp_4.stop(); // the Routine "ByeBye" was not non-slip safe, so reset the non-slip timer routineTimer.reset(); // Routines running outside a loop should always advance the datafile row if (currentLoop === psychoJS.experiment) { psychoJS.experiment.nextEntry(snapshot); } return Scheduler.Event.NEXT; } } function importConditions(currentLoop) { return async function () { psychoJS.importAttributes(currentLoop.getCurrentTrial()); return Scheduler.Event.NEXT; }; } async function quitPsychoJS(message, isCompleted) { // Check for and save orphaned data if (psychoJS.experiment.isEntryEmpty()) { psychoJS.experiment.nextEntry(); } psychoJS.window.close(); psychoJS.quit({message: message, isCompleted: isCompleted}); return Scheduler.Event.QUIT; }