jspsych 8.1.0 → 8.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,70 +51,7 @@ var jsPsychModule = (function (exports) {
51
51
 
52
52
  var autoBind$1 = /*@__PURE__*/getDefaultExportFromCjs(autoBind);
53
53
 
54
- var _package = {
55
- name: "jspsych",
56
- version: "8.1.0",
57
- description: "Behavioral experiments in a browser",
58
- type: "module",
59
- main: "dist/index.cjs",
60
- exports: {
61
- ".": {
62
- import: "./dist/index.js",
63
- require: "./dist/index.cjs"
64
- },
65
- "./css/*": "./css/*"
66
- },
67
- typings: "dist/index.d.ts",
68
- unpkg: "dist/index.browser.min.js",
69
- files: [
70
- "src",
71
- "dist",
72
- "css"
73
- ],
74
- source: "src/index.ts",
75
- scripts: {
76
- test: "jest",
77
- "test:watch": "npm test -- --watch",
78
- tsc: "tsc",
79
- "build:js": "rollup --config",
80
- "build:styles": "webpack-cli",
81
- build: "run-p build:js build:styles",
82
- "build:watch": 'run-p "build:js -- --watch" "build:styles watch"',
83
- prepack: "cp ../../README.md ."
84
- },
85
- repository: {
86
- type: "git",
87
- url: "git+https://github.com/jspsych/jsPsych.git",
88
- directory: "packages/jspsych"
89
- },
90
- author: "Josh de Leeuw",
91
- license: "MIT",
92
- bugs: {
93
- url: "https://github.com/jspsych/jsPsych/issues"
94
- },
95
- homepage: "https://www.jspsych.org",
96
- dependencies: {
97
- "auto-bind": "^4.0.0",
98
- "random-words": "^1.1.1",
99
- seedrandom: "^3.0.5",
100
- "type-fest": "^2.9.0"
101
- },
102
- devDependencies: {
103
- "@fontsource/open-sans": "4.5.3",
104
- "@jspsych/config": "^3.0.1",
105
- "@types/dom-mediacapture-record": "^1.0.11",
106
- "base64-inline-loader": "^2.0.1",
107
- "css-loader": "^6.6.0",
108
- "mini-css-extract-plugin": "^2.5.3",
109
- "npm-run-all": "^4.1.5",
110
- "replace-in-file-webpack-plugin": "^1.0.6",
111
- sass: "^1.43.5",
112
- "sass-loader": "^12.4.0",
113
- webpack: "^5.76.0",
114
- "webpack-cli": "^4.9.2",
115
- "webpack-remove-empty-scripts": "^0.7.2"
116
- }
117
- };
54
+ var version = "8.2.1";
118
55
 
119
56
  class ExtensionManager {
120
57
  constructor(dependencies, extensionsConfiguration) {
@@ -130,7 +67,6 @@ var jsPsychModule = (function (exports) {
130
67
  static getExtensionNameByClass(extensionClass) {
131
68
  return extensionClass["info"].name;
132
69
  }
133
- extensions;
134
70
  getExtensionInstanceByClass(extensionClass) {
135
71
  return this.extensions[ExtensionManager.getExtensionNameByClass(extensionClass)];
136
72
  }
@@ -187,8 +123,7 @@ var jsPsychModule = (function (exports) {
187
123
  return [...new Set(arr)];
188
124
  }
189
125
  function deepCopy(obj) {
190
- if (!obj)
191
- return obj;
126
+ if (!obj) return obj;
192
127
  let out;
193
128
  if (Array.isArray(obj)) {
194
129
  out = [];
@@ -235,9 +170,9 @@ var jsPsychModule = (function (exports) {
235
170
 
236
171
  var utils = /*#__PURE__*/Object.freeze({
237
172
  __proto__: null,
238
- unique: unique,
239
173
  deepCopy: deepCopy,
240
- deepMerge: deepMerge
174
+ deepMerge: deepMerge,
175
+ unique: unique
241
176
  });
242
177
 
243
178
  class DataColumn {
@@ -383,16 +318,13 @@ var jsPsychModule = (function (exports) {
383
318
  const b = {};
384
319
  for (let i = 0; i < a.length; ++i) {
385
320
  const p = a[i].split("=", 2);
386
- if (p.length == 1)
387
- b[p[0]] = "";
388
- else
389
- b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
321
+ if (p.length == 1) b[p[0]] = "";
322
+ else b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
390
323
  }
391
324
  return b;
392
325
  }
393
326
 
394
327
  class DataCollection {
395
- trials;
396
328
  constructor(data = []) {
397
329
  this.trials = data;
398
330
  }
@@ -411,26 +343,44 @@ var jsPsychModule = (function (exports) {
411
343
  return new DataCollection([this.trials[this.trials.length - 1]]);
412
344
  }
413
345
  }
346
+ /**
347
+ * Queries the first n elements in a collection of trials.
348
+ *
349
+ * @param n A positive integer of elements to return. A value of
350
+ * n that is less than 1 will throw an error.
351
+ *
352
+ * @return First n objects of a collection of trials. If fewer than
353
+ * n trials are available, the trials.length elements will
354
+ * be returned.
355
+ *
356
+ */
414
357
  first(n = 1) {
415
358
  if (n < 1) {
416
359
  throw `You must query with a positive nonzero integer. Please use a
417
360
  different value for n.`;
418
361
  }
419
- if (this.trials.length === 0)
420
- return new DataCollection();
421
- if (n > this.trials.length)
422
- n = this.trials.length;
362
+ if (this.trials.length === 0) return new DataCollection();
363
+ if (n > this.trials.length) n = this.trials.length;
423
364
  return new DataCollection(this.trials.slice(0, n));
424
365
  }
366
+ /**
367
+ * Queries the last n elements in a collection of trials.
368
+ *
369
+ * @param n A positive integer of elements to return. A value of
370
+ * n that is less than 1 will throw an error.
371
+ *
372
+ * @return Last n objects of a collection of trials. If fewer than
373
+ * n trials are available, the trials.length elements will
374
+ * be returned.
375
+ *
376
+ */
425
377
  last(n = 1) {
426
378
  if (n < 1) {
427
379
  throw `You must query with a positive nonzero integer. Please use a
428
380
  different value for n.`;
429
381
  }
430
- if (this.trials.length === 0)
431
- return new DataCollection();
432
- if (n > this.trials.length)
433
- n = this.trials.length;
382
+ if (this.trials.length === 0) return new DataCollection();
383
+ if (n > this.trials.length) n = this.trials.length;
434
384
  return new DataCollection(this.trials.slice(this.trials.length - n, this.trials.length));
435
385
  }
436
386
  values() {
@@ -550,13 +500,26 @@ var jsPsychModule = (function (exports) {
550
500
  class JsPsychData {
551
501
  constructor(dependencies) {
552
502
  this.dependencies = dependencies;
503
+ /** Data properties for all trials */
504
+ this.dataProperties = {};
505
+ this.interactionListeners = {
506
+ blur: () => {
507
+ this.addInteractionRecord("blur");
508
+ },
509
+ focus: () => {
510
+ this.addInteractionRecord("focus");
511
+ },
512
+ fullscreenchange: () => {
513
+ this.addInteractionRecord(
514
+ // @ts-expect-error
515
+ document.isFullScreen || // @ts-expect-error
516
+ document.webkitIsFullScreen || // @ts-expect-error
517
+ document.mozIsFullScreen || document.fullscreenElement ? "fullscreenenter" : "fullscreenexit"
518
+ );
519
+ }
520
+ };
553
521
  this.reset();
554
522
  }
555
- results;
556
- resultToTrialMap;
557
- interactionRecords;
558
- dataProperties = {};
559
- query_string;
560
523
  reset() {
561
524
  this.results = new DataCollection();
562
525
  this.resultToTrialMap = /* @__PURE__ */ new WeakMap();
@@ -615,19 +578,6 @@ var jsPsychModule = (function (exports) {
615
578
  this.interactionRecords.push(record);
616
579
  this.dependencies.onInteractionRecordAdded(record);
617
580
  }
618
- interactionListeners = {
619
- blur: () => {
620
- this.addInteractionRecord("blur");
621
- },
622
- focus: () => {
623
- this.addInteractionRecord("focus");
624
- },
625
- fullscreenchange: () => {
626
- this.addInteractionRecord(
627
- document.isFullScreen || document.webkitIsFullScreen || document.mozIsFullScreen || document.fullscreenElement ? "fullscreenenter" : "fullscreenexit"
628
- );
629
- }
630
- };
631
581
  createInteractionListeners() {
632
582
  window.addEventListener("blur", this.interactionListeners.blur);
633
583
  window.addEventListener("focus", this.interactionListeners.focus);
@@ -652,12 +602,16 @@ var jsPsychModule = (function (exports) {
652
602
  this.getRootElement = getRootElement;
653
603
  this.areResponsesCaseSensitive = areResponsesCaseSensitive;
654
604
  this.minimumValidRt = minimumValidRt;
605
+ this.listeners = /* @__PURE__ */ new Set();
606
+ this.heldKeys = /* @__PURE__ */ new Set();
607
+ this.areRootListenersRegistered = false;
655
608
  autoBind$1(this);
656
609
  this.registerRootListeners();
657
610
  }
658
- listeners = /* @__PURE__ */ new Set();
659
- heldKeys = /* @__PURE__ */ new Set();
660
- areRootListenersRegistered = false;
611
+ /**
612
+ * If not previously done and `this.getRootElement()` returns an element, adds the root key
613
+ * listeners to that element.
614
+ */
661
615
  registerRootListeners() {
662
616
  if (!this.areRootListenersRegistered) {
663
617
  const rootElement = this.getRootElement();
@@ -773,11 +727,6 @@ var jsPsychModule = (function (exports) {
773
727
  })(ParameterType || {});
774
728
 
775
729
  class AudioPlayer {
776
- audio;
777
- webAudioBuffer;
778
- audioContext;
779
- useWebAudio;
780
- src;
781
730
  constructor(src, options = { useWebAudio: false }) {
782
731
  this.src = src;
783
732
  this.useWebAudio = options.useWebAudio;
@@ -794,8 +743,7 @@ var jsPsychModule = (function (exports) {
794
743
  if (this.audio instanceof HTMLAudioElement) {
795
744
  this.audio.play();
796
745
  } else {
797
- if (!this.audio)
798
- this.audio = this.getAudioSourceNode(this.webAudioBuffer);
746
+ if (!this.audio) this.audio = this.getAudioSourceNode(this.webAudioBuffer);
799
747
  this.audio.start();
800
748
  }
801
749
  }
@@ -857,19 +805,28 @@ var jsPsychModule = (function (exports) {
857
805
  class MediaAPI {
858
806
  constructor(useWebaudio) {
859
807
  this.useWebaudio = useWebaudio;
808
+ // video //
809
+ this.video_buffers = {};
810
+ // audio //
811
+ this.context = null;
812
+ this.audio_buffers = [];
813
+ // preloading stimuli //
814
+ this.preload_requests = [];
815
+ this.img_cache = {};
816
+ this.preloadMap = /* @__PURE__ */ new Map();
817
+ this.microphone_recorder = null;
818
+ this.camera_stream = null;
819
+ this.camera_recorder = null;
860
820
  if (this.useWebaudio && typeof window !== "undefined" && typeof window.AudioContext !== "undefined") {
861
821
  this.context = new AudioContext();
862
822
  }
863
823
  }
864
- video_buffers = {};
865
824
  getVideoBuffer(videoID) {
866
825
  if (videoID.startsWith("blob:")) {
867
826
  this.video_buffers[videoID] = videoID;
868
827
  }
869
828
  return this.video_buffers[videoID];
870
829
  }
871
- context = null;
872
- audio_buffers = [];
873
830
  audioContext() {
874
831
  if (this.context && this.context.state !== "running") {
875
832
  this.context.resume();
@@ -888,8 +845,6 @@ var jsPsychModule = (function (exports) {
888
845
  return this.audio_buffers[audioID];
889
846
  }
890
847
  }
891
- preload_requests = [];
892
- img_cache = {};
893
848
  preloadAudio(files, callback_complete = () => {
894
849
  }, callback_load = (filepath) => {
895
850
  }, callback_error = (error) => {
@@ -994,7 +949,6 @@ var jsPsychModule = (function (exports) {
994
949
  this.preload_requests.push(request);
995
950
  }
996
951
  }
997
- preloadMap = /* @__PURE__ */ new Map();
998
952
  getAutoPreloadList(timeline_description) {
999
953
  const preloadPaths = Object.fromEntries(
1000
954
  preloadParameterTypes.map((type) => [type, /* @__PURE__ */ new Set()])
@@ -1054,7 +1008,6 @@ var jsPsychModule = (function (exports) {
1054
1008
  }
1055
1009
  this.preload_requests = [];
1056
1010
  }
1057
- microphone_recorder = null;
1058
1011
  initializeMicrophoneRecorder(stream) {
1059
1012
  const recorder = new MediaRecorder(stream);
1060
1013
  this.microphone_recorder = recorder;
@@ -1062,8 +1015,6 @@ var jsPsychModule = (function (exports) {
1062
1015
  getMicrophoneRecorder() {
1063
1016
  return this.microphone_recorder;
1064
1017
  }
1065
- camera_stream = null;
1066
- camera_recorder = null;
1067
1018
  initializeCameraRecorder(stream, opts) {
1068
1019
  this.camera_stream = stream;
1069
1020
  const recorder = new MediaRecorder(stream, opts);
@@ -1085,12 +1036,25 @@ var jsPsychModule = (function (exports) {
1085
1036
  dispatchEvent(event) {
1086
1037
  this.getDisplayContainerElement().dispatchEvent(event);
1087
1038
  }
1039
+ /**
1040
+ * Dispatches a `keydown` event for the specified key
1041
+ * @param key Character code (`.key` property) for the key to press.
1042
+ */
1088
1043
  keyDown(key) {
1089
1044
  this.dispatchEvent(new KeyboardEvent("keydown", { key }));
1090
1045
  }
1046
+ /**
1047
+ * Dispatches a `keyup` event for the specified key
1048
+ * @param key Character code (`.key` property) for the key to press.
1049
+ */
1091
1050
  keyUp(key) {
1092
1051
  this.dispatchEvent(new KeyboardEvent("keyup", { key }));
1093
1052
  }
1053
+ /**
1054
+ * Dispatches a `keydown` and `keyup` event in sequence to simulate pressing a key.
1055
+ * @param key Character code (`.key` property) for the key to press.
1056
+ * @param delay Length of time to wait (ms) before executing action
1057
+ */
1094
1058
  pressKey(key, delay = 0) {
1095
1059
  if (delay > 0) {
1096
1060
  this.setJsPsychTimeout(() => {
@@ -1102,6 +1066,11 @@ var jsPsychModule = (function (exports) {
1102
1066
  this.keyUp(key);
1103
1067
  }
1104
1068
  }
1069
+ /**
1070
+ * Dispatches `mousedown`, `mouseup`, and `click` events on the target element
1071
+ * @param target The element to click
1072
+ * @param delay Length of time to wait (ms) before executing action
1073
+ */
1105
1074
  clickTarget(target, delay = 0) {
1106
1075
  if (delay > 0) {
1107
1076
  this.setJsPsychTimeout(() => {
@@ -1115,6 +1084,12 @@ var jsPsychModule = (function (exports) {
1115
1084
  target.dispatchEvent(new MouseEvent("click", { bubbles: true }));
1116
1085
  }
1117
1086
  }
1087
+ /**
1088
+ * Sets the value of a target text input
1089
+ * @param target A text input element to fill in
1090
+ * @param text Text to input
1091
+ * @param delay Length of time to wait (ms) before executing action
1092
+ */
1118
1093
  fillTextInput(target, text, delay = 0) {
1119
1094
  if (delay > 0) {
1120
1095
  this.setJsPsychTimeout(() => {
@@ -1124,6 +1099,12 @@ var jsPsychModule = (function (exports) {
1124
1099
  target.value = text;
1125
1100
  }
1126
1101
  }
1102
+ /**
1103
+ * Picks a valid key from `choices`, taking into account jsPsych-specific
1104
+ * identifiers like "NO_KEYS" and "ALL_KEYS".
1105
+ * @param choices Which keys are valid.
1106
+ * @returns A key selected at random from the valid keys.
1107
+ */
1127
1108
  getValidKey(choices) {
1128
1109
  const possible_keys = [
1129
1110
  "a",
@@ -1214,39 +1195,1017 @@ var jsPsychModule = (function (exports) {
1214
1195
  }
1215
1196
  }
1216
1197
 
1217
- class TimeoutAPI {
1218
- timeout_handlers = [];
1219
- setTimeout(callback, delay) {
1220
- const handle = window.setTimeout(callback, delay);
1221
- this.timeout_handlers.push(handle);
1222
- return handle;
1223
- }
1224
- clearAllTimeouts() {
1225
- for (const handler of this.timeout_handlers) {
1226
- clearTimeout(handler);
1227
- }
1228
- this.timeout_handlers = [];
1229
- }
1230
- }
1198
+ class TimeoutAPI {
1199
+ constructor() {
1200
+ this.timeout_handlers = [];
1201
+ }
1202
+ /**
1203
+ * Calls a function after a specified delay, in milliseconds.
1204
+ * @param callback The function to call after the delay.
1205
+ * @param delay The number of milliseconds to wait before calling the function.
1206
+ * @returns A handle that can be used to clear the timeout with clearTimeout.
1207
+ */
1208
+ setTimeout(callback, delay) {
1209
+ const handle = window.setTimeout(callback, delay);
1210
+ this.timeout_handlers.push(handle);
1211
+ return handle;
1212
+ }
1213
+ /**
1214
+ * Clears all timeouts that have been created with setTimeout.
1215
+ */
1216
+ clearAllTimeouts() {
1217
+ for (const handler of this.timeout_handlers) {
1218
+ clearTimeout(handler);
1219
+ }
1220
+ this.timeout_handlers = [];
1221
+ }
1222
+ }
1223
+
1224
+ function createJointPluginAPIObject(jsPsych) {
1225
+ const settings = jsPsych.getInitSettings();
1226
+ const keyboardListenerAPI = new KeyboardListenerAPI(
1227
+ jsPsych.getDisplayContainerElement,
1228
+ settings.case_sensitive_responses,
1229
+ settings.minimum_valid_rt
1230
+ );
1231
+ const timeoutAPI = new TimeoutAPI();
1232
+ const mediaAPI = new MediaAPI(settings.use_webaudio);
1233
+ const simulationAPI = new SimulationAPI(
1234
+ jsPsych.getDisplayContainerElement,
1235
+ timeoutAPI.setTimeout.bind(timeoutAPI)
1236
+ );
1237
+ return Object.assign(
1238
+ {},
1239
+ ...[keyboardListenerAPI, timeoutAPI, mediaAPI, simulationAPI].map((object) => autoBind$1(object))
1240
+ );
1241
+ }
1242
+
1243
+ var alea$1 = {exports: {}};
1244
+
1245
+ alea$1.exports;
1246
+
1247
+ (function (module) {
1248
+ // A port of an algorithm by Johannes Baagøe <baagoe@baagoe.com>, 2010
1249
+ // http://baagoe.com/en/RandomMusings/javascript/
1250
+ // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
1251
+ // Original work is under MIT license -
1252
+
1253
+ // Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>
1254
+ //
1255
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1256
+ // of this software and associated documentation files (the "Software"), to deal
1257
+ // in the Software without restriction, including without limitation the rights
1258
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1259
+ // copies of the Software, and to permit persons to whom the Software is
1260
+ // furnished to do so, subject to the following conditions:
1261
+ //
1262
+ // The above copyright notice and this permission notice shall be included in
1263
+ // all copies or substantial portions of the Software.
1264
+ //
1265
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1266
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1267
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1268
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1269
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1270
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1271
+ // THE SOFTWARE.
1272
+
1273
+
1274
+
1275
+ (function(global, module, define) {
1276
+
1277
+ function Alea(seed) {
1278
+ var me = this, mash = Mash();
1279
+
1280
+ me.next = function() {
1281
+ var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32
1282
+ me.s0 = me.s1;
1283
+ me.s1 = me.s2;
1284
+ return me.s2 = t - (me.c = t | 0);
1285
+ };
1286
+
1287
+ // Apply the seeding algorithm from Baagoe.
1288
+ me.c = 1;
1289
+ me.s0 = mash(' ');
1290
+ me.s1 = mash(' ');
1291
+ me.s2 = mash(' ');
1292
+ me.s0 -= mash(seed);
1293
+ if (me.s0 < 0) { me.s0 += 1; }
1294
+ me.s1 -= mash(seed);
1295
+ if (me.s1 < 0) { me.s1 += 1; }
1296
+ me.s2 -= mash(seed);
1297
+ if (me.s2 < 0) { me.s2 += 1; }
1298
+ mash = null;
1299
+ }
1300
+
1301
+ function copy(f, t) {
1302
+ t.c = f.c;
1303
+ t.s0 = f.s0;
1304
+ t.s1 = f.s1;
1305
+ t.s2 = f.s2;
1306
+ return t;
1307
+ }
1308
+
1309
+ function impl(seed, opts) {
1310
+ var xg = new Alea(seed),
1311
+ state = opts && opts.state,
1312
+ prng = xg.next;
1313
+ prng.int32 = function() { return (xg.next() * 0x100000000) | 0; };
1314
+ prng.double = function() {
1315
+ return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
1316
+ };
1317
+ prng.quick = prng;
1318
+ if (state) {
1319
+ if (typeof(state) == 'object') copy(state, xg);
1320
+ prng.state = function() { return copy(xg, {}); };
1321
+ }
1322
+ return prng;
1323
+ }
1324
+
1325
+ function Mash() {
1326
+ var n = 0xefc8249d;
1327
+
1328
+ var mash = function(data) {
1329
+ data = String(data);
1330
+ for (var i = 0; i < data.length; i++) {
1331
+ n += data.charCodeAt(i);
1332
+ var h = 0.02519603282416938 * n;
1333
+ n = h >>> 0;
1334
+ h -= n;
1335
+ h *= n;
1336
+ n = h >>> 0;
1337
+ h -= n;
1338
+ n += h * 0x100000000; // 2^32
1339
+ }
1340
+ return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
1341
+ };
1342
+
1343
+ return mash;
1344
+ }
1345
+
1346
+
1347
+ if (module && module.exports) {
1348
+ module.exports = impl;
1349
+ } else {
1350
+ this.alea = impl;
1351
+ }
1352
+
1353
+ })(
1354
+ commonjsGlobal,
1355
+ module);
1356
+ } (alea$1));
1357
+
1358
+ var aleaExports = alea$1.exports;
1359
+ var seedrandom$3 = /*@__PURE__*/getDefaultExportFromCjs(aleaExports);
1360
+
1361
+ var xor128$1 = {exports: {}};
1362
+
1363
+ xor128$1.exports;
1364
+
1365
+ (function (module) {
1366
+ // A Javascript implementaion of the "xor128" prng algorithm by
1367
+ // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper
1368
+
1369
+ (function(global, module, define) {
1370
+
1371
+ function XorGen(seed) {
1372
+ var me = this, strseed = '';
1373
+
1374
+ me.x = 0;
1375
+ me.y = 0;
1376
+ me.z = 0;
1377
+ me.w = 0;
1378
+
1379
+ // Set up generator function.
1380
+ me.next = function() {
1381
+ var t = me.x ^ (me.x << 11);
1382
+ me.x = me.y;
1383
+ me.y = me.z;
1384
+ me.z = me.w;
1385
+ return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8);
1386
+ };
1387
+
1388
+ if (seed === (seed | 0)) {
1389
+ // Integer seed.
1390
+ me.x = seed;
1391
+ } else {
1392
+ // String seed.
1393
+ strseed += seed;
1394
+ }
1395
+
1396
+ // Mix in string seed, then discard an initial batch of 64 values.
1397
+ for (var k = 0; k < strseed.length + 64; k++) {
1398
+ me.x ^= strseed.charCodeAt(k) | 0;
1399
+ me.next();
1400
+ }
1401
+ }
1402
+
1403
+ function copy(f, t) {
1404
+ t.x = f.x;
1405
+ t.y = f.y;
1406
+ t.z = f.z;
1407
+ t.w = f.w;
1408
+ return t;
1409
+ }
1410
+
1411
+ function impl(seed, opts) {
1412
+ var xg = new XorGen(seed),
1413
+ state = opts && opts.state,
1414
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
1415
+ prng.double = function() {
1416
+ do {
1417
+ var top = xg.next() >>> 11,
1418
+ bot = (xg.next() >>> 0) / 0x100000000,
1419
+ result = (top + bot) / (1 << 21);
1420
+ } while (result === 0);
1421
+ return result;
1422
+ };
1423
+ prng.int32 = xg.next;
1424
+ prng.quick = prng;
1425
+ if (state) {
1426
+ if (typeof(state) == 'object') copy(state, xg);
1427
+ prng.state = function() { return copy(xg, {}); };
1428
+ }
1429
+ return prng;
1430
+ }
1431
+
1432
+ if (module && module.exports) {
1433
+ module.exports = impl;
1434
+ } else {
1435
+ this.xor128 = impl;
1436
+ }
1437
+
1438
+ })(
1439
+ commonjsGlobal,
1440
+ module);
1441
+ } (xor128$1));
1442
+
1443
+ var xor128Exports = xor128$1.exports;
1444
+
1445
+ var xorwow$1 = {exports: {}};
1446
+
1447
+ xorwow$1.exports;
1448
+
1449
+ (function (module) {
1450
+ // A Javascript implementaion of the "xorwow" prng algorithm by
1451
+ // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper
1452
+
1453
+ (function(global, module, define) {
1454
+
1455
+ function XorGen(seed) {
1456
+ var me = this, strseed = '';
1457
+
1458
+ // Set up generator function.
1459
+ me.next = function() {
1460
+ var t = (me.x ^ (me.x >>> 2));
1461
+ me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v;
1462
+ return (me.d = (me.d + 362437 | 0)) +
1463
+ (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0;
1464
+ };
1465
+
1466
+ me.x = 0;
1467
+ me.y = 0;
1468
+ me.z = 0;
1469
+ me.w = 0;
1470
+ me.v = 0;
1471
+
1472
+ if (seed === (seed | 0)) {
1473
+ // Integer seed.
1474
+ me.x = seed;
1475
+ } else {
1476
+ // String seed.
1477
+ strseed += seed;
1478
+ }
1479
+
1480
+ // Mix in string seed, then discard an initial batch of 64 values.
1481
+ for (var k = 0; k < strseed.length + 64; k++) {
1482
+ me.x ^= strseed.charCodeAt(k) | 0;
1483
+ if (k == strseed.length) {
1484
+ me.d = me.x << 10 ^ me.x >>> 4;
1485
+ }
1486
+ me.next();
1487
+ }
1488
+ }
1489
+
1490
+ function copy(f, t) {
1491
+ t.x = f.x;
1492
+ t.y = f.y;
1493
+ t.z = f.z;
1494
+ t.w = f.w;
1495
+ t.v = f.v;
1496
+ t.d = f.d;
1497
+ return t;
1498
+ }
1499
+
1500
+ function impl(seed, opts) {
1501
+ var xg = new XorGen(seed),
1502
+ state = opts && opts.state,
1503
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
1504
+ prng.double = function() {
1505
+ do {
1506
+ var top = xg.next() >>> 11,
1507
+ bot = (xg.next() >>> 0) / 0x100000000,
1508
+ result = (top + bot) / (1 << 21);
1509
+ } while (result === 0);
1510
+ return result;
1511
+ };
1512
+ prng.int32 = xg.next;
1513
+ prng.quick = prng;
1514
+ if (state) {
1515
+ if (typeof(state) == 'object') copy(state, xg);
1516
+ prng.state = function() { return copy(xg, {}); };
1517
+ }
1518
+ return prng;
1519
+ }
1520
+
1521
+ if (module && module.exports) {
1522
+ module.exports = impl;
1523
+ } else {
1524
+ this.xorwow = impl;
1525
+ }
1526
+
1527
+ })(
1528
+ commonjsGlobal,
1529
+ module);
1530
+ } (xorwow$1));
1531
+
1532
+ var xorwowExports = xorwow$1.exports;
1533
+
1534
+ var xorshift7$1 = {exports: {}};
1535
+
1536
+ xorshift7$1.exports;
1537
+
1538
+ (function (module) {
1539
+ // A Javascript implementaion of the "xorshift7" algorithm by
1540
+ // François Panneton and Pierre L'ecuyer:
1541
+ // "On the Xorgshift Random Number Generators"
1542
+ // http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf
1543
+
1544
+ (function(global, module, define) {
1545
+
1546
+ function XorGen(seed) {
1547
+ var me = this;
1548
+
1549
+ // Set up generator function.
1550
+ me.next = function() {
1551
+ // Update xor generator.
1552
+ var X = me.x, i = me.i, t, v;
1553
+ t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24);
1554
+ t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10);
1555
+ t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3);
1556
+ t = X[(i + 4) & 7]; v ^= t ^ (t << 7);
1557
+ t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9);
1558
+ X[i] = v;
1559
+ me.i = (i + 1) & 7;
1560
+ return v;
1561
+ };
1562
+
1563
+ function init(me, seed) {
1564
+ var j, X = [];
1565
+
1566
+ if (seed === (seed | 0)) {
1567
+ // Seed state array using a 32-bit integer.
1568
+ X[0] = seed;
1569
+ } else {
1570
+ // Seed state using a string.
1571
+ seed = '' + seed;
1572
+ for (j = 0; j < seed.length; ++j) {
1573
+ X[j & 7] = (X[j & 7] << 15) ^
1574
+ (seed.charCodeAt(j) + X[(j + 1) & 7] << 13);
1575
+ }
1576
+ }
1577
+ // Enforce an array length of 8, not all zeroes.
1578
+ while (X.length < 8) X.push(0);
1579
+ for (j = 0; j < 8 && X[j] === 0; ++j);
1580
+ if (j == 8) X[7] = -1; else X[j];
1581
+
1582
+ me.x = X;
1583
+ me.i = 0;
1584
+
1585
+ // Discard an initial 256 values.
1586
+ for (j = 256; j > 0; --j) {
1587
+ me.next();
1588
+ }
1589
+ }
1590
+
1591
+ init(me, seed);
1592
+ }
1593
+
1594
+ function copy(f, t) {
1595
+ t.x = f.x.slice();
1596
+ t.i = f.i;
1597
+ return t;
1598
+ }
1599
+
1600
+ function impl(seed, opts) {
1601
+ if (seed == null) seed = +(new Date);
1602
+ var xg = new XorGen(seed),
1603
+ state = opts && opts.state,
1604
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
1605
+ prng.double = function() {
1606
+ do {
1607
+ var top = xg.next() >>> 11,
1608
+ bot = (xg.next() >>> 0) / 0x100000000,
1609
+ result = (top + bot) / (1 << 21);
1610
+ } while (result === 0);
1611
+ return result;
1612
+ };
1613
+ prng.int32 = xg.next;
1614
+ prng.quick = prng;
1615
+ if (state) {
1616
+ if (state.x) copy(state, xg);
1617
+ prng.state = function() { return copy(xg, {}); };
1618
+ }
1619
+ return prng;
1620
+ }
1621
+
1622
+ if (module && module.exports) {
1623
+ module.exports = impl;
1624
+ } else {
1625
+ this.xorshift7 = impl;
1626
+ }
1627
+
1628
+ })(
1629
+ commonjsGlobal,
1630
+ module);
1631
+ } (xorshift7$1));
1632
+
1633
+ var xorshift7Exports = xorshift7$1.exports;
1634
+
1635
+ var xor4096$1 = {exports: {}};
1636
+
1637
+ xor4096$1.exports;
1638
+
1639
+ (function (module) {
1640
+ // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm.
1641
+ //
1642
+ // This fast non-cryptographic random number generator is designed for
1643
+ // use in Monte-Carlo algorithms. It combines a long-period xorshift
1644
+ // generator with a Weyl generator, and it passes all common batteries
1645
+ // of stasticial tests for randomness while consuming only a few nanoseconds
1646
+ // for each prng generated. For background on the generator, see Brent's
1647
+ // paper: "Some long-period random number generators using shifts and xors."
1648
+ // http://arxiv.org/pdf/1004.3115v1.pdf
1649
+ //
1650
+ // Usage:
1651
+ //
1652
+ // var xor4096 = require('xor4096');
1653
+ // random = xor4096(1); // Seed with int32 or string.
1654
+ // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits.
1655
+ // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits.
1656
+ //
1657
+ // For nonzero numeric keys, this impelementation provides a sequence
1658
+ // identical to that by Brent's xorgens 3 implementaion in C. This
1659
+ // implementation also provides for initalizing the generator with
1660
+ // string seeds, or for saving and restoring the state of the generator.
1661
+ //
1662
+ // On Chrome, this prng benchmarks about 2.1 times slower than
1663
+ // Javascript's built-in Math.random().
1664
+
1665
+ (function(global, module, define) {
1666
+
1667
+ function XorGen(seed) {
1668
+ var me = this;
1669
+
1670
+ // Set up generator function.
1671
+ me.next = function() {
1672
+ var w = me.w,
1673
+ X = me.X, i = me.i, t, v;
1674
+ // Update Weyl generator.
1675
+ me.w = w = (w + 0x61c88647) | 0;
1676
+ // Update xor generator.
1677
+ v = X[(i + 34) & 127];
1678
+ t = X[i = ((i + 1) & 127)];
1679
+ v ^= v << 13;
1680
+ t ^= t << 17;
1681
+ v ^= v >>> 15;
1682
+ t ^= t >>> 12;
1683
+ // Update Xor generator array state.
1684
+ v = X[i] = v ^ t;
1685
+ me.i = i;
1686
+ // Result is the combination.
1687
+ return (v + (w ^ (w >>> 16))) | 0;
1688
+ };
1689
+
1690
+ function init(me, seed) {
1691
+ var t, v, i, j, w, X = [], limit = 128;
1692
+ if (seed === (seed | 0)) {
1693
+ // Numeric seeds initialize v, which is used to generates X.
1694
+ v = seed;
1695
+ seed = null;
1696
+ } else {
1697
+ // String seeds are mixed into v and X one character at a time.
1698
+ seed = seed + '\0';
1699
+ v = 0;
1700
+ limit = Math.max(limit, seed.length);
1701
+ }
1702
+ // Initialize circular array and weyl value.
1703
+ for (i = 0, j = -32; j < limit; ++j) {
1704
+ // Put the unicode characters into the array, and shuffle them.
1705
+ if (seed) v ^= seed.charCodeAt((j + 32) % seed.length);
1706
+ // After 32 shuffles, take v as the starting w value.
1707
+ if (j === 0) w = v;
1708
+ v ^= v << 10;
1709
+ v ^= v >>> 15;
1710
+ v ^= v << 4;
1711
+ v ^= v >>> 13;
1712
+ if (j >= 0) {
1713
+ w = (w + 0x61c88647) | 0; // Weyl.
1714
+ t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array.
1715
+ i = (0 == t) ? i + 1 : 0; // Count zeroes.
1716
+ }
1717
+ }
1718
+ // We have detected all zeroes; make the key nonzero.
1719
+ if (i >= 128) {
1720
+ X[(seed && seed.length || 0) & 127] = -1;
1721
+ }
1722
+ // Run the generator 512 times to further mix the state before using it.
1723
+ // Factoring this as a function slows the main generator, so it is just
1724
+ // unrolled here. The weyl generator is not advanced while warming up.
1725
+ i = 127;
1726
+ for (j = 4 * 128; j > 0; --j) {
1727
+ v = X[(i + 34) & 127];
1728
+ t = X[i = ((i + 1) & 127)];
1729
+ v ^= v << 13;
1730
+ t ^= t << 17;
1731
+ v ^= v >>> 15;
1732
+ t ^= t >>> 12;
1733
+ X[i] = v ^ t;
1734
+ }
1735
+ // Storing state as object members is faster than using closure variables.
1736
+ me.w = w;
1737
+ me.X = X;
1738
+ me.i = i;
1739
+ }
1740
+
1741
+ init(me, seed);
1742
+ }
1743
+
1744
+ function copy(f, t) {
1745
+ t.i = f.i;
1746
+ t.w = f.w;
1747
+ t.X = f.X.slice();
1748
+ return t;
1749
+ }
1750
+ function impl(seed, opts) {
1751
+ if (seed == null) seed = +(new Date);
1752
+ var xg = new XorGen(seed),
1753
+ state = opts && opts.state,
1754
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
1755
+ prng.double = function() {
1756
+ do {
1757
+ var top = xg.next() >>> 11,
1758
+ bot = (xg.next() >>> 0) / 0x100000000,
1759
+ result = (top + bot) / (1 << 21);
1760
+ } while (result === 0);
1761
+ return result;
1762
+ };
1763
+ prng.int32 = xg.next;
1764
+ prng.quick = prng;
1765
+ if (state) {
1766
+ if (state.X) copy(state, xg);
1767
+ prng.state = function() { return copy(xg, {}); };
1768
+ }
1769
+ return prng;
1770
+ }
1771
+
1772
+ if (module && module.exports) {
1773
+ module.exports = impl;
1774
+ } else {
1775
+ this.xor4096 = impl;
1776
+ }
1777
+
1778
+ })(
1779
+ commonjsGlobal, // window object or global
1780
+ module);
1781
+ } (xor4096$1));
1782
+
1783
+ var xor4096Exports = xor4096$1.exports;
1784
+
1785
+ var tychei$1 = {exports: {}};
1786
+
1787
+ tychei$1.exports;
1788
+
1789
+ (function (module) {
1790
+ // A Javascript implementaion of the "Tyche-i" prng algorithm by
1791
+ // Samuel Neves and Filipe Araujo.
1792
+ // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf
1793
+
1794
+ (function(global, module, define) {
1795
+
1796
+ function XorGen(seed) {
1797
+ var me = this, strseed = '';
1798
+
1799
+ // Set up generator function.
1800
+ me.next = function() {
1801
+ var b = me.b, c = me.c, d = me.d, a = me.a;
1802
+ b = (b << 25) ^ (b >>> 7) ^ c;
1803
+ c = (c - d) | 0;
1804
+ d = (d << 24) ^ (d >>> 8) ^ a;
1805
+ a = (a - b) | 0;
1806
+ me.b = b = (b << 20) ^ (b >>> 12) ^ c;
1807
+ me.c = c = (c - d) | 0;
1808
+ me.d = (d << 16) ^ (c >>> 16) ^ a;
1809
+ return me.a = (a - b) | 0;
1810
+ };
1811
+
1812
+ /* The following is non-inverted tyche, which has better internal
1813
+ * bit diffusion, but which is about 25% slower than tyche-i in JS.
1814
+ me.next = function() {
1815
+ var a = me.a, b = me.b, c = me.c, d = me.d;
1816
+ a = (me.a + me.b | 0) >>> 0;
1817
+ d = me.d ^ a; d = d << 16 ^ d >>> 16;
1818
+ c = me.c + d | 0;
1819
+ b = me.b ^ c; b = b << 12 ^ d >>> 20;
1820
+ me.a = a = a + b | 0;
1821
+ d = d ^ a; me.d = d = d << 8 ^ d >>> 24;
1822
+ me.c = c = c + d | 0;
1823
+ b = b ^ c;
1824
+ return me.b = (b << 7 ^ b >>> 25);
1825
+ }
1826
+ */
1827
+
1828
+ me.a = 0;
1829
+ me.b = 0;
1830
+ me.c = 2654435769 | 0;
1831
+ me.d = 1367130551;
1832
+
1833
+ if (seed === Math.floor(seed)) {
1834
+ // Integer seed.
1835
+ me.a = (seed / 0x100000000) | 0;
1836
+ me.b = seed | 0;
1837
+ } else {
1838
+ // String seed.
1839
+ strseed += seed;
1840
+ }
1841
+
1842
+ // Mix in string seed, then discard an initial batch of 64 values.
1843
+ for (var k = 0; k < strseed.length + 20; k++) {
1844
+ me.b ^= strseed.charCodeAt(k) | 0;
1845
+ me.next();
1846
+ }
1847
+ }
1848
+
1849
+ function copy(f, t) {
1850
+ t.a = f.a;
1851
+ t.b = f.b;
1852
+ t.c = f.c;
1853
+ t.d = f.d;
1854
+ return t;
1855
+ }
1856
+ function impl(seed, opts) {
1857
+ var xg = new XorGen(seed),
1858
+ state = opts && opts.state,
1859
+ prng = function() { return (xg.next() >>> 0) / 0x100000000; };
1860
+ prng.double = function() {
1861
+ do {
1862
+ var top = xg.next() >>> 11,
1863
+ bot = (xg.next() >>> 0) / 0x100000000,
1864
+ result = (top + bot) / (1 << 21);
1865
+ } while (result === 0);
1866
+ return result;
1867
+ };
1868
+ prng.int32 = xg.next;
1869
+ prng.quick = prng;
1870
+ if (state) {
1871
+ if (typeof(state) == 'object') copy(state, xg);
1872
+ prng.state = function() { return copy(xg, {}); };
1873
+ }
1874
+ return prng;
1875
+ }
1876
+
1877
+ if (module && module.exports) {
1878
+ module.exports = impl;
1879
+ } else {
1880
+ this.tychei = impl;
1881
+ }
1882
+
1883
+ })(
1884
+ commonjsGlobal,
1885
+ module);
1886
+ } (tychei$1));
1887
+
1888
+ var tycheiExports = tychei$1.exports;
1889
+
1890
+ var seedrandom$2 = {exports: {}};
1891
+
1892
+ /*
1893
+ Copyright 2019 David Bau.
1894
+
1895
+ Permission is hereby granted, free of charge, to any person obtaining
1896
+ a copy of this software and associated documentation files (the
1897
+ "Software"), to deal in the Software without restriction, including
1898
+ without limitation the rights to use, copy, modify, merge, publish,
1899
+ distribute, sublicense, and/or sell copies of the Software, and to
1900
+ permit persons to whom the Software is furnished to do so, subject to
1901
+ the following conditions:
1902
+
1903
+ The above copyright notice and this permission notice shall be
1904
+ included in all copies or substantial portions of the Software.
1905
+
1906
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1907
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1908
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1909
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1910
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1911
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1912
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1231
1913
 
1232
- function createJointPluginAPIObject(jsPsych) {
1233
- const settings = jsPsych.getInitSettings();
1234
- const keyboardListenerAPI = new KeyboardListenerAPI(
1235
- jsPsych.getDisplayContainerElement,
1236
- settings.case_sensitive_responses,
1237
- settings.minimum_valid_rt
1238
- );
1239
- const timeoutAPI = new TimeoutAPI();
1240
- const mediaAPI = new MediaAPI(settings.use_webaudio);
1241
- const simulationAPI = new SimulationAPI(
1242
- jsPsych.getDisplayContainerElement,
1243
- timeoutAPI.setTimeout.bind(timeoutAPI)
1244
- );
1245
- return Object.assign(
1246
- {},
1247
- ...[keyboardListenerAPI, timeoutAPI, mediaAPI, simulationAPI].map((object) => autoBind$1(object))
1248
- );
1249
- }
1914
+ */
1915
+
1916
+ (function (module) {
1917
+ (function (global, pool, math) {
1918
+ //
1919
+ // The following constants are related to IEEE 754 limits.
1920
+ //
1921
+
1922
+ var width = 256, // each RC4 output is 0 <= x < 256
1923
+ chunks = 6, // at least six RC4 outputs for each double
1924
+ digits = 52, // there are 52 significant digits in a double
1925
+ rngname = 'random', // rngname: name for Math.random and Math.seedrandom
1926
+ startdenom = math.pow(width, chunks),
1927
+ significance = math.pow(2, digits),
1928
+ overflow = significance * 2,
1929
+ mask = width - 1,
1930
+ nodecrypto; // node.js crypto module, initialized at the bottom.
1931
+
1932
+ //
1933
+ // seedrandom()
1934
+ // This is the seedrandom function described above.
1935
+ //
1936
+ function seedrandom(seed, options, callback) {
1937
+ var key = [];
1938
+ options = (options == true) ? { entropy: true } : (options || {});
1939
+
1940
+ // Flatten the seed string or build one from local entropy if needed.
1941
+ var shortseed = mixkey(flatten(
1942
+ options.entropy ? [seed, tostring(pool)] :
1943
+ (seed == null) ? autoseed() : seed, 3), key);
1944
+
1945
+ // Use the seed to initialize an ARC4 generator.
1946
+ var arc4 = new ARC4(key);
1947
+
1948
+ // This function returns a random double in [0, 1) that contains
1949
+ // randomness in every bit of the mantissa of the IEEE 754 value.
1950
+ var prng = function() {
1951
+ var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48
1952
+ d = startdenom, // and denominator d = 2 ^ 48.
1953
+ x = 0; // and no 'extra last byte'.
1954
+ while (n < significance) { // Fill up all significant digits by
1955
+ n = (n + x) * width; // shifting numerator and
1956
+ d *= width; // denominator and generating a
1957
+ x = arc4.g(1); // new least-significant-byte.
1958
+ }
1959
+ while (n >= overflow) { // To avoid rounding up, before adding
1960
+ n /= 2; // last byte, shift everything
1961
+ d /= 2; // right using integer math until
1962
+ x >>>= 1; // we have exactly the desired bits.
1963
+ }
1964
+ return (n + x) / d; // Form the number within [0, 1).
1965
+ };
1966
+
1967
+ prng.int32 = function() { return arc4.g(4) | 0; };
1968
+ prng.quick = function() { return arc4.g(4) / 0x100000000; };
1969
+ prng.double = prng;
1970
+
1971
+ // Mix the randomness into accumulated entropy.
1972
+ mixkey(tostring(arc4.S), pool);
1973
+
1974
+ // Calling convention: what to return as a function of prng, seed, is_math.
1975
+ return (options.pass || callback ||
1976
+ function(prng, seed, is_math_call, state) {
1977
+ if (state) {
1978
+ // Load the arc4 state from the given state if it has an S array.
1979
+ if (state.S) { copy(state, arc4); }
1980
+ // Only provide the .state method if requested via options.state.
1981
+ prng.state = function() { return copy(arc4, {}); };
1982
+ }
1983
+
1984
+ // If called as a method of Math (Math.seedrandom()), mutate
1985
+ // Math.random because that is how seedrandom.js has worked since v1.0.
1986
+ if (is_math_call) { math[rngname] = prng; return seed; }
1987
+
1988
+ // Otherwise, it is a newer calling convention, so return the
1989
+ // prng directly.
1990
+ else return prng;
1991
+ })(
1992
+ prng,
1993
+ shortseed,
1994
+ 'global' in options ? options.global : (this == math),
1995
+ options.state);
1996
+ }
1997
+
1998
+ //
1999
+ // ARC4
2000
+ //
2001
+ // An ARC4 implementation. The constructor takes a key in the form of
2002
+ // an array of at most (width) integers that should be 0 <= x < (width).
2003
+ //
2004
+ // The g(count) method returns a pseudorandom integer that concatenates
2005
+ // the next (count) outputs from ARC4. Its return value is a number x
2006
+ // that is in the range 0 <= x < (width ^ count).
2007
+ //
2008
+ function ARC4(key) {
2009
+ var t, keylen = key.length,
2010
+ me = this, i = 0, j = me.i = me.j = 0, s = me.S = [];
2011
+
2012
+ // The empty key [] is treated as [0].
2013
+ if (!keylen) { key = [keylen++]; }
2014
+
2015
+ // Set up S using the standard key scheduling algorithm.
2016
+ while (i < width) {
2017
+ s[i] = i++;
2018
+ }
2019
+ for (i = 0; i < width; i++) {
2020
+ s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))];
2021
+ s[j] = t;
2022
+ }
2023
+
2024
+ // The "g" method returns the next (count) outputs as one number.
2025
+ (me.g = function(count) {
2026
+ // Using instance members instead of closure state nearly doubles speed.
2027
+ var t, r = 0,
2028
+ i = me.i, j = me.j, s = me.S;
2029
+ while (count--) {
2030
+ t = s[i = mask & (i + 1)];
2031
+ r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))];
2032
+ }
2033
+ me.i = i; me.j = j;
2034
+ return r;
2035
+ // For robust unpredictability, the function call below automatically
2036
+ // discards an initial batch of values. This is called RC4-drop[256].
2037
+ // See http://google.com/search?q=rsa+fluhrer+response&btnI
2038
+ })(width);
2039
+ }
2040
+
2041
+ //
2042
+ // copy()
2043
+ // Copies internal state of ARC4 to or from a plain object.
2044
+ //
2045
+ function copy(f, t) {
2046
+ t.i = f.i;
2047
+ t.j = f.j;
2048
+ t.S = f.S.slice();
2049
+ return t;
2050
+ }
2051
+ //
2052
+ // flatten()
2053
+ // Converts an object tree to nested arrays of strings.
2054
+ //
2055
+ function flatten(obj, depth) {
2056
+ var result = [], typ = (typeof obj), prop;
2057
+ if (depth && typ == 'object') {
2058
+ for (prop in obj) {
2059
+ try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
2060
+ }
2061
+ }
2062
+ return (result.length ? result : typ == 'string' ? obj : obj + '\0');
2063
+ }
2064
+
2065
+ //
2066
+ // mixkey()
2067
+ // Mixes a string seed into a key that is an array of integers, and
2068
+ // returns a shortened string seed that is equivalent to the result key.
2069
+ //
2070
+ function mixkey(seed, key) {
2071
+ var stringseed = seed + '', smear, j = 0;
2072
+ while (j < stringseed.length) {
2073
+ key[mask & j] =
2074
+ mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++));
2075
+ }
2076
+ return tostring(key);
2077
+ }
2078
+
2079
+ //
2080
+ // autoseed()
2081
+ // Returns an object for autoseeding, using window.crypto and Node crypto
2082
+ // module if available.
2083
+ //
2084
+ function autoseed() {
2085
+ try {
2086
+ var out;
2087
+ if (nodecrypto && (out = nodecrypto.randomBytes)) {
2088
+ // The use of 'out' to remember randomBytes makes tight minified code.
2089
+ out = out(width);
2090
+ } else {
2091
+ out = new Uint8Array(width);
2092
+ (global.crypto || global.msCrypto).getRandomValues(out);
2093
+ }
2094
+ return tostring(out);
2095
+ } catch (e) {
2096
+ var browser = global.navigator,
2097
+ plugins = browser && browser.plugins;
2098
+ return [+new Date, global, plugins, global.screen, tostring(pool)];
2099
+ }
2100
+ }
2101
+
2102
+ //
2103
+ // tostring()
2104
+ // Converts an array of charcodes to a string
2105
+ //
2106
+ function tostring(a) {
2107
+ return String.fromCharCode.apply(0, a);
2108
+ }
2109
+
2110
+ //
2111
+ // When seedrandom.js is loaded, we immediately mix a few bits
2112
+ // from the built-in RNG into the entropy pool. Because we do
2113
+ // not want to interfere with deterministic PRNG state later,
2114
+ // seedrandom will not call math.random on its own again after
2115
+ // initialization.
2116
+ //
2117
+ mixkey(math.random(), pool);
2118
+
2119
+ //
2120
+ // Nodejs and AMD support: export the implementation as a module using
2121
+ // either convention.
2122
+ //
2123
+ if (module.exports) {
2124
+ module.exports = seedrandom;
2125
+ // When in node.js, try using crypto package for autoseeding.
2126
+ try {
2127
+ nodecrypto = require('crypto');
2128
+ } catch (ex) {}
2129
+ } else {
2130
+ // When included as a plain script, set up Math.seedrandom global.
2131
+ math['seed' + rngname] = seedrandom;
2132
+ }
2133
+
2134
+
2135
+ // End anonymous scope, and pass initial values.
2136
+ })(
2137
+ // global: `self` in browsers (including strict mode and web workers),
2138
+ // otherwise `this` in Node and other environments
2139
+ (typeof self !== 'undefined') ? self : commonjsGlobal,
2140
+ [], // pool: entropy pool starts empty
2141
+ Math // math: package containing random, pow, and seedrandom
2142
+ );
2143
+ } (seedrandom$2));
2144
+
2145
+ var seedrandomExports = seedrandom$2.exports;
2146
+
2147
+ // A library of seedable RNGs implemented in Javascript.
2148
+ //
2149
+ // Usage:
2150
+ //
2151
+ // var seedrandom = require('seedrandom');
2152
+ // var random = seedrandom(1); // or any seed.
2153
+ // var x = random(); // 0 <= x < 1. Every bit is random.
2154
+ // var x = random.quick(); // 0 <= x < 1. 32 bits of randomness.
2155
+
2156
+ // alea, a 53-bit multiply-with-carry generator by Johannes Baagøe.
2157
+ // Period: ~2^116
2158
+ // Reported to pass all BigCrush tests.
2159
+ var alea = aleaExports;
2160
+
2161
+ // xor128, a pure xor-shift generator by George Marsaglia.
2162
+ // Period: 2^128-1.
2163
+ // Reported to fail: MatrixRank and LinearComp.
2164
+ var xor128 = xor128Exports;
2165
+
2166
+ // xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl.
2167
+ // Period: 2^192-2^32
2168
+ // Reported to fail: CollisionOver, SimpPoker, and LinearComp.
2169
+ var xorwow = xorwowExports;
2170
+
2171
+ // xorshift7, by François Panneton and Pierre L'ecuyer, takes
2172
+ // a different approach: it adds robustness by allowing more shifts
2173
+ // than Marsaglia's original three. It is a 7-shift generator
2174
+ // with 256 bits, that passes BigCrush with no systmatic failures.
2175
+ // Period 2^256-1.
2176
+ // No systematic BigCrush failures reported.
2177
+ var xorshift7 = xorshift7Exports;
2178
+
2179
+ // xor4096, by Richard Brent, is a 4096-bit xor-shift with a
2180
+ // very long period that also adds a Weyl generator. It also passes
2181
+ // BigCrush with no systematic failures. Its long period may
2182
+ // be useful if you have many generators and need to avoid
2183
+ // collisions.
2184
+ // Period: 2^4128-2^32.
2185
+ // No systematic BigCrush failures reported.
2186
+ var xor4096 = xor4096Exports;
2187
+
2188
+ // Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random
2189
+ // number generator derived from ChaCha, a modern stream cipher.
2190
+ // https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf
2191
+ // Period: ~2^127
2192
+ // No systematic BigCrush failures reported.
2193
+ var tychei = tycheiExports;
2194
+
2195
+ // The original ARC4-based prng included in this library.
2196
+ // Period: ~2^1600
2197
+ var sr = seedrandomExports;
2198
+
2199
+ sr.alea = alea;
2200
+ sr.xor128 = xor128;
2201
+ sr.xorwow = xorwow;
2202
+ sr.xorshift7 = xorshift7;
2203
+ sr.xor4096 = xor4096;
2204
+ sr.tychei = tychei;
2205
+
2206
+ var seedrandom$1 = sr;
2207
+
2208
+ var seedrandom = seedrandom$1;
1250
2209
 
1251
2210
  var wordList = [
1252
2211
  // Borrowed from xkcd password generator which borrowed it from wherever
@@ -1497,6 +2456,8 @@ var jsPsychModule = (function (exports) {
1497
2456
  ];
1498
2457
 
1499
2458
  function words(options) {
2459
+ // initalize random number generator for words if options.seed is provided
2460
+ const random = options?.seed ? new seedrandom(options.seed) : null;
1500
2461
 
1501
2462
  function word() {
1502
2463
  if (options && options.maxLength > 1) {
@@ -1523,8 +2484,10 @@ var jsPsychModule = (function (exports) {
1523
2484
  return wordList[randInt(wordList.length)];
1524
2485
  }
1525
2486
 
2487
+ // random int as seeded by options.seed if applicable, or Math.random() otherwise
1526
2488
  function randInt(lessThan) {
1527
- return Math.floor(Math.random() * lessThan);
2489
+ const r = random ? random() : Math.random();
2490
+ return Math.floor(r * lessThan);
1528
2491
  }
1529
2492
 
1530
2493
  // No arguments = generate one word
@@ -1591,130 +2554,8 @@ var jsPsychModule = (function (exports) {
1591
2554
 
1592
2555
  var rw = /*@__PURE__*/getDefaultExportFromCjs(randomWords$1);
1593
2556
 
1594
- var alea = {exports: {}};
1595
-
1596
- alea.exports;
1597
-
1598
- (function (module) {
1599
- // A port of an algorithm by Johannes Baagøe <baagoe@baagoe.com>, 2010
1600
- // http://baagoe.com/en/RandomMusings/javascript/
1601
- // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
1602
- // Original work is under MIT license -
1603
-
1604
- // Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>
1605
- //
1606
- // Permission is hereby granted, free of charge, to any person obtaining a copy
1607
- // of this software and associated documentation files (the "Software"), to deal
1608
- // in the Software without restriction, including without limitation the rights
1609
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1610
- // copies of the Software, and to permit persons to whom the Software is
1611
- // furnished to do so, subject to the following conditions:
1612
- //
1613
- // The above copyright notice and this permission notice shall be included in
1614
- // all copies or substantial portions of the Software.
1615
- //
1616
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1617
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1618
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1619
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1620
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1621
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1622
- // THE SOFTWARE.
1623
-
1624
-
1625
-
1626
- (function(global, module, define) {
1627
-
1628
- function Alea(seed) {
1629
- var me = this, mash = Mash();
1630
-
1631
- me.next = function() {
1632
- var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32
1633
- me.s0 = me.s1;
1634
- me.s1 = me.s2;
1635
- return me.s2 = t - (me.c = t | 0);
1636
- };
1637
-
1638
- // Apply the seeding algorithm from Baagoe.
1639
- me.c = 1;
1640
- me.s0 = mash(' ');
1641
- me.s1 = mash(' ');
1642
- me.s2 = mash(' ');
1643
- me.s0 -= mash(seed);
1644
- if (me.s0 < 0) { me.s0 += 1; }
1645
- me.s1 -= mash(seed);
1646
- if (me.s1 < 0) { me.s1 += 1; }
1647
- me.s2 -= mash(seed);
1648
- if (me.s2 < 0) { me.s2 += 1; }
1649
- mash = null;
1650
- }
1651
-
1652
- function copy(f, t) {
1653
- t.c = f.c;
1654
- t.s0 = f.s0;
1655
- t.s1 = f.s1;
1656
- t.s2 = f.s2;
1657
- return t;
1658
- }
1659
-
1660
- function impl(seed, opts) {
1661
- var xg = new Alea(seed),
1662
- state = opts && opts.state,
1663
- prng = xg.next;
1664
- prng.int32 = function() { return (xg.next() * 0x100000000) | 0; };
1665
- prng.double = function() {
1666
- return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
1667
- };
1668
- prng.quick = prng;
1669
- if (state) {
1670
- if (typeof(state) == 'object') copy(state, xg);
1671
- prng.state = function() { return copy(xg, {}); };
1672
- }
1673
- return prng;
1674
- }
1675
-
1676
- function Mash() {
1677
- var n = 0xefc8249d;
1678
-
1679
- var mash = function(data) {
1680
- data = String(data);
1681
- for (var i = 0; i < data.length; i++) {
1682
- n += data.charCodeAt(i);
1683
- var h = 0.02519603282416938 * n;
1684
- n = h >>> 0;
1685
- h -= n;
1686
- h *= n;
1687
- n = h >>> 0;
1688
- h -= n;
1689
- n += h * 0x100000000; // 2^32
1690
- }
1691
- return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
1692
- };
1693
-
1694
- return mash;
1695
- }
1696
-
1697
-
1698
- if (module && module.exports) {
1699
- module.exports = impl;
1700
- } else if (define && define.amd) {
1701
- define(function() { return impl; });
1702
- } else {
1703
- this.alea = impl;
1704
- }
1705
-
1706
- })(
1707
- commonjsGlobal,
1708
- module, // present in node.js
1709
- (typeof undefined) == 'function' // present with an AMD loader
1710
- );
1711
- } (alea));
1712
-
1713
- var aleaExports = alea.exports;
1714
- var seedrandom = /*@__PURE__*/getDefaultExportFromCjs(aleaExports);
1715
-
1716
2557
  function setSeed(seed = Math.random().toString()) {
1717
- Math.random = seedrandom(seed);
2558
+ Math.random = seedrandom$3(seed);
1718
2559
  return seed;
1719
2560
  }
1720
2561
  function repeat(array, repetitions, unpack = false) {
@@ -1940,10 +2781,8 @@ var jsPsychModule = (function (exports) {
1940
2781
  }
1941
2782
  function randn_bm() {
1942
2783
  var u = 0, v = 0;
1943
- while (u === 0)
1944
- u = Math.random();
1945
- while (v === 0)
1946
- v = Math.random();
2784
+ while (u === 0) u = Math.random();
2785
+ while (v === 0) v = Math.random();
1947
2786
  return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
1948
2787
  }
1949
2788
  function unpackArray(array) {
@@ -1961,21 +2800,21 @@ var jsPsychModule = (function (exports) {
1961
2800
 
1962
2801
  var randomization = /*#__PURE__*/Object.freeze({
1963
2802
  __proto__: null,
1964
- setSeed: setSeed,
1965
- repeat: repeat,
1966
- shuffle: shuffle,
1967
- shuffleNoRepeats: shuffleNoRepeats,
1968
- shuffleAlternateGroups: shuffleAlternateGroups,
1969
- sampleWithoutReplacement: sampleWithoutReplacement,
1970
- sampleWithReplacement: sampleWithReplacement,
1971
2803
  factorial: factorial,
1972
2804
  randomID: randomID,
1973
2805
  randomInt: randomInt,
2806
+ randomWords: randomWords,
2807
+ repeat: repeat,
1974
2808
  sampleBernoulli: sampleBernoulli,
1975
- sampleNormal: sampleNormal,
1976
- sampleExponential: sampleExponential,
1977
2809
  sampleExGaussian: sampleExGaussian,
1978
- randomWords: randomWords
2810
+ sampleExponential: sampleExponential,
2811
+ sampleNormal: sampleNormal,
2812
+ sampleWithReplacement: sampleWithReplacement,
2813
+ sampleWithoutReplacement: sampleWithoutReplacement,
2814
+ setSeed: setSeed,
2815
+ shuffle: shuffle,
2816
+ shuffleAlternateGroups: shuffleAlternateGroups,
2817
+ shuffleNoRepeats: shuffleNoRepeats
1979
2818
  });
1980
2819
 
1981
2820
  function turkInfo() {
@@ -2007,8 +2846,7 @@ var jsPsychModule = (function (exports) {
2007
2846
  const turk = turkInfo();
2008
2847
  const assignmentId = turk.assignmentId;
2009
2848
  const turkSubmitTo = turk.turkSubmitTo;
2010
- if (!assignmentId || !turkSubmitTo)
2011
- return;
2849
+ if (!assignmentId || !turkSubmitTo) return;
2012
2850
  const form = document.createElement("form");
2013
2851
  form.method = "POST";
2014
2852
  form.action = turkSubmitTo + "/mturk/externalSubmit?assignmentId=" + assignmentId;
@@ -2028,19 +2866,18 @@ var jsPsychModule = (function (exports) {
2028
2866
 
2029
2867
  var turk = /*#__PURE__*/Object.freeze({
2030
2868
  __proto__: null,
2031
- turkInfo: turkInfo,
2032
- submitToTurk: submitToTurk
2869
+ submitToTurk: submitToTurk,
2870
+ turkInfo: turkInfo
2033
2871
  });
2034
2872
 
2035
2873
  class ProgressBar {
2036
2874
  constructor(containerElement, message) {
2037
2875
  this.containerElement = containerElement;
2038
2876
  this.message = message;
2877
+ this._progress = 0;
2039
2878
  this.setupElements();
2040
2879
  }
2041
- _progress = 0;
2042
- innerDiv;
2043
- messageSpan;
2880
+ /** Adds the progress bar HTML code into `this.containerElement` */
2044
2881
  setupElements() {
2045
2882
  this.messageSpan = document.createElement("span");
2046
2883
  this.innerDiv = document.createElement("div");
@@ -2052,6 +2889,7 @@ var jsPsychModule = (function (exports) {
2052
2889
  this.containerElement.appendChild(this.messageSpan);
2053
2890
  this.containerElement.appendChild(outerDiv);
2054
2891
  }
2892
+ /** Updates the progress bar according to `this.progress` */
2055
2893
  update() {
2056
2894
  this.innerDiv.style.width = this._progress * 100 + "%";
2057
2895
  if (typeof this.message === "function") {
@@ -2060,6 +2898,10 @@ var jsPsychModule = (function (exports) {
2060
2898
  this.messageSpan.innerHTML = this.message;
2061
2899
  }
2062
2900
  }
2901
+ /**
2902
+ * The bar's current position as a number in the closed interval [0, 1]. Set this to update the
2903
+ * progress bar accordingly.
2904
+ */
2063
2905
  set progress(progress) {
2064
2906
  if (typeof progress !== "number" || progress < 0 || progress > 1) {
2065
2907
  throw new Error("jsPsych.progressBar.progress must be a number between 0 and 1");
@@ -2108,8 +2950,6 @@ var jsPsychModule = (function (exports) {
2108
2950
  constructor() {
2109
2951
  this.reset();
2110
2952
  }
2111
- promise;
2112
- resolvePromise;
2113
2953
  reset() {
2114
2954
  this.promise = new Promise((resolve) => {
2115
2955
  this.resolvePromise = resolve;
@@ -2140,6 +2980,9 @@ var jsPsychModule = (function (exports) {
2140
2980
  return typeof value === "object" && value !== null;
2141
2981
  }
2142
2982
  class ParameterObjectPathCache {
2983
+ constructor() {
2984
+ this.cache = /* @__PURE__ */ new Map();
2985
+ }
2143
2986
  static lookupChild(objectOrArray, childName) {
2144
2987
  let doesPathExist = false;
2145
2988
  let childValue;
@@ -2156,16 +2999,12 @@ var jsPsychModule = (function (exports) {
2156
2999
  }
2157
3000
  return { doesPathExist, value: childValue };
2158
3001
  }
2159
- cache = /* @__PURE__ */ new Map();
2160
- rootObject;
2161
3002
  get(path) {
2162
3003
  return this.cache.get(path.join("."));
2163
3004
  }
2164
3005
  has(path) {
2165
3006
  return this.cache.has(path.join("."));
2166
3007
  }
2167
- constructor() {
2168
- }
2169
3008
  initialize(rootObject) {
2170
3009
  this.rootObject = rootObject;
2171
3010
  this.cache.set("", rootObject);
@@ -2206,20 +3045,42 @@ var jsPsychModule = (function (exports) {
2206
3045
  class TimelineNode {
2207
3046
  constructor(dependencies) {
2208
3047
  this.dependencies = dependencies;
3048
+ this.status = TimelineNodeStatus.PENDING;
3049
+ this.parameterValueCache = new ParameterObjectPathCache();
2209
3050
  }
2210
- index;
2211
- status = TimelineNodeStatus.PENDING;
2212
3051
  getStatus() {
2213
3052
  return this.status;
2214
3053
  }
2215
- parameterValueCache = new ParameterObjectPathCache();
3054
+ /**
3055
+ * Initializes the parameter value cache with `this.description`. To be called by subclass
3056
+ * constructors after setting `this.description`.
3057
+ */
2216
3058
  initializeParameterValueCache() {
2217
3059
  this.parameterValueCache.initialize(this.description);
2218
3060
  }
3061
+ /**
3062
+ * Resets all cached parameter values in this timeline node and all of its parents. This is
3063
+ * necessary to re-evaluate function parameters and timeline variables at each new trial.
3064
+ */
2219
3065
  resetParameterValueCache() {
2220
3066
  this.parameterValueCache.reset();
2221
3067
  this.parent?.resetParameterValueCache();
2222
3068
  }
3069
+ /**
3070
+ * Retrieves a parameter value from the description of this timeline node, recursively falling
3071
+ * back to the description of each parent timeline node unless `recursive` is set to `false`. If
3072
+ * the parameter...
3073
+ *
3074
+ * * is a timeline variable, evaluates the variable and returns the result.
3075
+ * * is not specified, returns `undefined`.
3076
+ * * is a function and `evaluateFunctions` is not set to `false`, invokes the function and returns
3077
+ * its return value
3078
+ * * has previously been looked up, return the cached result of the previous lookup
3079
+ *
3080
+ * @param parameterPath The path of the respective parameter in the timeline node description. If
3081
+ * the path is an array, nested object properties or array items will be looked up.
3082
+ * @param options See {@link GetParameterValueOptions}
3083
+ */
2223
3084
  getParameterValue(parameterPath, options = {}) {
2224
3085
  const {
2225
3086
  evaluateFunctions = true,
@@ -2248,6 +3109,11 @@ var jsPsychModule = (function (exports) {
2248
3109
  }
2249
3110
  return result;
2250
3111
  }
3112
+ /**
3113
+ * Retrieves and evaluates the `data` parameter. It is different from other parameters in that
3114
+ * it's properties may be functions that have to be evaluated, and parent nodes' data parameter
3115
+ * properties are merged into the result.
3116
+ */
2251
3117
  getDataParameter() {
2252
3118
  const data = this.getParameterValue("data", { recursive: false });
2253
3119
  return {
@@ -2264,10 +3130,19 @@ var jsPsychModule = (function (exports) {
2264
3130
  super(dependencies);
2265
3131
  this.description = description;
2266
3132
  this.parent = parent;
3133
+ this.onLoad = () => {
3134
+ this.runParameterCallback("on_load");
3135
+ this.dependencies.runOnLoadExtensionCallbacks(this.getParameterValue("extensions"));
3136
+ };
2267
3137
  this.initializeParameterValueCache();
2268
3138
  this.trialObject = deepCopy(description);
2269
3139
  this.pluginClass = this.getParameterValue("type", { evaluateFunctions: false });
2270
- this.pluginInfo = this.pluginClass["info"];
3140
+ this.pluginInfo = this.pluginClass?.["info"];
3141
+ if (!this.pluginInfo) {
3142
+ throw new Error(
3143
+ "Plugin not recognized. Please provide a valid plugin using the 'type' parameter."
3144
+ );
3145
+ }
2271
3146
  if (!("version" in this.pluginInfo) && !("data" in this.pluginInfo)) {
2272
3147
  console.warn(
2273
3148
  this.pluginInfo["name"],
@@ -2285,12 +3160,6 @@ var jsPsychModule = (function (exports) {
2285
3160
  );
2286
3161
  }
2287
3162
  }
2288
- pluginClass;
2289
- pluginInstance;
2290
- trialObject;
2291
- index;
2292
- result;
2293
- pluginInfo;
2294
3163
  async run() {
2295
3164
  this.status = TimelineNodeStatus.RUNNING;
2296
3165
  this.processParameters();
@@ -2355,10 +3224,16 @@ var jsPsychModule = (function (exports) {
2355
3224
  )
2356
3225
  };
2357
3226
  }
3227
+ /**
3228
+ * Cleanup the trial by removing the display element and removing event listeners
3229
+ */
2358
3230
  cleanupTrial() {
2359
3231
  this.dependencies.clearAllTimeouts();
2360
3232
  this.dependencies.getDisplayElement().innerHTML = "";
2361
3233
  }
3234
+ /**
3235
+ * Add the CSS classes from the `css_classes` parameter to the display element
3236
+ */
2362
3237
  addCssClasses() {
2363
3238
  const classes = this.getParameterValue("css_classes");
2364
3239
  const classList = this.dependencies.getDisplayElement().classList;
@@ -2368,6 +3243,9 @@ var jsPsychModule = (function (exports) {
2368
3243
  classList.add(...classes);
2369
3244
  }
2370
3245
  }
3246
+ /**
3247
+ * Removes the provided css classes from the display element
3248
+ */
2371
3249
  removeCssClasses() {
2372
3250
  const classes = this.getParameterValue("css_classes");
2373
3251
  if (classes) {
@@ -2416,6 +3294,12 @@ var jsPsychModule = (function (exports) {
2416
3294
  }
2417
3295
  return result;
2418
3296
  }
3297
+ /**
3298
+ * Runs a callback function retrieved from a parameter value and returns its result.
3299
+ *
3300
+ * @param parameterName The name of the parameter to retrieve the callback function from.
3301
+ * @param callbackParameters The parameters (if any) to be passed to the callback function
3302
+ */
2419
3303
  runParameterCallback(parameterName, ...callbackParameters) {
2420
3304
  const callback = this.getParameterValue(parameterName, { evaluateFunctions: false });
2421
3305
  if (callback) {
@@ -2427,10 +3311,6 @@ var jsPsychModule = (function (exports) {
2427
3311
  this.runParameterCallback("on_start", this.trialObject);
2428
3312
  this.dependencies.runOnStartExtensionCallbacks(this.getParameterValue("extensions"));
2429
3313
  }
2430
- onLoad = () => {
2431
- this.runParameterCallback("on_load");
2432
- this.dependencies.runOnLoadExtensionCallbacks(this.getParameterValue("extensions"));
2433
- };
2434
3314
  async onFinish() {
2435
3315
  const extensionResults = await this.dependencies.runOnFinishExtensionCallbacks(
2436
3316
  this.getParameterValue("extensions")
@@ -2450,6 +3330,10 @@ var jsPsychModule = (function (exports) {
2450
3330
  }
2451
3331
  return super.getParameterValue(parameterPath, options);
2452
3332
  }
3333
+ /**
3334
+ * Retrieves and evaluates the `simulation_options` parameter, considering nested properties and
3335
+ * global simulation options.
3336
+ */
2453
3337
  getSimulationOptions() {
2454
3338
  const simulationOptions = this.getParameterValue("simulation_options", {
2455
3339
  replaceResult: (result = {}) => {
@@ -2479,6 +3363,10 @@ var jsPsychModule = (function (exports) {
2479
3363
  }
2480
3364
  return simulationOptions;
2481
3365
  }
3366
+ /**
3367
+ * Returns the result object of this trial or `undefined` if the result is not yet known or the
3368
+ * `record_data` trial parameter is `false`.
3369
+ */
2482
3370
  getResult() {
2483
3371
  return this.getParameterValue("record_data") === false ? void 0 : this.result;
2484
3372
  }
@@ -2486,6 +3374,12 @@ var jsPsychModule = (function (exports) {
2486
3374
  const result = this.getResult();
2487
3375
  return result ? [result] : [];
2488
3376
  }
3377
+ /**
3378
+ * Checks that the parameters provided in the trial description align with the plugin's info
3379
+ * object, resolves missing parameter values from the parent timeline, resolves timeline variable
3380
+ * parameters, evaluates parameter functions if the expected parameter type is not `FUNCTION`, and
3381
+ * sets default values for optional parameters.
3382
+ */
2489
3383
  processParameters() {
2490
3384
  const assignParameterValues = (parameterObject, parameterInfos, parentParameterPath = []) => {
2491
3385
  for (const [parameterName, parameterConfig] of Object.entries(parameterInfos)) {
@@ -2545,13 +3439,12 @@ var jsPsychModule = (function (exports) {
2545
3439
  constructor(dependencies, description, parent) {
2546
3440
  super(dependencies);
2547
3441
  this.parent = parent;
3442
+ this.children = [];
3443
+ this.shouldAbort = false;
3444
+ this.resumePromise = new PromiseWrapper();
2548
3445
  this.description = Array.isArray(description) ? { timeline: description } : description;
2549
3446
  this.initializeParameterValueCache();
2550
3447
  }
2551
- children = [];
2552
- description;
2553
- currentChild;
2554
- shouldAbort = false;
2555
3448
  async run() {
2556
3449
  if (typeof this.index === "undefined") {
2557
3450
  this.index = 0;
@@ -2612,7 +3505,6 @@ var jsPsychModule = (function (exports) {
2612
3505
  }
2613
3506
  this.status = TimelineNodeStatus.PAUSED;
2614
3507
  }
2615
- resumePromise = new PromiseWrapper();
2616
3508
  resume() {
2617
3509
  if (this.status == TimelineNodeStatus.PAUSED) {
2618
3510
  if (this.currentChild instanceof Timeline) {
@@ -2622,6 +3514,9 @@ var jsPsychModule = (function (exports) {
2622
3514
  this.resumePromise.resolve();
2623
3515
  }
2624
3516
  }
3517
+ /**
3518
+ * If the timeline is running or paused, aborts the timeline after the current trial has completed
3519
+ */
2625
3520
  abort() {
2626
3521
  if (this.status === TimelineNodeStatus.RUNNING || this.status === TimelineNodeStatus.PAUSED) {
2627
3522
  if (this.currentChild instanceof Timeline) {
@@ -2638,13 +3533,17 @@ var jsPsychModule = (function (exports) {
2638
3533
  this.children.push(newChildNode);
2639
3534
  return newChildNode;
2640
3535
  }
2641
- currentTimelineVariables;
2642
3536
  setCurrentTimelineVariablesByIndex(index) {
2643
3537
  this.currentTimelineVariables = {
2644
3538
  ...this.parent?.getAllTimelineVariables(),
2645
3539
  ...index === null ? void 0 : this.description.timeline_variables[index]
2646
3540
  };
2647
3541
  }
3542
+ /**
3543
+ * If the timeline has timeline variables, returns the order of `timeline_variables` array indices
3544
+ * to be used, according to the timeline's `sample` setting. If the timeline has no timeline
3545
+ * variables, returns `[null]`.
3546
+ */
2648
3547
  generateTimelineVariableOrder() {
2649
3548
  const timelineVariableLength = this.description.timeline_variables?.length;
2650
3549
  if (!timelineVariableLength) {
@@ -2671,7 +3570,8 @@ var jsPsychModule = (function (exports) {
2671
3570
  break;
2672
3571
  default:
2673
3572
  throw new Error(
2674
- `Invalid type "${sample.type}" in timeline sample parameters. Valid options for type are "custom", "with-replacement", "without-replacement", "fixed-repetitions", and "alternate-groups"`
3573
+ `Invalid type "${// @ts-expect-error TS doesn't have a type for `sample` in this case
3574
+ sample.type}" in timeline sample parameters. Valid options for type are "custom", "with-replacement", "without-replacement", "fixed-repetitions", and "alternate-groups"`
2675
3575
  );
2676
3576
  }
2677
3577
  }
@@ -2680,6 +3580,9 @@ var jsPsychModule = (function (exports) {
2680
3580
  }
2681
3581
  return order;
2682
3582
  }
3583
+ /**
3584
+ * Returns the current values of all timeline variables, including those from parent timelines
3585
+ */
2683
3586
  getAllTimelineVariables() {
2684
3587
  return this.currentTimelineVariables;
2685
3588
  }
@@ -2703,6 +3606,10 @@ var jsPsychModule = (function (exports) {
2703
3606
  }
2704
3607
  return results;
2705
3608
  }
3609
+ /**
3610
+ * Returns the naive progress of the timeline (as a fraction), without considering conditional or
3611
+ * loop functions.
3612
+ */
2706
3613
  getNaiveProgress() {
2707
3614
  if (this.status === TimelineNodeStatus.PENDING) {
2708
3615
  return 0;
@@ -2717,6 +3624,10 @@ var jsPsychModule = (function (exports) {
2717
3624
  }
2718
3625
  return Math.min(completedTrials / this.getNaiveTrialCount(), 1);
2719
3626
  }
3627
+ /**
3628
+ * Recursively computes the naive number of trials in the timeline, without considering
3629
+ * conditional or loop functions.
3630
+ */
2720
3631
  getNaiveTrialCount() {
2721
3632
  const getTrialCount = (description) => {
2722
3633
  const getTimelineArrayTrialCount = (description2) => description2.map((childDescription) => getTrialCount(childDescription)).reduce((a, b) => a + b);
@@ -2758,24 +3669,70 @@ var jsPsychModule = (function (exports) {
2758
3669
  }
2759
3670
 
2760
3671
  class JsPsych {
2761
- turk = turk;
2762
- randomization = randomization;
2763
- utils = utils;
2764
- data;
2765
- pluginAPI;
2766
- version() {
2767
- return _package.version;
2768
- }
2769
- options = {};
2770
- timeline;
2771
- displayContainerElement;
2772
- displayElement;
2773
- experimentStartTime;
2774
- isFileProtocolUsed = false;
2775
- simulationMode;
2776
- simulationOptions;
2777
- extensionManager;
2778
3672
  constructor(options) {
3673
+ this.turk = turk;
3674
+ this.randomization = randomization;
3675
+ this.utils = utils;
3676
+ // prettier-ignore
3677
+ this.citation = {
3678
+ "apa": "de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351 ",
3679
+ "bibtex": '@article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } '
3680
+ };
3681
+ /** Options */
3682
+ this.options = {};
3683
+ /**
3684
+ * Whether the page is retrieved directly via the `file://` protocol (true) or hosted on a web
3685
+ * server (false)
3686
+ */
3687
+ this.isFileProtocolUsed = false;
3688
+ this.finishTrialPromise = new PromiseWrapper();
3689
+ this.timelineDependencies = {
3690
+ onTrialStart: (trial) => {
3691
+ this.options.on_trial_start(trial.trialObject);
3692
+ this.getDisplayContainerElement().focus();
3693
+ this.getDisplayElement().scrollTop = 0;
3694
+ },
3695
+ onTrialResultAvailable: (trial) => {
3696
+ const result = trial.getResult();
3697
+ if (result) {
3698
+ result.time_elapsed = this.getTotalTime();
3699
+ this.data.write(trial);
3700
+ }
3701
+ },
3702
+ onTrialFinished: (trial) => {
3703
+ const result = trial.getResult();
3704
+ this.options.on_trial_finish(result);
3705
+ if (result) {
3706
+ this.options.on_data_update(result);
3707
+ }
3708
+ if (this.progressBar && this.options.auto_update_progress_bar) {
3709
+ this.progressBar.progress = this.timeline.getNaiveProgress();
3710
+ }
3711
+ },
3712
+ runOnStartExtensionCallbacks: (extensionsConfiguration) => this.extensionManager.onStart(extensionsConfiguration),
3713
+ runOnLoadExtensionCallbacks: (extensionsConfiguration) => this.extensionManager.onLoad(extensionsConfiguration),
3714
+ runOnFinishExtensionCallbacks: (extensionsConfiguration) => this.extensionManager.onFinish(extensionsConfiguration),
3715
+ getSimulationMode: () => this.simulationMode,
3716
+ getGlobalSimulationOptions: () => this.simulationOptions,
3717
+ instantiatePlugin: (pluginClass) => new pluginClass(this),
3718
+ getDisplayElement: () => this.getDisplayElement(),
3719
+ getDefaultIti: () => this.getInitSettings().default_iti,
3720
+ finishTrialPromise: this.finishTrialPromise,
3721
+ clearAllTimeouts: () => this.pluginAPI.clearAllTimeouts()
3722
+ };
3723
+ this.extensionManagerDependencies = {
3724
+ instantiateExtension: (extensionClass) => new extensionClass(this)
3725
+ };
3726
+ this.dataDependencies = {
3727
+ getProgress: () => ({
3728
+ time: this.getTotalTime(),
3729
+ trial: this.timeline?.getLatestNode().index ?? 0
3730
+ }),
3731
+ onInteractionRecordAdded: (record) => {
3732
+ this.options.on_interaction_data_update(record);
3733
+ },
3734
+ getDisplayElement: () => this.getDisplayElement()
3735
+ };
2779
3736
  options = {
2780
3737
  display_element: void 0,
2781
3738
  on_finish: () => {
@@ -2818,7 +3775,15 @@ var jsPsychModule = (function (exports) {
2818
3775
  options.extensions
2819
3776
  );
2820
3777
  }
2821
- endMessage;
3778
+ version() {
3779
+ return version;
3780
+ }
3781
+ /**
3782
+ * Starts an experiment using the provided timeline and returns a promise that is resolved when
3783
+ * the experiment is finished.
3784
+ *
3785
+ * @param timeline The timeline to be run
3786
+ */
2822
3787
  async run(timeline) {
2823
3788
  if (typeof timeline === "undefined") {
2824
3789
  console.error("No timeline declared in jsPsych.run(). Cannot start experiment.");
@@ -2832,7 +3797,7 @@ var jsPsychModule = (function (exports) {
2832
3797
  await this.prepareDom();
2833
3798
  await this.extensionManager.initializeExtensions();
2834
3799
  document.documentElement.setAttribute("jspsych", "present");
2835
- this.experimentStartTime = new Date();
3800
+ this.experimentStartTime = /* @__PURE__ */ new Date();
2836
3801
  await this.timeline.run();
2837
3802
  await Promise.resolve(this.options.on_finish(this.data.get()));
2838
3803
  if (this.endMessage) {
@@ -2845,7 +3810,6 @@ var jsPsychModule = (function (exports) {
2845
3810
  this.simulationOptions = simulation_options;
2846
3811
  await this.run(timeline);
2847
3812
  }
2848
- progressBar;
2849
3813
  getProgress() {
2850
3814
  return {
2851
3815
  total_trials: this.timeline?.getNaiveTrialCount(),
@@ -2860,7 +3824,7 @@ var jsPsychModule = (function (exports) {
2860
3824
  if (!this.experimentStartTime) {
2861
3825
  return 0;
2862
3826
  }
2863
- return new Date().getTime() - this.experimentStartTime.getTime();
3827
+ return (/* @__PURE__ */ new Date()).getTime() - this.experimentStartTime.getTime();
2864
3828
  }
2865
3829
  getDisplayElement() {
2866
3830
  return this.displayElement;
@@ -2884,6 +3848,11 @@ var jsPsychModule = (function (exports) {
2884
3848
  currentTimeline.abort();
2885
3849
  }
2886
3850
  }
3851
+ /**
3852
+ * Aborts a named timeline. The timeline must be currently running in order to abort it.
3853
+ *
3854
+ * @param name The name of the timeline to abort. Timelines can be given names by setting the `name` parameter in the description of the timeline.
3855
+ */
2887
3856
  abortTimelineByName(name) {
2888
3857
  const timeline = this.timeline?.getActiveTimelineByName(name);
2889
3858
  if (timeline) {
@@ -2918,6 +3887,36 @@ var jsPsychModule = (function (exports) {
2918
3887
  getTimeline() {
2919
3888
  return this.timeline?.description.timeline;
2920
3889
  }
3890
+ /**
3891
+ * Prints out a string containing citations for the jsPsych library and all input plugins/extensions in the specified format.
3892
+ * If called without input, prints citation for jsPsych library.
3893
+ *
3894
+ * @param plugins The plugins/extensions to generate citations for. Always prints the citation for the jsPsych library at the top.
3895
+ * @param format The desired output citation format. Currently supports "apa" and "bibtex".
3896
+ * @returns String containing citations separated with newline character.
3897
+ */
3898
+ getCitations(plugins = [], format = "apa") {
3899
+ const formatOptions = ["apa", "bibtex"];
3900
+ format = format.toLowerCase();
3901
+ if (!Array.isArray(plugins)) {
3902
+ throw new Error("Expected array of plugins/extensions");
3903
+ } else if (!formatOptions.includes(format)) {
3904
+ throw new Error("Unsupported citation format");
3905
+ } else {
3906
+ const jsPsychCitation = this.citation[format];
3907
+ const citationSet = /* @__PURE__ */ new Set([jsPsychCitation]);
3908
+ for (const plugin of plugins) {
3909
+ try {
3910
+ const pluginCitation = plugin["info"].citations[format];
3911
+ citationSet.add(pluginCitation);
3912
+ } catch {
3913
+ console.error(`${plugin} does not have citation in ${format} format.`);
3914
+ }
3915
+ }
3916
+ const citationList = Array.from(citationSet).join("\n");
3917
+ return citationList;
3918
+ }
3919
+ }
2921
3920
  get extensions() {
2922
3921
  return this.extensionManager?.extensions ?? {};
2923
3922
  }
@@ -2970,57 +3969,9 @@ var jsPsychModule = (function (exports) {
2970
3969
  this.getDisplayContainerElement().insertAdjacentElement("afterbegin", progressBarContainer);
2971
3970
  }
2972
3971
  }
2973
- finishTrialPromise = new PromiseWrapper();
2974
3972
  finishTrial(data) {
2975
3973
  this.finishTrialPromise.resolve(data);
2976
3974
  }
2977
- timelineDependencies = {
2978
- onTrialStart: (trial) => {
2979
- this.options.on_trial_start(trial.trialObject);
2980
- this.getDisplayContainerElement().focus();
2981
- this.getDisplayElement().scrollTop = 0;
2982
- },
2983
- onTrialResultAvailable: (trial) => {
2984
- const result = trial.getResult();
2985
- if (result) {
2986
- result.time_elapsed = this.getTotalTime();
2987
- this.data.write(trial);
2988
- }
2989
- },
2990
- onTrialFinished: (trial) => {
2991
- const result = trial.getResult();
2992
- this.options.on_trial_finish(result);
2993
- if (result) {
2994
- this.options.on_data_update(result);
2995
- }
2996
- if (this.progressBar && this.options.auto_update_progress_bar) {
2997
- this.progressBar.progress = this.timeline.getNaiveProgress();
2998
- }
2999
- },
3000
- runOnStartExtensionCallbacks: (extensionsConfiguration) => this.extensionManager.onStart(extensionsConfiguration),
3001
- runOnLoadExtensionCallbacks: (extensionsConfiguration) => this.extensionManager.onLoad(extensionsConfiguration),
3002
- runOnFinishExtensionCallbacks: (extensionsConfiguration) => this.extensionManager.onFinish(extensionsConfiguration),
3003
- getSimulationMode: () => this.simulationMode,
3004
- getGlobalSimulationOptions: () => this.simulationOptions,
3005
- instantiatePlugin: (pluginClass) => new pluginClass(this),
3006
- getDisplayElement: () => this.getDisplayElement(),
3007
- getDefaultIti: () => this.getInitSettings().default_iti,
3008
- finishTrialPromise: this.finishTrialPromise,
3009
- clearAllTimeouts: () => this.pluginAPI.clearAllTimeouts()
3010
- };
3011
- extensionManagerDependencies = {
3012
- instantiateExtension: (extensionClass) => new extensionClass(this)
3013
- };
3014
- dataDependencies = {
3015
- getProgress: () => ({
3016
- time: this.getTotalTime(),
3017
- trial: this.timeline?.getLatestNode().index ?? 0
3018
- }),
3019
- onInteractionRecordAdded: (record) => {
3020
- this.options.on_interaction_data_update(record);
3021
- },
3022
- getDisplayElement: () => this.getDisplayElement()
3023
- };
3024
3975
  }
3025
3976
 
3026
3977
  class MigrationError extends Error {
@@ -3066,6 +4017,7 @@ var jsPsychModule = (function (exports) {
3066
4017
  init: "`jsPsych.init()` was replaced by `initJsPsych()` in jsPsych v7.",
3067
4018
  ALL_KEYS: 'jsPsych.ALL_KEYS was replaced by the "ALL_KEYS" string in jsPsych v7.',
3068
4019
  NO_KEYS: 'jsPsych.NO_KEYS was replaced by the "NO_KEYS" string in jsPsych v7.',
4020
+ // Getter functions that were renamed
3069
4021
  currentTimelineNodeID: "`currentTimelineNodeID()` was renamed to `getCurrentTimelineNodeID()` in jsPsych v7.",
3070
4022
  progress: "`progress()` was renamed to `getProgress()` in jsPsych v7.",
3071
4023
  startTime: "`startTime()` was renamed to `getStartTime()` in jsPsych v7.",
@@ -3099,4 +4051,4 @@ var jsPsychModule = (function (exports) {
3099
4051
 
3100
4052
  })({});
3101
4053
  var initJsPsych = jsPsychModule.initJsPsych;
3102
- //# sourceMappingURL=https://unpkg.com/jspsych@8.1.0/dist/index.browser.js.map
4054
+ //# sourceMappingURL=https://unpkg.com/jspsych@8.2.1/dist/index.browser.js.map