jspsych 6.3.1 → 7.1.2
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.
- package/README.md +36 -37
- package/css/jspsych.css +39 -39
- package/dist/JsPsych.d.ts +112 -0
- package/dist/TimelineNode.d.ts +34 -0
- package/dist/index.browser.js +3171 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.browser.min.js +2 -0
- package/dist/index.browser.min.js.map +1 -0
- package/dist/index.cjs +3165 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +3159 -0
- package/dist/index.js.map +1 -0
- package/dist/migration.d.ts +3 -0
- package/dist/modules/data/DataCollection.d.ts +45 -0
- package/dist/modules/data/DataColumn.d.ts +15 -0
- package/dist/modules/data/index.d.ts +25 -0
- package/dist/modules/data/utils.d.ts +3 -0
- package/dist/modules/extensions.d.ts +22 -0
- package/dist/modules/plugin-api/HardwareAPI.d.ts +15 -0
- package/dist/modules/plugin-api/KeyboardListenerAPI.d.ts +34 -0
- package/dist/modules/plugin-api/MediaAPI.d.ts +27 -0
- package/dist/modules/plugin-api/SimulationAPI.d.ts +41 -0
- package/dist/modules/plugin-api/TimeoutAPI.d.ts +5 -0
- package/dist/modules/plugin-api/index.d.ts +8 -0
- package/dist/modules/plugins.d.ts +136 -0
- package/dist/modules/randomization.d.ts +35 -0
- package/dist/modules/turk.d.ts +40 -0
- package/dist/modules/utils.d.ts +7 -0
- package/package.json +32 -15
- package/src/JsPsych.ts +884 -0
- package/src/TimelineNode.ts +536 -0
- package/src/index.ts +71 -0
- package/src/migration.ts +37 -0
- package/src/modules/data/DataCollection.ts +198 -0
- package/src/modules/data/DataColumn.ts +86 -0
- package/src/modules/data/index.ts +174 -0
- package/src/modules/data/utils.ts +75 -0
- package/src/modules/extensions.ts +23 -0
- package/src/modules/plugin-api/HardwareAPI.ts +32 -0
- package/src/modules/plugin-api/KeyboardListenerAPI.ts +165 -0
- package/src/modules/plugin-api/MediaAPI.ts +337 -0
- package/src/modules/plugin-api/SimulationAPI.ts +181 -0
- package/src/modules/plugin-api/TimeoutAPI.ts +16 -0
- package/src/modules/plugin-api/index.ts +28 -0
- package/src/modules/plugins.ts +165 -0
- package/src/modules/randomization.ts +327 -0
- package/src/modules/turk.ts +99 -0
- package/src/modules/utils.ts +30 -0
- package/.github/workflows/jest.yml +0 -20
- package/code-of-conduct.md +0 -56
- package/contributors.md +0 -61
- package/docs/CNAME +0 -1
- package/docs/about/about.md +0 -18
- package/docs/about/contributing.md +0 -43
- package/docs/about/license.md +0 -25
- package/docs/about/support.md +0 -7
- package/docs/core_library/jspsych-core.md +0 -719
- package/docs/core_library/jspsych-data.md +0 -587
- package/docs/core_library/jspsych-pluginAPI.md +0 -624
- package/docs/core_library/jspsych-randomization.md +0 -389
- package/docs/core_library/jspsych-turk.md +0 -98
- package/docs/extensions/extensions.md +0 -83
- package/docs/extensions/jspsych-ext-webgazer.md +0 -137
- package/docs/img/blue.png +0 -0
- package/docs/img/devtools-change-css.png +0 -0
- package/docs/img/devtools-css-errors.png +0 -0
- package/docs/img/devtools-inspect-element.png +0 -0
- package/docs/img/folder-setup.png +0 -0
- package/docs/img/folder-with-html.png +0 -0
- package/docs/img/githubreleases.jpg +0 -0
- package/docs/img/jspsych-favicon.png +0 -0
- package/docs/img/jspsych-logo-no-text-mono.svg +0 -493
- package/docs/img/jspsych-logo.jpg +0 -0
- package/docs/img/orange.png +0 -0
- package/docs/img/palmer_stim.png +0 -0
- package/docs/img/progress_bar.png +0 -0
- package/docs/img/prolific-study-completion.png +0 -0
- package/docs/img/prolific-study-link.png +0 -0
- package/docs/img/visual_search_example.jpg +0 -0
- package/docs/index.md +0 -9
- package/docs/overview/browser-device-support.md +0 -35
- package/docs/overview/callbacks.md +0 -180
- package/docs/overview/data.md +0 -281
- package/docs/overview/dynamic-parameters.md +0 -147
- package/docs/overview/exclude-browser.md +0 -32
- package/docs/overview/experiment-options.md +0 -149
- package/docs/overview/eye-tracking.md +0 -271
- package/docs/overview/fullscreen.md +0 -36
- package/docs/overview/media-preloading.md +0 -369
- package/docs/overview/mturk.md +0 -77
- package/docs/overview/plugins.md +0 -320
- package/docs/overview/progress-bar.md +0 -110
- package/docs/overview/prolific.md +0 -78
- package/docs/overview/record-browser-interactions.md +0 -23
- package/docs/overview/running-experiments.md +0 -95
- package/docs/overview/style.md +0 -293
- package/docs/overview/timeline.md +0 -457
- package/docs/plugins/jspsych-animation.md +0 -40
- package/docs/plugins/jspsych-audio-button-response.md +0 -60
- package/docs/plugins/jspsych-audio-keyboard-response.md +0 -58
- package/docs/plugins/jspsych-audio-slider-response.md +0 -53
- package/docs/plugins/jspsych-call-function.md +0 -81
- package/docs/plugins/jspsych-canvas-button-response.md +0 -66
- package/docs/plugins/jspsych-canvas-keyboard-response.md +0 -68
- package/docs/plugins/jspsych-canvas-slider-response.md +0 -89
- package/docs/plugins/jspsych-categorize-animation.md +0 -60
- package/docs/plugins/jspsych-categorize-html.md +0 -53
- package/docs/plugins/jspsych-categorize-image.md +0 -53
- package/docs/plugins/jspsych-cloze.md +0 -45
- package/docs/plugins/jspsych-external-html.md +0 -70
- package/docs/plugins/jspsych-free-sort.md +0 -56
- package/docs/plugins/jspsych-fullscreen.md +0 -57
- package/docs/plugins/jspsych-html-button-response.md +0 -42
- package/docs/plugins/jspsych-html-keyboard-response.md +0 -51
- package/docs/plugins/jspsych-html-slider-response.md +0 -45
- package/docs/plugins/jspsych-iat-html.md +0 -64
- package/docs/plugins/jspsych-iat-image.md +0 -64
- package/docs/plugins/jspsych-image-button-response.md +0 -48
- package/docs/plugins/jspsych-image-keyboard-response.md +0 -58
- package/docs/plugins/jspsych-image-slider-response.md +0 -54
- package/docs/plugins/jspsych-instructions.md +0 -58
- package/docs/plugins/jspsych-maxdiff.md +0 -41
- package/docs/plugins/jspsych-preload.md +0 -128
- package/docs/plugins/jspsych-rdk.md +0 -119
- package/docs/plugins/jspsych-reconstruction.md +0 -48
- package/docs/plugins/jspsych-resize.md +0 -39
- package/docs/plugins/jspsych-same-different-html.md +0 -53
- package/docs/plugins/jspsych-same-different-image.md +0 -66
- package/docs/plugins/jspsych-serial-reaction-time-mouse.md +0 -52
- package/docs/plugins/jspsych-serial-reaction-time.md +0 -57
- package/docs/plugins/jspsych-survey-html-form.md +0 -50
- package/docs/plugins/jspsych-survey-likert.md +0 -70
- package/docs/plugins/jspsych-survey-multi-choice.md +0 -48
- package/docs/plugins/jspsych-survey-multi-select.md +0 -53
- package/docs/plugins/jspsych-survey-text.md +0 -63
- package/docs/plugins/jspsych-video-button-response.md +0 -54
- package/docs/plugins/jspsych-video-keyboard-response.md +0 -50
- package/docs/plugins/jspsych-video-slider-response.md +0 -60
- package/docs/plugins/jspsych-virtual-chinrest.md +0 -105
- package/docs/plugins/jspsych-visual-search-circle.md +0 -52
- package/docs/plugins/jspsych-vsl-animate-occlusion.md +0 -55
- package/docs/plugins/jspsych-vsl-grid-scene.md +0 -62
- package/docs/plugins/jspsych-webgazer-calibrate.md +0 -61
- package/docs/plugins/jspsych-webgazer-init-camera.md +0 -30
- package/docs/plugins/jspsych-webgazer-validate.md +0 -44
- package/docs/plugins/list-of-plugins.md +0 -54
- package/docs/tutorials/hello-world.md +0 -162
- package/docs/tutorials/rt-task.md +0 -1334
- package/docs/tutorials/video-tutorials.md +0 -11
- package/examples/add-to-end-of-timeline.html +0 -38
- package/examples/case-sensitive-responses.html +0 -45
- package/examples/conditional-and-loop-functions.html +0 -64
- package/examples/css/jquery-ui.css +0 -1225
- package/examples/css-classes-parameter.html +0 -145
- package/examples/data-add-properties.html +0 -44
- package/examples/data-as-function.html +0 -39
- package/examples/data-from-timeline.html +0 -52
- package/examples/data-from-url.html +0 -21
- package/examples/demo-flanker.html +0 -117
- package/examples/demo-simple-rt-task.html +0 -120
- package/examples/demos/demo_1.html +0 -35
- package/examples/demos/demo_2.html +0 -50
- package/examples/demos/demo_3.html +0 -63
- package/examples/display-element-to-embed-experiment.html +0 -79
- package/examples/end-active-node.html +0 -52
- package/examples/end-experiment.html +0 -45
- package/examples/exclusions.html +0 -32
- package/examples/external_html/simple_consent.html +0 -4
- package/examples/img/1.gif +0 -0
- package/examples/img/10.gif +0 -0
- package/examples/img/11.gif +0 -0
- package/examples/img/12.gif +0 -0
- package/examples/img/2.gif +0 -0
- package/examples/img/3.gif +0 -0
- package/examples/img/4.gif +0 -0
- package/examples/img/5.gif +0 -0
- package/examples/img/6.gif +0 -0
- package/examples/img/7.gif +0 -0
- package/examples/img/8.gif +0 -0
- package/examples/img/9.gif +0 -0
- package/examples/img/age/of1.jpg +0 -0
- package/examples/img/age/of2.jpg +0 -0
- package/examples/img/age/of3.jpg +0 -0
- package/examples/img/age/om1.jpg +0 -0
- package/examples/img/age/om2.jpg +0 -0
- package/examples/img/age/om3.jpg +0 -0
- package/examples/img/age/yf1.jpg +0 -0
- package/examples/img/age/yf4.jpg +0 -0
- package/examples/img/age/yf5.jpg +0 -0
- package/examples/img/age/ym2.jpg +0 -0
- package/examples/img/age/ym3.jpg +0 -0
- package/examples/img/age/ym5.jpg +0 -0
- package/examples/img/backwardN.gif +0 -0
- package/examples/img/blue.png +0 -0
- package/examples/img/card.png +0 -0
- package/examples/img/con1.png +0 -0
- package/examples/img/con2.png +0 -0
- package/examples/img/fixation.gif +0 -0
- package/examples/img/happy_face_1.jpg +0 -0
- package/examples/img/happy_face_2.jpg +0 -0
- package/examples/img/happy_face_3.jpg +0 -0
- package/examples/img/happy_face_4.jpg +0 -0
- package/examples/img/inc1.png +0 -0
- package/examples/img/inc2.png +0 -0
- package/examples/img/normalN.gif +0 -0
- package/examples/img/orange.png +0 -0
- package/examples/img/redX.png +0 -0
- package/examples/img/ribbon.jpg +0 -0
- package/examples/img/sad_face_1.jpg +0 -0
- package/examples/img/sad_face_2.jpg +0 -0
- package/examples/img/sad_face_3.jpg +0 -0
- package/examples/img/sad_face_4.jpg +0 -0
- package/examples/js/snap.svg-min.js +0 -21
- package/examples/js/webgazer/ridgeWorker.mjs +0 -135
- package/examples/js/webgazer/webgazer.js +0 -88909
- package/examples/js/webgazer/worker_scripts/mat.js +0 -306
- package/examples/js/webgazer/worker_scripts/util.js +0 -398
- package/examples/jspsych-RDK.html +0 -58
- package/examples/jspsych-animation.html +0 -39
- package/examples/jspsych-audio-button-response.html +0 -58
- package/examples/jspsych-audio-keyboard-response.html +0 -68
- package/examples/jspsych-audio-slider-response.html +0 -61
- package/examples/jspsych-call-function.html +0 -32
- package/examples/jspsych-canvas-button-response.html +0 -95
- package/examples/jspsych-canvas-keyboard-response.html +0 -78
- package/examples/jspsych-canvas-slider-response.html +0 -67
- package/examples/jspsych-categorize-animation.html +0 -49
- package/examples/jspsych-categorize-html.html +0 -33
- package/examples/jspsych-categorize-image.html +0 -44
- package/examples/jspsych-cloze.html +0 -37
- package/examples/jspsych-free-sort.html +0 -109
- package/examples/jspsych-fullscreen.html +0 -45
- package/examples/jspsych-html-button-response.html +0 -43
- package/examples/jspsych-html-keyboard-response.html +0 -42
- package/examples/jspsych-html-slider-response.html +0 -53
- package/examples/jspsych-iat.html +0 -520
- package/examples/jspsych-image-button-response.html +0 -91
- package/examples/jspsych-image-keyboard-response.html +0 -85
- package/examples/jspsych-image-slider-response.html +0 -85
- package/examples/jspsych-instructions.html +0 -37
- package/examples/jspsych-maxdiff.html +0 -33
- package/examples/jspsych-preload.html +0 -140
- package/examples/jspsych-reconstruction.html +0 -43
- package/examples/jspsych-resize.html +0 -34
- package/examples/jspsych-same-different-html.html +0 -28
- package/examples/jspsych-same-different-image.html +0 -39
- package/examples/jspsych-serial-reaction-time-mouse.html +0 -98
- package/examples/jspsych-serial-reaction-time.html +0 -54
- package/examples/jspsych-survey-html-form.html +0 -33
- package/examples/jspsych-survey-likert.html +0 -42
- package/examples/jspsych-survey-multi-choice.html +0 -40
- package/examples/jspsych-survey-multi-select.html +0 -42
- package/examples/jspsych-survey-text.html +0 -34
- package/examples/jspsych-video-button-response.html +0 -65
- package/examples/jspsych-video-keyboard-response.html +0 -61
- package/examples/jspsych-video-slider-response.html +0 -63
- package/examples/jspsych-virtual-chinrest.html +0 -69
- package/examples/jspsych-visual-search-circle.html +0 -64
- package/examples/jspsych-vsl-animate-occlusion.html +0 -35
- package/examples/jspsych-vsl-grid-scene.html +0 -47
- package/examples/lexical-decision.html +0 -134
- package/examples/manual-preloading.html +0 -59
- package/examples/pause-unpause.html +0 -33
- package/examples/progress-bar.html +0 -68
- package/examples/save-trial-parameters.html +0 -98
- package/examples/sound/hammer.mp3 +0 -0
- package/examples/sound/sound.mp3 +0 -0
- package/examples/sound/speech_blue.mp3 +0 -0
- package/examples/sound/speech_green.mp3 +0 -0
- package/examples/sound/speech_joke.mp3 +0 -0
- package/examples/sound/speech_red.mp3 +0 -0
- package/examples/sound/tone.mp3 +0 -0
- package/examples/timeline-variables-sampling.html +0 -50
- package/examples/timeline-variables.html +0 -64
- package/examples/video/sample_video.mp4 +0 -0
- package/examples/webgazer.html +0 -174
- package/examples/webgazer_audio.html +0 -90
- package/examples/webgazer_image.html +0 -60
- package/extensions/jspsych-ext-webgazer.js +0 -265
- package/jspsych.js +0 -3023
- package/license.txt +0 -21
- package/mkdocs.yml +0 -118
- package/plugins/jspsych-animation.js +0 -189
- package/plugins/jspsych-audio-button-response.js +0 -269
- package/plugins/jspsych-audio-keyboard-response.js +0 -209
- package/plugins/jspsych-audio-slider-response.js +0 -278
- package/plugins/jspsych-call-function.js +0 -58
- package/plugins/jspsych-canvas-button-response.js +0 -199
- package/plugins/jspsych-canvas-keyboard-response.js +0 -155
- package/plugins/jspsych-canvas-slider-response.js +0 -207
- package/plugins/jspsych-categorize-animation.js +0 -266
- package/plugins/jspsych-categorize-html.js +0 -220
- package/plugins/jspsych-categorize-image.js +0 -222
- package/plugins/jspsych-cloze.js +0 -112
- package/plugins/jspsych-external-html.js +0 -112
- package/plugins/jspsych-free-sort.js +0 -478
- package/plugins/jspsych-fullscreen.js +0 -106
- package/plugins/jspsych-html-button-response.js +0 -188
- package/plugins/jspsych-html-keyboard-response.js +0 -149
- package/plugins/jspsych-html-slider-response.js +0 -202
- package/plugins/jspsych-iat-html.js +0 -284
- package/plugins/jspsych-iat-image.js +0 -286
- package/plugins/jspsych-image-button-response.js +0 -327
- package/plugins/jspsych-image-keyboard-response.js +0 -263
- package/plugins/jspsych-image-slider-response.js +0 -369
- package/plugins/jspsych-instructions.js +0 -237
- package/plugins/jspsych-maxdiff.js +0 -173
- package/plugins/jspsych-preload.js +0 -345
- package/plugins/jspsych-rdk.js +0 -1373
- package/plugins/jspsych-reconstruction.js +0 -134
- package/plugins/jspsych-resize.js +0 -166
- package/plugins/jspsych-same-different-html.js +0 -168
- package/plugins/jspsych-same-different-image.js +0 -169
- package/plugins/jspsych-serial-reaction-time-mouse.js +0 -212
- package/plugins/jspsych-serial-reaction-time.js +0 -247
- package/plugins/jspsych-survey-html-form.js +0 -171
- package/plugins/jspsych-survey-likert.js +0 -195
- package/plugins/jspsych-survey-multi-choice.js +0 -208
- package/plugins/jspsych-survey-multi-select.js +0 -232
- package/plugins/jspsych-survey-text.js +0 -185
- package/plugins/jspsych-video-button-response.js +0 -335
- package/plugins/jspsych-video-keyboard-response.js +0 -279
- package/plugins/jspsych-video-slider-response.js +0 -351
- package/plugins/jspsych-virtual-chinrest.js +0 -471
- package/plugins/jspsych-visual-search-circle.js +0 -259
- package/plugins/jspsych-vsl-animate-occlusion.js +0 -196
- package/plugins/jspsych-vsl-grid-scene.js +0 -103
- package/plugins/jspsych-webgazer-calibrate.js +0 -161
- package/plugins/jspsych-webgazer-init-camera.js +0 -139
- package/plugins/jspsych-webgazer-validate.js +0 -314
- package/plugins/template/jspsych-plugin-template.js +0 -35
- package/tests/README.md +0 -7
- package/tests/jsPsych/case-sensitive-responses.test.js +0 -53
- package/tests/jsPsych/css-classes-parameter.test.js +0 -107
- package/tests/jsPsych/default-iti.test.js +0 -51
- package/tests/jsPsych/default-parameters.test.js +0 -58
- package/tests/jsPsych/endexperiment.test.js +0 -49
- package/tests/jsPsych/events.test.js +0 -606
- package/tests/jsPsych/functions-as-parameters.test.js +0 -210
- package/tests/jsPsych/init.test.js +0 -48
- package/tests/jsPsych/loads.test.js +0 -7
- package/tests/jsPsych/min-rt.test.js +0 -58
- package/tests/jsPsych/progressbar.test.js +0 -202
- package/tests/jsPsych/timeline-variables.test.js +0 -531
- package/tests/jsPsych/timelines.test.js +0 -569
- package/tests/jsPsych.data/data-csv-conversion.test.js +0 -85
- package/tests/jsPsych.data/data-json-conversion.test.js +0 -120
- package/tests/jsPsych.data/datacollection.test.js +0 -117
- package/tests/jsPsych.data/datacolumn.test.js +0 -50
- package/tests/jsPsych.data/datamodule.test.js +0 -152
- package/tests/jsPsych.data/dataparameter.test.js +0 -251
- package/tests/jsPsych.data/interactions.test.js +0 -109
- package/tests/jsPsych.data/trialparameters.test.js +0 -175
- package/tests/jsPsych.extensions/extensions.test.js +0 -207
- package/tests/jsPsych.extensions/test-extension.js +0 -42
- package/tests/jsPsych.pluginAPI/pluginapi.test.js +0 -365
- package/tests/jsPsych.pluginAPI/preloads.test.js +0 -43
- package/tests/jsPsych.randomization/randomziation.test.js +0 -27
- package/tests/jsPsych.utils/utils.test.js +0 -58
- package/tests/plugins/plugin-animation.test.js +0 -34
- package/tests/plugins/plugin-audio-button-response.test.js +0 -15
- package/tests/plugins/plugin-audio-keyboard-response.test.js +0 -15
- package/tests/plugins/plugin-audio-slider-response.test.js +0 -15
- package/tests/plugins/plugin-call-function.test.js +0 -49
- package/tests/plugins/plugin-categorize-animation.test.js +0 -263
- package/tests/plugins/plugin-categorize-html.test.js +0 -17
- package/tests/plugins/plugin-categorize-image.test.js +0 -17
- package/tests/plugins/plugin-cloze.test.js +0 -157
- package/tests/plugins/plugin-free-sort.test.js +0 -106
- package/tests/plugins/plugin-fullscreen.test.js +0 -41
- package/tests/plugins/plugin-html-button-response.test.js +0 -161
- package/tests/plugins/plugin-html-keyboard-response.test.js +0 -139
- package/tests/plugins/plugin-html-slider-response.test.js +0 -155
- package/tests/plugins/plugin-iat-html.test.js +0 -299
- package/tests/plugins/plugin-iat-image.test.js +0 -298
- package/tests/plugins/plugin-image-button-response.test.js +0 -174
- package/tests/plugins/plugin-image-keyboard-response.test.js +0 -147
- package/tests/plugins/plugin-image-slider-response.test.js +0 -174
- package/tests/plugins/plugin-instructions.test.js +0 -85
- package/tests/plugins/plugin-maxdiff.test.js +0 -39
- package/tests/plugins/plugin-preload.test.js +0 -916
- package/tests/plugins/plugin-rdk.test.js +0 -61
- package/tests/plugins/plugin-reconstruction.test.js +0 -16
- package/tests/plugins/plugin-resize.test.js +0 -16
- package/tests/plugins/plugin-same-different-html.test.js +0 -17
- package/tests/plugins/plugin-same-different-image.test.js +0 -17
- package/tests/plugins/plugin-serial-reaction-time-mouse.test.js +0 -42
- package/tests/plugins/plugin-serial-reaction-time.test.js +0 -109
- package/tests/plugins/plugin-survey-html-form.test.js +0 -44
- package/tests/plugins/plugin-survey-likert.test.js +0 -48
- package/tests/plugins/plugin-survey-multi-choice.test.js +0 -47
- package/tests/plugins/plugin-survey-multi-select.test.js +0 -71
- package/tests/plugins/plugin-survey-text.test.js +0 -115
- package/tests/plugins/plugin-video-button-response.test.js +0 -32
- package/tests/plugins/plugin-video-keyboard-response.test.js +0 -32
- package/tests/plugins/plugin-video-slider-response.test.js +0 -31
- package/tests/plugins/plugin-visual-search-circle.test.js +0 -16
- package/tests/plugins/plugin-vsl-animate-occlusion.test.js +0 -16
- package/tests/plugins/plugin-vsl-grid-scene.test.js +0 -16
- package/tests/testing-utils.js +0 -13
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import autoBind from "auto-bind";
|
|
2
|
+
|
|
3
|
+
import { JsPsych } from "../../JsPsych";
|
|
4
|
+
import { HardwareAPI } from "./HardwareAPI";
|
|
5
|
+
import { KeyboardListenerAPI } from "./KeyboardListenerAPI";
|
|
6
|
+
import { MediaAPI } from "./MediaAPI";
|
|
7
|
+
import { SimulationAPI } from "./SimulationAPI";
|
|
8
|
+
import { TimeoutAPI } from "./TimeoutAPI";
|
|
9
|
+
|
|
10
|
+
export function createJointPluginAPIObject(jsPsych: JsPsych) {
|
|
11
|
+
const settings = jsPsych.getInitSettings();
|
|
12
|
+
return Object.assign(
|
|
13
|
+
{},
|
|
14
|
+
...[
|
|
15
|
+
new KeyboardListenerAPI(
|
|
16
|
+
jsPsych.getDisplayContainerElement,
|
|
17
|
+
settings.case_sensitive_responses,
|
|
18
|
+
settings.minimum_valid_rt
|
|
19
|
+
),
|
|
20
|
+
new TimeoutAPI(),
|
|
21
|
+
new MediaAPI(settings.use_webaudio, jsPsych.webaudio_context),
|
|
22
|
+
new HardwareAPI(),
|
|
23
|
+
new SimulationAPI(),
|
|
24
|
+
].map((object) => autoBind(object))
|
|
25
|
+
) as KeyboardListenerAPI & TimeoutAPI & MediaAPI & HardwareAPI & SimulationAPI;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type PluginAPI = ReturnType<typeof createJointPluginAPIObject>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Flatten the type output to improve type hints shown in editors.
|
|
3
|
+
Borrowed from type-fest
|
|
4
|
+
*/
|
|
5
|
+
type Simplify<T> = { [KeyType in keyof T]: T[KeyType] };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
Create a type that makes the given keys required. The remaining keys are kept as is.
|
|
9
|
+
Borrowed from type-fest
|
|
10
|
+
*/
|
|
11
|
+
type SetRequired<BaseType, Keys extends keyof BaseType> = Simplify<
|
|
12
|
+
Omit<BaseType, Keys> & Required<Pick<BaseType, Keys>>
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parameter types for plugins
|
|
17
|
+
*/
|
|
18
|
+
export enum ParameterType {
|
|
19
|
+
BOOL,
|
|
20
|
+
STRING,
|
|
21
|
+
INT,
|
|
22
|
+
FLOAT,
|
|
23
|
+
FUNCTION,
|
|
24
|
+
KEY,
|
|
25
|
+
KEYS,
|
|
26
|
+
SELECT,
|
|
27
|
+
HTML_STRING,
|
|
28
|
+
IMAGE,
|
|
29
|
+
AUDIO,
|
|
30
|
+
VIDEO,
|
|
31
|
+
OBJECT,
|
|
32
|
+
COMPLEX,
|
|
33
|
+
TIMELINE,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type ParameterTypeMap = {
|
|
37
|
+
[ParameterType.BOOL]: boolean;
|
|
38
|
+
[ParameterType.STRING]: string;
|
|
39
|
+
[ParameterType.INT]: number;
|
|
40
|
+
[ParameterType.FLOAT]: number;
|
|
41
|
+
[ParameterType.FUNCTION]: (...args: any[]) => any;
|
|
42
|
+
[ParameterType.KEY]: string;
|
|
43
|
+
[ParameterType.KEYS]: string[] | "ALL_KEYS" | "NO_KEYS";
|
|
44
|
+
[ParameterType.SELECT]: any;
|
|
45
|
+
[ParameterType.HTML_STRING]: string;
|
|
46
|
+
[ParameterType.IMAGE]: string;
|
|
47
|
+
[ParameterType.AUDIO]: string;
|
|
48
|
+
[ParameterType.VIDEO]: string;
|
|
49
|
+
[ParameterType.OBJECT]: object;
|
|
50
|
+
[ParameterType.COMPLEX]: any;
|
|
51
|
+
[ParameterType.TIMELINE]: any;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export interface ParameterInfo {
|
|
55
|
+
type: ParameterType;
|
|
56
|
+
array?: boolean;
|
|
57
|
+
pretty_name?: string;
|
|
58
|
+
default?: any;
|
|
59
|
+
preload?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ParameterInfos {
|
|
63
|
+
[key: string]: ParameterInfo;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type InferredParameter<I extends ParameterInfo> = I["array"] extends true
|
|
67
|
+
? Array<ParameterTypeMap[I["type"]]>
|
|
68
|
+
: ParameterTypeMap[I["type"]];
|
|
69
|
+
|
|
70
|
+
type RequiredParameterNames<I extends ParameterInfos> = {
|
|
71
|
+
[K in keyof I]: I[K]["default"] extends undefined ? K : never;
|
|
72
|
+
}[keyof I];
|
|
73
|
+
|
|
74
|
+
type InferredParameters<I extends ParameterInfos> = SetRequired<
|
|
75
|
+
{
|
|
76
|
+
[Property in keyof I]?: InferredParameter<I[Property]>;
|
|
77
|
+
},
|
|
78
|
+
RequiredParameterNames<I>
|
|
79
|
+
>;
|
|
80
|
+
|
|
81
|
+
export const universalPluginParameters = <const>{
|
|
82
|
+
/**
|
|
83
|
+
* Data to add to this trial (key-value pairs)
|
|
84
|
+
*/
|
|
85
|
+
data: {
|
|
86
|
+
type: ParameterType.OBJECT,
|
|
87
|
+
pretty_name: "Data",
|
|
88
|
+
default: {},
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* Function to execute when trial begins
|
|
92
|
+
*/
|
|
93
|
+
on_start: {
|
|
94
|
+
type: ParameterType.FUNCTION,
|
|
95
|
+
pretty_name: "On start",
|
|
96
|
+
default: function () {
|
|
97
|
+
return;
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
/**
|
|
101
|
+
* Function to execute when trial is finished
|
|
102
|
+
*/
|
|
103
|
+
on_finish: {
|
|
104
|
+
type: ParameterType.FUNCTION,
|
|
105
|
+
pretty_name: "On finish",
|
|
106
|
+
default: function () {
|
|
107
|
+
return;
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* Function to execute after the trial has loaded
|
|
112
|
+
*/
|
|
113
|
+
on_load: {
|
|
114
|
+
type: ParameterType.FUNCTION,
|
|
115
|
+
pretty_name: "On load",
|
|
116
|
+
default: function () {
|
|
117
|
+
return;
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
/**
|
|
121
|
+
* Length of gap between the end of this trial and the start of the next trial
|
|
122
|
+
*/
|
|
123
|
+
post_trial_gap: {
|
|
124
|
+
type: ParameterType.INT,
|
|
125
|
+
pretty_name: "Post trial gap",
|
|
126
|
+
default: null,
|
|
127
|
+
},
|
|
128
|
+
/**
|
|
129
|
+
* A list of CSS classes to add to the jsPsych display element for the duration of this trial
|
|
130
|
+
*/
|
|
131
|
+
css_classes: {
|
|
132
|
+
type: ParameterType.STRING,
|
|
133
|
+
pretty_name: "Custom CSS classes",
|
|
134
|
+
default: null,
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* Options to control simulation mode for the trial.
|
|
138
|
+
*/
|
|
139
|
+
simulation_options: {
|
|
140
|
+
type: ParameterType.COMPLEX,
|
|
141
|
+
default: null,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export type UniversalPluginParameters = InferredParameters<typeof universalPluginParameters>;
|
|
146
|
+
|
|
147
|
+
export interface PluginInfo {
|
|
148
|
+
name: string;
|
|
149
|
+
parameters: {
|
|
150
|
+
[key: string]: ParameterInfo;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface JsPsychPlugin<I extends PluginInfo> {
|
|
155
|
+
trial(
|
|
156
|
+
display_element: HTMLElement,
|
|
157
|
+
trial: TrialType<I>,
|
|
158
|
+
on_load?: () => void
|
|
159
|
+
): void | Promise<any>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type TrialType<I extends PluginInfo> = InferredParameters<I["parameters"]> &
|
|
163
|
+
UniversalPluginParameters;
|
|
164
|
+
|
|
165
|
+
export type PluginParameters<I extends PluginInfo> = InferredParameters<I["parameters"]>;
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import rw from "random-words";
|
|
2
|
+
|
|
3
|
+
export function repeat(array, repetitions, unpack = false) {
|
|
4
|
+
const arr_isArray = Array.isArray(array);
|
|
5
|
+
const rep_isArray = Array.isArray(repetitions);
|
|
6
|
+
|
|
7
|
+
// if array is not an array, then we just repeat the item
|
|
8
|
+
if (!arr_isArray) {
|
|
9
|
+
if (!rep_isArray) {
|
|
10
|
+
array = [array];
|
|
11
|
+
repetitions = [repetitions];
|
|
12
|
+
} else {
|
|
13
|
+
repetitions = [repetitions[0]];
|
|
14
|
+
console.log(
|
|
15
|
+
"Unclear parameters given to randomization.repeat. Multiple set sizes specified, but only one item exists to sample. Proceeding using the first set size."
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
} else {
|
|
19
|
+
// if repetitions is not an array, but array is, then we
|
|
20
|
+
// repeat repetitions for each entry in array
|
|
21
|
+
if (!rep_isArray) {
|
|
22
|
+
let reps = [];
|
|
23
|
+
for (let i = 0; i < array.length; i++) {
|
|
24
|
+
reps.push(repetitions);
|
|
25
|
+
}
|
|
26
|
+
repetitions = reps;
|
|
27
|
+
} else {
|
|
28
|
+
if (array.length != repetitions.length) {
|
|
29
|
+
console.warn(
|
|
30
|
+
"Unclear parameters given to randomization.repeat. Items and repetitions are unequal lengths. Behavior may not be as expected."
|
|
31
|
+
);
|
|
32
|
+
// throw warning if repetitions is too short, use first rep ONLY.
|
|
33
|
+
if (repetitions.length < array.length) {
|
|
34
|
+
let reps = [];
|
|
35
|
+
for (let i = 0; i < array.length; i++) {
|
|
36
|
+
reps.push(repetitions);
|
|
37
|
+
}
|
|
38
|
+
repetitions = reps;
|
|
39
|
+
} else {
|
|
40
|
+
// throw warning if too long, and then use the first N
|
|
41
|
+
repetitions = repetitions.slice(0, array.length);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// should be clear at this point to assume that array and repetitions are arrays with == length
|
|
48
|
+
let allsamples = [];
|
|
49
|
+
for (let i = 0; i < array.length; i++) {
|
|
50
|
+
for (let j = 0; j < repetitions[i]; j++) {
|
|
51
|
+
if (array[i] == null || typeof array[i] != "object") {
|
|
52
|
+
allsamples.push(array[i]);
|
|
53
|
+
} else {
|
|
54
|
+
allsamples.push(Object.assign({}, array[i]));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let out: any = shuffle(allsamples);
|
|
60
|
+
|
|
61
|
+
if (unpack) {
|
|
62
|
+
out = unpackArray(out);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function shuffle(array: Array<any>) {
|
|
69
|
+
if (!Array.isArray(array)) {
|
|
70
|
+
console.error("Argument to shuffle() must be an array.");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const copy_array = array.slice(0);
|
|
74
|
+
let m = copy_array.length,
|
|
75
|
+
t,
|
|
76
|
+
i;
|
|
77
|
+
|
|
78
|
+
// While there remain elements to shuffle…
|
|
79
|
+
while (m) {
|
|
80
|
+
// Pick a remaining element…
|
|
81
|
+
i = Math.floor(Math.random() * m--);
|
|
82
|
+
|
|
83
|
+
// And swap it with the current element.
|
|
84
|
+
t = copy_array[m];
|
|
85
|
+
copy_array[m] = copy_array[i];
|
|
86
|
+
copy_array[i] = t;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return copy_array;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function shuffleNoRepeats(arr: Array<any>, equalityTest: (a: any, b: any) => boolean) {
|
|
93
|
+
if (!Array.isArray(arr)) {
|
|
94
|
+
console.error("First argument to shuffleNoRepeats() must be an array.");
|
|
95
|
+
}
|
|
96
|
+
if (typeof equalityTest !== "undefined" && typeof equalityTest !== "function") {
|
|
97
|
+
console.error("Second argument to shuffleNoRepeats() must be a function.");
|
|
98
|
+
}
|
|
99
|
+
// define a default equalityTest
|
|
100
|
+
if (typeof equalityTest == "undefined") {
|
|
101
|
+
equalityTest = function (a, b) {
|
|
102
|
+
if (a === b) {
|
|
103
|
+
return true;
|
|
104
|
+
} else {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const random_shuffle = shuffle(arr);
|
|
111
|
+
for (let i = 0; i < random_shuffle.length - 1; i++) {
|
|
112
|
+
if (equalityTest(random_shuffle[i], random_shuffle[i + 1])) {
|
|
113
|
+
// neighbors are equal, pick a new random neighbor to swap (not the first or last element, to avoid edge cases)
|
|
114
|
+
let random_pick = Math.floor(Math.random() * (random_shuffle.length - 2)) + 1;
|
|
115
|
+
// test to make sure the new neighbor isn't equal to the old one
|
|
116
|
+
while (
|
|
117
|
+
equalityTest(random_shuffle[i + 1], random_shuffle[random_pick]) ||
|
|
118
|
+
equalityTest(random_shuffle[i + 1], random_shuffle[random_pick + 1]) ||
|
|
119
|
+
equalityTest(random_shuffle[i + 1], random_shuffle[random_pick - 1])
|
|
120
|
+
) {
|
|
121
|
+
random_pick = Math.floor(Math.random() * (random_shuffle.length - 2)) + 1;
|
|
122
|
+
}
|
|
123
|
+
const new_neighbor = random_shuffle[random_pick];
|
|
124
|
+
random_shuffle[random_pick] = random_shuffle[i + 1];
|
|
125
|
+
random_shuffle[i + 1] = new_neighbor;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return random_shuffle;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function shuffleAlternateGroups(arr_groups, random_group_order = false) {
|
|
133
|
+
const n_groups = arr_groups.length;
|
|
134
|
+
if (n_groups == 1) {
|
|
135
|
+
console.warn(
|
|
136
|
+
"shuffleAlternateGroups() was called with only one group. Defaulting to simple shuffle."
|
|
137
|
+
);
|
|
138
|
+
return shuffle(arr_groups[0]);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let group_order = [];
|
|
142
|
+
for (let i = 0; i < n_groups; i++) {
|
|
143
|
+
group_order.push(i);
|
|
144
|
+
}
|
|
145
|
+
if (random_group_order) {
|
|
146
|
+
group_order = shuffle(group_order);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const randomized_groups = [];
|
|
150
|
+
let min_length = null;
|
|
151
|
+
for (let i = 0; i < n_groups; i++) {
|
|
152
|
+
min_length =
|
|
153
|
+
min_length === null ? arr_groups[i].length : Math.min(min_length, arr_groups[i].length);
|
|
154
|
+
randomized_groups.push(shuffle(arr_groups[i]));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const out = [];
|
|
158
|
+
for (let i = 0; i < min_length; i++) {
|
|
159
|
+
for (let j = 0; j < group_order.length; j++) {
|
|
160
|
+
out.push(randomized_groups[group_order[j]][i]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function sampleWithoutReplacement(arr, size) {
|
|
168
|
+
if (!Array.isArray(arr)) {
|
|
169
|
+
console.error("First argument to sampleWithoutReplacement() must be an array");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (size > arr.length) {
|
|
173
|
+
console.error("Cannot take a sample larger than the size of the set of items to sample.");
|
|
174
|
+
}
|
|
175
|
+
return shuffle(arr).slice(0, size);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function sampleWithReplacement(arr, size, weights?) {
|
|
179
|
+
if (!Array.isArray(arr)) {
|
|
180
|
+
console.error("First argument to sampleWithReplacement() must be an array");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const normalized_weights = [];
|
|
184
|
+
if (typeof weights !== "undefined") {
|
|
185
|
+
if (weights.length !== arr.length) {
|
|
186
|
+
console.error(
|
|
187
|
+
"The length of the weights array must equal the length of the array " +
|
|
188
|
+
"to be sampled from."
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
let weight_sum = 0;
|
|
192
|
+
for (const weight of weights) {
|
|
193
|
+
weight_sum += weight;
|
|
194
|
+
}
|
|
195
|
+
for (const weight of weights) {
|
|
196
|
+
normalized_weights.push(weight / weight_sum);
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
for (let i = 0; i < arr.length; i++) {
|
|
200
|
+
normalized_weights.push(1 / arr.length);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const cumulative_weights = [normalized_weights[0]];
|
|
205
|
+
for (let i = 1; i < normalized_weights.length; i++) {
|
|
206
|
+
cumulative_weights.push(normalized_weights[i] + cumulative_weights[i - 1]);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const samp = [];
|
|
210
|
+
for (let i = 0; i < size; i++) {
|
|
211
|
+
const rnd = Math.random();
|
|
212
|
+
let index = 0;
|
|
213
|
+
while (rnd > cumulative_weights[index]) {
|
|
214
|
+
index++;
|
|
215
|
+
}
|
|
216
|
+
samp.push(arr[index]);
|
|
217
|
+
}
|
|
218
|
+
return samp;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function factorial(factors: Record<string, any>, repetitions = 1, unpack = false) {
|
|
222
|
+
let design = [{}];
|
|
223
|
+
for (const [factorName, factor] of Object.entries(factors)) {
|
|
224
|
+
const new_design = [];
|
|
225
|
+
for (const level of factor) {
|
|
226
|
+
for (const cell of design) {
|
|
227
|
+
new_design.push({ ...cell, [factorName]: level });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
design = new_design;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return repeat(design, repetitions, unpack);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function randomID(length = 32) {
|
|
237
|
+
let result = "";
|
|
238
|
+
const chars = "0123456789abcdefghjklmnopqrstuvwxyz";
|
|
239
|
+
for (let i = 0; i < length; i++) {
|
|
240
|
+
result += chars[Math.floor(Math.random() * chars.length)];
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Generate a random integer from `lower` to `upper`, inclusive of both end points.
|
|
247
|
+
* @param lower The lowest value it is possible to generate
|
|
248
|
+
* @param upper The highest value it is possible to generate
|
|
249
|
+
* @returns A random integer
|
|
250
|
+
*/
|
|
251
|
+
export function randomInt(lower: number, upper: number) {
|
|
252
|
+
if (upper < lower) {
|
|
253
|
+
throw new Error("Upper boundary must be less than or equal to lower boundary");
|
|
254
|
+
}
|
|
255
|
+
return lower + Math.floor(Math.random() * (upper - lower + 1));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Generates a random sample from a Bernoulli distribution.
|
|
260
|
+
* @param p The probability of sampling 1.
|
|
261
|
+
* @returns 0, with probability 1-p, or 1, with probability p.
|
|
262
|
+
*/
|
|
263
|
+
export function sampleBernoulli(p: number) {
|
|
264
|
+
return Math.random() <= p ? 1 : 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function sampleNormal(mean: number, standard_deviation: number) {
|
|
268
|
+
return randn_bm() * standard_deviation + mean;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function sampleExponential(rate: number) {
|
|
272
|
+
return -Math.log(Math.random()) / rate;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function sampleExGaussian(
|
|
276
|
+
mean: number,
|
|
277
|
+
standard_deviation: number,
|
|
278
|
+
rate: number,
|
|
279
|
+
positive = false
|
|
280
|
+
) {
|
|
281
|
+
let s = sampleNormal(mean, standard_deviation) + sampleExponential(rate);
|
|
282
|
+
if (positive) {
|
|
283
|
+
while (s <= 0) {
|
|
284
|
+
s = sampleNormal(mean, standard_deviation) + sampleExponential(rate);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return s;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Generate one or more random words.
|
|
292
|
+
*
|
|
293
|
+
* This is a wrapper function for the {@link https://www.npmjs.com/package/random-words `random-words` npm package}.
|
|
294
|
+
*
|
|
295
|
+
* @param opts An object with optional properties `min`, `max`, `exactly`,
|
|
296
|
+
* `join`, `maxLength`, `wordsPerString`, `separator`, and `formatter`.
|
|
297
|
+
*
|
|
298
|
+
* @returns An array of words or a single string, depending on parameter choices.
|
|
299
|
+
*/
|
|
300
|
+
export function randomWords(opts) {
|
|
301
|
+
return rw(opts);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Box-Muller transformation for a random sample from normal distribution with mean = 0, std = 1
|
|
305
|
+
// https://stackoverflow.com/a/36481059/3726673
|
|
306
|
+
function randn_bm() {
|
|
307
|
+
var u = 0,
|
|
308
|
+
v = 0;
|
|
309
|
+
while (u === 0) u = Math.random(); //Converting [0,1) to (0,1)
|
|
310
|
+
while (v === 0) v = Math.random();
|
|
311
|
+
return Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function unpackArray(array) {
|
|
315
|
+
const out = {};
|
|
316
|
+
|
|
317
|
+
for (const x of array) {
|
|
318
|
+
for (const key of Object.keys(x)) {
|
|
319
|
+
if (typeof out[key] === "undefined") {
|
|
320
|
+
out[key] = [];
|
|
321
|
+
}
|
|
322
|
+
out[key].push(x[key]);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return out;
|
|
327
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
interface turkInformation {
|
|
2
|
+
/**
|
|
3
|
+
* Is the experiment being loaded in preview mode on Mechanical Turk?
|
|
4
|
+
*/
|
|
5
|
+
previewMode: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Is the experiment being loaded outside of the Mechanical Turk environment?
|
|
8
|
+
*/
|
|
9
|
+
outsideTurk: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The HIT ID.
|
|
12
|
+
*/
|
|
13
|
+
hitId: string;
|
|
14
|
+
/**
|
|
15
|
+
* The Assignment ID.
|
|
16
|
+
*/
|
|
17
|
+
assignmentId: string;
|
|
18
|
+
/**
|
|
19
|
+
* The worker ID.
|
|
20
|
+
*/
|
|
21
|
+
workerId: string;
|
|
22
|
+
/**
|
|
23
|
+
* URL for submission of the HIT.
|
|
24
|
+
*/
|
|
25
|
+
turkSubmitTo: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Gets information about the Mechanical Turk Environment, HIT, Assignment, and Worker
|
|
30
|
+
* by parsing the URL variables that Mechanical Turk generates.
|
|
31
|
+
* @returns An object containing information about the Mechanical Turk Environment, HIT, Assignment, and Worker.
|
|
32
|
+
*/
|
|
33
|
+
export function turkInfo(): turkInformation {
|
|
34
|
+
const turk: turkInformation = {
|
|
35
|
+
previewMode: false,
|
|
36
|
+
outsideTurk: false,
|
|
37
|
+
hitId: "INVALID_URL_PARAMETER",
|
|
38
|
+
assignmentId: "INVALID_URL_PARAMETER",
|
|
39
|
+
workerId: "INVALID_URL_PARAMETER",
|
|
40
|
+
turkSubmitTo: "INVALID_URL_PARAMETER",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const param = function (url, name) {
|
|
44
|
+
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
|
45
|
+
const regexS = "[\\?&]" + name + "=([^&#]*)";
|
|
46
|
+
const regex = new RegExp(regexS);
|
|
47
|
+
const results = regex.exec(url);
|
|
48
|
+
return results == null ? "" : results[1];
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const src = param(window.location.href, "assignmentId")
|
|
52
|
+
? window.location.href
|
|
53
|
+
: document.referrer;
|
|
54
|
+
|
|
55
|
+
const keys = ["assignmentId", "hitId", "workerId", "turkSubmitTo"];
|
|
56
|
+
keys.map(function (key) {
|
|
57
|
+
turk[key] = unescape(param(src, key));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
turk.previewMode = turk.assignmentId == "ASSIGNMENT_ID_NOT_AVAILABLE";
|
|
61
|
+
|
|
62
|
+
turk.outsideTurk =
|
|
63
|
+
!turk.previewMode && turk.hitId === "" && turk.assignmentId == "" && turk.workerId == "";
|
|
64
|
+
|
|
65
|
+
return turk;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Send data to Mechnical Turk for storage.
|
|
70
|
+
* @param data An object containing `key:value` pairs to send to Mechanical Turk. Values
|
|
71
|
+
* cannot contain nested objects, arrays, or functions.
|
|
72
|
+
* @returns Nothing
|
|
73
|
+
*/
|
|
74
|
+
export function submitToTurk(data) {
|
|
75
|
+
const turk = turkInfo();
|
|
76
|
+
const assignmentId = turk.assignmentId;
|
|
77
|
+
const turkSubmitTo = turk.turkSubmitTo;
|
|
78
|
+
|
|
79
|
+
if (!assignmentId || !turkSubmitTo) return;
|
|
80
|
+
|
|
81
|
+
const form = document.createElement("form");
|
|
82
|
+
form.method = "POST";
|
|
83
|
+
form.action = turkSubmitTo + "/mturk/externalSubmit?assignmentId=" + assignmentId;
|
|
84
|
+
|
|
85
|
+
for (const key in data) {
|
|
86
|
+
if (data.hasOwnProperty(key)) {
|
|
87
|
+
const hiddenField = document.createElement("input");
|
|
88
|
+
hiddenField.type = "hidden";
|
|
89
|
+
hiddenField.name = key;
|
|
90
|
+
hiddenField.id = key;
|
|
91
|
+
hiddenField.value = data[key];
|
|
92
|
+
|
|
93
|
+
form.appendChild(hiddenField);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
document.body.appendChild(form);
|
|
98
|
+
form.submit();
|
|
99
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds all of the unique items in an array.
|
|
3
|
+
* @param arr The array to extract unique values from
|
|
4
|
+
* @returns An array with one copy of each unique item in `arr`
|
|
5
|
+
*/
|
|
6
|
+
export function unique(arr: Array<any>) {
|
|
7
|
+
return [...new Set(arr)];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function deepCopy(obj) {
|
|
11
|
+
if (!obj) return obj;
|
|
12
|
+
let out;
|
|
13
|
+
if (Array.isArray(obj)) {
|
|
14
|
+
out = [];
|
|
15
|
+
for (const x of obj) {
|
|
16
|
+
out.push(deepCopy(x));
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
} else if (typeof obj === "object" && obj !== null) {
|
|
20
|
+
out = {};
|
|
21
|
+
for (const key in obj) {
|
|
22
|
+
if (obj.hasOwnProperty(key)) {
|
|
23
|
+
out[key] = deepCopy(obj[key]);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
} else {
|
|
28
|
+
return obj;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
|
2
|
-
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
|
3
|
-
|
|
4
|
-
name: Jest Test
|
|
5
|
-
|
|
6
|
-
on: [ push, pull_request ]
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
build:
|
|
10
|
-
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v2
|
|
15
|
-
- name: Use Node.js
|
|
16
|
-
uses: actions/setup-node@v1
|
|
17
|
-
with:
|
|
18
|
-
node-version: '14.x'
|
|
19
|
-
- run: npm ci
|
|
20
|
-
- run: npm test
|